Module 01 — Names, Resolvers & Your First Query

Updated 20 August 2026

Module 01 · Names, Resolvers & Your First Query

This module assumes zero DNS knowledge. It takes you from "what is a name" to reading a dig response line by line and telling four different kinds of failure apart — which is most of what DNS troubleshooting actually is.

🧠 concept → 🧪 exercise → ✅ expected result (hidden) → 🎯 interview questions (answers hidden)

Prerequisite: none. A Linux shell and an internet connection.


Part A · What a name actually is

A1 · The problem DNS solves

The analogy. Think of the contacts app on your phone. You never memorise phone numbers — you save a name and tap it. Now imagine nobody had a shared contacts app, and instead everyone kept a paper address book they copied by hand. The moment one person changes their number, every book in the country is wrong, and nobody knows it.

That paper book is /etc/hosts. DNS is the shared, always-current contacts app that replaced it.

A network moves packets between IP addresses. Nothing in the network layer understands the word example.com — a router has never heard of it. So something has to turn the name a human types into the address a packet needs. That something is DNS.

The first solution was not DNS. It was one text file, HOSTS.TXT, maintained by hand at the Stanford Research Institute, which every machine on the ARPANET downloaded periodically. Your /etc/hosts file is the direct descendant of it, and it still works exactly the same way.

That design died of three separate diseases, and each one explains a feature of DNS:

Problem with one fileWhat went wrongWhat DNS does instead
LoadEvery host on the network fetching the same file from one machineDistributed — the data lives on thousands of independent servers
Name collisionsOne flat list, so two organisations could not both have a machine called mailHierarchicalmail.a.com and mail.b.com are different names
StalenessYour copy was wrong from the moment someone else changed theirsDelegated + cached with a TTL — the owner changes it, caches expire on a timer
The one-line definition worth memorising: DNS is a distributed, hierarchical, delegated, cached database, whose most common use is mapping names to IP addresses. Every word in that sentence is a separate interview answer, and the rest of this module unpacks them in order.
DNS is a database, not a routing protocol. It hands you data and then gets out of the way. It does not connect you to anything, it does not check that the address it gave you is alive, and it has no idea whether the server behind that address is healthy. "DNS is broken" is a diagnosis people reach for far too early — very often DNS answered correctly and quickly, and the thing at the other end was down.
🧪 Exercise A1.1 — Look at the file DNS replaced
bash
cat /etc/hosts
Expected result — click to reveal
plain text
127.0.0.1	localhost
127.0.1.1	dev-box

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

What to read out of it. Each line is address then name then optional aliases. That is the entire data model of the pre-DNS internet, and it is still consulted on every lookup your machine makes.

Notice what is missing, because the missing things are precisely what DNS adds:

  • No expiry. Nothing tells the machine when this information goes stale. It is right until a human edits it.
  • No authority. Nothing records who is entitled to say what dev-box means. Whoever can write the file wins.
  • No sharing. This file is true on this machine only. The machine next to it can disagree, and neither will ever know.

Now imagine this at 500 hosts. One IP change means pushing a file to 500 machines. Any host that misses the push is silently, confidently wrong — and "silently wrong" is far more expensive to debug than "loudly broken". That single sentence is the reason DNS exists.

🎯 Interview questions — What DNS is

Q. What is DNS and what problem does it solve?

DNS is a distributed, hierarchical, delegated and cached database. Its best-known job is translating human-readable names into IP addresses, but it is a general-purpose lookup system — the same machinery carries mail routing, service discovery, certificate issuance policy and text-based ownership proofs.

The problem it solves is not just "names are nicer than numbers". It is decentralised administration at scale: it lets the owner of a name change what that name points to, without coordinating with anyone else, and without any central authority holding the data.

The detail that separates a strong candidate: pointing out that DNS is a database, not a connection. It returns data and stops. It performs no health checking of the address it returns, so a correct DNS answer and a dead service are entirely compatible states. Candidates who understand this stop blaming DNS first.

Q. Why was a single hosts file not good enough?

Three independent failures, and it is worth naming all three because each maps to a DNS feature.

Load — one server distributing one file to every host on the network does not scale, which is why DNS data is spread over many independent servers.

Collisions — a flat namespace means one global mail. Hierarchy fixes this: mail.a.com and mail.b.com coexist because the name includes the administrative path to its owner.

Consistency — with copies everywhere and no expiry, every copy is wrong between edits. DNS replaces "copy the file" with "ask the owner, then cache the answer for a stated TTL", which bounds how wrong you can be.

Worth adding: /etc/hosts did not disappear. It is still consulted first on most Linux systems, which is why it is a standard debugging and incident tool — and a standard cause of "it works on my machine".


A2 · The namespace is an inverted tree

The analogy. Think of a postal address, written backwards. On an envelope you write name, then street, then city, then country — smallest thing first, biggest last.

A domain name is exactly that: www.example.com means "the machine called www, inside example, inside com". And just like the post office, each level only has to know about the level below it — the country's sorting office doesn't need to know your house number.

The namespace is a tree, drawn upside down: the root at the top, branching downwards. Every node in the tree has a short text label. A domain name is simply the list of labels on the path from a node back up to the root, written left to right, separated by dots.

Diagram source
flowchart TD
    ROOT["root<br>label is empty<br>written as a bare dot"]
    ROOT --> COM["com"]
    ROOT --> ORG["org"]
    ROOT --> UK["uk"]
    COM --> EX["example<br>= example.com"]
    COM --> OTHER["acme"]
    UK --> CO["co"]
    CO --> BBC["bbc<br>= bbc.co.uk"]
    EX --> WWW["www<br>= www.example.com"]
    EX --> ENG["eng"]
    ENG --> API["api<br>= api.eng.example.com"]
    style ROOT fill:#8b5cf6,color:#fff
    style EX fill:#22c55e,color:#fff
    style API fill:#22c55e,color:#fff

Read the diagram from the bottom up, not the top down. api.eng.example.com is api inside eng inside example inside com inside the root. The name is a path, and it is written in the opposite order to a filesystem path — which is the first thing that trips people up.

TermWhat it means, precisely
LabelOne node's name. www, example, com. The root's label is the empty string
Domain nameThe full path of labels from a node to the root, dot-separated
RootThe top of the tree. Written as a single dot . and served by 13 named root server identities
TLDTop-level domain — a label directly under the root. com, org, uk, dev
SubdomainA relative term, not an absolute one. eng.example.com is a subdomain of example.com, which is itself a subdomain of com
Why hierarchy is the whole trick. Because example sits under com, the operator of com can say "anything ending in example.com — ask these servers, not me". That single sentence is delegation, and it is what makes the system scale: nobody has to hold the whole database, and nobody has to be asked permission to change their own slice of it.
"There are only 13 root servers" is a trap. There are 13 root server identitiesa.root-servers.net through m.root-servers.net — because 13 addresses was what fitted in an early response size limit. Behind those 13 names sit well over a thousand physical servers in hundreds of locations, all answering on the same addresses. The mechanism that makes that possible has a name and appears in Module 09.
🧪 Exercise A2.1 — Walk three names of different depths, one of which does not exist
bash
ping -c 1 example.com
ping -c 1 www.example.com
ping -c 1 definitely-not-real.example.com
Expected result — click to reveal
plain text
PING example.com (23.215.0.136) 56(84) bytes of data.
64 bytes from 23.215.0.136: icmp_seq=1 ttl=54 time=11.9 ms

--- example.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

PING www.example.com (23.215.0.138) 56(84) bytes of data.
64 bytes from 23.215.0.138: icmp_seq=1 ttl=54 time=12.1 ms

--- www.example.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

ping: definitely-not-real.example.com: Name or service not known

Your addresses will differ from theseexample.com is served from many locations and the addresses change. That is normal and is itself the point: the name is stable, the address behind it is not.

Three things to read out of this.

1. example.com and www.example.com are different names, and here they resolve to different addresses. They are two separate nodes in the tree. There is no rule anywhere in DNS that makes www.x behave like x — that is a convention people set up by hand, and forgetting to set it up is a common outage.

2. The third failure is a different kind of failure. Look at the wording: Name or service not known. Not Destination Host Unreachable, not Request timed out. ping never sent a packet, because it never got an address to send it to. Resolution failed before the network was involved at all.

3. That distinction is the single most useful reflex in this whole subject. "Name or service not known" means take the network off the suspect list and look at DNS. "Destination Host Unreachable" means DNS did its job and something downstream is wrong. Engineers who cannot tell these apart spend hours on the wrong half of the stack.

What ping will not tell you is why resolution failed — whether the name genuinely does not exist, whether your resolver was unreachable, or whether the name was malformed. Those look identical here. Getting that detail is exactly what dig is for, and that is Part C.

🎯 Interview questions — The namespace

Q. Describe the structure of the DNS namespace.

An inverted tree with an unnamed root at the top. Each node carries a label; a domain name is the path of labels from a node up to the root, written left to right and separated by dots — so it reads most-specific-first, the opposite of a filesystem path.

Directly under the root are the top-level domains, then registrable domains beneath those, then whatever structure the owner chooses.

The point worth making explicitly: the hierarchy is not cosmetic, it is the administrative boundary. Because the tree is nested, authority can be handed downwards one branch at a time, which is what lets the database be maintained by millions of unrelated parties with no central coordination.

Q. How many root servers are there?

Thirteen root server identities, a through m under root-servers.net, operated by twelve independent organisations. Thirteen because that many addresses fitted inside the original 512-byte UDP response limit.

But thirteen identities is not thirteen machines. Each identity is served by many physical instances in many countries, all announcing the same address, so the practical count is over a thousand servers.

The trap in this question is answering "13" and stopping. The interviewer is usually checking whether you know the difference between a name, an address, and a server — three things this question deliberately blurs.


A3 · Absolute names, relative names, and the trailing dot

The analogy. Think of giving someone directions. If you say "the bakery on Jalan Ampang", that works fine if you are both standing in Kuala Lumpur. Say it to someone in another country and they have no idea where you mean — unless you add "… in Kuala Lumpur, Malaysia".

A name without a trailing dot is the short version, and something may quietly fill in the rest for you. The trailing dot is the "… Malaysia" — it says "this is the complete address, do not add anything".

