std.dns

import std.dns

dns.resolve("ecko.sh")              # A/AAAA addresses
dns.resolve("ecko.sh", "MX")        # a record type
dns.reverse("93.184.216.34")        # PTR
dns.lookup("ecko.sh")               # the system resolver

Needs net. Record types: A, AAAA, CNAME, MX, TXT.

resolve or lookup

lookup uses the system resolver, so it honours /etc/hosts, your search domains and any local DNS configuration. That is what you want to answer "what would this machine connect to?"

resolve queries DNS for a specific record type, which is what you want to inspect a domain's actual records - MX before sending mail, TXT for a verification token.

MX records

for mx in dns.resolve("example.com", "MX") {
    print("{mx.priority} {mx.host}")
}

Sorted by priority, lowest first - which is delivery order. Pair with smtp.

Errors

A name that does not resolve raises { kind: "net", host } rather than returning an empty list, so a typo does not read as "no records". Catch it where the name came from outside:

try { addrs = dns.resolve(domain) } catch (e) { reject("unknown host") }

DNS is not validation

Two habits worth having:

  • Resolving a domain does not mean an address is deliverable. A valid MX record

says nothing about whether the mailbox exists. Only sending finds that out.

  • DNS answers change. They are cached, they vary by resolver, and they are

attacker-influenceable on a hostile network. Do not use a DNS result as an authorization decision.

Not for connecting

You do not need to resolve before connecting - std.net and std.http take a hostname and resolve it themselves. Resolving first and connecting to the address means you lose TLS hostname verification unless you are careful, so pass the name.