RouteHardenHire us
Back to Networking Fundamentals
Networking Fundamentals · Part 9 of 12·Network Hardening··21 min read·intermediate

DNS — name resolution end to end

DNS from first principles: zones, delegation, recursive vs authoritative resolvers, the wire format, caching, DNSSEC, DoH/DoT/DoQ, and where privacy actually leaks.

DNS is the protocol that makes the internet usable for humans, and getting any of it slightly wrong makes everything slightly broken. Almost every other protocol on the modern internet — HTTP, TLS, SMTP, even cookies and CDNs — has at least one DNS lookup in its critical path. The system has been running, with substantively the same wire format, since 1987. It's also the most widely-misunderstood protocol in everyday operations, partly because the everyday model (example.com "is" an IP) hides the layers of caching, delegation, and metadata signaling that actually drive behavior. This module is the foundational pass: enough to read a packet capture of a real lookup, explain why DNSSEC isn't encryption, and have a defensible opinion about whether DoH or DoT is the privacy-preserving choice for your network.

Prerequisites

Learning objectives

By the end of this module you should be able to:

  1. Trace a DNS lookup from stub resolver, through recursive resolver, root, TLD, and authoritative servers, naming who does which work.
  2. Decode the major fields of a DNS message — header, question, answer/authority/additional sections, label encoding, EDNS — and recognize why compression and TTLs matter.
  3. Explain what DNSSEC authenticates, what it doesn't, and how the chain of trust is built from the root.
  4. Compare classic UDP/TCP DNS, DNS-over-TLS (DoT), DNS-over-HTTPS (DoH), and DNS-over-QUIC (DoQ) on the dimensions that actually differ — privacy from path observers, privacy from resolvers, latency, deployability.
  5. Use dig to inspect zone delegation, DNSSEC chains, and TCP fallback behavior.

DNS is a distributed database with a small query language

The folk model of DNS as a "phone book" is wrong in a way that breaks operational reasoning. A phone book is a single book everyone consults. DNS is a distributed, cached, delegated database — keyed by names and record types — where no single party holds the whole thing and the system's correctness depends on a long chain of trust between administrators.

Conceptually, the database is an inverted tree. The root sits at the top, with empty label .. Below it sit the top-level domains (TLDs): com., org., net., io., country codes like cn. de. jp., and a long list of generic ones. Below each TLD sit the second-level domains administered by individual registrants: example.com., routeharden.com.. Below those sit anything the owner wants: mail.example.com., www.routeharden.com., etc.

A zone is a contiguous subtree of this database administered as a unit. A zone has one or more authoritative servers — machines that hold the zone's data and can answer questions about it definitively. Authority for a zone can be delegated to other servers for child subtrees: routeharden.com.'s authoritative servers might delegate eu.routeharden.com. to a different set of servers entirely. The delegation appears as NS records in the parent zone pointing at the child's authoritative servers.

Every record in DNS has a type. The common ones:

  • A — an IPv4 address.
  • AAAA — an IPv6 address.
  • CNAME — a canonical name, an alias for another name.
  • MX — mail exchanger for the zone.
  • NS — nameserver for the zone.
  • TXT — arbitrary text. Used for SPF, DKIM, domain-verification tokens.
  • SRV — service record locating a service within a zone (_imaps._tcp.example.com).
  • HTTPS and SVCB — modern records for HTTPS endpoint discovery (RFC 9460), bringing protocol selection and ALPN hints into DNS.

A name plus a type identifies a resource record set (RRset): all records of that type at that name. A query asks for a specific name and type; an answer is one or more records from the matching RRset.

The query language is intentionally small — name, type, class — because the protocol's design assumed clients would be small, embedded, or both. Everything that looks like complexity in DNS is actually layered on top of those three fields: caching policy, security extensions, encrypted transports, modern endpoint hints. The wire format barely changes; the surrounding ecosystem does.

Stub resolver vs recursive resolver

A typical client interaction with DNS looks like this:

  1. The application calls getaddrinfo() (or equivalent) to resolve www.example.com.
  2. The OS's stub resolver sends a single query to a configured recursive resolver — typically the LAN's DHCP-supplied resolver, or a public one like 8.8.8.8 or 1.1.1.1.
  3. The recursive resolver does the actual work of asking root, TLD, and authoritative servers in turn — or returns a cached answer if it has one.
  4. The recursive resolver sends back the final answer.
  5. The stub resolver returns it to the application.