Because the root's label is empty, the truly complete form of a name ends in a dot:

plain text
www.example.com.
│   │       │  └── the root, whose label is empty
│   │       └───── com
│   └───────────── example
└───────────────── www

A name written with that final dot is absolute — it is anchored at the root and means exactly one thing everywhere in the world. The formal term is FQDN, fully qualified domain name.

A name written without the final dot is relative, and something is entitled to add labels to it before looking it up.

This is genuinely counter-intuitive, so state it plainly: www.example.com and www.example.com. are not guaranteed to be the same query. The version without the dot may be expanded into www.example.com.corp.internal. before it is ever sent. On a laptop at home the two behave identically and you will never notice. Inside a corporate network or a Kubernetes pod they behave differently, and the difference is a well-known source of five-second delays and bewildering resolution failures.

The rules that govern that expansion — the search list and ndots — are the subject of Module 06. What matters now is only this: the trailing dot means "do not touch this name, send it as written".

🧪 Exercise A3.1 — Prove the trailing dot is legal, then break the name deliberately
bash
ping -c 1 example.com.
ping -c 1 example.com..
Expected result — click to reveal
plain text
PING example.com (23.215.0.136) 56(84) bytes of data.
64 bytes from 23.215.0.136: icmp_seq=1 ttl=54 time=12.0 ms

--- example.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

ping: example.com..: Name or service not known

The first command works and most people are surprised by that. The trailing dot is not a typo and not decoration — it is the root label, and it is the more correct way to write a name. ping strips or ignores it and resolves normally.

The second fails because it contains an empty label in the middle. example.com.. asks for a label between the two final dots, and that label is the empty string — which is reserved for the root and cannot appear anywhere else. This one is not a network failure; the name itself is invalid.

Where you will actually meet the trailing dot. In zone files, where a name without a trailing dot silently gets the zone name appended — so writing www.example.com inside the example.com zone produces www.example.com.example.com.. That is one of the most common zone-file mistakes there is, it produces a valid file that loads without complaint, and Module 02 makes you commit it on purpose so you recognise it.

🎯 Interview questions — FQDNs

Q. What is an FQDN, and what does the trailing dot mean?

A fully qualified domain name specifies the complete path to the root, so it is unambiguous globally. The trailing dot is the root — the root's label is the empty string, so example.com. has labels example, com, and empty.

A name without the trailing dot is relative and may have a search domain appended before it is queried.

Where this earns you credit: naming the two places it bites. In zone files, an unqualified name silently gets the origin appended, producing www.example.com.example.com. from a file that loads cleanly. In resolver configuration, the trailing dot is how you force a single absolute query and skip search-list expansion — which is the standard trick for proving that a slow or failing lookup is a search-domain problem rather than a server problem.


The analogy. Think of filling in an official form. The "phone number" box will not accept letters. The "name" box has a maximum number of characters. The rules feel arbitrary until you realise the boxes are a fixed size on the paper.

Same here — and the twist worth remembering: "valid DNS name" and "valid host name" are two different forms with two different rule sets. Something can pass one and fail the other.

RuleDetail, and why it exists
A label is at most 63 octetsThe length is encoded on the wire in a byte whose top two bits are reserved, leaving six bits — and six bits counts to 63
A whole name is at most 255 octetsCounting the length byte in front of every label plus the final zero byte. In practice this caps you at roughly 253 printable characters
Host names: letters, digits, hyphenThe "LDH" rule from RFC 1035, relaxed by RFC 1123 to allow a leading digit. A hyphen may not start or end a label
Comparison is case-insensitiveExample.COM and example.com are the same name. Case is preserved on output but never affects matching
The wire is 8-bit cleanDNS itself can carry arbitrary bytes in a label. The LDH restriction is a host name rule, not a DNS rule — which is why _dmarc and _sip._tcp are perfectly valid DNS labels
The distinction nearly everyone misses. "Valid DNS name" and "valid host name" are two different rule sets. DNS will happily store and serve a label starting with an underscore; it is host name syntax that forbids it. This is why service-discovery names like _sip._tcp.example.com exist and are legal — they are deliberately outside host-name syntax so they cannot collide with a real machine name.
🧪 Exercise A4.1 — Prove case does not matter, then build an illegal label
bash
ping -c 1 ExAmPlE.cOm

# a 64-character label - one octet over the limit
ping -c 1 $(printf 'a%.0s' {1..64}).example.com
Expected result — click to reveal
plain text
PING ExAmPlE.cOm (23.215.0.136) 56(84) bytes of data.
64 bytes from 23.215.0.136: icmp_seq=1 ttl=54 time=11.8 ms

--- ExAmPlE.cOm ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms

ping: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com: Name or service not known

The mixed-case lookup succeeds and the tool echoes back your capitalisation. Case is preserved for display and ignored for matching — those are two different behaviours and both are in RFC 4343.

Now the important part, and it is about what you cannot see. The 64-character label failed with Name or service not known — the exact same message you got in Exercise A2.1 for a name that simply did not exist. But these are completely different events:

  • In A2.1 a query was sent and the network answered "no such name"
  • Here no query was ever sent — the resolver library rejected the name locally, because 64 does not fit in six bits

ping collapses both into one message, and that is its fatal weakness as a DNS tool. It tells you that resolution failed and never why. Every incident where the answer is "we spent two hours on the wrong thing" starts here.

You will repeat this exact command with dig in Exercise C6.2 and watch it name the real cause in one line.

🎯 Interview questions — Name syntax

Q. What are the length limits on a DNS name?

63 octets per label, 255 octets for the whole name on the wire — which works out to about 253 characters once you account for the length byte before each label and the terminating zero byte.

The answer that shows you understand the format rather than the trivia: 63 is not arbitrary. Each label on the wire is preceded by a length byte, and the top two bits of that byte are reserved as a flag for message compression. Six bits remain, and six bits counts to 63. Knowing why the number is 63 signals that you have read the wire format, which Module 04 covers in full.

Q. Is DNS case sensitive?

No for matching, yes for storage. Lookups and comparisons fold ASCII case, so EXAMPLE.com and example.com are the same name. Case is meant to be preserved when a name is echoed back.

The senior-level addition: because case is preserved but ignored, resolvers can randomise the case of the name they query and require the response to echo it back exactly. That is 0x20 encoding, and it is a cheap defence against off-path spoofing — the attacker has to guess the capitalisation pattern as well as everything else. It comes up again in Module 09.

Q. Is an underscore allowed in a DNS name?

In DNS, yes. In a host name, no. They are separate rule sets and conflating them is the mistake the question is fishing for.

DNS labels are 8-bit clean; the letters-digits-hyphen restriction comes from host name syntax in RFC 1035 and RFC 1123. That is exactly why the underscore prefix was chosen for service and metadata records — _dmarc, _acme-challenge, _sip._tcp — since a label starting with an underscore can never collide with a legitimate machine name.

The practical trap worth mentioning: some validating tools, load balancers and certificate authorities apply host-name rules where DNS rules apply, and reject underscore labels that are perfectly valid. Knowing which layer is complaining saves an afternoon.


Part B · Who answers the question

B1 · The three roles

The analogy. Think of asking a hotel concierge for a restaurant. You ask one person, once. The concierge then phones around — the tourist office, then a district guide, then the restaurant itself — and comes back to you with a single answer. You never see any of that.

You are the stub resolver. The concierge is the recursive resolver. The restaurant is the authoritative server — it knows its own opening hours and nothing about anyone else's.

There are only three roles a piece of software can play in a DNS lookup. Almost every confusing DNS conversation comes from someone using the word "DNS server" for two of them at once.

Diagram source
flowchart LR
    APP["your application<br>curl, browser, ping"]
    STUB["STUB RESOLVER<br>a library inside your OS<br>knows almost nothing<br>asks one server and waits"]
    REC["RECURSIVE RESOLVER<br>a real server, often your ISP<br>or 1.1.1.1 / 8.8.8.8<br>does the work, keeps a cache"]
    AUTH["AUTHORITATIVE SERVER<br>holds the real data for a zone<br>never asks anyone else<br>keeps no cache"]
    APP --> STUB
    STUB -->|"one question<br>please do the work"| REC
    REC -->|"many questions<br>walking down the tree"| AUTH
    style STUB fill:#f59e0b,color:#fff
    style REC fill:#8b5cf6,color:#fff
    style AUTH fill:#22c55e,color:#fff
RoleWhat it doesWhere it lives
Stub resolverAsks one configured server the whole question and waits for the whole answer. Has no cache of its own and no knowledge of the treeA library inside your OS — code, not a service you can log in to
Recursive resolverAccepts "tell me everything about this name", does whatever work is needed, caches what it learns, returns one final answerYour ISP, your router, your company, or a public service such as 1.1.1.1
Authoritative serverHolds the actual configured data for a zone and answers only about that zone. Never asks anyone else on your behalfRun by the domain owner, or by their DNS provider
The mechanism, not the rule. A recursive resolver is permitted to do the work on your behalf, and an authoritative server is not. That is not a capability difference, it is a policy difference expressed by a single bit in every DNS message — the client sets "recursion desired", and the server sets "recursion available" if it is willing. An authoritative server simply never sets that bit. You will see both bits with your own eyes in Exercise C4.1, and Module 04 takes the message format apart properly.
One machine can play two roles, and that is a classic misconfiguration. BIND can serve a zone authoritatively and offer recursion to anyone who asks. Doing that on a public address gives the internet a free amplifier to attack other people with, and it is one of the oldest findings in any DNS audit. You will separate the two deliberately in Module 05.
🧪 Exercise B1.1 — Predict the traffic before you can measure it

No commands for this one. Decide your answer for each case out loud before opening the toggle. Assume a normal laptop using a normal ISP resolver.

  1. You look up example.com. Nobody on your network has asked for it in days.
  2. Immediately afterwards, your colleague on the same office network looks up example.com.
  3. You look up does-not-exist-at-all.example.com.
  4. You look up a name in /etc/hosts.

For each: does a DNS packet leave your laptop, and does one leave your resolver?

Expected result — click to reveal

1. Cold lookup. A packet leaves your laptop. Your resolver has nothing cached, so it does real work out on the internet and packets leave it too. This is the slow case — typically tens to hundreds of milliseconds.

