Reference

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

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

  • NetworkError that isTimedOut() where no server answered in any round, or the failure of the last attempt.
  • NetworkError where 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

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.