Markdown source

DNS Resolution: The Full Picture Markdown source

Readable source view for humans. The raw Markdown endpoint remains available for crawlers and agent readers.

---
title: "DNS Resolution: The Full Picture"
description: "How DNS resolution works — root servers, TLD nameservers, record types, response codes, zone files, and why queries are nearly invisible."
kind: guide
maturity: budding
confidence: high
origin: ai-drafted
author: "Agent"
directedBy: "krow"
tags: [dns, networking, fundamentals]
published: 2026-03-28
modified: 2026-03-28
wordCount: 3171
readingTime: 15
series: "domain-infrastructure" (#1)
related: [whois-dead-long-live-rdap, bot-detection-2026, aimd-rate-limiting]
url: https://krowdev.com/guide/dns-resolution-full-picture/
---
## Agent Context

- Canonical: https://krowdev.com/guide/dns-resolution-full-picture/
- Markdown: https://krowdev.com/guide/dns-resolution-full-picture.md
- Full corpus: https://krowdev.com/llms-full.txt
- Kind: guide
- Maturity: budding
- Confidence: high
- Origin: ai-drafted
- Author: Agent
- Directed by: krow
- Published: 2026-03-28
- Modified: 2026-03-28
- Words: 3171 (15 min read)
- Tags: dns, networking, fundamentals
- Series: domain-infrastructure (#1)
- Related: whois-dead-long-live-rdap, bot-detection-2026, aimd-rate-limiting
- Content map:
  - h2: The Hierarchy
  - h3: Root servers
  - h3: TLD nameservers
  - h3: Authoritative nameservers
  - h2: Resolution Walk-Through
  - h3: Why it feels instant
  - h3: What dig shows you
  - h2: Record Types That Matter
  - h3: A and AAAA
  - h3: NS
  - h3: SOA
  - h3: MX
  - h3: CNAME
  - h3: TXT
  - h2: Response Codes
  - h2: DNS over HTTPS (DoH)
  - h3: Cloudflare DoH
  - h3: Google DoH
  - h3: Why DoH matters
  - h2: DNS Query Anatomy
  - h3: The fingerprint surface comparison
  - h2: Zone Files
  - h3: BIND format
  - h3: Scale
  - h3: What zone files don't contain
  - h3: Zone file diffing
  - h2: Putting It Together
  - h2: Sources
- Diagrams: Mermaid fences are paired with adjacent ASCII companions in this document (3 Mermaid, 3 ASCII); HTML figures expose rendered SVG plus copyable Mermaid/ASCII source tabs.
- Crawl policy: same canonical content is exposed through HTML, Markdown, and llms-full; no crawler-specific content gate.

DNS is a hierarchical, distributed database that turns names into numbers. You type `example.com`, and somewhere between your keyboard and a TCP connection opening, a chain of servers conspires to produce `93.184.216.34`. This guide covers every layer of that process — the hierarchy, the resolution walk, the record types, the response codes, the wire format, and the zone files that make it all work.

## The Hierarchy

Every domain name resolution walks down a tree. The tree has exactly three levels that matter:

```mermaid
graph TD
  root["<b>.</b> (root)"]
  com[com]
  net[net]
  org[org]
  ex1[example]
  ex2[example]
  ex3[example]
  www[www]

  root --> com
  root --> net
  root --> org
  com --> ex1
  net --> ex2
  org --> ex3
  ex1 --> www

  classDef tld fill:transparent,stroke-dasharray:0;
  class com,net,org tld;
```

```ascii
                    . (root)
                    |
        ┌───────────┼───────────┐
       com         net         org        ← TLD (Top-Level Domain)
        |           |           |
    example      example     example      ← Second-Level Domain (SLD)
        |
       www                                ← Subdomain / host
```

*Levels: root → TLD (`com`, `net`, `org`) → second-level domain → subdomain.*

Each node in the tree has its own set of authoritative nameservers — servers that are the final source of truth for records at that level. The root knows about TLDs. TLD servers know about second-level domains. Authoritative nameservers know about everything under their domain. The [domain registration process](/note/domain-registration-icann-to-browser/) determines which nameservers appear at each level.

### Root servers

There are [13 root server identities](https://www.iana.org/domains/root/servers), named `a.root-servers.net` through `m.root-servers.net`, operated by 12 organizations (Verisign operates two). Through anycast routing, those 13 identities map to [over 1,700 physical instances](https://root-servers.org/) worldwide. A query to `a.root-servers.net` from Tokyo hits a different machine than the same query from London, but both return the same answer.

Root servers answer exactly one question: *"Who is authoritative for this TLD?"* They don't know about `example.com`. They know that `.com` is handled by Verisign's `a.gtld-servers.net` through `m.gtld-servers.net`.

### TLD nameservers

Each TLD has its own set of nameservers operated by the registry. For `.com`, that's Verisign. For `.org`, that's Public Interest Registry. For `.de`, that's DENIC.

TLD nameservers answer: *"Who is authoritative for this second-level domain?"* They store NS (nameserver) records pointing to each registered domain's authoritative nameservers. This is essentially the content of the zone file.

### Authoritative nameservers

The final stop. These are the nameservers set by the domain owner (or their hosting provider). They hold the actual records — A records, MX records, CNAME records, everything. When Cloudflare or AWS Route 53 "hosts your DNS," they're running your authoritative nameservers.

## Resolution Walk-Through

When you look up `example.com`, your resolver performs an iterative walk down the hierarchy. Here's the full sequence:

```mermaid
sequenceDiagram
  autonumber
  participant C as Client
  participant R as Recursive resolver
  participant Root as Root server
  participant TLD as .com TLD server
  participant Auth as Authoritative NS

  C->>R: What is example.com?
  R->>Root: Who handles .com?
  Root-->>R: Ask a.gtld-servers.net (Verisign)
  R->>TLD: Who handles example.com?
  TLD-->>R: Ask ns1.example.com at 93.184.216.34
  R->>Auth: What is example.com?
  Auth-->>R: A record 93.184.216.34
  R-->>C: 93.184.216.34
```

```ascii
1. Client → Recursive resolver: "What is example.com?"
2. Resolver → Root server: "Who handles .com?"
   Root → Resolver: "Ask a.gtld-servers.net (Verisign)"
3. Resolver → TLD server: "Who handles example.com?"
   TLD → Resolver: "Ask ns1.example.com at 93.184.216.34"
4. Resolver → Authoritative NS: "What is example.com?"
   Auth NS → Resolver: "A record: 93.184.216.34"
5. Resolver → Client: "93.184.216.34"
```

Three actors make this work:

**Recursive resolver** — does the full walk for you. This is 1.1.1.1 (Cloudflare), 8.8.8.8 (Google), or whatever your ISP provides. When you configure DNS settings on your machine, you're choosing your recursive resolver. It caches aggressively — after the first lookup, it knows who handles `.com` for hours.

**TLD nameserver** — operated by the registry (e.g., Verisign for `.com`). Contains NS records for every registered domain under that TLD. The `.com` TLD servers know about all ~160 million `.com` domains.

**Authoritative nameserver** — the final source of truth for a domain's records. Set by the domain owner or their hosting provider. This is where your A record, MX record, and everything else actually lives.

### Why it feels instant

In practice, steps 2 and 3 are almost always cached. Your recursive resolver already knows who handles `.com` (the TTL on root-to-TLD delegations is 48 hours). It probably has the NS records for popular domains cached too. The typical cold lookup takes 50-100ms. A warm lookup (fully cached) takes under 5ms.

### What `dig` shows you

You can watch this process with `dig`:

```bash
# Full recursive trace — shows each step
dig +trace example.com

# Ask a specific resolver
dig @1.1.1.1 example.com A

# Ask an authoritative server directly
dig @ns1.example.com example.com A +norecurse

# Query for NS records (who handles this domain?)
dig example.com NS

# Get the SOA record (zone metadata)
dig example.com SOA
```

The `+trace` flag is particularly instructive. It starts at the root and follows each delegation, showing you exactly which server returned what. The output reads like a conversation between your machine and the hierarchy.

## Record Types That Matter

DNS has dozens of record types. Seven of them cover nearly everything you'll encounter:

| Type | Purpose | Example | TTL range |
|------|---------|---------|-----------|
| **A** | IPv4 address | `example.com → 93.184.216.34` | 60s – 86400s |
| **AAAA** | IPv6 address | `example.com → 2606:2800:220:1:248:1893:25c8:1946` | 60s – 86400s |
| **NS** | Nameserver delegation | `example.com → ns1.example.com` | 3600s – 172800s |
| **SOA** | Start of Authority (zone metadata) | Serial number, refresh intervals | 3600s – 86400s |
| **MX** | Mail server (with priority) | `10 mail.example.com` | 3600s – 86400s |
| **CNAME** | Alias to another name | `www.example.com → example.com` | 60s – 86400s |
| **TXT** | Arbitrary text data | SPF records, domain verification tokens | 300s – 86400s |

### A and AAAA

The workhorses. An A record maps a name to an IPv4 address. AAAA does the same for IPv6. A domain can have multiple A records (round-robin load balancing) and both A and AAAA records simultaneously (dual-stack).

### NS

Nameserver records define delegation. The NS records in the `.com` zone for `example.com` point to `ns1.example.com` and `ns2.example.com`. These are what the TLD server returns in step 3 of the resolution walk. Without NS records, a domain can be registered but won't resolve — it's not in the zone.

### SOA

Every zone has exactly one SOA (Start of Authority) record. It contains the primary nameserver name, the responsible party's email (encoded as a DNS name), a serial number that increments on changes, and timing parameters for zone transfers. The serial number is how secondary nameservers know when to pull updates.

### MX

Mail exchange records have a priority value (lower = preferred) and a target hostname. When sending email to `user@​example.com`, the sender's mail server queries the MX records for `example.com` and connects to the lowest-priority server that responds. Multiple MX records with different priorities provide failover.

### CNAME

A canonical name record is an alias. `www.example.com CNAME example.com` means "look up `example.com` instead." CNAMEs can't coexist with other record types at the same name — a name is either a CNAME or it has direct records, never both. This constraint trips people up regularly (you can't put a CNAME at the zone apex because SOA and NS records must exist there).

### TXT

Free-form text records. Originally meant for human-readable notes, now heavily used for machine-readable data: SPF records for email authentication (`v=spf1 include:_spf.google.com ~all`), DKIM public keys, domain verification tokens for Google/Microsoft/Cloudflare, and DMARC policies. A single domain commonly has 5-10 TXT records.

## Response Codes

Every DNS response includes a 4-bit response code (RCODE) in the header. Four codes matter in practice:

| Code | Name | Meaning | What it tells you |
|------|------|---------|-------------------|
| 0 | **NOERROR** | Name exists, records returned | The domain resolves. Records are in the answer section. |
| 3 | **NXDOMAIN** | Name does not exist | The authoritative server for this zone has no record of this name. For a query against a TLD server, this means no registrar has placed the domain in the zone. |
| 2 | **SERVFAIL** | Server failure | The resolver couldn't complete the query. Could be a timeout talking to an upstream server, a DNSSEC validation failure, or a misconfigured zone. Retry with a different resolver. |
| 5 | **REFUSED** | Policy refusal | The server declined to answer. Usually means you're querying a server that doesn't serve that zone, or an authoritative server that doesn't allow recursive queries. Try a different server. |

**NXDOMAIN** is the most interesting signal. When a TLD nameserver returns NXDOMAIN for `example.com`, it means no delegation exists — no registrar has placed NS records for that name in the zone. This is the fastest possible way to determine that a domain doesn't resolve (a single UDP round-trip to the TLD server).

**The caveat**: A domain can be registered but absent from the zone. Domains in `serverHold` or `clientHold` status, domains with no nameservers configured, and domains in `redemptionPeriod` are all registered but return NXDOMAIN. An NXDOMAIN response tells you the domain isn't in the zone — not that it's unregistered.

## DNS over HTTPS (DoH)

Traditional DNS uses UDP on port 53, unencrypted. Every query and response travels in plaintext. Your ISP can see every domain you look up. Any network middlebox can intercept and modify responses.

DNS over HTTPS wraps DNS queries inside standard HTTPS requests. From a network perspective, DoH traffic is indistinguishable from normal web browsing — it's TLS-encrypted traffic on port 443.

### Cloudflare DoH

```bash
curl -s "https://cloudflare-dns.com/dns-query?name=example.com&type=A" \
  -H "Accept: application/dns-json" | jq .
```

Response:

```json
{
  "Status": 0,
  "TC": false,
  "RD": true,
  "RA": true,
  "AD": true,
  "CD": false,
  "Question": [
    { "name": "example.com", "type": 1 }
  ],
  "Answer": [
    {
      "name": "example.com",
      "type": 1,
      "TTL": 3600,
      "data": "93.184.216.34"
    }
  ]
}
```

The fields in the response map directly to DNS header flags: `Status` is the RCODE (0 = NOERROR), `TC` is Truncated, `RD` is Recursion Desired, `RA` is Recursion Available, `AD` is Authenticated Data (DNSSEC validated), and `CD` is Checking Disabled.

For a non-existent domain, `Status` would be `3` (NXDOMAIN) and the `Answer` array would be empty.

### Google DoH

```bash
curl -s "https://dns.google/resolve?name=example.com&type=A" | jq .
```

Same JSON structure with minor field name differences. Both services support `type=A`, `type=AAAA`, `type=NS`, `type=MX`, `type=TXT`, and any other valid record type.

### Why DoH matters

Three reasons, in order of practical importance:

1. **Privacy**: Your DNS queries are encrypted. Your ISP (and anyone else on the network path) can't see which domains you're looking up. They can see you're talking to `cloudflare-dns.com`, but not what you're asking.

2. **Integrity**: HTTPS provides authenticity. A network middlebox can't inject forged DNS responses (a technique used by some ISPs to redirect failed lookups to ad pages and by some governments for censorship).

3. **Convenience**: JSON responses are trivial to parse in any language. No DNS library needed — any HTTP client works. This makes DNS lookups accessible from environments where raw UDP isn't available (browsers, serverless functions, restricted networks).

The tradeoff is latency. A raw UDP DNS query to 1.1.1.1 completes in ~10ms. A DoH query adds TLS handshake overhead on the first request (~50ms total), though subsequent queries reuse the connection.

## DNS Query Anatomy

A DNS query is remarkably small. When `dig` sends a query, it constructs a single UDP datagram:

```mermaid
flowchart TB
  Header["<b>Header</b> (12 bytes)<br/>Transaction ID: random 16-bit<br/>Flags: RD=1 (recursion desired)<br/>Question count: 1"]
  Question["<b>Question section</b><br/>Name: example.com (variable length)<br/>Type: A, AAAA, NS, MX, ...<br/>Class: IN (Internet)"]
  EDNS["<b>EDNS(0) OPT record</b> (optional, ~11 bytes)<br/>UDP payload size: 4096<br/>DNSSEC OK (DO) flag: 0 or 1<br/>DNS Cookie (optional)"]

  Header --> Question --> EDNS
```

```ascii
┌──────────────────────────────────────────┐
│ Header (12 bytes)                        │
│  - Transaction ID: random 16-bit         │
│  - Flags: RD=1 (recursion desired)       │
│  - Question count: 1                     │
├──────────────────────────────────────────┤
│ Question section                         │
│  - Name: example.com (variable length)   │
│  - Type: A (or AAAA, NS, MX, etc.)      │
│  - Class: IN (Internet)                  │
├──────────────────────────────────────────┤
│ EDNS(0) OPT record (optional, ~11 bytes) │
│  - UDP payload size: 4096                │
│  - DNSSEC OK (DO) flag: 0 or 1          │
│  - DNS Cookie (optional)                 │
└──────────────────────────────────────────┘
Total: ~40–80 bytes. Single UDP datagram.
```

That's the entire request. No TLS handshake. No HTTP framing. No headers. No User-Agent. No Accept-Language. No cookies. The response is similarly compact — a single UDP datagram back.

### The fingerprint surface comparison

This matters if you care about privacy or anonymity. Compare what a DNS query reveals about the sender versus what an HTTPS request reveals:

**What a DNS query exposes:**

| Element | Typical values | Identifiability |
|---------|----------------|-----------------|
| Source IP | Your IP or proxy IP | Primary identifier |
| EDNS buffer size | 4096 (dig), 1232 (newer default), 512 (legacy) | Minor signal |
| DNSSEC OK flag | 0 or 1 | Negligible |
| DNS Cookie | Present or absent | Negligible |
| Transaction ID | Random 16-bit | Expected to vary |
| RD (Recursion Desired) | Almost always 1 | Universal — not distinguishing |

**What an HTTPS request exposes:**

TLS version, 15+ cipher suites in a specific order, 20+ TLS extensions with GREASE values, HTTP/2 SETTINGS frame, WINDOW_UPDATE size, HEADERS frame priority, 12+ HTTP headers in a specific order, User-Agent string, Accept-Language, Sec-Ch-Ua (browser brand/version), Sec-Ch-Ua-Platform, Sec-Fetch-Site, Sec-Fetch-Mode, cookie jar, and more.

DNS queries are effectively anonymous except for the source IP. The protocol simply doesn't carry enough metadata to fingerprint the client. This is a fundamental property of UDP-based protocols with fixed, minimal headers — there's no room for the kind of feature negotiation that makes [TLS and HTTP so fingerprintable](/article/bot-detection-2026/).

## Zone Files

A zone file is a text file that describes a DNS zone — the complete set of records that an authoritative nameserver serves. For a TLD like `.com`, the zone file is the master list: every registered domain that has nameserver delegations.

### BIND format

Zone files use BIND format (named after the Berkeley Internet Name Daemon, the most widely deployed DNS server software). Here's a simplified view of what the `.com` zone file looks like:

```bind
; .com zone file (simplified)
$ORIGIN com.
$TTL 172800

; SOA record — zone metadata
com.  IN  SOA  a.gtld-servers.net. nstld.verisign-grs.com. (
              1710000000 ; serial (increments on each update)
              1800       ; refresh (30 min)
              900        ; retry (15 min)
              604800     ; expire (7 days)
              86400 )    ; minimum TTL (1 day)

; TLD nameservers
com.  IN  NS  a.gtld-servers.net.
com.  IN  NS  b.gtld-servers.net.
; ... 11 more

; Domain delegations — one block per registered domain
example.com.  IN  NS  ns1.example.com.
example.com.  IN  NS  ns2.example.com.
; Glue records (needed when NS is under the delegated domain)
ns1.example.com.  IN  A  93.184.216.34
ns2.example.com.  IN  A  93.184.216.34

google.com.   IN  NS  ns1.google.com.
google.com.   IN  NS  ns2.google.com.
; ... ~160 million more entries
```

The `$ORIGIN` directive sets the default suffix. The `$TTL` directive sets the default time-to-live for records. Lines starting with `;` are comments. The SOA record's serial number is the version — secondary nameservers compare their serial to the primary's and pull a zone transfer (AXFR or IXFR) when it's behind.

Glue records deserve a note. When `example.com` delegates to `ns1.example.com`, there's a circular dependency — you need to resolve `ns1.example.com` to find the nameserver for `example.com`, but `ns1.example.com` is under `example.com`. Glue records break the cycle by embedding the A record for the nameserver directly in the parent zone.

### Scale

The `.com` zone file contains approximately 160 million domain delegations. Compressed with gzip, it's roughly 4-5 GB. Uncompressed: 15-20 GB. Verisign regenerates it multiple times per day.

ICANN's Centralized Zone Data Service (CZDS) provides access to TLD zone files for approved purposes. You apply at czds.icann.org, each TLD registry reviews independently, and once approved you get API access for programmatic daily downloads.

### What zone files don't contain

Zone files are a subset of the registry database. They contain only domains that are active and have nameserver delegations. Missing from the zone:

- Domains in `serverHold` or `clientHold` status (suspended by registry or registrar)
- Domains in `pendingDelete` status (queued for deletion)
- Domains in `redemptionPeriod` (expired, recoverable at penalty cost)
- Domains registered but with no nameservers configured
- Registrant or contact information
- Registration and expiry dates

This distinction matters. A domain that returns NXDOMAIN in DNS could be registered but held, suspended, or in a grace period. The zone file reflects what resolves, not what's registered.

### Zone file diffing

Because zone files are regenerated daily, comparing consecutive snapshots reveals domains entering and leaving the zone:

```
Day 1 zone: {example.com, test.com, mydomain.com, ...}
Day 2 zone: {example.com, test.com, ...}

Diff: mydomain.com disappeared from the zone
```

A domain disappearing from the zone could mean:

1. It entered `pendingDelete` — will be fully deleted in 5 days
2. It was placed on `serverHold` or `clientHold` — still registered, just suspended
3. Its nameservers were removed — still registered, just not delegated
4. It entered `redemptionPeriod` — might become available in 30-35 days

The zone file tells you *what changed*. To understand *why*, you need to query the registry's [RDAP service](/note/whois-dead-long-live-rdap/), where the domain's status flags reveal its actual state.

## Putting It Together

DNS resolution is elegant because each layer knows only what it needs to. Root servers know TLDs. TLD servers know second-level domains. Authoritative servers know records. No single server has to know everything, and the caching at every level means the system handles billions of queries per day with response times measured in milliseconds.

The key things to remember:

- **The hierarchy is strict**: root, TLD, authoritative. Three levels. Always.
- **Recursive resolvers do the work**: your machine asks once; the resolver walks the tree.
- **Caching makes it fast**: TTL values control how long each answer stays cached.
- **NXDOMAIN means "not in the zone"**: it doesn't always mean "not registered."
- **DNS queries are tiny**: 40-80 bytes, single UDP datagram, near-zero fingerprint surface.
- **Zone files are the ground truth**: what's in the zone is what resolves. Everything else is metadata stored elsewhere.

The protocol is 40 years old ([RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035), November 1987) and still handles the internet's naming layer with minimal changes to its core design. The extensions — DNSSEC, DoH, DoT, EDNS — are layers on top, not replacements. The hierarchy and the delegation model are the same ones Paul Mockapetris designed in 1983.

## Sources

- [RFC 1034](https://datatracker.ietf.org/doc/html/rfc1034) — Domain Names: Concepts and Facilities (the design document)
- [RFC 1035](https://datatracker.ietf.org/doc/html/rfc1035) — Domain Names: Implementation and Specification (the wire format)
- [RFC 8499](https://datatracker.ietf.org/doc/html/rfc8499) — DNS Terminology (canonical definitions of resolver, authoritative, etc.)
- [RFC 8484](https://datatracker.ietf.org/doc/html/rfc8484) — DNS Queries over HTTPS (DoH)
- [IANA Root Servers](https://www.iana.org/domains/root/servers) — the 13 root server identities and their operators
- [Root Server Technical Operations](https://root-servers.org/) — real-time root server instance map
- [Verisign Domain Name Industry Brief](https://www.verisign.com/en_US/domain-names/dnib/index.xhtml) — TLD registration statistics