2. Your colleague, seconds later. A packet leaves their laptop — the stub resolver has no cache, so it always asks. But nothing leaves the resolver: it answers from cache, usually in single-digit milliseconds. Your colleague benefits from your lookup and has no idea.

3. A name that does not exist. A packet leaves your laptop, and the resolver does real work to establish the name is absent. The "no" is then cached too — that is negative caching, and it is why a name you have just created can stay "missing" for minutes after you create it. Module 03 explains where the timer for that comes from.

4. A name in /etc/hosts. No DNS packet at all. The lookup is satisfied locally before DNS is consulted. This is why dig can return a perfectly good answer while your application connects somewhere completely different — dig speaks DNS directly and skips /etc/hosts entirely. That divergence is one of the most confusing things in this subject and Module 06 is dedicated to it.

The pattern to take away: the stub asks every single time; the resolver is where caching happens; and the highest-value thing a cache stores is often the negative answer.

🎯 Interview questions — The three roles

Q. What is the difference between a recursive resolver and an authoritative server?

A recursive resolver answers "what is the address of X" by doing whatever work is required — it queries other servers, follows the hierarchy down, caches every step, and hands back one final answer. It owns no data.

An authoritative server holds the configured data for the zones it serves and answers only for those. It does not chase answers for anyone and normally keeps no cache, because it is the source.

The framing interviewers respond to: the resolver is optimised for reads and lives or dies on its cache hit rate; the authoritative server is the source of truth and lives or dies on correctness and availability. They have opposite failure modes — a resolver failure affects everyone who uses that resolver, an authoritative failure affects everyone in the world looking up that zone once caches drain.

Q. What is a stub resolver?

The minimal DNS client built into the operating system — for most Linux systems, code inside glibc rather than a running daemon. It knows how to format a question, send it to the servers listed in its configuration, and read the reply. It cannot walk the hierarchy itself and traditionally holds no cache.

Why it matters operationally: because it holds no cache, every lookup by every process crosses the network to the resolver. That is why an unreachable resolver hangs applications rather than degrading them, and it is why local caching layers such as systemd-resolved, dnsmasq or NodeLocal DNSCache exist. Those layers change the picture significantly, and they are Module 06 and Module 08.

Q. What is an open resolver and why is it a problem?

A recursive resolver that will do work for any client on the internet rather than only its own users.

It is a problem for two reasons. It lets strangers consume your capacity, and — far worse — it makes you a reflector and amplifier: an attacker sends a small query with a forged source address, and your server sends a much larger response to the victim. The response can be many times the size of the query, so the attacker multiplies their bandwidth.

What separates a strong answer: naming the fix rather than just the risk. Split the roles onto different servers or different addresses, restrict recursion to known client ranges, and enable response rate limiting on the authoritative side. Module 05 sets this up and Module 09 covers the attack in detail.


B2 · Where your machine gets its resolver from

The analogy. Think of the emergency number stuck to your fridge. Your machine has one number written down that it calls for every question. This file is that sticky note.

The catch: sometimes the number on the note is an internal extension, not the real outside line — so reading the note tells you who picks up first, not who actually answers.

Official docs: resolv.conf(5) · hosts(5)

The stub resolver has to be told which server to ask. On Linux that comes from /etc/resolv.conf.

The file has three kinds of line. Only one of them matters in this module:

DirectiveMeaning
nameserver <ip>A recursive resolver to ask. Up to three are used by default, in order, as failover — not as load balancing
search <domains>Suffixes that may be appended to relative names. Introduced properly in Module 06
options ...Resolver tuning, including ndots, timeout and attempts. Also Module 06
The second nameserver line is not a backup you should rely on. The stub tries the first server, waits for the full timeout — 5 seconds by default — and only then tries the second. It is failover measured in seconds, not milliseconds, and to a user or a health check that is indistinguishable from an outage. Redundancy that costs 5 seconds per lookup is not the redundancy people assume they are buying.
🧪 Exercise B2.1 — Find out who your machine actually asks
bash
cat /etc/resolv.conf
Expected result — click to reveal

You will see one of roughly three shapes. All three are normal.

Shape 1 — a real resolver on your network:

plain text
nameserver 192.168.1.1
search home

Shape 2 — a public resolver, common on a cloud VM:

plain text
nameserver 8.8.8.8
nameserver 8.8.4.4

Shape 3 — a local stub listener, the default on modern Ubuntu and Fedora:

plain text
# This is /run/systemd/resolve/stub-resolv.conf managed by man:systemd-resolved(8).
# Do not edit.
nameserver 127.0.0.53
options edns0 trust-ad
search .

If you got shape 3, read this carefully, because it is the single most misleading line in Linux networking. 127.0.0.53 is on your own machine. It is a local caching stub listener run by systemd-resolved, and the real upstream resolvers are configured somewhere else entirely and are not shown in this file.

The practical consequence: on such a machine, cat /etc/resolv.conf cannot answer the question "which resolver is my traffic actually going to". Editing the file usually does nothing either, because it is regenerated. Module 06 shows the command that gives the true answer.

Now imagine this at 500 hosts. Half your fleet reads its upstream from this file and half does not. Any runbook step that says "check /etc/resolv.conf" is correct on some hosts and quietly wrong on the others — which is exactly how an incident ends up with two engineers looking at the same output and reaching opposite conclusions.

🎯 Interview questions — Resolver configuration

Q. How does a Linux machine know which DNS server to use?

From the nameserver lines in /etc/resolv.conf, which the stub resolver reads. The file is usually generated — by DHCP, by NetworkManager, by cloud-init, or by systemd-resolved — rather than hand-edited, so editing it directly is often undone on the next network event.

The detail that matters in production: multiple nameserver lines are sequential failover, not load balancing. The resolver uses the first and only moves on after a timeout, five seconds by default. So a dead primary does not cost you nothing, it costs you five seconds on every lookup until the configuration changes.

And if the file says 127.0.0.53, it is not telling you the upstream at all — that is a local systemd-resolved listener and the real servers are configured elsewhere.


Part C · Installing the tools and asking the question yourself

C1 · Installing dig

The analogy. Think of keeping a torch in the drawer. You buy it before the power cut, not during one.

dig lives in a package whose name has nothing to do with the word "dig", and production containers usually ship with no tools at all — so the moment you need it is the moment you cannot install it.

digdomain information groper — is the tool. It ships as part of BIND, the reference DNS implementation, which is why it is not always installed by default: it lives in a package whose name has nothing to do with the word dig.

DistributionInstall command
Debian, Ubuntusudo apt update && sudo apt install -y bind9-dnsutils
RHEL, Rocky, Alma, Fedorasudo dnf install -y bind-utils
Alpinesudo apk add bind-tools
Archsudo pacman -S bind
macOSAlready present. brew install bind if you want a newer version
On Debian and Ubuntu the old package name was dnsutils. It still works because it is kept as a transitional package that pulls in bind9-dnsutils, but you will see both names in tutorials and in old runbooks. Use the current name.
🧪 Exercise C1.1 — Meet the failure first, in a container that has nothing
bash
# a deliberately bare image - this is what your CI runners and
# slim application images actually look like
docker run --rm -it ubuntu:24.04 bash

# inside the container:
dig example.com
ping -c 1 example.com
Expected result — click to reveal
plain text
root@3f9c1a2b4d5e:/# dig example.com
bash: dig: command not found

root@3f9c1a2b4d5e:/# ping -c 1 example.com
bash: ping: command not found

Both tools are missing, and this is the single most common wasted hour in container debugging. You are trying to establish whether DNS works inside a pod, and the image contains no DNS tooling at all — so every diagnostic you reach for reports command not found, which looks alarmingly like a broken system.

Read the error precisely. bash: dig: command not found is your shell speaking, not DNS. Compare it with ping: example.com: Name or service not known, which is a resolution failure. Same feeling of "it's broken", completely different cause. Getting fast at classifying error messages by who emitted them is most of what troubleshooting skill actually is.

What to do instead in a bare container, before installing anything — because the ability to resolve is already there even when the tools are not:

bash
apt update && apt install -y bind9-dnsutils iputils-ping

Now imagine this at 500 hosts. You cannot apt install inside a production pod on a locked-down cluster, and you should not want to. This is why teams keep a purpose-built debug image with dig, ping, curl and ss in it, and attach that to a running pod instead of mutating the application container. Module 08 shows the exact pattern.

🧪 Exercise C1.2 — Install it and confirm which version you have
bash
sudo apt update && sudo apt install -y bind9-dnsutils   # or dnf install bind-utils
dig -v
Expected result — click to reveal
plain text
DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu

Note the version, because dig output has changed over the years. Two differences you will actually trip over when comparing your output against a blog post or a colleague's terminal:

  • BIND 9.16 and later print an OPT PSEUDOSECTION by default. Older output does not have it
  • Recent versions append the transport to the SERVER: line, as (UDP) or (TCP). Older versions do not

dig -v writes to standard error, not standard output, which surprises people scripting it. Use dig -v 2>&1 if you are capturing it.

🎯 Interview questions — Tooling

Q. Which command-line tools do you use for DNS, and which do you reach for first?

dig first, essentially always. It shows the complete response — the header, the flags, every section, the TTL, which server answered and how long it took — and it lets me target a specific server, which is the thing that actually isolates a fault.

host for a quick one-line check in a script. nslookup only when I am on a machine that has nothing else, typically Windows.

getent hosts when the question is not "what does DNS say" but "what will the application see", because that goes through the full system resolution path including /etc/hosts — and those two answers differing is a real and common failure mode.

The addition that lands well: naming what you would avoid. ping is not a DNS tool. It collapses every possible resolution failure into one message and tells you nothing about which one you hit.


C2 · Your first query

The analogy. Think of asking at a counter and getting the whole printed slip back. You asked one short question; dig hands you the complete form — your question repeated back, the answer, who served you, and how long it took.

It does not summarise and it does not tidy up. That is the point: everything you need to diagnose a problem is on the slip.

The simplest possible form is dig followed by a name.

bash
dig example.com

