Back to Computing & Systems Foundations Series

Part 12: DNS Deep Dive — Resolution & Record Types

May 13, 2026Wasil Zafar18 min read

DNS is the internet's phone book — it translates human-readable domain names into IP addresses. Understanding the resolution chain, record types, and caching layers is essential for debugging connectivity issues, configuring infrastructure, and securing your domains.

Table of Contents

  1. How DNS Works
  2. DNS Record Types
  3. DNS Caching & TTL
  4. Zones & Authoritative Nameservers
  5. Debugging DNS
  6. Exercises
  7. Conclusion

How DNS Works

The Domain Name System (DNS) is a distributed, hierarchical database that maps domain names (e.g., www.example.com) to IP addresses (e.g., 93.184.216.34). Without DNS, you'd need to memorise IP addresses for every website. DNS operates primarily over UDP port 53 (falling back to TCP for responses larger than 512 bytes or zone transfers).

The DNS namespace is a tree: the root (.) at the top, then Top-Level Domains (TLDs: .com, .org, .uk), then second-level domains (example.com), then subdomains (www.example.com). Each level is managed by different organisations — this delegation is what makes DNS scalable to billions of names.

Recursive vs Iterative Queries

There are two query modes in DNS:

  • Recursive query: The client asks a resolver to do all the work — "give me the final answer or an error." Your stub resolver (OS) sends recursive queries to your configured DNS resolver (e.g., 8.8.8.8).
  • Iterative query: The server responds with the best answer it has — either the final answer or a referral to another nameserver. Recursive resolvers use iterative queries when walking the DNS tree.

The Resolution Chain

When you type www.example.com in a browser, this is what happens:

DNS Recursive Resolution
sequenceDiagram
    participant App as Application
    participant Stub as Stub Resolver (OS)
    participant Rec as Recursive Resolver (ISP/8.8.8.8)
    participant Root as Root Nameserver (.)
    participant TLD as TLD Nameserver (.com)
    participant Auth as Authoritative NS (example.com)

    App->>Stub: resolve www.example.com
    Stub->>Rec: recursive query: www.example.com A?
    Rec->>Root: iterative: www.example.com A?
    Root-->>Rec: referral → .com TLD servers
    Rec->>TLD: iterative: www.example.com A?
    TLD-->>Rec: referral → example.com NS servers
    Rec->>Auth: iterative: www.example.com A?
    Auth-->>Rec: answer: 93.184.216.34 (TTL=3600)
    Rec-->>Stub: 93.184.216.34 (cached)
    Stub-->>App: 93.184.216.34
            
# Trace the full resolution chain with dig +trace
dig +trace www.example.com

# Output shows each step:
# .                  → root servers (a.root-servers.net, etc.)
# com.               → TLD servers (a.gtld-servers.net, etc.)
# example.com.       → authoritative NS (ns1.example.com)
# www.example.com. A → final answer: 93.184.216.34
Key Insight: The recursive resolver does the heavy lifting — it walks the tree on your behalf and caches every answer along the way. Your stub resolver (the OS) just talks to one recursive resolver. This is why changing your DNS server (to 8.8.8.8, 1.1.1.1, or 9.9.9.9) can change resolution speed, privacy, and even which IPs you get (CDN routing depends on resolver location).

DNS Record Types

DNS doesn't just map names to IPs — it stores many types of records. Each record type serves a different purpose:

TypePurposeExample
AMaps domain to IPv4 addressexample.com. A 93.184.216.34
AAAAMaps domain to IPv6 addressexample.com. AAAA 2606:2800:220:1:...
CNAMEAlias — points one name to anotherwww.example.com. CNAME example.com.
MXMail exchange — where to deliver emailexample.com. MX 10 mail.example.com.
TXTArbitrary text (SPF, DKIM, domain verification)example.com. TXT "v=spf1 include:_spf.google.com ~all"
NSNameserver — delegates a zoneexample.com. NS ns1.example.com.
SOAStart of Authority — zone metadata (serial, refresh, retry)example.com. SOA ns1.example.com. admin.example.com. ...
PTRReverse DNS — maps IP to domain34.216.184.93.in-addr.arpa. PTR example.com.
SRVService locator (port, weight, priority)_sip._tcp.example.com. SRV 10 60 5060 sip.example.com.
CAACertificate Authority Authorization — which CAs can issue certsexample.com. CAA 0 issue "letsencrypt.org"
# Query specific record types with dig
dig example.com A +short            # IPv4 address
dig example.com AAAA +short         # IPv6 address
dig example.com MX +short           # Mail servers
dig example.com TXT +short          # TXT records (SPF, DKIM, verification)
dig example.com NS +short           # Nameservers
dig example.com SOA +short          # Start of Authority
dig example.com CAA +short          # Certificate Authority Authorization

