DNS Authoritative and Recursive
October 31, 2026
DNS Authoritative and Recursive
Name resolution fails more often than forwarding. This chapter treats DNS roles—stub, recursive, authoritative—as lab-first architecture: who answers from zone data, who walks the tree, what gets cached, and how operators verify SOA/NS/glue and DNSSEC with dig. Tooling stays free Linux containers in Containerlab (mid-2026 path): CoreDNS for authoritative lab zones, Unbound for recursion/validation, bind-tools / dig for truth.
Learning goals
By the end of this chapter you can:
- Draw the stub → recursive → authoritative path and predict failure symptoms
- Distinguish authoritative answers (AA) from referrals and cached recursed answers
- Explain SOA, NS, glue, and why in-bailiwick names need A/AAAA glue
- Run a two-node lab: CoreDNS authoritative + Unbound recursive
- Verify with
dig(+trace, +norecurse, DNSSEC flags) and a short checklist
- State what DNSSEC validates for an operator (and what it does not)
Why roles matter
| Role | Answers from | Typical lab tool |
|---|---|---|
| Stub resolver | Asks one or two configured servers | /etc/resolv.conf |
| Recursive resolver | Cache, else iterative queries toward authority | Unbound |
| Authoritative server | Local zone data (primary/secondary) | CoreDNS, BIND, Knot, PowerDNS |
Mixing roles on one daemon is possible (classic BIND “do everything”) but lab clarity comes from splitting: one box owns lab.example, another recurses for clients.
Application
→ stub (/etc/resolv.conf)
→ recursive (Unbound)
→ root / TLD / child authoritative (or lab fake root)
On the public Internet the recursive walks from the root. In a closed lab you either:
- Forward Unbound to a reachable upstream recursive, or
- Serve a private root / stub zones that point at your authoritative.
This chapter uses a private zone plus Unbound stub-zone / forward to the CoreDNS auth IP—no need for a full root mirror.
Concepts — recursive vs authoritative
Authoritative
Configured for a set of zones. Answers from local data without querying others for those names. Flags AA (Authoritative Answer) when the response is from that zone’s data.
Primary vs secondary: secondaries still answer authoritatively once they hold a zone copy (IXFR/AXFR). Delegation in the parent does not by itself make a server authoritative—you must configure the zone.
Recursive
Receives queries from stubs (RD=1). Satisfies from cache when possible; otherwise starts at a configured root or forwarder and follows referrals until an authoritative answer is obtained, then returns it to the client (usually with AA clear on the final client-facing message, AD set if DNSSEC validation succeeded—see below).
Stub
Library or OS resolver: almost no policy. Points at recursive IPs. Failures here look like “DNS is down” even when the path to 8.8.8.8 is fine but resolv.conf points at a black hole inside the namespace.
Concepts — SOA, NS, glue
| Record | Operator meaning |
|---|---|
| SOA | Apex start-of-authority: primary name, contact, serial, refresh/retry/expire/minimum (negative TTL flavor) |
| NS | Nameserver hostnames for the zone (apex) or delegation (parent) |
| Glue | A/AAAA for NS hostnames that lie inside the child zone (in-bailiwick)—parent must supply them in additional data or resolution cannot start |
Parent (.example) referral for lab.example:
NS ns1.lab.example.
Additional: ns1.lab.example. A 10.50.0.53 ← glue
Child apex (authoritative):
lab.example. SOA ...
lab.example. NS ns1.lab.example.
ns1.lab.example. A 10.50.0.53
Parent NS/glue and child apex NS should agree. Mismatches are a classic “works from some resolvers” outage (parent-centric vs child-centric resolver behavior differs; treat consistency as hygiene).
Concepts — caching
Recursors cache positive answers and negative answers (NXDOMAIN / NODATA) within TTL / SOA minimum policies. Operator effects:
- Lower TTL → faster change pickup, more query load on auth
- Raise TTL carefully on stable records
- Flush cache after lab zone edits when testing (
unbound-control flushor restart)
Authoritative servers may also cache nothing for their own zones—they serve configured data. Do not expect editing a zone file on auth to update a recursive client until TTL expires or cache is flushed.
Concepts — DNSSEC at operator level
DNSSEC adds authenticity and integrity (not confidentiality). Chain of trust:
Trust anchor (root DS/DNSKEY in validator)
→ DS at parent points to child DNSKEY
→ RRSIGs over RRSets in the child
What to verify as an operator:
| Check | Tooling idea |
|---|---|
| Validator has a current trust anchor | Unbound auto-trust-anchor-file / system anchors |
AD bit on answers you care about |
dig +dnssec example.com from the recursive |
| Broken chain symptoms | SERVFAIL from validating resolver; dig from non-validating still “works” |
| Delegation consistency | Parent DS matches child DNSKEY; NS/glue still required |
Lab note: signing a private lab.example needs a trust anchor you install in Unbound, or you practice DNSSEC against public zones from a recursive that can reach the Internet. Do not confuse AD (Authenticated Data from a validator) with AA (Authoritative Answer from a zone server).
Addressing plan (DNS roles lab)
client ---- (L2) ---- recur ---- (L2) ---- auth
10.50.0.0/24
| Node | IP | Role |
|---|---|---|
| auth | 10.50.0.53/24 | CoreDNS authoritative for lab.example |
| recur | 10.50.0.54/24 | Unbound recursive; stub-zone → auth |
| client | 10.50.0.10/24 | Stub → 10.50.0.54 |
Topology YAML
name: dns-roles
topology:
nodes:
auth:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils bind-tools
# Install coredns binary via your preferred lab method
# (apk package, static binary bind-mount, or distro package).
recur:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils bind-tools unbound
client:
kind: linux
image: alpine:3.20
exec:
- apk add --no-cache iproute2 iputils bind-tools
links:
- endpoints: ["auth:eth1", "recur:eth1"]
- endpoints: ["recur:eth2", "client:eth1"]Adjust images if you standardize on a CoreDNS-bearing image. The verification culture below is what matters more than the exact package name.
Authoritative zone (CoreDNS sketch)
Zone file lab.example.db:
$ORIGIN lab.example.
$TTL 60
@ IN SOA ns1.lab.example. hostmaster.lab.example. (
2026100301 ; serial
300 ; refresh
60 ; retry
86400 ; expire
60 ; minimum
)
@ IN NS ns1.lab.example.
ns1 IN A 10.50.0.53
www IN A 10.50.0.80
api IN A 10.50.0.81
Corefile:
lab.example:53 {
file /etc/coredns/lab.example.db
log
errors
}
Bring-up sketch:
docker exec clab-dns-roles-auth ip addr add 10.50.0.53/24 dev eth1
docker exec clab-dns-roles-auth ip link set eth1 up
# copy zone + Corefile, then:
docker exec clab-dns-roles-auth coredns -conf /etc/coredns/CorefileDirect auth checks (no recursion)
dig @10.50.0.53 www.lab.example A +norecurse
dig @10.50.0.53 lab.example SOA +norecurse
dig @10.50.0.53 lab.example NS +norecurseExpect AA on answers for names in zone. Querying a name outside the zone should fail closed (REFUSED/NXDOMAIN per config)—auth should not recurse unless you deliberately enable it.
Recursive (Unbound) sketch
/etc/unbound/unbound.conf fragment:
server:
interface: 0.0.0.0
access-control: 10.50.0.0/24 allow
do-ip6: no
# For public DNSSEC labs, keep trust anchors enabled.
# auto-trust-anchor-file: "/usr/share/dnssec-root/root.key"
stub-zone:
name: "lab.example"
stub-addr: 10.50.0.53
forward-zone:
name: "."
# Optional: only if auth/private root is not enough and egress exists
# forward-addr: 1.1.1.1
docker exec clab-dns-roles-recur ip addr add 10.50.0.54/24 dev eth1
docker exec clab-dns-roles-recur ip link set eth1 up
docker exec clab-dns-roles-recur unbound -d -c /etc/unbound/unbound.conf &Client stub:
dig verification workflows
1. Happy path via recursive
Predict: answer 10.50.0.80, from recursive (AA typically unset on the client-facing message).
2. Prove auth is the source of truth
Change the zone A record / bump SOA serial / reload CoreDNS, then:
3. Trace mindset (public names)
When the recursive has real root access:
Shows iterative referrals. In a closed lab, +trace may fail at root—use stub-zone labs instead of forcing a fake public trace.
4. Glue / NS consistency
If you later add a parent zone, inspect additional section glue on the referral.
5. DNSSEC operator glance (public)
dig @10.50.0.54 cloudflare.com A +dnssec
# Look for ad flag when validation works; SERVFAIL when chain breaksCompare with a non-validating query path if you temporarily disable validation—difference isolates DNSSEC vs reachability.
Predict → observe → fix
Scenario A — client NXDOMAIN for www.lab.example
- Predict: wrong stub IP, auth down, or typo in zone
- Observe:
dig @10.50.0.54, thendig @10.50.0.53 +norecurse
- Fix: restore auth listening; fix zone; fix resolv.conf
Scenario B — auth works, recursive SERVFAIL
- Predict: stub-zone missing, auth unreachable from recur, or DNSSEC failure
- Observe:
dig @10.50.0.53OK;dig @10.50.0.54SERVFAIL; check Unbound log
- Fix: routing between recur↔︎auth; stub-addr; trust anchor only if validating private zones incorrectly
Scenario C — “update not visible”
- Predict: recursive cache / TTL
- Observe: auth shows new A; recur shows old
- Fix: wait TTL, lower lab TTL, or flush cache
Scenario D — AA vs AD confusion
- Predict: operator expects AD on auth dig
- Observe:
dig @authhas AA, not AD
- Fix: AD comes from a validating recursive, not from AA
Verification checklist
| Check | Intent |
|---|---|
dig @auth SOA |
AA + expected serial |
dig @auth NS + glue A |
Apex NS resolve |
dig @recur name |
Client path works |
| Cache flush drill | TTL behavior understood |
| resolv.conf | Stub points at recur, not auth (unless intentional) |
| Logs | CoreDNS/Unbound query logs on failure |
| DNSSEC (optional) | AD on public name; document trust anchors |
Common mistakes
| Mistake | Symptom |
|---|---|
| Pointing stubs at authoritative only | Public names fail; private names OK |
| Enabling recursion on Internet-exposed auth | Abuse / cache poisoning risk |
| Missing glue for in-bailiwick NS | Delegation black hole |
| Forgetting SOA serial bump on secondaries | Stale secondaries (when you add transfers later) |
| Assuming AA means DNSSEC-valid | Conflates authority with authenticity |
| Lab resolv.conf → Docker host DNS unreachable | Intermittent or total failure inside netns |
Summary
- Authoritative servers answer from zone data (AA); recursives cache and walk or stub toward authority
- Stubs are configuration—wrong
nameserverlines create false “network down” stories
- SOA/NS/glue consistency is operational hygiene; dig
+norecurseagainst auth is your ground truth
- DNSSEC: verify AD via a validating recursive and keep DS/DNSKEY aligned—do not confuse with AA
- Split CoreDNS (auth) and Unbound (recur) in Containerlab until the roles are muscle memory
Next edge labs can reuse this DNS path whenever VIP names and dual-home failovers need human-readable verification.