dig builds a DNS question, sends it to the first server in /etc/resolv.conf, waits, and prints the entire response in a fixed layout. It does not interpret anything for you and it does not consult /etc/hosts — it speaks DNS and only DNS.

🧪 Exercise C2.1 — Run it, and do not try to understand the output yet
bash
dig example.com
Expected result — click to reveal
plain text
; <<>> DiG 9.18.30-0ubuntu0.24.04.2-Ubuntu <<>> example.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 47823
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.com.			IN	A

;; ANSWER SECTION:
example.com.		277	IN	A	23.215.0.136
example.com.		277	IN	A	96.7.128.175
example.com.		277	IN	A	23.192.228.80
example.com.		277	IN	A	23.215.0.138
example.com.		277	IN	A	96.7.128.198
example.com.		277	IN	A	23.192.228.84

;; Query time: 4 msec
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)
;; WHEN: Mon Aug 17 13:41:02 +08 2026
;; MSG SIZE  rcvd: 128

Three quick observations before the detailed reading in C3.

1. You asked for a name and got six addresses. You did not ask for six. The zone owner published six, and every one of them is a valid answer. Whatever connects next will pick one — and which one it picks is decided by the client, not by DNS.

2. You never said A, and yet the QUESTION SECTION says A. dig's default query type is A, the IPv4 address record. Nothing about the name implied that. Record types are Module 02.

3. dig added the trailing dot for you — you typed example.com and the question reads example.com.. It qualified the name into an absolute one before sending it. How it decided to do that, and when it decides differently, is Module 06.


C3 · Reading the response, line by line

The analogy. Think of a parcel delivery slip. The slip has a status ("delivered successfully") and it has contents (what was actually in the box).

Those are two different things — a slip can honestly say delivered, no problems while the box is empty. In DNS, status: tells you the counter staff were happy; the ANSWER: count tells you whether you actually got anything. Read both, every time.

This is the most valuable skill in the module. Every DNS response has the same five parts, and knowing what each one is for turns a wall of text into four facts.

Line or sectionWhat it tells you
->>HEADER<<-status: is the verdict. NOERROR means the server answered successfully — it does not mean you got data
flags:Who did what. qr = this is a response · rd = recursion was requested · ra = the server offers recursion · aa = the answer came from an authoritative server
The countersANSWER: 6 is the number to read first. ANSWER: 0 with status: NOERROR is a distinct and very common situation, covered in Part D
QUESTION SECTIONThe question as the server understood it. Always check this — it is where you discover a search domain was appended, or that you typo'd the name
ANSWER SECTIONThe data. Five columns: name, TTL, class, type, value
AUTHORITY / ADDITIONALSupporting records. Empty here; they carry real weight in Module 03
Query time:Round trip in milliseconds. Single digits means a cache hit; tens or hundreds means real work happened
SERVER:Which server actually answered. The first thing to check when an answer is not what you expect

One answer line, decomposed:

plain text
example.com.        277     IN      A       23.215.0.136
│                   │       │       │       └── RDATA - the value
│                   │       │       └────────── TYPE  - what kind of record
│                   │       └────────────────── CLASS - always IN in practice
│                   └────────────────────────── TTL   - seconds this may be cached
└────────────────────────────────────────────── NAME  - what this record is about
Every DNS record has exactly this shape — name, TTL, class, type, value. Learn the shape once and every record type you meet from Module 02 onwards is just a different TYPE and a different RDATA. There is nothing else to it.
NOERROR does not mean "found it". It means "the server processed your question without malfunctioning". A server can answer NOERROR with zero records, entirely correctly, and that combination is one of the most misread outputs in DNS. status: tells you whether the server is happy; the ANSWER: counter tells you whether you got what you wanted. Read both, every time.
🧪 Exercise C3.1 — Strip the output down to just the data
bash
dig example.com +noall +answer
dig example.com +short
Expected result — click to reveal
plain text
$ dig example.com +noall +answer
example.com.		241	IN	A	23.192.228.80
example.com.		241	IN	A	23.215.0.138
example.com.		241	IN	A	96.7.128.198
example.com.		241	IN	A	23.192.228.84
example.com.		241	IN	A	23.215.0.136
example.com.		241	IN	A	96.7.128.175

$ dig example.com +short
23.192.228.84
23.215.0.136
96.7.128.198
23.215.0.138
23.192.228.80
96.7.128.175

+noall +answer is the form to build a habit around. It reads as "turn off every section, then turn the answer section back on". You keep the TTL, the type and the record name — which is almost always the information you actually need — and lose the noise.

+short is for scripts, and it is lossy in a way that matters. It prints values only. No TTL, no type, no status. Which means an empty result from +short is ambiguous: it could be NXDOMAIN, it could be NOERROR with no records, it could be SERVFAIL, it could be a timeout. Four completely different problems, one identical empty output.

Notice the order changed between the two commands. The resolver rotated the records. That is deliberate — it is the crudest form of DNS load balancing, and it is why you must never assume "the first address" is stable. Module 09 covers what this technique can and cannot do.

Now imagine this at 500 hosts. A monitoring check written as dig +short myservice.internal and tested against "is the output empty" will report the same failure for a deleted record, a broken resolver and a network partition. On-call gets one alert that means four things. Check status: in automation, never emptiness.

🎯 Interview questions — Reading a response

Q. Walk me through the output of dig example.com.

Top down: the header line gives the status — the RCODE — and the flags; then the counters for each section; then the question as the server understood it; then the answer records; then metadata about the transaction itself.

In the flags I read qr for response, rd for recursion desired, ra for recursion available, and aa if the answer was authoritative. Each answer record is name, TTL, class, type, then the value.

At the bottom, Query time tells me whether it was a cache hit, and SERVER tells me who answered.

The two lines a strong candidate says they check first: SERVER, because a surprising answer is very often the right answer from the wrong server; and the QUESTION SECTION, because that is where you see that a search domain was appended or that the name was not what you thought you typed. Junior candidates read the answer section and nothing else.

Q. What does the aa flag mean, and why would you care?

Authoritative answer — the response came from a server that holds the zone itself rather than from a cache.

You care because it is how you separate "the record is wrong" from "the record is right and something is serving a stale copy". If the authoritative server has the new value and a resolver still returns the old one, the change is fine and you are simply waiting out a TTL. If the authoritative server itself has the old value, the change never landed.

That single check is the correct first step in any "I updated DNS and nothing happened" investigation, and it saves you from waiting on a TTL for a change that was never made.


C4 · Choosing which server to ask

The analogy. Think of asking three colleagues the same question. If all three say the same thing, you can stop worrying. If one of them says something different, you have not just found the wrong answer — you have found who is wrong, which is far more useful.

That is what @server gives you: the ability to ask the same question of different people and compare.

Prefixing a server with @ sends the query there instead of to your configured resolver. This is the feature that makes dig a diagnostic tool rather than a lookup tool: it lets you ask the same question of different servers and compare, which is how you find out where a wrong answer is coming from.

bash
dig @1.1.1.1 example.com          # ask Cloudflare's public resolver
dig @8.8.8.8 example.com          # ask Google's public resolver
dig @a.root-servers.net example.com   # ask a root server
🧪 Exercise C4.1 — Watch the recursion bits change, and meet a server that refuses to work for you
bash
dig @1.1.1.1 example.com | head -6
dig +norecurse @1.1.1.1 example.com | head -6
dig @a.root-servers.net example.com | head -8
Expected result — click to reveal
plain text
$ dig @1.1.1.1 example.com | head -6
; <<>> DiG 9.18.30 <<>> @1.1.1.1 example.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12045
;; flags: qr rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

$ dig +norecurse @1.1.1.1 example.com | head -6
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 33871
;; flags: qr ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

$ dig @a.root-servers.net example.com | head -8
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59102
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 13, ADDITIONAL: 27

Compare the three flags: lines. That is the whole exercise.

Query 1 — qr rd ra. You asked for recursion (rd) and the server told you it provides recursion (ra). You got six answers. Normal.

Query 2 — qr ra, and rd is gone. +norecurse cleared the request. ra is still set because the server still offers recursion — it just was not asked to use it. You still got six answers, because they were already in Cloudflare's cache. Ask for a name nobody has looked up recently and this query returns ANSWER: 0 — you have asked a cache for something it does not have and forbidden it from finding out. That is exactly how you inspect a cache without warming it.

Query 3 — qr rd and no ra. You asked for recursion and the root server declined to offer it. This is the concrete meaning of "authoritative servers do not do the work for you", the policy point from B1, visible as one missing two-letter flag.

Also note query 3 returned ANSWER: 0 but AUTHORITY: 13. It did not fail and it did not answer — it pointed you somewhere else. That is a referral, and following referrals is the entire subject of Module 03.

Why this is the most useful dig feature in an incident. "The site is broken for some users." Ask your resolver, ask 1.1.1.1, ask 8.8.8.8. If they disagree, you are looking at a caching or propagation problem, and you already know which resolvers are affected. If they all agree and the answer is wrong, the data at the source is wrong. One command, and the search space halves.

🎯 Interview questions — Targeting servers

Q. Users report a site is unreachable but it works for you. How do you use DNS to narrow it down?

I would ask several resolvers the same question and compare — my own, 1.1.1.1, 8.8.8.8, and ideally a resolver on the affected users' network — using dig @server name.

If the answers differ, it is a cache or propagation issue and the differing resolvers tell me the blast radius. If every resolver agrees, DNS is consistent and the fault is downstream: routing, TLS, the application, or a health check.

What makes this a strong answer rather than a list of commands: saying explicitly that I check the authoritative source too, so I can tell "the record is wrong" apart from "the record is right and a cache is stale". Those two have completely different remedies — one is a fix, the other is patience or a TTL change — and confusing them is how teams end up making a second wrong change on top of the first.

Q. What does +norecurse do and when is it genuinely useful?

It clears the recursion-desired bit, so the server answers only from what it already holds.

Its real use is inspecting a cache without disturbing it. A normal query makes the resolver go and fetch the record, which destroys the evidence — after that you can no longer tell whether it was cached before you asked. +norecurse answers "was this already in the cache, and with what remaining TTL" without warming anything.

Where it earns its keep: confirming that a specific resolver is the one holding a stale record during a migration, and checking whether a resolver you do not control is still serving an old address after a cutover.


