kex docs Standard Library

Net.DNS

module Net.DNS

Typed DNS lookup with explicit resolver ownership and bounded caching.

Use DNS.addresses for an occasional hostname lookup. Own a Resolver when a service performs repeated lookups, needs cache statistics, or must query a particular nameserver. Resolver ownership makes both caching and cleanup visible instead of hiding process-wide state behind every lookup.

using Net.DNS

let resolver = Resolver.system.try
let name = Name.parse("example.test").try
let addresses = resolver.addresses(name).try
resolver.close

record Name

A validated DNS name with caller-facing and IDNA ASCII spellings.

display keeps the readable form supplied by the caller; ascii is the wire-safe IDNA form used in DNS queries. Keeping both lets an error message say what the user typed without sending noncanonical labels to a resolver.

Fields

display
String
ascii
String

type RecordType

Record families supported by Resolver.lookup.

Variants

  • A
  • AAAA
  • CNAME
  • MX
  • TXT
  • SRV
  • PTR

type DNSSECStatus

DNSSEC state reported by the underlying resolver. Kex does not independently validate DNSSEC and therefore commonly reports Indeterminate.

Variants

  • Secure
  • Insecure
  • Bogus
  • Indeterminate

type DNSRecord

Typed DNS resource records, preserving MX/SRV priorities and TXT chunks.

Variants

  • AddressRecord(Net.IP.Address)
  • CanonicalName(Name)
  • MailExchange(Integer, Name)
  • TextRecord([String])
  • ServiceRecord(Integer, Integer, Net.Port, Name)
  • PointerRecord(Name)

record LookupResponse

Records and the reported DNSSEC state from one lookup.

Fields

records
[DNSRecord]

record CacheOptions

Bounds for a resolver-owned positive and negative cache.

Positive answers honor their DNS TTL up to maximumTtl. Failed lookups are cached for negativeTtl, preventing a missing hostname from hammering the configured nameserver on every request.

Fields

entries
Integer optional
maximumTtl
Duration optional
negativeTtl
Duration optional

record Nameserver

One DNS server used by a custom resolver.

Fields

address
Net.IP.Address
port
Net.Port

record ResolverOptions

Isolated resolver configuration. An empty search list only queries the name as written; search domains are tried in order for single-label names.

Fields

cache
CacheOptions optional
nameservers
[Nameserver]
search
[Name] optional
retries
Integer optional
timeout
Duration optional

record CacheStatistics

Lifetime cache counters. clear empties entries but keeps these counters.

Compare hits with misses when tuning entries or TTL bounds. A rising evictions count means the resolver is seeing more distinct names than its cache can retain.

Fields

entries
Integer
misses
Integer
negativeHits
Integer
evictions
Integer

type Resolver

An opaque, process-safe resolver that owns its cache.

Methods

addresses

addresses(name: Name) -> Result<[Net.IP.Address], NetError>

Resolves AAAA and A records, returning IPv6 addresses first.

This is the convenient operation for connecting to a host. Use lookup when record type, TTL-related behavior, or DNSSEC status matters.

Parameters
name
the validated hostname

Returns addresses or Resolve

Examples

Resolving an application upstream

let host = Name.parse("api.example.com").try
let addresses = resolver.addresses(host).try

lookup

lookup(kind: RecordType, name: Name) -> Result<LookupResponse, NetError>

Looks up one supported resource-record family.

Parameters
kind
the requested family
name
the validated owner name

Returns typed records or Resolve

Examples

Discovering a domain's mail exchangers

let response = resolver.lookup(MX, Name.parse("example.com").try).try
response.records.each { |record| IO.inspect(record) }

clear

clear : Void

Empties cached entries without resetting lifetime counters.

Existing statistics remain meaningful across a manual refresh, while the next lookup is forced back to DNS.

Examples

Refreshing service discovery after configuration changes

resolver.clear

statistics

statistics : CacheStatistics

Reports current occupancy and lifetime cache counters.

Returns current entries and lifetime counters

Examples

Reporting whether the cache is doing useful work

let stats = resolver.statistics
IO.printLine("DNS cache: ${stats.hits} hits, ${stats.misses} misses")

close

close : Void

Idempotently closes the resolver.

Calls after closing fail with Closed; closing again is harmless.

module Net.DNS.Name

Validation and IDNA conversion for DNS names.

parse

parse(text: String) -> Result<Name, NetError>

Validates a name and converts Unicode labels to IDNA ASCII.

Parameters
text
a dotted hostname, optionally with a trailing dot

Returns the name, or Parse

Examples

Preparing a user-supplied hostname for lookup

let name = Name.parse("münich.example").try
IO.printLine(name.display)
resolver.addresses(name).try

module Net.DNS.Resolver

Constructors for long-lived, cache-owning resolvers.

system

system(cache: CacheOptions) -> Result<Resolver, NetError>

Opens a resolver using system configuration and default cache bounds.

Reuse the returned resolver for the lifetime of a service so repeated names benefit from its bounded cache, then close it during shutdown.

Returns a resolver handle

Examples

A service-owned resolver

let resolver = Resolver.system.try
let upstream = resolver.addresses(Name.parse("api.example.com").try).try
resolver.close

custom

custom(options: ResolverOptions) -> Result<Resolver, NetError>

Opens an isolated resolver with typed nameservers and query bounds.

This does not inherit the machine's search domains or nameservers. It is useful for tests, service discovery, and applications with their own DNS policy.

Parameters
options
nameservers, search domains, retry count,

Returns a resolver, or Parse

Examples

Querying a DNS server used by a local integration test

let nameserver = Nameserver {
  address: Net.IP.Address.parse("127.0.0.1").try,
  port: Net.Port.from(5353).try
}
Resolver.custom(ResolverOptions {
  nameservers: [nameserver],
  timeout: 100.milliseconds
}).try

module Net.DNS.DNS

Convenience lookup operations for callers that do not need resolver ownership or cache reuse.

addresses

addresses(name: Name) -> Result<[Net.IP.Address], NetError>

Resolves a name once with a short-lived system resolver.

Prefer this for command-line tools and one-off checks. A server that looks up names repeatedly should own a Resolver so it can reuse cached answers.

Parameters
name
the validated hostname

Returns addresses or Resolve

Examples

Resolving one host in a short-lived command

let addresses = DNS.addresses(Name.parse("example.com").try).try