std/network/dns
std/network/src/dns.trb
DNS lookups: the stub resolver that asks a recursive name server for the records of a name (docs/design/DNS.md
section 7). The messages are std/dns's values; this module moves their bytes - over UDP, and over TCP where a
response came back truncated (RFC 7766) - with a timeout per attempt and every server of the list tried in turn.
resolve(host) stays what connecting uses: the system's own resolver, with its cache, its hosts file and its search
domains. lookup is for a program that wants records rather than addresses - MX, TXT, SRV, HTTPS - or wants
to ask a server of its own choosing.
type Resolver
type Resolver
How lookup asks: which name servers, how long an attempt waits, and how many rounds over the servers it makes. The
default asks the servers the system is configured with - the adapters' on Windows, /etc/resolv.conf elsewhere - two
seconds per attempt, two rounds.
const resolver = Resolver(servers: [SocketAddress(IpAddress.tryFrom("192.0.2.53")?, 53)])
const records = resolver.lookup(DomainName.tryFrom("example.test")?, RecordType.Mx).await()?
Times are milliseconds, because a field's default is a constant and a Duration is none.
field servers
servers: List<SocketAddress> = []
The recursive name servers to ask, in order; empty asks the ones the system is configured with.
field attemptMilliseconds
attemptMilliseconds: Int = 2000
How long one attempt - one datagram to one server, or one exchange over TCP - waits for its answer.
field rounds
rounds: Int = 2
How many times each server is asked before the lookup gives up.
fn lookup
fn lookup(name: DomainName, recordType: RecordType): Task<Result<List<Record>, NetworkError>>
The records of recordType that name has, CNAME chains followed within the answer: what a stub resolver answers.
A name that exists without such records answers an empty list.
Errors
NetworkErrorthatisHostNotFound()where the name does not exist (NXDOMAIN).- Every failure of
Resolver.exchange.
fn exchange
fn exchange(name: DomainName, recordType: RecordType): Task<Result<Message, NetworkError>>
The whole response to a query for recordType at name: each server in turn is asked over UDP, with a random
identifier and a new socket per attempt, so an answer that does not match the question - another query's, a stale
one, a forged one - is dropped rather than read. A truncated response is asked again over TCP of the same server
(RFC 7766). A server that answers SERVFAIL, REFUSED or NOTIMP, or not at all within the attempt's time, hands
the question to the next one; NXDOMAIN and an empty answer are answers.
Errors
NetworkErrorthatisTimedOut()where no server answered in any round, or the failure of the last attempt.NetworkErrorwhere the system is configured with no name server and none was given.
fn lookup
fn lookup(name: DomainName, recordType: RecordType): Task<Result<List<Record>, NetworkError>>
The records of recordType that name has, asked of the name servers the system is configured with: Resolver()'s
Resolver.lookup.
const exchanges = lookup(DomainName.tryFrom("example.test")?, RecordType.Mx).await()?
fn systemNameServers
fn systemNameServers(): Result<List<SocketAddress>, NetworkError>
The name servers the system is configured with, in its order, on port 53: the servers of the network adapters that
are up on Windows, the nameserver lines of /etc/resolv.conf elsewhere.
Errors
NetworkErrorwhere the system names none.
fn randomQueryIdentifier
fn randomQueryIdentifier(): Int
A random identifier for a DNS query, from the system's randomness (RFC 5452 section 9.2): what every transport of DNS draws for each question it sends, so that a forged answer has to guess it.