C5 · The TTL is a live countdown

The analogy. Think of the expiry date on a carton of milk in your fridge. The carton did not start with the date it has now — time has been running down since the shop stocked it.

Two different shops stock their fridges at different times, so their cartons have different dates left, even though it is the same milk. That is why two DNS resolvers show different TTLs for the same record: they fetched it at different moments and each is counting down its own copy.

The TTL in an answer is not a fixed property of the record. It is the remaining lifetime of that particular cached copy, and it is decremented by the cache as it ages. The authoritative server always states the full value; every cache in between counts it down and discards the record at zero.

🧪 Exercise C5.1 — Watch a cache age in real time
bash
dig +noall +answer example.com
sleep 10
dig +noall +answer example.com
sleep 10
dig +noall +answer example.com
Expected result — click to reveal
plain text
example.com.		298	IN	A	23.215.0.136
example.com.		288	IN	A	23.215.0.136
example.com.		278	IN	A	23.215.0.136

Only the first of six records shown for brevity — you will see all six each time.

The TTL dropped by exactly 10 each time, because you slept 10 seconds. You are watching a cache entry expire. This is worth doing once with your own eyes because it converts TTL from a number in a config file into a thing that is visibly happening.

What to read out of it.

  • A TTL below the configured maximum means you are talking to a cache, and it tells you how long ago that cache fetched the record
  • A TTL that resets to the full value means the entry expired and was re-fetched
  • A TTL that is always the full value means you are talking to the authoritative server, or to something that is not caching

The operational consequence, and it is the reason TTL comes up in every DNS interview. A record with a 300-second TTL means that after you change it, some clients keep using the old value for up to 300 more seconds. Nothing you can do makes them stop — you do not control their cache. So the standard migration procedure is: lower the TTL first, wait for the old high TTL to fully expire everywhere, then make the change, then raise the TTL again afterwards. Lowering the TTL at the same time as making the change achieves nothing, because the clients that need to see the low TTL are exactly the ones still holding the old record.

Now imagine this at 500 hosts behind a resolver with a 24-hour TTL on the record. A rollback is not a rollback for a day. That is why TTL planning is part of change planning, not an afterthought.

🧪 Exercise C5.2 — Make two resolvers disagree
bash
dig +noall +answer @1.1.1.1 example.com
dig +noall +answer @8.8.8.8 example.com
Expected result — click to reveal
plain text
$ dig +noall +answer @1.1.1.1 example.com
example.com.		112	IN	A	23.215.0.136

$ dig +noall +answer @8.8.8.8 example.com
example.com.		267	IN	A	23.215.0.136

Same record, same value, different TTL — and neither is wrong. The two resolvers fetched the record at different moments, so their copies are at different points in their lifetimes. Cloudflare fetched about 3 minutes ago; Google about 30 seconds ago.

This is the concrete mechanism behind the phrase "DNS propagation", and it is why the phrase is misleading. Nothing propagates. No update is pushed anywhere. Each cache independently discovers the new value when its own copy of the old one expires — which is why a change appears to roll out gradually and unevenly across the world, and why "it works for me" and "it doesn't work for me" are both true at the same time. Module 03 takes this apart properly.

If the two resolvers had shown different values, you would be looking at a change in flight, and the TTLs would tell you roughly how much longer the stale one has to live.

🎯 Interview questions — TTL and caching

Q. What is TTL in DNS and why does it matter?

Time to live, in seconds — how long a resolver may cache a record before it must fetch it again. The authoritative server publishes the full value; each cache counts it down and evicts at zero.

It is a direct trade-off. High TTL means fewer queries, faster responses and more resilience if the authoritative servers become unreachable, but slower change. Low TTL means agility at the cost of query volume and a harder dependency on your authoritative servers being up.

The operational detail that separates candidates: the ordering of a TTL change. You must lower the TTL and then wait out the old TTL before making the change, because caches holding the old record never see the new low value until their copy expires. Lowering it at the same time as the change is a no-op for exactly the clients you were worried about. Typical practice is to drop to 60 seconds a day ahead of a planned cutover, and raise it again once the change has settled.

Q. What is DNS propagation, and how long does it take?

Strictly speaking there is no such thing — the word implies a push, and DNS has none. Authoritative data changes in one place, and every cache independently picks up the new value when its own cached copy expires.

So the honest answer to "how long" is: up to the TTL that was in effect on the record before you changed it, per cache, plus the time your own provider takes to distribute the change across its authoritative servers.

What marks out a strong candidate: refusing the premise politely, then naming the two things that actually make it take longer than the TTL suggests. First, intermediate resolvers that clamp or extend TTLs to their own minimums and maximums regardless of what you published. Second, application-level caches — a JVM caching DNS forever by default is a genuinely notorious case, and no amount of TTL tuning touches it.


C6 · host, nslookup, and what dig tells you that ping cannot

The analogy. Think of the difference between "I feel unwell" and a thermometer reading. Both tell you something is wrong. Only one tells you what.

ping is "I feel unwell" — it reports that a name did not work, and gives the same message whether the name was mistyped, does not exist, or your resolver is down. dig is the thermometer.

ToolUse it forWhy it is not your default
digEverything diagnostic
hostA quick, readable one-linerHides the flags, the TTL and the status. Fine for a yes/no, useless for a diagnosis
nslookupWindows, or a box with nothing elseIts "Non-authoritative answer" and "server can't find" wording actively misleads people, and it reports some errors identically
delvChecking DNSSEC validationNot needed until Module 07
🧪 Exercise C6.1 — The same question through three tools
bash
dig +short example.com
host example.com
nslookup example.com
Expected result — click to reveal
plain text
$ dig +short example.com
23.215.0.136
96.7.128.175
...

$ host example.com
example.com has address 23.215.0.136
example.com has address 96.7.128.175
example.com has IPv6 address 2600:1408:ec00:36::1736:7f24
example.com mail is handled by 0 .

$ nslookup example.com
Server:		127.0.0.53
Address:	127.0.0.53#53

Non-authoritative answer:
Name:	example.com
Address:	23.215.0.136
Address:	96.7.128.175

host quietly asked three questions, not one. With no type specified it looks up addresses and mail routing, which is why you got lines you did not ask for. Convenient interactively, surprising in a script.

nslookup's "Non-authoritative answer" is not a warning. It means "this came from a cache", which is the normal and expected case for essentially every lookup you will ever do. It is phrased like a problem and is not one, and it has sent a great many engineers looking for a fault that does not exist. This wording alone is a good reason to prefer dig, where the same fact is one flag — aa present or absent.

Neither host nor nslookup shows you the TTL by default, so neither can tell you whether you are looking at a fresh record or a stale one — which is the question you most often actually have.

🧪 Exercise C6.2 — Revisit the illegal label, and finally see the real reason
bash
# the same 64-character label that failed in Exercise A4.1
dig $(printf 'a%.0s' {1..64}).example.com

# and a name that is merely absent
dig definitely-not-real.example.com +noall +comments
Expected result — click to reveal
plain text
$ dig aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com
dig: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.example.com' is not a legal name (label too long)

$ dig definitely-not-real.example.com +noall +comments
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 8842
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

This is the payoff for Part A. In Exercise A4.1 both of these produced the identical message Name or service not known and you could not tell them apart. Now they are obviously two different events:

  • is not a legal name (label too long)dig rejected the name locally. No packet was ever sent. The problem is in your input, not in the network, not in the zone, not in the resolver
  • status: NXDOMAIN — a packet was sent, a server answered, and the answer was an authoritative "that name does not exist". The system worked perfectly; the name genuinely is not there

The generalisable lesson, which is worth more than either fact. When a tool gives you one message for many causes, replace the tool — do not start guessing. ping merges local rejection, NXDOMAIN, SERVFAIL, REFUSED and timeout into a single sentence. dig distinguishes all five, and Part D is about telling them apart.

🎯 Interview questions — Tool differences

Q. nslookup says "Non-authoritative answer". Is that a problem?

No. It means the answer came from a cache rather than from a server that holds the zone, which is the normal case for almost every lookup on the internet.

The wording is unfortunate — it reads like a warning and is merely a statement of fact. In dig the same information is the presence or absence of the aa flag, with no editorial.

Where it does matter: when you are verifying a change you just made. Then you specifically want an authoritative answer, so you query the zone's own servers directly rather than a resolver — and there you would expect aa to be set. Otherwise, non-authoritative is exactly what you should see.


Part D · Reading failure

D1 · There are five ways a lookup can fail, and they are not interchangeable

The analogy. Think of knocking on a door to deliver a parcel. Five things can happen, and they are not the same problem:

· Nobody answers at all — you don't even know if anyone lives there

· "No such address" — the street number does not exist

· "He lives here, but he has no phone" — right person, thing you asked for isn't there

· "I tried to check and our system is down" — something is broken on their side

· "I'm not allowed to tell you" — nothing is broken; you are just not on the list

Five situations, five different people to go and see next. The whole skill is telling them apart.

Almost all DNS debugging comes down to correctly classifying the failure in front of you. There are five distinct outcomes, they have five different causes, and five different people fix them.

What you seeWhat it meansWho fixes it
status: NOERROR ANSWER: 0The name exists. It has no record of the type you asked for. Often called NODATAThe zone owner — a record is missing, or you asked for the wrong type
status: NXDOMAINThe name does not exist at all, and an authoritative server said soWhoever typed the name, or the zone owner
status: SERVFAILThe resolver tried and could not complete the job. A failure on the answering sideThe resolver operator, or the zone's authoritative servers
status: REFUSEDThe server understood you perfectly and declined by policyThe server operator — you are asking the wrong server, or you are not allowed
connection timed out or connection refusedNo DNS-level answer at all. This is a network or process problem, not a DNS answerNetworking, firewall, or whoever should be running the daemon
The mechanism that makes this classification reliable. The first four are DNS responses — a server received your question, formed an opinion, and sent it back. The fifth is the absence of a response. So the first question in any DNS failure is not "what is the error" but "did I get a DNS response at all?" If yes, the RCODE tells you who owns the problem. If no, DNS has told you nothing and you are debugging the network.
Diagram source
flowchart TD
    Q["you run dig"] --> GOT{"did a DNS<br>response come back?"}
    GOT -->|"no"| NET["timed out or refused<br>NETWORK PROBLEM<br>firewall, routing,<br>nothing listening"]
    GOT -->|"yes"| RC{"read status:"}
    RC -->|"NOERROR<br>ANSWER greater than 0"| OK["success<br>you have data"]
    RC -->|"NOERROR<br>ANSWER 0"| NODATA["NODATA<br>name exists,<br>wrong record type"]
    RC -->|"NXDOMAIN"| NX["name does not exist<br>check spelling,<br>check the zone"]
    RC -->|"SERVFAIL"| SF["the answering side broke<br>try another resolver<br>to localise it"]
    RC -->|"REFUSED"| RF["policy<br>wrong server, or<br>you are not permitted"]
    style NET fill:#ef4444,color:#fff
    style OK fill:#22c55e,color:#fff
    style NODATA fill:#f59e0b,color:#fff
    style NX fill:#f59e0b,color:#fff
    style SF fill:#ef4444,color:#fff
    style RF fill:#8b5cf6,color:#fff