The split is important. The stub resolver is small, simple, and trusts whoever it's configured to talk to. The recursive resolver is the one that knows how to walk delegation chains, follow NS referrals, manage cache state, and generally hold the operational complexity. End-user devices don't do recursion themselves; they outsource it.

Why does this matter? Because the configuration of "which recursive resolver" governs an enormous amount of your network's privacy and performance:

  • The recursive resolver sees every domain you query. It can log them, build a profile, sell the data, or be coerced into doing so by its operator's jurisdiction.
  • The recursive resolver's cache determines latency. A cache miss means the resolver has to walk the delegation chain to authoritative servers — multiple round trips. A cache hit returns instantly.
  • The recursive resolver enforces (or doesn't) DNSSEC validation. If the resolver validates, your client gets cryptographic guarantees. If it doesn't, those guarantees are absent regardless of the zone's signing.

ISPs typically run their own recursive resolvers and configure customers to use them via DHCP. Public alternatives — Google's 8.8.8.8, Cloudflare's 1.1.1.1, Quad9's 9.9.9.9 — are commonly used by privacy-conscious users, though the privacy story varies by operator. The choice is yours; the model is that you pick a resolver you trust to do recursion on your behalf.

The resolution walk

Suppose your laptop has just been told to resolve www.example.com. and your recursive resolver has nothing in cache. Here's what happens:

Step 1: ask a root nameserver. The resolver picks one of the 13 root server addresses (which it has hardcoded — root server addresses are a.root-servers.net through m.root-servers.net; in practice each address is anycast to many physical servers). It sends a query for www.example.com. A to the chosen root.

Step 2: receive a referral to .com. The root doesn't know about www.example.com.. It does know about .com.. It returns NS records pointing at the .com. TLD nameservers (a.gtld-servers.net, b.gtld-servers.net, etc.) plus glue (their IP addresses).

Step 3: ask a .com. TLD nameserver. Resolver picks one of the .com. nameservers and asks for www.example.com. A.

Step 4: receive a referral to example.com.'s authoritative servers. The TLD nameserver returns NS records pointing at example.com.'s authoritative servers — typically a set the registrant designated when registering the domain.

Step 5: ask example.com.'s authoritative server. Finally, the resolver asks for www.example.com. A directly.

Step 6: get the answer. The authoritative server returns one or more A records for www.example.com.. The answer is marked authoritative (the AA bit is set in the response header) and includes a TTL.

Step 7: cache and return. The resolver caches the answer for the duration of the TTL and returns it to the stub.

In a real environment, most of these steps are skipped because the resolver has cached intermediate answers from previous queries. The resolver's cache holds the root NS records for days, the TLD NS records for hours, and the final A record for whatever TTL the authoritative set on it. A typical lookup for a popular domain is a single round trip from resolver to authoritative — or zero, if the answer is fully cached.

The recursive resolver is doing work; the stub resolver is just asking. This is also why your laptop's "DNS query" view is misleadingly simple — it sees one packet out and one packet in. The real complexity lives at the recursive resolver.

A practical exercise: run dig +trace www.example.com and watch the recursive walk. The +trace flag tells dig to do its own recursion locally rather than asking a configured resolver, so each step is visible. You'll see the root, TLD, and authoritative answers in order.

DNS wire format

A DNS message has five sections:

+------------+
|  Header    |   12 bytes, fixed
+------------+
|  Question  |   the question(s) being asked
+------------+
|  Answer    |   resource records answering the question
+------------+
|  Authority |   resource records pointing at authoritative servers
+------------+
| Additional |   extra useful info, especially glue
+------------+

The header is 12 bytes:

  • ID (16 bits) — chosen by the requester, echoed in the response. Used to match responses to outstanding queries.
  • Flags (16 bits) — QR (query/response), opcode, AA (authoritative answer), TC (truncated), RD (recursion desired), RA (recursion available), RCODE (response code), and a few others.
  • Counts of questions, answers, authority records, and additional records.

A question is <name, type, class>. Class is almost always IN (Internet). The name is encoded as a sequence of length-prefixed labels: \x03www\x07example\x03com\x00. The terminating null byte is the root.

A resource record in answer/authority/additional sections is <name, type, class, TTL, data length, data>. The data depends on the type — 4 bytes for A, 16 bytes for AAAA, a name for NS, etc.

Two wire-format details that bite the unwary:

Label compression. A name appearing multiple times in a message is encoded once and referenced by offset thereafter. Compression pointers are 16-bit values where the top two bits are 11 and the lower 14 bits are an offset into the message. This makes dig's "name foo.bar.com" appear as a 2-byte pointer rather than a re-encoded label sequence in tightly-packed responses.

512-byte UDP limit. Classic DNS over UDP has a hard 512-byte response size limit. Larger responses set the TC (truncated) flag, signaling the client to retry over TCP. This was reasonable in 1987 and is awkward in 2026 because DNSSEC signatures push response sizes well beyond 512 bytes routinely.

EDNS (Extension Mechanisms for DNS) extends UDP DNS beyond 512 bytes via an OPT pseudo-record in the additional section. The client advertises a larger receive size (typically 1232 bytes for IPv6 safety, 4096 for IPv4 networks); the server responds in segments up to that size. EDNS is universally supported on modern resolvers and authoritative servers.

Caching, TTLs, and negative answers

DNS performance and behavior is dominated by caching. The TTL field on every record tells caches how long the record can be considered fresh. Common values:

  • A few seconds for highly dynamic records (load balancers).
  • Minutes to hours for typical service A/AAAA records.
  • Days to weeks for stable infrastructure (NS records, MX records).

A cache that's holding a record can answer queries for it directly without going back to authoritative servers. This is the operational lifeline of DNS — without caching, root and TLD servers would be unable to handle the query volume of the modern internet.

Two subtleties:

Negative caching. When a query asks for a name that doesn't exist, the response is NXDOMAIN. Caches store this negative answer for a duration controlled by the SOA record's MINIMUM field — typically minutes to an hour. So if you accidentally type www.exaample.com and your resolver caches the NXDOMAIN, retrying the correct spelling does work, but a follow-up typo of the same wrong name will hit the cache.

TTL is a hint, not a guarantee. A cache may evict records before TTL expires (memory pressure) or hold them longer (broken caches that ignore TTL). Most well-run caches respect TTL within reason. But "set TTL to 5 seconds and expect global propagation in 5 seconds" is not how DNS works in practice; some caches will hold for longer, some for shorter, and the operational reality is that DNS changes propagate over hours, not seconds.

Transport evolution: UDP, TCP, DoT, DoH, DoQ

Classic DNS uses UDP on port 53 by default and TCP on port 53 as fallback for large responses or zone transfers. Both are unencrypted: any router on the path can see queries and answers in plaintext, and so can ISPs and corporate firewalls.

The privacy gap was identified for years before someone built the practical fixes. The modern encrypted transports:

DoT (DNS-over-TLS, RFC 7858, 2016). DNS messages over TLS 1.2+ on TCP port 853. Provides confidentiality and integrity from path observers. The resolver is identified by hostname and authenticated by certificate. Operationally similar to running TLS to a known DoT-capable resolver like 1.1.1.1 or 9.9.9.9. Easy to block at the network level (anyone can drop port 853).

DoH (DNS-over-HTTPS, RFC 8484, 2018). DNS messages encoded as HTTP requests over HTTPS, typically to a /dns-query endpoint. Indistinguishable on the wire from regular HTTPS traffic, which makes it harder for networks to selectively block. The downside: it's also harder for legitimate network operators to inspect DNS-driven traffic for security purposes. DoH's deployment has been politically charged for exactly this reason.

DoQ (DNS-over-QUIC, RFC 9250, 2022). DNS messages over QUIC. Combines DoT-style direct queries with QUIC's faster connection setup and stream multiplexing. Increasingly common; supported by Cloudflare, Adguard, and others.

The privacy story for each:

  • All three hide query content from on-path observers.
  • All three reveal that "this client is talking to this resolver," which is partial metadata.
  • None of them provide privacy from the resolver. The resolver sees every query, just like with classic DNS.

So "encrypted DNS" reduces leakage to network observers but doesn't remove leakage to whoever runs the resolver. Picking a resolver you trust matters more than picking the encrypted transport, in many threat models.

DNSSEC

DNSSEC (RFC 4033 family) adds data origin authentication and integrity to DNS responses. It does not add confidentiality. Encrypted transports (DoT/DoH/DoQ) are confidentiality; DNSSEC is authenticity.

The mechanism is digital signatures attached to RRsets. Each authoritative zone has a key pair (the zone signing key, ZSK). Records in the zone are signed with the ZSK, producing RRSIG records that travel alongside the data. A resolver receiving a signed response can verify the signature using the ZSK; the ZSK itself is published as a DNSKEY record in the zone.

This shifts the trust problem one level up: how does the resolver trust the ZSK? The answer is the chain of trust:

  1. The zone's ZSK is signed by the zone's key signing key (KSK).
  2. The KSK's hash is published in the parent zone as a DS (Delegation Signer) record.
  3. The parent zone's DS record is itself signed by the parent's ZSK.
  4. The parent zone's ZSK is signed by its parent's KSK, and so on...
  5. Up to the root. The root zone's KSK is the trust anchor — its hash is hardcoded into validating resolvers.

The chain bottoms out at the root. Every signed zone's authenticity can, in principle, be verified by walking up the chain to the root and confirming each signature with each parent's published DS.

What DNSSEC catches:

  • Forged answers that would otherwise pass UDP-level checks.
  • Cache poisoning attacks where an attacker injects fake records.
  • Authoritative compromise where the attacker doesn't have the zone's signing keys.

What DNSSEC doesn't catch:

  • A compromise of the signing keys themselves.
  • A resolver that doesn't validate (most ISP resolvers historically didn't; modern public resolvers do).
  • Anything outside DNS — DNSSEC says nothing about whether the IP address you got is the right one for the service you wanted.

