DNS Fundamentals¶
Overview¶
DNS (Domain Name System) is the distributed phone book of the internet. Every curl, browser request, database connection string, and Kubernetes service lookup depends on translating human-readable names like api.example.com into IP addresses. When DNS breaks, everything looks like a network outage — even when routing and firewalls are fine.
This tutorial is Tutorial 8 in Module 3: Transport & DNS of the REBASH Academy Networking series. You will learn the hierarchical namespace, the difference between recursive and iterative queries, how Linux resolves names, and how to debug with dig and nslookup. For Linux resolver configuration overlap, see Linux Networking Essentials; here we focus on DNS architecture and query mechanics.
Prerequisites¶
- Complete TCP and UDP Deep Dive or understand UDP/TCP port 53
- Linux VM or cloud instance with network access
digandnslookupinstalled (sudo apt install dnsutilson Debian/Ubuntu)- Optional: access to modify
/etc/hostsfor lab exercises
Learning Objectives¶
By the end of this tutorial, you will be able to:
- Explain the DNS hierarchy from root to authoritative nameservers
- Distinguish recursive vs iterative DNS queries
- Describe the role of stub resolvers, recursive resolvers, and caching
- Configure and inspect
/etc/hosts,/etc/resolv.conf, and systemd-resolved - Perform lookups with
digand interpret query flags and sections - Trace resolution paths with
dig +tracefor delegation debugging
Architecture Diagram¶
flowchart TB
subgraph Client
APP[Application]
STUB["Stub Resolver<br/>glibc / systemd-resolved"]
end
subgraph Resolver
REC["Recursive Resolver<br/>8.8.8.8 / corporate DNS"]
CACHE["(Local Cache")]
end
subgraph Authoritative
ROOT[Root .]
TLD[TLD .com]
AUTH["Auth NS<br/>example.com"]
end
APP --> STUB
STUB --> REC
REC --> CACHE
REC -->|iterative| ROOT
ROOT -->|referral| TLD
TLD -->|referral| AUTH
AUTH -->|answer| REC
REC --> STUB
STUB --> APP```
## Theory
### Why DNS Exists
IP addresses change — load balancers fail over, CDNs rotate edges, autoscaling adds nodes. DNS provides a **stable name** that maps to current addresses. Applications call `getaddrinfo()`; the resolver handles the rest.
DNS messages are typically **UDP port 53** for queries under 512 bytes (4096 with EDNS0). Large responses or zone transfers use **TCP 53**.
### The DNS Namespace Hierarchy
Domains are read **right to left**, ending with the implicit root `.`:
```text
www.api.example.com.
│ │ │ │ └── root (usually omitted)
│ │ │ └────── TLD: com
│ │ └────────────── domain: example
│ └────────────────── subdomain: api
└────────────────────── host: www | Level | Example | Operator |
|---|---|---|
| Root | . | Root server operators (13 logical clusters) |
| TLD | .com, .org, .io | Registries (Verisign, etc.) |
| Domain | example.com | Registrant / organization |
| Subdomain | api.example.com | Domain owner via NS delegation |
Delegation happens through NS records at each level. Parent zone says "ask these nameservers for child zone."
Query Types: Recursive vs Iterative¶
| Type | Who performs | Behavior |
|---|---|---|
| Recursive | Resolver on client's behalf | Client asks resolver; resolver chases referrals until final answer or NXDOMAIN |
| Iterative | Each server in chain | Server returns best answer or referral to next level; querier continues |
Your laptop's configured nameserver (8.8.8.8, corporate DNS, 127.0.0.53) is typically a recursive resolver. Root and TLD servers respond iteratively — they don't chase queries for clients.
Stub resolver (in glibc, musl, or systemd-resolved) forwards queries to the recursive resolver listed in /etc/resolv.conf. It does not implement full recursion itself.
Caching and TTL¶
Resolvers cache answers based on TTL (Time To Live) from records. Short TTL (60s) enables fast failover; long TTL (86400s) reduces query load but slows propagation after changes.
Negative answers (NXDOMAIN — name doesn't exist) also cache with negative TTL from SOA record.
Linux Name Resolution Order¶
/etc/nsswitch.conf controls lookup order:
files— check/etc/hostsfirstdns— query resolver via/etc/resolv.confmyhostname— systemd local hostname resolution
This explains why a stale /etc/hosts entry breaks DNS testing even when dig returns correct answers — dig bypasses nsswitch and talks directly to DNS servers.
Key Configuration Files¶
| File | Purpose |
|---|---|
/etc/hosts | Static name-to-IP overrides |
/etc/resolv.conf | Nameserver list, search domains, options |
/etc/nsswitch.conf | Resolution order (files, dns) |
/run/systemd/resolve/stub-resolv.conf | systemd-resolved stub (127.0.0.53) |
On systemd systems, /etc/resolv.conf may be a symlink — edit via netplan, NetworkManager, or resolvectl, not manual overwrite.
dig Output Sections¶
;; QUESTION SECTION: — what was asked
;; ANSWER SECTION: — direct answer records
;; AUTHORITY SECTION: — nameservers for the zone
;; ADDITIONAL SECTION: — glue records (A/AAAA for NS hostnames)
Flags: qr query/response, aa authoritative answer, rd recursion desired, ra recursion available, ad authenticated data (DNSSEC).
Hands-on Lab¶
Step 1 – Basic lookup with dig¶
Command:
Explanation: +noall +answer shows only answer section. +short returns IP only — good for scripts.
Expected output:
Step 2 – Full dig output interpretation¶
Command:
Explanation: Study HEADER flags, QUESTION, ANSWER, AUTHORITY sections. Note TTL and IN (Internet) class.
Expected output:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12345
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 3600 IN A 93.184.216.34
Step 3 – Query specific nameserver¶
Command:
dig @8.8.8.8 example.com A +short
dig @1.1.1.1 example.com A +short
dig @ns1.example.com example.com A 2>&1 | tail -5
Explanation: @server targets a specific resolver or authoritative NS. Last command may fail if ns1.example.com isn't real — demonstrates syntax.
Expected output:
Step 4 – Trace delegation chain¶
Command:
Explanation: Simulates iterative resolution from root downward. Essential for "works in one region, not another" debugging.
Expected output:
. 518400 IN NS a.root-servers.net.
...
com. 172800 IN NS a.gtld-servers.net.
...
example.com. 3600 IN A 93.184.216.34
Step 5 – nslookup comparison¶
Command:
Explanation: nslookup is interactive and legacy but still common. -type selects record type.
Expected output:
Step 6 – /etc/hosts override lab¶
Command:
grep example.com /etc/hosts || true
echo "127.0.0.99 example.com" | sudo tee -a /etc/hosts
getent hosts example.com
dig +short example.com A
curl -s -o /dev/null -w "%{http_code}\n" --connect-timeout 2 http://example.com || true
sudo sed -i '/127.0.0.99 example.com/d' /etc/hosts
Explanation: getent uses nsswitch (sees hosts file); dig queries DNS directly. Demonstrates split behavior.
Expected output:
Step 7 – Inspect resolver configuration¶
Command:
Explanation: Identifies upstream DNS, search domains, and lookup order.
Expected output:
nameserver 127.0.0.53
options edns0 trust-ad
search ec2.internal us-west-2.compute.internal
hosts: files dns myhostname
Step 8 – Reverse lookup intro¶
Command:
Explanation: -x performs reverse PTR lookup (IP → name). Requires PTR records in in-addr.arpa zones.
Expected output:
Commands & Code¶
| Command | Description | Example |
|---|---|---|
dig DOMAIN TYPE | Standard DNS lookup | dig example.com A |
dig +short DOMAIN | Answer only | dig +short google.com |
dig @NS DOMAIN | Query specific server | dig @8.8.8.8 example.com |
dig +trace DOMAIN | Trace delegation from root | dig +trace example.com |
dig -x IP | Reverse PTR lookup | dig -x 10.0.0.1 |
dig +noall +answer | Minimal output | Script-friendly |
nslookup DOMAIN | Legacy lookup | nslookup example.com |
getent hosts NAME | glibc resolution path | Includes /etc/hosts |
resolvectl query NAME | systemd-resolved lookup | resolvectl query example.com |
resolvectl status | Per-link DNS config | Shows DNS servers |
host DOMAIN | Simple lookup utility | host example.com |
DNS resolution diagnostic script¶
#!/usr/bin/env bash
# dns-check.sh — compare nsswitch vs direct DNS
set -euo pipefail
NAME="${1:?usage: dns-check.sh hostname}"
echo "=== nsswitch (getent) ==="
getent hosts "$NAME" || echo "getent: no entry"
echo ""
echo "=== dig +short (direct DNS) ==="
dig +short "$NAME" A || echo "dig A: no answer"
dig +short "$NAME" AAAA 2>/dev/null | head -3 || true
echo ""
echo "=== Resolver config ==="
grep -E '^nameserver|^search' /etc/resolv.conf 2>/dev/null | head -5
echo ""
echo "=== resolvectl (if available) ==="
resolvectl query "$NAME" 2>/dev/null | head -10 || echo "resolvectl not available"
Batch lookup from file¶
#!/usr/bin/env bash
# bulk-dig.sh — resolve hostnames from list
while read -r host; do
[[ -z "$host" || "$host" =~ ^# ]] && continue
ip=$(dig +short "$host" A | head -1)
printf "%-40s %s\n" "$host" "${ip:-NXDOMAIN/empty}"
done < "${1:?hostfile}"
Common Mistakes¶
Trusting dig when apps fail
Applications use nsswitch — /etc/hosts or LDAP may override DNS. Always compare getent hosts with dig.
Manually editing resolv.conf on cloud images
cloud-init, NetworkManager, or systemd-resolved overwrite manual edits. Configure DNS at the source (netplan, NM, DHCP).
Assuming NXDOMAIN means typo only
NXDOMAIN can mean DNS hijacking, split-horizon misconfiguration, or wrong search domain appended.
Ignoring search domain behavior
With search example.com, querying api may resolve api.example.com. Unexpected suffixes cause "works on my laptop" bugs.
Using nslookup in scripts
Output format varies; dig +short is script-safe and consistent.
Best Practices¶
Use dig +trace for delegation issues
When records are wrong after zone changes, trace shows whether root, TLD, or authoritative server returns stale data.
Specify record type explicitly
Default is A; modern dual-stack services need AAAA. Use dig AAAA and dig A separately.
Document internal vs external resolvers
Corporate split-horizon DNS returns different answers inside vs outside. Runbooks should list which resolver to test from each zone.
Prefer systemd-resolved or dedicated caching forwarder
Local caching reduces latency and upstream load — important for high-churn microservices.
Set reasonable TTL before migrations
Lower TTL 24–48 hours before IP changes to speed propagation.
Troubleshooting¶
| Issue | Cause | Solution |
|---|---|---|
dig works, app fails | /etc/hosts override or nsswitch | Compare getent vs dig; inspect hosts file |
| Intermittent resolution | Flaky upstream resolver | Switch to reliable DNS; check resolvectl statistics |
| Wrong IP returned | Split-horizon or stale cache | Query authoritative NS directly; flush local cache |
SERVFAIL | Auth server error or DNSSEC failure | Check auth NS health; dig +dnssec for validation errors |
NXDOMAIN | Name doesn't exist or wrong domain | Verify spelling; check search domain suffix |
| Slow lookups | High latency to resolver | Use local cache; pick geographically close DNS |
| No reverse DNS | Missing PTR record | PTR is optional; create in IP owner zone if needed |
| TCP 53 timeouts | Large response needs TCP | Normal for big zones; ensure firewall allows TCP 53 |
connection timed out; no servers could be reached | No route to resolver | Fix routing; verify /etc/resolv.conf nameservers |
Summary¶
- DNS is a hierarchical, distributed system delegating authority from root through TLD to domain owners
- Recursive resolvers chase queries for clients; iterative servers return referrals or answers
- Linux resolves via nsswitch (
filesthendns) —/etc/hostscan override DNS for applications digis the primary diagnostic tool;+tracereveals delegation problems- Understand TTL, caching, and search domains before blaming application code for name failures
- UDP 53 is default transport; TCP 53 used for large responses and zone transfers
Interview Questions¶
- Explain the DNS hierarchy from root to authoritative nameserver.
- What is the difference between recursive and iterative DNS queries?
- Why might
dig example.comandping example.comresolve differently? - What does
dig +traceshow and when would you use it? - What is the purpose of
/etc/hostsand nsswitch.conf? - Why do resolvers cache DNS answers and what is TTL?
- What ports does DNS use and when does it switch to TCP?
- What is a stub resolver?
- Explain the difference between forward and reverse DNS.
- What does NXDOMAIN mean?
Sample Answers (Questions 3, 4, and 7)
Q3 — dig vs ping difference: dig queries DNS servers directly. ping calls the system resolver via nsswitch, which checks /etc/hosts first, then DNS. A hosts file entry can redirect ping while dig still shows the public IP.
Q4 — dig +trace: Performs iterative queries starting at root servers, following NS referrals through TLD to authoritative nameservers. Use when propagation issues occur, when validating zone delegation, or when different resolvers return conflicting answers.
Q7 — DNS ports: Most queries use UDP 53. TCP 53 is used when response exceeds 512 bytes (or EDNS buffer), for zone transfers (AXFR/IXFR), and when truncation (TC bit) forces retry over TCP.
Related Tutorials¶
- Networking – Category Overview
- TCP and UDP Deep Dive (previous)
- DNS Records and Troubleshooting (next)
- Linux Networking Essentials
- HTTP, HTTPS, and the Application Layer
- Learning Paths – DevOps Engineer