D2 · NXDOMAIN versus NOERROR with no data

The analogy. Think of looking someone up in the company directory.

· "There is nobody by that name here" — that is NXDOMAIN. You probably have the name wrong

· "She works here, but she has no mobile number listed" — that is NODATA. The person is real; the detail you asked for is missing

On screen these two look almost identical. In practice one sends you back to check the spelling, and the other sends you to whoever maintains the directory.

These two look almost identical on screen and mean opposite things.

  • NXDOMAIN — there is no node at that point in the tree. Nothing of any type exists there.
  • NOERROR with ANSWER: 0 — the node exists and has records, just not of the type you asked for.
Why the distinction is worth real money. NXDOMAIN says the name is wrong. NODATA says the name is right and the record is missing. Those send you to two different places: one is a typo or a name that was never created, the other is a zone that is incomplete. Reading NODATA as "not found" and going to re-check your spelling is one of the most reliable ways to waste twenty minutes.
🧪 Exercise D2.1 — Produce both, deliberately, and compare them side by side
bash
# a name that does not exist -> NXDOMAIN
dig definitely-not-real.example.com +noall +comments +authority

# a name that DOES exist, asked for a record type it does not have.
# MX records carry mail routing - Module 02 covers the types; all you
# need here is that this particular name has none.
dig MX www.example.com +noall +comments +authority
Expected result — click to reveal
plain text
$ dig definitely-not-real.example.com +noall +comments +authority
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 21044
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; AUTHORITY SECTION:
example.com.		900	IN	SOA	ns.icann.org. noc.dns.icann.org. 2025011653 7200 3600 1209600 3600

$ dig MX www.example.com +noall +comments +authority
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39517
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; AUTHORITY SECTION:
example.com.		900	IN	SOA	ns.icann.org. noc.dns.icann.org. 2025011653 7200 3600 1209600 3600

Look at how similar these are. Both have ANSWER: 0. Both have one AUTHORITY record. Both return the same SOA record. The only difference in the entire output is the word after status: — and that one word is the difference between "you typed the wrong name" and "the zone is missing a record".

This is exactly why dig +short is dangerous in scripts. Run either of these with +short and you get an empty line for both. Two different problems, one indistinguishable output.

Why is there an SOA record in a negative answer? Because a "no" needs an expiry date just as much as a "yes" does. There is no record to attach a TTL to, so the server sends the zone's SOA record instead, and one of the numbers inside it states how long this "no" may be cached. That is why a name you have just created can keep returning NXDOMAIN for minutes after you create it — you are being served a cached "no". The SOA fields and negative caching are Module 02 and Module 03; the reflex to learn now is: if I get NXDOMAIN for something I just created, suspect a cached negative answer before suspecting my change.

Now imagine this at 500 hosts. A new service name is added and half the fleet reports NXDOMAIN for the next hour because they queried it once, a second too early, and cached the "no". Every one of those hosts is behaving correctly. The mistake was querying before publishing.

🎯 Interview questions — NXDOMAIN and NODATA

Q. What is the difference between NXDOMAIN and an empty NOERROR response?

NXDOMAIN means no node exists at that name — nothing of any type is there. NOERROR with a zero answer count, sometimes called NODATA, means the name does exist and has records, just none of the type requested.

Practically: NXDOMAIN points at the name, NODATA points at the record set.

The detail worth adding, because it shows you have read the response and not just the summary line: both come back with the zone's SOA in the AUTHORITY section, and that SOA is what makes the negative answer cacheable. So both can be served from cache, and a name you just created can keep returning NXDOMAIN until that cached negative expires. Checking the authoritative server directly is how you tell "my change didn't land" from "my change landed and I'm reading a cached no".

Q. You add a DNS record and it still returns NXDOMAIN. Walk me through it.

First, query the authoritative servers directly rather than a resolver. If they return the record, the change landed and I am looking at a cached negative answer — then I wait out the negative caching TTL, which comes from the zone's SOA rather than from the record I just added.

If the authoritative servers also say NXDOMAIN, the change did not take effect: I would check that I edited the zone I think I did, that the serial number was incremented, that the zone reloaded, and that secondaries actually transferred it.

The subtlety that impresses: the negative TTL is a property of the zone, not of the record you created, so it is often much longer than the TTL you carefully set on the new record. People set a 60-second TTL on a new record and are baffled that it takes an hour to appear — because the thing being cached is the absence, governed by the SOA.


D3 · SERVFAIL and REFUSED

The analogy. Think of phoning a bank's help desk.

· "Sorry, our system is down, I can't look that up"SERVFAIL. Something really is broken, and it is on their side

· "I'm not allowed to give out that information"REFUSED. Nothing is broken at all. You called the wrong department, or you are not authorised

Treating the second one as an outage is how teams spend an afternoon hunting a fault that does not exist.

RCODEWhat it actually means, and the usual causes
SERVFAIL"I tried and I could not finish." The answering server failed on your behalf. Usual causes: every authoritative server for the zone is unreachable; the delegation points at servers that do not serve the zone; a DNSSEC validation failure; or the resolver itself is broken or overloaded
REFUSED"I understood you and I decline." A policy decision, not a failure. Usual causes: you asked an authoritative-only server about a zone it does not host; you asked a resolver that restricts recursion to certain client ranges; or an ACL blocks the query type
The one-line discriminator. SERVFAIL means something is broken — go and find what. REFUSED means nothing is broken — you are asking the wrong server, or you are not on the list. Treating REFUSED as an outage sends a team hunting for a fault that does not exist.
SERVFAIL is the most over-reported and least specific code in DNS. It is what a resolver says when it has run out of options, and it deliberately does not tell you why — partly for security reasons, partly because the resolver often does not know. So SERVFAIL is never a diagnosis, only a prompt: ask a second resolver the same question. If only one resolver SERVFAILs, the resolver is the problem. If every resolver SERVFAILs, the zone or its delegation is the problem. That single follow-up query splits the search space in half and it is the correct next step every single time.
🧪 Exercise D3.1 — Earn a REFUSED on purpose
bash
# a.iana-servers.net is one of the authoritative servers for example.com.
# Taking that as given for now - Module 02 shows you how to find it yourself.
# Ask it about example.com  -> it will answer authoritatively
dig @a.iana-servers.net example.com +noall +comments

# now ask that same server about a zone it does not serve
dig @a.iana-servers.net google.com +noall +comments
Expected result — click to reveal
plain text
$ dig @a.iana-servers.net example.com +noall +comments
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5512
;; flags: qr aa rd; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 1

$ dig @a.iana-servers.net google.com +noall +comments
;; ->>HEADER<<- opcode: QUERY, status: REFUSED, id: 46108
;; flags: qr rd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1

Two things changed between those two responses, and both are worth naming.

1. The first response has aa set. This is the first time in this module you have seen it. The answer came from a server that holds the zone, not from a cache — and notice the TTLs on those records would be the full published values, not counted down. aa plus full TTLs is the signature of an authoritative answer.

2. The second response is REFUSED, and there is no ra flag anywhere. You asked an authoritative-only server to go and find something for you. It does not do that for anybody, so rather than fail, it declines. Nothing is broken here. The server is working exactly as designed and you asked the wrong question of the right server.

Where you will meet this for real. Someone points an application's resolv.conf at an authoritative server — often because "it's our DNS server" — and everything inside that one zone works while everything else in the world returns REFUSED. The symptom looks bizarre and random until you notice the pattern: only one domain resolves. That pattern is the diagnosis.

The other common source is an ACL. A company resolver that only serves the office ranges will REFUSE a VPN client whose new subnet was never added to the allow-list. Same code, same reasoning: policy, not fault.

🧪 Exercise D3.2 — Two ways of getting nothing at all, which mean different things
bash
# 192.0.2.1 is reserved for documentation and is not routed anywhere.
# Nothing will ever answer. Expect this to take about 15 seconds.
dig @192.0.2.1 example.com

# your own machine, on a port where almost certainly nothing is listening
dig @127.0.0.1 -p 5399 example.com
Expected result — click to reveal
plain text
$ dig @192.0.2.1 example.com
;; communications error to 192.0.2.1#53: timed out
;; communications error to 192.0.2.1#53: timed out
;; communications error to 192.0.2.1#53: timed out

; <<>> DiG 9.18.30 <<>> @192.0.2.1 example.com
; (1 server found)
;; global options: +cmd
;; no servers could be reached

$ dig @127.0.0.1 -p 5399 example.com
;; communications error to 127.0.0.1#5399: connection refused
;; communications error to 127.0.0.1#5399: connection refused
;; communications error to 127.0.0.1#5399: connection refused

; <<>> DiG 9.18.30 <<>> @127.0.0.1 -p 5399 example.com
;; global options: +cmd
;; no servers could be reached

Neither of these has a status: line, and that absence is the most important thing on the screen. There is no RCODE because there is no response. DNS did not answer you — so DNS has told you nothing, and every DNS-level theory you were forming should be set aside.