# Query all record types at once
dig example.com ANY +noall +answer

# CNAME example — www often aliases to the apex domain or CDN
dig www.github.com CNAME +short     # github.github.io.
dig www.netflix.com CNAME +short    # Usually points to CDN (Akamai, CloudFront)

DNS Caching & TTL

DNS responses include a TTL (Time To Live) — the number of seconds a resolver or client may cache the answer before re-querying. Caching happens at multiple layers, each reducing latency and load on authoritative servers:

DNS Caching Layers (checked in order):
  1. Browser cache — Chrome/Firefox cache DNS for ~60s (chrome://net-internals/#dns)
  2. OS cache — systemd-resolved, dnsmasq, or Windows DNS Client service
  3. Recursive resolver cache — your ISP or public resolver (8.8.8.8) caches based on TTL
  4. Authoritative server — the source of truth (only queried if all caches miss or TTL expired)
# View TTL in dig output (second column = remaining TTL in seconds)
dig example.com A

# ;; ANSWER SECTION:
# example.com.   3600   IN   A   93.184.216.34
#                ^^^^
#                TTL = 3600 seconds (1 hour)

# Query again — TTL decreases as cache ages
sleep 10 && dig example.com A +noall +answer
# example.com.   3590   IN   A   93.184.216.34

# View local DNS cache (Linux with systemd-resolved)
resolvectl statistics              # Cache size, hits, misses
resolvectl query example.com       # Query via systemd-resolved

# Flush DNS cache
# Linux (systemd-resolved):
sudo resolvectl flush-caches
# macOS:
# sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Windows:
# ipconfig /flushdns
DNS Propagation Delays: When you change a DNS record (e.g., migrating to a new server), the old IP may be cached worldwide for up to the previous TTL. If your TTL was 86400 (24 hours), some clients won't see the new IP for up to 24 hours. Best practice: Lower TTL to 300 (5 minutes) at least 24-48 hours before the migration, perform the change, verify, then raise TTL back. Some resolvers (notably ISP resolvers) may ignore TTL and cache longer — there's no way to force instant global propagation.

Zones & Authoritative Nameservers

A DNS zone is a portion of the DNS namespace managed by a specific organisation. The zone example.com contains records for example.com and all names beneath it (unless delegated to a sub-zone). Zones are served by authoritative nameservers — servers that hold the definitive records for that zone.

# Find the authoritative nameservers for a domain
dig example.com NS +short
# a.iana-servers.net.
# b.iana-servers.net.

# Query an authoritative server directly (bypasses cache)
dig @a.iana-servers.net example.com A +norecurse

# View the SOA record (zone metadata)
dig example.com SOA +short
# ns.icann.org. noc.dns.icann.org. 2024040100 7200 3600 1209600 3600
# Fields: primary NS, admin email, serial, refresh, retry, expire, minimum TTL

# Zone transfer (AXFR) — only works if server allows it
dig @ns1.example.com example.com AXFR
# Most servers deny AXFR from unauthorized IPs (security measure)

Zone delegation works via NS records and glue records. When .com delegates example.com to ns1.example.com, there's a chicken-and-egg problem: to find ns1.example.com's IP, you'd need to query example.com's nameserver — which is ns1.example.com. Glue records solve this by including the nameserver's A record in the parent zone's referral response.

Debugging DNS

dig (Domain Information Groper)

dig is the most powerful DNS debugging tool. It shows the full query/response with headers, flags, and timing.

# Basic query with full output (headers, question, answer, authority, additional)
dig example.com

# Short answer only
dig +short example.com

# Trace full resolution path (root → TLD → authoritative)
dig +trace example.com

# Query a specific DNS server
dig @8.8.8.8 example.com          # Google Public DNS
dig @1.1.1.1 example.com          # Cloudflare DNS
dig @9.9.9.9 example.com          # Quad9 (security-filtered)

# Reverse DNS lookup (PTR)
dig -x 8.8.8.8 +short             # dns.google.

# Query with TCP instead of UDP
dig +tcp example.com

# Show query time and server used
dig example.com | grep -E "Query time|SERVER"
# ;; Query time: 23 msec
# ;; SERVER: 127.0.0.53#53(127.0.0.53)

nslookup

nslookup is simpler than dig and available on all platforms (Windows, macOS, Linux). Useful for quick lookups but shows less detail.

# Basic lookup
nslookup example.com

# Query specific record type
nslookup -type=MX example.com
nslookup -type=TXT example.com
nslookup -type=NS example.com

# Use a specific DNS server
nslookup example.com 8.8.8.8

# Reverse lookup
nslookup 93.184.216.34

/etc/resolv.conf

On Linux, /etc/resolv.conf configures which DNS resolver the stub resolver uses. On modern systems with systemd-resolved, it often points to 127.0.0.53 (a local caching stub).

# View current DNS configuration
cat /etc/resolv.conf
# nameserver 127.0.0.53    ← systemd-resolved stub
# options edns0 trust-ad
# search localdomain

# View the actual upstream resolvers (systemd-resolved)
resolvectl status
# Shows: DNS Servers, DNS Domain, DNSSEC, DNS over TLS settings per interface

# View /etc/hosts (checked BEFORE DNS queries)
cat /etc/hosts
# 127.0.0.1   localhost
# ::1         localhost
# Custom entries override DNS (useful for local dev or blocking domains)

# Check resolution order (nsswitch.conf)
grep hosts /etc/nsswitch.conf
# hosts: files dns mymachines   ← files (/etc/hosts) checked first, then DNS
Cloud Native

How Kubernetes DNS Works

CoreDNS is the default DNS server in Kubernetes clusters. Every Service gets a DNS name: <service>.<namespace>.svc.cluster.local. When a pod resolves my-api.production.svc.cluster.local, CoreDNS returns the Service's ClusterIP. For headless Services (no ClusterIP), DNS returns the IPs of all backing Pods directly. Pod DNS is configured via /etc/resolv.conf injected by kubelet — it points to the CoreDNS service IP (usually 10.96.0.10) and adds search domains so you can use short names like my-api within the same namespace.

CoreDNSService DiscoveryPod DNS

Exercises

# Exercise 1: Trace DNS resolution for your favourite website
dig +trace google.com

# Exercise 2: Find all record types for a domain
dig google.com A +short
dig google.com AAAA +short
dig google.com MX +short
dig google.com TXT +short
dig google.com NS +short

# Exercise 3: Compare resolution time between DNS servers
dig @8.8.8.8 github.com | grep "Query time"
dig @1.1.1.1 github.com | grep "Query time"
dig @9.9.9.9 github.com | grep "Query time"

# Exercise 4: Find the authoritative nameservers and query directly
NS=$(dig github.com NS +short | head -1)
dig @$NS github.com A +norecurse

# Exercise 5: Reverse DNS lookup
dig -x 140.82.121.4 +short    # GitHub's IP → domain name

Conclusion & Next Steps

DNS is a distributed, hierarchical, heavily cached system that translates names to addresses. The resolution chain (stub → recursive resolver → root → TLD → authoritative) is walked via iterative queries by the recursive resolver, with aggressive caching at every layer controlled by TTL. Understanding record types (A, CNAME, MX, TXT, NS, SOA) lets you configure domains correctly, and mastering dig lets you debug resolution failures, propagation delays, and misconfigurations quickly. In the next part, we'll see what happens after DNS resolves — the HTTP request and TLS handshake that establish a secure connection.