DNSSEC adoption has been slow but steady. The root and most TLDs are signed; the second-level zone landscape is mixed. Enterprise zones are often signed; consumer zones rarely are. As of 2026, roughly a third of the public DNS zone landscape is signed.

Privacy failure modes

Even with DoT/DoH/DoQ and a trusted resolver, several leakage vectors remain:

EDNS Client Subnet (ECS). A resolver can include the client's subnet (truncated for privacy) in its query to authoritative servers, so the auth server can return a geographically-appropriate answer for CDN purposes. This leaks the client's approximate location to every authority queried. Cloudflare and Quad9 don't use ECS; Google's 8.8.8.8 does. Pick accordingly if location-leakage matters.

Resolver centralization. When you pick a public resolver, that operator sees all your queries. Switching from your ISP's resolver to 1.1.1.1 doesn't eliminate the privacy risk; it concentrates it in one place. Operators of public resolvers commit to privacy policies, but the threat model where you don't trust them remains.

Last-hop visibility. Even with encrypted DNS, the IP addresses your subsequent connections target are visible. If you DoH-resolve nytimes.com to 151.101.x.x and then make an HTTPS connection to 151.101.x.x, network observers know you connected to that IP. The DNS query is hidden, but the destination address is right there in the IP packet. SNI (the hostname in TLS) historically leaked too; ECH (Encrypted Client Hello, RFC 9180) is the recent fix.

