What Actually Happens When You Resolve a Domain Name
You type example.com in your browser. Milliseconds later, the page loads. What happened in between?
Most developers know DNS "turns names into IPs." Few can explain what actually happens when the cache is cold. Let's trace the full path—from your stub resolver to the root servers, through TLDs, to the authoritative answer—and the protocol details that make it work.
The Big Picture
DNS resolution is a distributed delegation chain. No single server knows everything. Each server knows only its zone and where to find the next level down.
Client → Stub Resolver → Recursive Resolver → Root → TLD → Authoritative → Answer
Your browser doesn't talk to root servers. It talks to a stub resolver (OS DNS client). That stub forwards to a recursive resolver (your ISP, 1.1.1.1, 8.8.8.8, or a local Unbound/BIND). The recursive resolver does the heavy lifting.
Step 0: The Cache Check
Before any network traffic, the recursive resolver checks its cache:
- Exact match? Return immediately.
- CNAME chain? Follow it, then return the final target.
- Negative cache (NXDOMAIN/NODATA)? Return "doesn't exist" without querying upstream.
- Partial match (NS records for a parent zone)? Start from there—this is the closest delegation point.
If the cache is cold (resolver just restarted), it has only root hints: a built-in list of 13 root server names (a.root-servers.net through m.root-servers.net) and their IPs.
Step 1: Priming — Getting the Real Root List
Root hints are hints. They can be stale. Before trusting them, the resolver sends a priming query (RFC 8109):
QNAME: . (root)
QTYPE: NS
RD: 0 or 1 (undefined for priming)
EDNS(0): YES, UDP payload ≥ 1024 bytes
DO bit: optionally set
Sent to one root hint address (selected randomly to spread load). The root responds with:
-
Answer section: NS RRset for
.(the 13 root server names) - Additional section: A/AAAA records for those names (glue records)
- AA bit = 1: authoritative answer
This primes the resolver with the current, authoritative root NS set and addresses. TTL is typically 6 days (518,400 seconds).
Step 2: The Descent — Iterative Queries
Now the resolver has a working root NS set. It begins iterative resolution (RD=0) for www.example.com:
Query to Root (.)
QNAME: www.example.com (or minimized: com — see QNAME minimization below)
QTYPE: A (or AAAA)
RD: 0
Root doesn't know example.com. It's only authoritative for .. It responds with a referral:
-
Authority section: NS records for
.com(the TLD nameservers) -
Additional section: Glue A/AAAA for those NS names (e.g.,
a.gtld-servers.net)
Query to TLD (.com)
Resolver picks one .com nameserver, sends:
QNAME: www.example.com (or minimized: example.com)
QTYPE: A
RD: 0
TLD server isn't authoritative for example.com either. Another referral:
-
Authority: NS records for
example.com(your domain's authoritative nameservers) -
Additional: Glue records if the NS names are inside
example.com(e.g.,ns1.example.com)
Query to Authoritative (example.com)
Resolver picks one authoritative NS for example.com:
QNAME: www.example.com
QTYPE: A
RD: 0
This server is authoritative. It responds with:
-
Answer section: The A record (e.g.,
93.184.216.34) - AA bit = 1: "I own this data"
- TTL: How long to cache (e.g., 3600 seconds)
Resolver caches the answer, the NS records, and glue—and returns it to the stub resolver.
QNAME Minimization: Privacy by Design (RFC 7816 / 9156)
Traditional resolvers send the full QNAME (www.example.com) to every server in the chain. The root doesn't need www.example.com—it only needs .com. The TLD only needs example.com.
QNAME minimization sends only what each server needs:
| Server | Traditional Query | Minimized Query |
|---|---|---|
| Root |
www.example.com A |
com NS |
| TLD |
www.example.com A |
example.com NS |
| Auth |
www.example.com A |
www.example.com A |
The resolver tracks zone cuts (delegation boundaries) in its cache. When it doesn't know where the cut is, it probes one label at a time (NS queries), caching NODATA responses to learn the boundary.
Why it matters: Root servers see only com, not your full browsing history. Reduces data exposure to authoritative operators. Also enables aggressive negative caching (RFC 8020): if .example doesn't exist, nothing under it exists either.
EDNS(0): Breaking the 512-Byte Limit (RFC 6891)
Original DNS: 512-byte UDP max. DNSSEC responses (with RRSIG, DNSKEY, NSEC) routinely exceed this.
EDNS(0) adds an OPT pseudo-record in the additional section:
NAME: . (root)
TYPE: OPT (41)
CLASS: Requestor's UDP payload size (e.g., 4096)
TTL: Extended RCODE (high 8 bits) + flags (DO bit in bit 15)
RDATA: Variable {option-code, option-length, option-data} tuples
Key fields:
- UDP payload size: "I can receive this many bytes." Default 4096. Values < 512 treated as 512.
- DO bit (DNSSEC OK): "Send me DNSSEC records."
- Options: COOKIE (RFC 7873), ECS (RFC 7871), PADDING, etc.
If a responder can't fit the answer in the advertised size, it sets TC=1 (truncated). Resolver retries over TCP.
Middlebox warning: Firewalls/load balancers that strip OPT records or block >512-byte UDP break DNSSEC and large responses. RFC 6891 says they MUST NOT do this—but they do.
The Kaminsky Attack & Why Source Port Randomization Matters
In 2008, Dan Kaminsky showed how to poison a resolver's cache off-path.
The vulnerability: Resolvers accepted the first response matching:
- Query name + QTYPE
- 16-bit Transaction ID (TXID)
- Source/destination IP
- Source/destination port (often fixed at 53)
Attacker floods resolver with spoofed responses, guessing TXID. With fixed source port, only 65,536 guesses needed—trivial.
The fix: Source port randomization (RFC 5452). Resolver picks a random ephemeral source port per query. Now attacker must guess TXID (16 bits) + source port (~15 bits) = ~31 bits of entropy. At 50,000 packets/sec, success probability drops from ~100% in seconds to ~64% in 24 hours with ~0.4 TB of traffic.
Remaining weaknesses:
- NAT devices with predictable port allocation (sequential, port-preserving) reduce entropy.
- ICMP side channels can leak source ports on some OS/resolver combos (CCS 2020).
- Real fix: DNSSEC (cryptographic validation). Port randomization is a band-aid; DNSSEC is the cure.
DNSSEC: The Chain of Trust
DNSSEC signs zones with asymmetric crypto. Each zone has:
- KSK (Key Signing Key): Signs the DNSKEY RRset. Published as DS record in parent zone.
- ZSK (Zone Signing Key): Signs all other records in the zone.
Validation flow for www.example.com:
- Resolver gets A record + RRSIG from
example.comauthoritative. - Resolver gets DNSKEY (ZSK) for
example.com+ RRSIG. - Resolver gets DS record for
example.comfrom.comTLD + RRSIG. - Resolver gets DNSKEY (KSK) for
.comfrom.comauthoritative + RRSIG. - Resolver gets DS record for
.comfrom root + RRSIG. - Resolver gets DNSKEY for root (trust anchor, pre-configured).
If every signature verifies up to the trust anchor → AD bit = 1 (Authenticated Data). If any break → SERVFAIL.
NSEC/NSEC3: Prove non-existence. NSEC lists "next secure name"—enables zone walking. NSEC3 hashes names (salted) to prevent enumeration.
Common Misconceptions
| Myth | Reality |
|---|---|
| "My browser queries root servers" | Browser → stub → recursive resolver. Recursive does the descent. |
| "DNS is a single database" | Distributed delegation. Each zone owns its data. |
| "TTL is a guarantee" | TTL is a hint. Resolvers may cap it (e.g., 2-day max). Negative TTL from SOA MINIMUM. |
| "CNAME at apex works" | RFC 1912: CNAME at zone apex breaks NS/SOA. Use ALIAS/ANAME (non-standard) or flattening (Cloudflare). |
| "DNSSEC encrypts queries" | DNSSEC signs data (authenticity/integrity). It does NOT encrypt. Use DoH/DoT/DoQ for privacy. |
| "13 root servers = 13 machines" | 13 identities (a–m.root-servers.net). Each is a global anycast constellation (hundreds of physical servers). |
Practical Takeaways
- Run a local validating resolver (Unbound, Knot Resolver). Cuts latency, enables DNSSEC validation, supports QNAME minimization.
- Enable DNSSEC validation. It's the only real protection against cache poisoning.
- Understand TTL caps. Don't rely on 60-second TTLs for fast failover—resolvers may ignore them.
- Monitor your glue. If you rename NS hosts inside your zone, update glue at the registrar before the old records expire.
-
Use
dig +traceto see the actual delegation chain.dig +dnssecto see validation.
The Mental Model
DNS isn't a lookup table. It's a tree of delegations, each signed (optionally), cached at every level, with privacy minimizations and protocol extensions layered on top. The next time you hit example.com, you're not "querying a database." You're walking a chain of trust from root to leaf—one referral at a time.
Tags: dns, networking, systems, security
Top comments (0)