But the two error words point in different directions, and this distinction is genuinely valuable:

  • timed out — your packet went out and nothing came back. Either it never arrived, or the reply never made it home. Suspect routing, or a firewall silently dropping the packet. Note dig tried three times before giving up: that is the default, and it is why a dead resolver costs you seconds rather than milliseconds
  • connection refused — you reached the host and it actively rejected the port, via an ICMP port-unreachable. The network is fine. Nothing is listening on that port. Suspect a stopped daemon, a service bound to the wrong address, or the wrong port

"Timed out" versus "refused" is the same distinction as an unanswered phone versus a disconnected number, and it routes the ticket to a different team. A silent drop is a network conversation; a refused connection is a process conversation.

Now imagine this at 500 hosts. A security group change removes UDP/53 egress. Every host now waits the full timeout on every lookup, three times, before falling back — so nothing reports as "DNS down", everything reports as "the application is slow". Latency, not errors, is how DNS failures usually present at scale, and that is why they are hard to spot.

🎯 Interview questions — SERVFAIL, REFUSED and timeouts

Q. What does SERVFAIL mean and how do you troubleshoot it?

It means the server answering you could not complete the resolution — it is a failure on the answering side, not a statement about whether the name exists.

My first move is always to ask a different resolver the identical question. If only one resolver fails, the fault is that resolver. If all of them fail, the fault is the zone: unreachable authoritative servers, a delegation pointing at servers that do not host the zone, or a DNSSEC validation failure.

Then I query the zone's authoritative servers directly to see whether they answer at all.

The specific cause worth naming, because it is the one people miss: DNSSEC validation failures surface as SERVFAIL and nothing else. An expired signature produces a plain SERVFAIL that looks like a network problem, and the way to confirm it is to re-query with validation disabled — if it succeeds without validation and fails with it, you have your answer. That is Module 07.

Q. What is the difference between SERVFAIL and REFUSED?

SERVFAIL is "I tried and failed". REFUSED is "I understood and I won't". The first is a malfunction somewhere, the second is a policy decision and means nothing is broken.

REFUSED usually means you are querying an authoritative-only server for a zone it does not host, or a resolver whose ACL does not include your source address.

The reason getting this right matters: the two codes route to different teams. SERVFAIL starts an investigation; REFUSED starts a configuration review. Escalating a REFUSED as an outage burns credibility, and every DNS server operator has watched it happen.

Q. dig reports "connection timed out; no servers could be reached". What do you check?

The absence of a status: line tells me this is not a DNS answer at all — nothing responded — so I stop reasoning about records and start reasoning about reachability.

I would check that I am querying the address I intended, that UDP/53 and TCP/53 egress is permitted, and that something is actually listening — from the server side, ss -ulnp | grep :53.

The distinction I would draw explicitly: timed out means the packet was silently dropped, which is firewall or routing. Connection refused means the host was reached and rejected the port, which means the daemon is not running or is bound to the wrong address. Those are different teams and different fixes, and the two words in the error message are the only clue you get.

And the scale point: at fleet scale this failure mode usually presents as latency rather than errors, because the stub waits out its full timeout and then succeeds against a secondary. You get "the app is slow", not "DNS is down".


Part E · Putting it together

E1 · How this all fits — the complete picture

Diagram source
flowchart TD
    subgraph LOCAL["🖥️ YOUR MACHINE"]
        APP["curl / browser / ping<br>wants an address"]
        HOSTS["/etc/hosts<br>checked first,<br>DNS never consulted"]
        STUB["stub resolver in libc<br>no cache of its own"]
        CONF["/etc/resolv.conf<br>nameserver lines<br>tried in order, 5s each"]
        DIG["dig<br>bypasses hosts and libc<br>speaks DNS directly"]
    end
    APP --> HOSTS
    HOSTS -->|"no match"| STUB
    CONF --> STUB
    STUB -->|"one query<br>rd bit set"| REC
    DIG -->|"@server lets you<br>choose the target"| REC
    REC["🌐 RECURSIVE RESOLVER<br>does the work<br>CACHES the result<br>counts the TTL down<br>sets ra"]
    REC -->|"only on a cache miss"| AUTH["📗 AUTHORITATIVE SERVERS<br>hold the zone<br>set aa<br>full TTL, no cache"]
    REC -->|"NOERROR + data<br>NODATA · NXDOMAIN<br>SERVFAIL · REFUSED<br>or silence"| STUB
    style HOSTS fill:#ef4444,color:#fff
    style REC fill:#8b5cf6,color:#fff
    style AUTH fill:#22c55e,color:#fff
    style DIG fill:#f59e0b,color:#fff

Three things in this diagram cause most of the confusion in DNS, and all three are now things you have seen with your own eyes.

  1. dig and your application do not take the same path. dig skips /etc/hosts and skips the libc resolution logic. A dig that works while curl fails is not a contradiction — it is a clue.
  2. The cache is the only place TTLs count down. Full TTL plus aa means authoritative; a reduced TTL and no aa means you are reading a cache.
  3. Silence is not an RCODE. If there is no status: line, DNS has told you nothing at all.

E2 · Production practice

HabitWhy
Read status: and the ANSWER: counter before reading anything elseNOERROR with zero answers is a completely different problem from NXDOMAIN, and they look nearly identical
Check the SERVER: line on every surprising resultA wrong answer is very often the right answer from the wrong server — a local stub, a VPN resolver, or a split-horizon view
Never use dig +short in automation or alertingIt collapses NXDOMAIN, NODATA, SERVFAIL, REFUSED and timeout into one empty string. One alert, five meanings
On SERVFAIL, immediately re-query a second resolverIt splits the search space in half: one resolver failing is a resolver fault, all of them failing is a zone or delegation fault
Query the authoritative servers directly when verifying a changeSeparates "my change did not land" from "my change landed and I am reading a cache" — two problems with opposite responses
Lower TTLs before a planned change, not during itCaches holding the old record never see the new low TTL until the old one expires, so a simultaneous change buys nothing
Treat REFUSED as a configuration review, not an incidentIt is a policy decision by a healthy server. Escalating it as an outage sends a team hunting a fault that does not exist
Keep a debug image with dig, ping, curl and ss in itProduction and CI images have no DNS tools, and installing packages into a running production container is not a plan
Distinguish timed out from connection refused before escalatingA silent drop means firewall or routing; refused means the daemon is not listening. Different teams, different fixes
Never rely on the second nameserver line as real redundancyFailover costs a full 5-second timeout per lookup, which users and health checks experience as an outage, not as resilience
Add the trailing dot when you want certainty about what was queriedIt disables search-list expansion, which is the fastest way to rule out a whole class of resolver-side problem

E3 · Capstone exercise

Do this without looking anything up, and without scrolling back. It exercises every concept in Module 01 at once — the namespace, FQDNs, the three roles, resolver configuration, reading a response, targeting servers, TTL as a countdown, and all five failure classes.

Brief. Using only dig, cat and sleep, produce a short written report that answers all six of the following. Capture the exact line of output that proves each one.

  1. Which resolver does this machine send queries to, and is that a local stub listener or a real remote server? State how you can tell.
  2. Trigger all five failure outcomes on purpose — NODATA, NXDOMAIN, SERVFAIL, REFUSED, and no-response — and for each, quote the single line that identifies it. If one of them will not reproduce reliably, say which and why.
  3. Prove that a particular answer came from a cache rather than from the authoritative source, and state how many more seconds that cached copy has to live.
  4. Prove that two different public resolvers are holding copies of the same record that were fetched at different times.
  5. Establish whether example.com and www.example.com are the same node in the namespace, and justify your conclusion from the output rather than from convention.
  6. Write a four-line decision procedure you would hand to a junior engineer on call, taking them from dig output to the name of the team that owns the problem.
Model answer — attempt it first, then click

1. Which resolver.

bash
cat /etc/resolv.conf

If it shows nameserver 127.0.0.53, that is a local stub listenersystemd-resolved on this machine — and the real upstream servers are configured elsewhere and are not visible in this file. Any other address, particularly a private range or a public resolver, is a real remote server.

The confirming evidence is in dig itself: the ;; SERVER: line reports who actually answered.

plain text
;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP)

2. All five failures.

bash
# NODATA - name exists, no record of that type
dig MX www.example.com +noall +comments
#   PROOF: status: NOERROR together with ANSWER: 0

# NXDOMAIN - no such name
dig definitely-not-real.example.com +noall +comments
#   PROOF: status: NXDOMAIN

# REFUSED - policy
dig @a.iana-servers.net google.com +noall +comments
#   PROOF: status: REFUSED, and no ra flag

# NO RESPONSE, silently dropped
dig @192.0.2.1 example.com
#   PROOF: ";; communications error ... timed out" and NO status: line at all

# NO RESPONSE, actively rejected
dig @127.0.0.1 -p 5399 example.com
#   PROOF: ";; communications error ... connection refused"

SERVFAIL is the one that will not reproduce reliably, and saying so is part of the correct answer. It requires something to actually be broken — an unreachable authoritative server, a lame delegation, or a DNSSEC validation failure — and you cannot break somebody else's zone to order. Public test domains for it exist but come and go. You will generate one deterministically in Module 07, on a zone you control.

3. Cached, not authoritative.

bash
dig +noall +answer example.com
# example.com.	241	IN	A	23.215.0.136

Two independent pieces of evidence, and you should cite both:

  • The aa flag is absent from the header, so this did not come from a server holding the zone
  • The TTL is not a round configured number — 241 rather than 300 — so it has been counted down. It has 241 seconds left

Contrast it with the authoritative source, where aa is set and the TTL is the full published value:

bash
dig @a.iana-servers.net example.com +noall +comments +answer

4. Two caches, fetched at different times.

bash
dig +noall +answer @1.1.1.1 example.com
dig +noall +answer @8.8.8.8 example.com

Same name, same value, different TTLs — for example 112 against 267. Neither is wrong. Each resolver fetched the record at a different moment and is counting down its own copy independently. This is the actual mechanism behind the phrase "DNS propagation", and it is why a change appears to roll out unevenly rather than everywhere at once.

5. Are they the same node?

bash
dig +noall +answer example.com
dig +noall +answer www.example.com

They are different nodes. The proof is that each response's answer records carry their own owner name in the first column — example.com. in one and www.example.com. in the other — so two distinct record sets exist at two distinct points in the tree. They may or may not hold the same values; that is a choice the zone owner made, not a rule of DNS. Nothing in the protocol links www.x to x, and assuming otherwise causes a recognisable class of outage.