Local resolver weirdness. Some networks (corporate, captive-portal Wi-Fi) intercept DNS traffic and substitute their own answers. A captive portal does this so unauthenticated browsers get redirected to the portal page. A corporate firewall does it for security policy. Both break encrypted DNS at the local network — DoT/DoH/DoQ to public resolvers is dropped or rerouted. The fix is recognizing the network's behavior and either accepting the local resolver or refusing to use the network.

Modern service discovery: SVCB and HTTPS records

RFC 9460 (2023) added SVCB and HTTPS record types — modern service binding that lets DNS announce protocol information beyond just IP addresses.

An HTTPS record can include:

  • Alternative endpoint targets (alpn=h3,h2, port=443).
  • IP hints (ipv4hint=..., ipv6hint=...) so the client doesn't need a separate A/AAAA query.
  • ECH configuration for the destination (the ech=... parameter).

This collapses three round trips (A query → AAAA query → ALPN negotiation in TLS) into one. Browsers that support HTTPS records can resolve, learn the protocol preferences, and start the connection in fewer round trips than the legacy A/AAAA → TCP → TLS sequence.

The HTTPS record is also the deployment mechanism for Encrypted Client Hello at scale: domains publish ech= in their HTTPS record, clients pick it up, and the SNI in the TLS handshake stops leaking the destination hostname.

This is the future of DNS-driven endpoint selection. Adoption is partial — major CDNs publish HTTPS records, but consumer browsers' use of them is still rolling out. By the late 2020s it should be the default path for browser HTTPS connections.

Hands-on exercise

Exercise 1 — Trace a real lookup

dig +trace www.example.com

Annotate the output:

  1. First block — the resolver asking . (root). Answer is a list of root NS records.
  2. Second block — the resolver asking a root server for www.example.com.. Answer is a referral: NS records for .com. plus glue.
  3. Third block — the resolver asking a .com. server. Answer is a referral to example.com.'s authoritative servers.
  4. Fourth block — the resolver asking example.com.'s authoritative server. Answer is the actual A record(s).

