← Skills Hub

DNS Deep Dive

Offered by Dead Brands

DNS (RFC 1034/1035) is the internet's distributed, cached, eventually-consistent database of name-to-data mappings.

Use it over MCP: connect to https://mcp.deadbrands.co/hub/mcp and call skills_get with slug dns-deep-dive.

Full skill

# DNS Deep Dive

Credit: SteTy — published free in the Skills Hub

DNS (RFC 1034/1035) is the internet's distributed, cached, eventually-consistent database of name-to-data mappings. This skill covers the record types an operator actually touches, how TTL and caching really behave (and why "propagation" is a myth), CNAME flattening, the DNSSEC chain of trust, debugging with `dig`, and the three email-authentication systems — SPF, DKIM, DMARC — that live as DNS records.

## Overview

A lookup walks a hierarchy: the stub resolver in the OS asks a **recursive resolver** (your ISP's, or a public one), which — on a cache miss — asks the **root** servers where to find the TLD (`.com`, `.org`), asks the TLD servers where to find the domain's **authoritative** nameservers, and asks one of those for the record. Every answer is cached at each layer for the record's TTL. Most real-world lookups never walk the chain; they are served from a resolver's cache. DNS runs primarily on UDP port 53, falling back to TCP for oversized responses (and for DNS-over-TLS/HTTPS variants DoT/DoH).

The operational consequence: **you do not control when the world sees a change — you control the maximum staleness**, via TTLs set *before* the change.

## Core Principles

1. **Authoritative vs recursive answers differ by design.** An authoritative server returns the full configured TTL and sets the `aa` flag. A recursive resolver returns the *remaining* TTL, counting down. Same question, two legitimate answers during cache expiry.
2. **There is no propagation.** Nobody pushes your change anywhere. Old answers simply age out of thousands of independent caches, each on its own schedule. "Waiting for propagation" means waiting for the *previous* TTL to expire everywhere.
3. **A CNAME cannot coexist with any other record at the same name** (RFC 1034 §3.6.2) — and the zone apex must hold SOA and NS records, so a bare CNAME at the apex is illegal.
4. **Negative answers are cached too.** NXDOMAIN and "name exists, type doesn't" responses are cached for the zone's SOA MINIMUM value (RFC 2308) — a record created a minute after someone looked it up may stay invisible for that long.
5. **DNSSEC proves authenticity, not confidentiality.** Signatures say "this answer really came from the zone owner, unmodified." Queries and answers remain visible; encryption is DoT/DoH's separate job.

## Techniques

**The record types that matter:**

| Type | Value | Rules and notes |
|---|---|---|
| **A** | IPv4 address | Multiple A records = round-robin across all of them; no health awareness |
| **AAAA** | IPv6 address | Publish only if IPv6 actually works end-to-end — clients will prefer it and fail hard |
| **CNAME** | Alias to another hostname | Target must be a *name*, never an IP; chains are legal but each hop costs a lookup; forbidden at the apex and alongside any sibling record |
| **MX** | Mail host + preference | Lower preference number wins (`10` before `20`); target must be a hostname with its own A/AAAA, never an IP and never a CNAME |
| **TXT** | Arbitrary text strings | Home of SPF, DMARC, domain-verification tokens, DKIM (under selectors); strings over 255 characters are split and rejoined — quote carefully |
| **SRV** | `_service._proto` → host, port, priority, weight | Format: `priority weight port target` (e.g. `0 5 443 host.example.com`); used by SIP, XMPP, VoIP, service discovery; the client picks the port from here, not from convention |
| **CAA** | Which CAs may issue certificates | `0 issue "letsencrypt.org"`; `iodef` adds a reporting address; no CAA record = *any* public CA may issue. If you publish CAA, list every CA you use or issuance breaks |
| **NS** | Delegation to nameservers | Set at the registrar/parent; changing them moves the entire zone |
| **SOA** | Zone metadata | Primary NS, admin email (first dot = `@`), serial, refresh/retry/expire timers, negative-cache MINIMUM |
| **PTR** | IP → name (reverse DNS) | Lives in `in-addr.arpa`/`ip6.arpa`, controlled by the IP owner, not the domain owner; matters for mail deliverability |

**TTL strategy:** 300s for records you fail over or migrate, 3600s for stable service records, 86400s for NS. The migration play, in order: (1) lower the TTL to 60–300 **at least one old-TTL period in advance**; (2) wait for the old TTL to fully expire; (3) make the change; (4) keep the old endpoint alive and serving until caches drain; (5) raise the TTL again. Lowering the TTL *after* the change does nothing for caches already holding the old answer.

**CNAME flattening (ALIAS/ANAME):** because a CNAME is illegal at the apex, DNS providers offer proprietary ALIAS or ANAME records: the provider's authoritative server resolves the target itself and answers with synthesized A/AAAA records. To clients it looks like plain address records; the TTL is chosen by the provider, and DNSSEC signing happens on the synthesized answer. Use it to point an apex at a hosted platform; use ordinary CNAMEs everywhere else.

**DNSSEC chain of trust:** the zone signs its record sets with a **ZSK** (zone-signing key, used daily), producing **RRSIG** records. A **KSK** (key-signing key) signs only the DNSKEY set. The parent zone publishes a **DS** record — a hash of the child's KSK — signed by the parent's keys, and so on up to the root, whose key is the trust anchor resolvers ship with. A validating resolver checks each link; any break (expired RRSIG, DS mismatch after a botched rollover) yields **SERVFAIL** for the whole zone — DNSSEC failures are total, not degraded. The `ad` flag in a response means the resolver validated successfully. NSEC/NSEC3 records prove that non-existent names really don't exist.

**Debugging with `dig`:**
- `dig example.com A +short` — just the answer values.
- `dig @1.1.1.1 example.com MX` — ask a specific resolver; compare `@8.8.8.8` and your default to spot cache divergence.
- `dig @ns1.provider.example example.com A` — ask the authoritative server directly: full TTL + `aa` flag = ground truth.
- `dig example.com +trace` — walk root → TLD → authoritative yourself; finds broken delegations and missing glue.
- Read the header first: `status:` **NOERROR** (answered — maybe not what you wanted), **NXDOMAIN** (name doesn't exist), **SERVFAIL** (server-side failure — DNSSEC bogus, lame delegation, timeout upstream), **REFUSED** (server won't answer you). Then flags: `aa` authoritative, `ra` recursion available, `ad` DNSSEC-validated, `tc` truncated (retry over TCP: `+tcp`).
- The TTL column in a resolver's answer is a *countdown*: query twice, watch it drop; that's exactly how long that resolver keeps serving the old value.
- `dig -x 192.0.2.10` — reverse lookup (PTR). `dig example.com TXT +short`, `dig _dmarc.example.com TXT`, `dig selector1._domainkey.example.com TXT` for mail auth.

**Email authentication as DNS citizens:**
- **SPF (RFC 7208)** — a TXT record at the domain: `v=spf1 include:_spf.example.com ip4:192.0.2.0/24 -all`. Declares which hosts may send mail *for the envelope sender*. Mechanisms are evaluated in order; `include:` recurses into another domain's policy. Hard limit: **10 DNS lookups** total across nested includes — exceeding it returns PermError and SPF fails. `-all` = hard fail for everyone else; `~all` = softfail (usually still delivered/marked). Exactly **one** SPF record per name — two records invalidate both.
- **DKIM (RFC 6376)** — the sending server signs selected headers + body hash with a private key; the public key is a TXT record at `<selector>._domainkey.example.com`: `v=DKIM1; k=rsa; p=<base64 key>`. The selector (e.g. `google`, `selector1`) lets multiple senders sign for one domain and enables key rotation: publish new selector, switch signing, retire old. DKIM survives forwarding, which SPF does not.
- **DMARC (RFC 7489)** — a TXT record at `_dmarc.example.com`: `v=DMARC1; p=reject; rua=mailto:reports@example.com`. It ties the two together: a message passes DMARC if SPF **or** DKIM passes *and* the authenticated domain **aligns** with the visible `From:` domain. Policy `p=` escalates `none` (monitor only) → `quarantine` (spam folder) → `reject`. `rua`/`ruf` request aggregate/forensic reports so you can see who is sending as you. Roll out in that order — never jump straight to `reject`.

## Worked Examples

"Site still points at the old server for some users after yesterday's move": TTL was 86400 and was lowered *at* move time. Check `dig @<authoritative> example.com A` (shows the new IP, TTL 300) vs `dig @8.8.8.8 example.com A` (shows the old IP with TTL counting down from ~80,000). Nothing is broken — the caches that hold the old answer keep it until their countdown ends. Fix next time: lower TTL a full day ahead.

"Mail from our new sender lands in spam": `dig example.com TXT +short` shows two `v=spf1` records → both invalid → SPF PermError. Merge them into one record, count the includes (each `include:` costs lookups), confirm under 10, then check `_dmarc` alignment with the sender's domain.

## Common Pitfalls

- **CNAME at the apex** — illegal; silently breaks other apex records (including MX) on strict providers. Use ALIAS/ANAME flattening.
- **MX pointing at a CNAME or an IP** — both forbidden; some receivers refuse the mail outright.
- **Two SPF records, or >10 SPF lookups** — the classic self-inflicted PermError.
- **AAAA on a broken IPv6 path** — clients prefer IPv6; a dead AAAA is worse than none.
- **Lowering TTL after the change** — useless for caches already holding the old answer.
- **DNSSEC rollover without updating DS** — the zone becomes bogus and validating resolvers return SERVFAIL for everyone.
- **CAA record listing only one CA** while a second CA renews your other certs — issuance starts failing at renewal time.
- **Deleting "mystery" TXT records** — they are usually verification or mail-auth records; removing them breaks things days later, far from the edit.

## Practice Drills

1. For any domain you know: pull A, AAAA, MX, TXT, CAA, and `_dmarc` records with `dig +short`; explain every value you find.
2. Run `dig +trace` on a domain and narrate each hop — root, TLD, authoritative — and where the delegation lives.
3. Query the same record at the authoritative server and at two public resolvers; compare TTLs and compute when the slowest cache converges after a hypothetical change.
4. Audit an SPF record: expand every `include:` by hand and count total DNS lookups; state whether it passes the 10-lookup limit.
5. Deliberately query a non-existent subdomain and inspect the AUTHORITY section — find the SOA and read off the negative-cache lifetime.

## When to Use and Limits

- **Use it when:** a task calls for dns deep dive, as laid out in the Techniques and Worked Examples above.
- **Watch first for:** CNAME at the apex; MX pointing at a CNAME or an IP; Two SPF records, or >10 SPF lookups (see Common Pitfalls).
- **Limits:** this is a general reference drawn from public sources; check exact values against the current standard or vendor docs before relying on them, and get expert review for production security decisions.

## Quick Reference

- A/AAAA = addresses · CNAME = alias (never at apex, never with siblings) · MX = mail host + priority (lower wins) · SRV = service + port · CAA = who may issue certs.
- TTL = max staleness; lower it *before* changes, one full old-TTL ahead.
- Propagation doesn't exist — caches expire independently.
- `dig @server name TYPE`, `+short`, `+trace`, `+tcp`; statuses: NOERROR / NXDOMAIN / SERVFAIL / REFUSED; flags: `aa` authoritative, `ad` DNSSEC-valid.
- DNSSEC: RRSIG signs data, KSK signs keys, DS in the parent links the chain; breakage = SERVFAIL.
- SPF = who may send (≤10 lookups, one record) · DKIM = signed messages, key at `selector._domainkey` · DMARC = alignment + policy at `_dmarc`.

All skills · The Commons · llms.txt