A browser reports DNS_PROBE_FINISHED_NXDOMAIN and the user says the internet is down. The network is fine. The name does not exist — or the resolver cannot reach the server that would know.

DNS is the service with the widest gap between "it works" and "I know why it works." This article closes that gap from the client outward, because that is the order the packets travel.

The cast

Role What it does In a district
Stub resolver Asks one question and waits The laptop, phone, Chromebook
Recursive resolver Finds the answer, caches it 10.0.0.3 / 10.0.0.4, the domain controllers
Forwarder Passes queries upstream The DCs' forwarders, or the gateway
Authoritative server Owns a zone and answers from it Your public DNS host; AD-integrated zones

The stub resolver does no work. It sends a query with the "recursion desired" bit set and expects a complete answer. Everything interesting happens one hop up.

The walk

For www.example.com, with an empty cache:

  1. Root. The resolver asks a root server: who handles .com? It gets a referral, not an answer.
  2. TLD. It asks a .com server: who handles example.com? Another referral.
  3. Authoritative. It asks example.com's nameserver for www, and gets an A record.
  4. Cache. It returns the answer to the client and stores it for the record's TTL.

That is three round trips on a cold cache, usually under 100 ms total because the root and TLD answers are themselves cached by the resolver from previous queries. On a warm cache it is one local lookup.

Cold lookup walks the hierarchy; warm lookups stop at the cache.

Recursion versus iteration

The distinction matters when you are reading a capture:

  • Iterative queries are what the resolver sends to root, TLD, and authoritative servers. Each one either answers or refers you elsewhere.
  • Recursive is what your client sends to its resolver, and what the resolver promises to finish on your behalf.

A recursive resolver that is misconfigured to only iterate will still "work" for cached names and fail for everything else. That is a confusing failure to debug without knowing the difference.

TTL and negative caching

TTL is how long an answer may be cached, in seconds. It is a trade:

TTL Effect
300 (5 min) Changes propagate quickly; more query volume
3600 (1 hour) Balanced, and the common default
86400 (1 day) Few queries, and a bad record sticks for a day

Negative answers are cached too. The NXDOMAIN or NODATA response carries a TTL derived from the zone's SOA minimum, so a typo can persist after you fix it. During a migration, lower the TTL before the move, not after.

The cache is part of the answer

"I changed the record and it still resolves to the old address" is almost never a DNS bug. It is a cached answer with a TTL you set. Flush the resolver cache, not the client, and check the TTL before you assume propagation is instant.

Forwarders: the district pattern

Domain controllers run AD-integrated DNS for the internal zone and forward everything else. That forwarder is where filtering lives.

Client → 10.0.0.3 (DC, AD zone) → forwarder → Securly / public resolver

Two rules follow from that picture:

  • Domain-joined clients must use the DCs. AD needs SRV records that exist only in the internal zone. Pointing them at a public resolver breaks logins, Group Policy, and printing in ways that look unrelated to DNS.
  • The DC's forwarder is a security control. If it points at 1.1.1.1, every filtered category is bypassed for every domain-joined device. That single setting decides whether content filtering works for staff.

Worked example

A staff laptop at 10.40.60.84, DNS 10.0.0.3, asks for accounts.google.com:

  1. Stub sends a recursive query to 10.0.0.3, source port 51422.
  2. The DC checks its cache: miss.
  3. It checks whether it is authoritative: no (not marionisd.net).
  4. It forwards to its configured forwarder.
  5. The forwarder resolves and returns an A record with TTL 300.
  6. The DC caches it, returns it to the client, and the client caches it too.

The next request from another laptop hits the DC cache and returns in under a millisecond. That is why the second page load feels instant and the first does not.

What breaks in production

  • Forwarder loop. Resolver A forwards to B, B forwards to A. Every uncached query times out after the resolver timeout, and cached names still work. The symptom is "some sites load, some hang."
  • One resolver. A single DNS server is a single point of failure for every device. Two DCs, both listed in DHCP option 6, is the minimum.
  • TTL set to a day during a migration. The old address follows you into the next sprint.
  • Clients pointed at the gateway, which forwards to a public resolver, so filtering silently stops for domain-joined devices.
  • IPv6-only AAAA answers returned to clients with no working IPv6 path, producing a timeout before the A record is tried.

Checklist

  1. Every client has two resolvers, both reachable from its VLAN.
  2. Domain-joined devices use the DCs; everything else uses a resolver that enforces filtering.
  3. The DC forwarders point at the filtering resolver, not at a public one.
  4. TTLs are lowered before a migration and restored after.
  5. You can explain the difference between NXDOMAIN, SERVFAIL, and a timeout, and what each implies.

Next

The resolver found the zone. Continue with Zones, Records, and Delegation to see how that zone is built and what a wrong record looks like.

  • DNS
  • Resolvers
  • Caching
  • TTL