Each step is one round trip in the recursive walk. In a normal cached resolver, most of these steps are skipped — only the deepest cache miss requires the full walk.

Stretch: repeat for a DNSSEC-signed domain like cloudflare.com and add +dnssec:

dig +trace +dnssec cloudflare.com

You'll see RRSIG records accompanying the answers. Each level of the trace shows the resolver gathering signed evidence to validate the next.

Exercise 2 — Inspect DNSSEC material

dig +dnssec org DNSKEY
dig +dnssec org DS @a.root-servers.net

The first command asks org's authoritative server for its DNSKEY set — the public keys with which records in .org are signed. The second asks the root for the DS record for org — the hash that proves the org DNSKEY set is genuine.

If you concatenate these — the root signs the DS for org, the DS hash matches one of org's DNSKEYs, and that DNSKEY signs records in org — you have the chain of trust from the root down to org. Validating resolvers do this on every query for a signed zone.

Exercise 3 — UDP vs TCP fallback

dig example.com
dig +tcp example.com

Both should return the same answer. The TCP variant explicitly asks for transport over TCP; the default uses UDP. Compare the round-trip times — TCP adds a handshake, so it's slower. But for large responses or zone transfers (AXFR), TCP is required; if the response would exceed UDP's size limit (around 1232 bytes for IPv6-safe networks, larger for IPv4), the server sets the TC flag and the resolver retries over TCP automatically.

To force a large response and watch the TCP fallback, query a DNSSEC-heavy domain:

dig +bufsize=512 +dnssec cloudflare.com

Limiting the EDNS buffer to 512 bytes forces the response to be truncated, which forces the resolver to retry over TCP. The timing difference shows the cost.

Common misconceptions

"DNS just maps names to IPs." It maps names to typed records. A CNAME points at another name. An MX record names a mail exchanger. An SRV record names a service endpoint. An HTTPS record names protocol preferences. The "name to IP" model is one specific case.

"The authoritative server is what my laptop talks to." Almost never. Your laptop talks to a recursive resolver, which talks to authoritative servers on your behalf. The recursive resolver does the actual work; your laptop sees one query and one answer.

"DNSSEC encrypts DNS." DNSSEC authenticates. It proves "this answer was signed by the zone's key, and the key is trustworthy via the chain to the root." It says nothing about confidentiality. For confidentiality you need DoT, DoH, or DoQ — separate mechanisms with separate threat models.

"DoH is always more private than DoT." Both hide query content from on-path observers. Their privacy stories diverge on (a) whether networks can identify and block them — DoT is easier to block, DoH harder; (b) who sees the query content at the destination — same set of resolvers, same trust required. The choice is more political (block-resistance) than technical (privacy).

"TTL is a freshness guarantee." TTL is the upper bound on how long a cache may legitimately hold the record before re-fetching. A cache may evict earlier (memory pressure) or may misbehave and hold longer. DNS changes propagate over hours regardless of how short you set TTLs.

Further reading

  1. RFC 1034 — Domain Names: Concepts and Facilities and RFC 1035 — Domain Names: Implementation and Specification. The 1987 specifications. Still substantively current — read once for the conceptual foundation.
  2. RFC 6891 — EDNS. The extension mechanism that makes modern DNS not crash on responses larger than 512 bytes.
  3. RFC 4033, 4034, 4035 — DNSSEC family. The authentication system and how the chain of trust works.
  4. RFC 8484 — DNS-over-HTTPS. The DoH spec.
  5. RFC 7858 — DNS-over-TLS. The DoT spec.
  6. RFC 9250 — DNS-over-QUIC. The DoQ spec, the most recent encrypted-transport addition.
  7. RFC 9460 — Service Binding (SVCB / HTTPS records). The modern endpoint-selection mechanism that's gradually replacing legacy A/AAAA queries for HTTPS targets.
  8. Paul Vixie's "What DNS Is Not" essay (search for Communications of the ACM, 2009). A working DNS architect's plea about treating DNS like the global database it is rather than the configuration file it isn't.

The next module — HTTP evolution: 1.1 to 3 — picks up where DNS stops, and follows what happens after a hostname becomes an IP — through TCP setup, TLS, and the HTTP request/response semantics that have evolved more in the last ten years than in the previous twenty.