🪜 How to check a delegation
Two separate places store a zone's nameserver list: the parent holds it as part of the handoff, the child holds its own copy at the apex (NS records). RFC 1034 §4.2.1 splits the record this way on purpose. Nobody keeps the two copies in sync automatically. Update one and forget the other, and they disagree.
Asks the parent zone who it delegates to.
dig -4 @a.gtld-servers.net isitdns.net NS +norecurseGO no aa, no answer, and the child nameservers in the authority section
NO GO an answer with aa, which means the parent serves the child zone itself
Step 1: find the parent's servers, then ask one#
The parent of isitdns.net is the .net zone itself. You do not have to memorise its servers, you ask DNS for them, the same way you would for any zone.
Client side:
dig @1.1.1.1 +short net. NSThe trailing dot matters: net. means "the TLD itself", not a hostname. Real output:
a.gtld-servers.net.
b.gtld-servers.net.
c.gtld-servers.net.
d.gtld-servers.net.Reading it: these are the .net zone's authoritative servers, and any one of them will do.
Now ask one of them what it holds for our zone:
dig -4 @a.gtld-servers.net isitdns.net NS +norecurse@a.gtld-servers.net: one of the.netservers found above.+norecurse: do not go and look it up, only tell me what you personally hold.
The parent does not consider itself authoritative for the child, so its answer arrives in the authority section rather than the answer section:
;; AUTHORITY SECTION:
isitdns.net. 172800 IN NS hera.ns.cloudflare.com.
isitdns.net. 172800 IN NS coleman.ns.cloudflare.com.Reading it: the parent believes two servers are in charge, and hands out that list with a TTL of 172800 seconds (48 hours, read straight off the block above). A wrong answer here can outlive a same-day fix, cached across the internet for two days.
This kind of response, pointing you somewhere else rather than answering, is called a referral.
Step 2: ask the child#
Now ask one of those nameservers the same question.
Client side:
dig -4 @coleman.ns.cloudflare.com isitdns.net NS +shortcoleman.ns.cloudflare.com.
hera.ns.cloudflare.com.Reading it: the child names the same two servers, and its answer carries the aa flag (RFC 1035 §4.1.1): this is the zone's own opinion, not hearsay.
Step 3: compare#
Put the two lists side by side. They should be identical, ignoring order.
| Result | Verdict |
|---|---|
| identical lists | consistent, nothing to do |
| parent lists a server the child does not | that server is not confirmed to serve the zone, and resolvers sent there can fail |
| child lists a server the parent does not | that server is invisible to most of the internet, because resolvers follow the parent |
In our example both sides list coleman and hera, so this delegation is consistent. Resolvers follow the parent's list, so a server the parent lists but the child does not is a live risk; a server the child lists but the parent does not is reached only through the child's NS set (RFC 2181 §5.4.1).
Step 4: check each listed server actually answers#
A name on the list means nothing until the box behind it responds. Test every one.
Client side:
for ns in $(dig -4 @a.gtld-servers.net isitdns.net NS +norecurse +noall +authority | awk '{print $5}'); do
echo "$ns -> $(dig -4 @"$ns" isitdns.net SOA +norecurse +short | awk '{print $3}')"
doneThis walks the parent's list and asks each server for the zone's serial number. The parent's
list comes out of AUTHORITY, so it takes +noall +authority and an awk on the rdata field;
+short on that first query prints nothing and the loop silently runs zero times. The inner
query is a normal authoritative answer, so +short is right there.
What you want: every server prints the same number.
What the failures mean:
- blank or an error for one server: it is not answering for this zone. That is a lame delegation (RFC 9499 §7), and it is the thing to fix first.
- a different number: the servers hold different versions of the zone (RFC 1035 §3.3.13). Not lame, but stale. See zone transfers.
Glue, and when you need it#
If a zone's nameservers are named inside the zone they serve, there is a chicken-and-egg problem: to find ns1.example.com you must ask example.com's nameservers, and ns1.example.com is one of them. The parent solves it by publishing glue, the IP addresses alongside the referral, in the additional section. RFC 1034 §4.2.1 names these glue RRs and requires them exactly in this case, when the nameserver's name sits below the cut.
isitdns.net uses *.ns.cloudflare.com nameservers, which live in a different zone and resolve independently, so no glue is required here. Missing glue, when it is required, makes the zone unresolvable from a cold cache while looking correct in every control panel. Full rule in delegations.
Quick reference#
The whole check, one block, client side:
echo "parent:"; dig -4 @a.gtld-servers.net isitdns.net NS +norecurse +noall +authority
echo "child:"; dig -4 @coleman.ns.cloudflare.com isitdns.net NS +short
echo "serials:"
for ns in $(dig -4 @a.gtld-servers.net isitdns.net NS +norecurse +noall +authority | awk '{print $5}'); do
echo "$ns -> $(dig -4 @"$ns" isitdns.net SOA +norecurse +short | awk '{print $3}')"
doneSwap in your zone, its TLD's servers, and its nameservers. Healthy is: both lists identical, every serial identical, nothing blank.
See also#
- check-an-auth: confirming a single authority is answering correctly
- wireshark-dns-filters: DNS capture and display filters, including for delegation traffic
- SOA records
- dnsviz: a visual view of a delegation chain, including DNSSEC
- Delegation trace: the walk from the root, with a reading of example.com