6. The four-line on-call procedure.

plain text
1. No "status:" line?            -> nobody answered. Networking / firewall team.
                                    "timed out" = silent drop. "refused" = nothing listening.
2. status: REFUSED?              -> healthy server, wrong server or missing ACL.
                                    Configuration review, not an incident.
3. status: SERVFAIL?             -> re-ask a second resolver NOW.
                                    One fails -> resolver operator. All fail -> zone owner / delegation.
4. status: NOERROR or NXDOMAIN?  -> DNS is working correctly.
                                    NXDOMAIN            = wrong name.
                                    NOERROR + ANSWER: 0 = right name, missing record -> zone owner.
                                    NOERROR + data      = DNS is fine, the fault is downstream.

The five things most people miss on this capstone:

  1. Admitting SERVFAIL cannot be reproduced to order. Inventing a command that "produces" it is worse than explaining why you cannot.
  2. Using the absent aa flag as evidence, not just the TTL. The TTL alone is suggestive; aa is decisive.
  3. Noticing that requirement 5 is answered by the owner name column, not by comparing addresses. Two names sharing an address proves nothing about the tree.
  4. Putting "no status: line" first in the procedure. It is the only check that removes DNS from the investigation entirely, so it belongs at the top.
  5. Ending line 4 with "the fault is downstream". A successful lookup is a result, and the most valuable thing DNS troubleshooting often produces is the conclusion that DNS is not the problem.

E4 · Official documentation

LinkCovers
RFC 1034 — Concepts and FacilitiesThe whole of Part A and Part B: the namespace, the tree, zones, resolvers and their roles. The readable one of the two founding RFCs
RFC 1035 — Implementation and Specification§2.3.1 and §2.3.4 for name syntax and the 63/255 limits · §3.2.1 for the TTL field · §4.1.1 for the header and RCODEs
RFC 9499 — DNS Terminology (BCP 219)The authoritative dictionary. Read this whenever two sources seem to use a word differently — usually one of them is wrong
RFC 1123 §2.1 — Requirements for Internet HostsHost name syntax, and the relaxation that allows a name to begin with a digit
RFC 4343 — DNS Case Insensitivity ClarificationExactly what "case insensitive" means: folded for matching, preserved on output
RFC 2308 — Negative Caching of DNS QueriesThe formal definitions of NXDOMAIN and NODATA, and why an SOA appears in a negative answer
dig manual — BIND 9 ARMEvery query option and display option, including +short, +noall, +norecurse, +comments
host manual · nslookup manualThe two alternatives, and what each one hides from you
resolv.conf(5) · hosts(5)Stub resolver configuration, and the local override file that bypasses DNS entirely
IANA DNS ParametersThe live registries: every RCODE, every record type, every EDNS option. Definitive, and always current
IANA Root Servers · IANA Root Zone DatabaseThe 13 root identities and their operators; every TLD and who runs it
BIND 9 Administrator Reference Manual · Troubleshooting chapterThe reference you will live in from Module 05 onwards
How to read these efficiently, because reading an RFC front to back wastes an evening.

Start with RFC 9499, not RFC 1034. It is a dictionary, it is recent, and it settles the vocabulary. Most DNS confusion is vocabulary confusion.

Check the banner of any RFC before trusting it. The header tells you whether it has been Obsoleted by or Updated by something newer. RFC 1034 and 1035 date from 1987 and have been updated many times — they remain correct on concepts and are out of date on specifics.

Search for MUST, MUST NOT and SHOULD. Those keywords mark the actual requirements; everything between them is explanation you can skim.

Prefer the IANA registries over any RFC for lists. Record types, RCODEs and EDNS options are added over time. The registry is current; an RFC is a snapshot of the year it was written.

The offline route. man dig gives you the complete manual with no browser, and dig -h prints every option in one screen — the fastest reference there is once you know what you are looking for. Both work on a locked-down bastion with no internet access, which is exactly where you will need them.


E5 · Self-assessment

Answer each one out loud before opening it.

1. Why is the DNS namespace hierarchical rather than flat, and what does that hierarchy actually buy you?

Two things, and the second matters more.

It removes name collisions: mail.a.com and mail.b.com can coexist because the name carries its administrative path.

More importantly it enables delegation — the operator of com can say "for anything under example.com, ask these other servers instead". That is what lets the database be maintained by millions of unrelated parties, with no central coordination and no central copy.

2. What is the trailing dot, and name one place where forgetting it causes a real bug.

It is the root, whose label is the empty string. A name ending in a dot is absolute; a name without one is relative and may have a suffix appended before it is queried.

The classic bug is in a zone file, where an unqualified name silently gets the zone origin appended — writing www.example.com inside the example.com zone produces www.example.com.example.com.. The file loads without complaint and the name simply does not work.

Its diagnostic use is the mirror image: adding the dot forces a single absolute query and skips search-list expansion, which rules out a whole class of resolver-side problem in one command.

3. Why is the maximum label length 63 octets rather than a rounder number?

Because the length is encoded in a single byte on the wire and the top two bits of that byte are reserved as a flag for message compression. Six bits remain, and six bits counts to 63.

The whole-name limit of 255 octets counts every label plus its length byte plus the terminating zero, which works out at roughly 253 printable characters.

4. Distinguish a stub resolver, a recursive resolver and an authoritative server.

The stub is library code inside your OS. It asks one configured server the whole question and waits. No cache, no knowledge of the tree.

The recursive resolver accepts the whole question, does whatever work is required, caches every step, and returns one final answer. It owns no data.

The authoritative server holds the configured data for its zones, answers only about those, and does not chase answers on anyone else's behalf.

The difference between the last two is expressed as a single bit — recursion available — not as a difference in capability.

5. Your /etc/resolv.conf says nameserver 127.0.0.53. What does that tell you, and what does it not tell you?

It tells you there is a local stub listener on this machine, almost certainly systemd-resolved, and that your queries go there first.

It tells you nothing whatsoever about the real upstream resolvers, which are configured elsewhere and do not appear in this file. Editing the file is also usually pointless, because it is regenerated.

Practically: on such a host, cat /etc/resolv.conf cannot answer the question "where is my DNS traffic actually going".

6. What do the flags qr, rd, ra and aa each mean?

qr — this message is a response rather than a query.

rd — recursion desired; the client asked the server to do the work.

ra — recursion available; the server is willing to do that work for clients.

aa — authoritative answer; this came from a server holding the zone rather than from a cache.

rd is set by the asker; ra and aa are set by the answerer. An authoritative-only server never sets ra.

7. Why is status: NOERROR not the same as "I found it"?

NOERROR means the server processed the question without malfunctioning. It says nothing about whether any records came back.

NOERROR with ANSWER: 0 is NODATA: the name exists but has no record of the requested type. That is a completely different problem from NXDOMAIN and it is frequently misread as "not found".

So you always read two things — status: for whether the server is happy, and the ANSWER: counter for whether you got data.

8. A TTL comes back as 241 when the zone publishes 300. What does that tell you?

That you are talking to a cache, that this copy was fetched 59 seconds ago, and that it has 241 seconds left before it is discarded.

A TTL that is always the full published value means you are talking to the authoritative server, or to something that is not caching at all — and in that case aa should be set too.

9. You must repoint a name that has a 24-hour TTL. Describe the procedure and its ordering.

Lower the TTL first — to 60 seconds, say — then wait a full 24 hours, because every cache currently holding the record keeps its old copy with the old 24-hour lifetime until it expires. Only once that has drained does the low TTL actually apply everywhere.

Then make the change, verify against the authoritative servers and against several public resolvers, and raise the TTL back up once it has settled.

Lowering the TTL at the same moment as making the change achieves nothing for exactly the clients you were worried about.

10. You get SERVFAIL. What is your very next command, and why that one?

The same query against a different resolver — dig @1.1.1.1 name, then dig @8.8.8.8 name.

Because SERVFAIL means "the answering side could not complete the job" and deliberately does not say which side. One resolver failing while others succeed makes it that resolver's fault. Every resolver failing makes it the zone's or the delegation's fault. One command, and the search space halves.

And if the cause is DNSSEC, it will present as a plain SERVFAIL with no other clue — which is why re-querying with validation disabled is the follow-up.

11. dig says "connection timed out" against one server and "connection refused" against another. What differs in the cause?

Neither produced a DNS response at all — there is no status: line, so DNS has told you nothing.

Timed out means the packet was silently dropped in one direction or the other: firewall or routing.

Connection refused means you reached the host and it rejected the port with an ICMP port-unreachable: the network is fine and nothing is listening — a stopped daemon, or one bound to the wrong address or port.

Different teams, different fixes, and the only clue is which of those two words appears.

12. Why should dig +short never appear in a monitoring check?

Because it prints values only and discards the status. An empty result from +short could be NXDOMAIN, NODATA, SERVFAIL, REFUSED, or no response at all — five different problems owned by four different teams, all producing one identical empty string.

A check should read status: and the ANSWER: counter explicitly, so the alert carries the classification instead of making on-call rediscover it at three in the morning.


Next — Module 02 · Resource Records & Zone Files.

You have seen the shape of a record — name, TTL, class, type, value — and used exactly one type, A. Module 02 fills in the rest: AAAA, CNAME, NS, MX, TXT, PTR, SRV, CAA, and the SOA record you have already met twice in negative answers without being told what it was. It then has you write a zone file by hand — including committing the trailing-dot mistake from A3 on purpose, and meeting the CNAME-at-the-apex rule that no vendor can engineer around.

📚 Sources for the interview questions

The technical content is taken from the primary specifications and was verified against them: RFC 1034, RFC 1035, RFC 1123, RFC 2308, RFC 4343, RFC 9499, the IANA DNS Parameters registry, and the BIND 9 Administrator Reference Manual.

Question selection was cross-referenced against publicly published 2026 DNS and networking interview question sets:

Answers were rewritten and deepened rather than reproduced. The published versions are usually correct but shallow — they state the rule and stop. The added operational detail, and the explicit notes on what separates a strong candidate from an average one, are the part that actually matters in the room.

Spotted a mistake or want something added? Send me a note.