LinuxXXII · Network TroubleshootingDNS
dig and nslookup - DNS diagnosis in detail
What you'll learn
- Use dig to query specific record types and resolvers
- Read dig output - status, answer, authority, additional
- Trace DNS resolution with dig +trace
- Diagnose DNS misconfiguration: stale caches, wrong resolvers, split horizon
- Isolate DNS transport faults using the TC flag, EDNS buffer size, and TCP/53
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
DNS is invisible when it works and dominant when it does not.
“Cannot reach host” is almost always “DNS cannot resolve
host”. dig, nslookup, and host are the tools that turn
a vague “DNS is broken” into a specific answer.
One thing to carry through this lesson: dig sends its query
straight to a resolver over the wire. It does not use the
/etc/nsswitch.conf path that your applications use, so it
skips /etc/hosts, skips the search list, and skips whatever
local stub resolver the host runs. That makes it the right
tool for asking “what does the DNS actually say” and the
wrong tool for asking “what will my application get”. Use
getent hosts for the second question. Part XXIII covers the
resolver architecture that produces the difference.
dig basics
dig example.com # A record (default)
dig example.com A # A record (explicit)
dig example.com AAAA # IPv6 record
dig example.com MX # mail server
dig example.com NS # authoritative servers
dig example.com TXT # SPF, DKIM, etc.
dig example.com CNAME # canonical name
dig example.com ANY # all records (often rate-limited)
dig -x 8.8.8.8 # reverse lookup (PTR)
dig @8.8.8.8 example.com # use a specific resolver
dig +short example.com # just the answer
dig +trace example.com # walk the resolution chain
dig +noall +answer example.com # show only the answer section
The @8.8.8.8 syntax means “send this query to 8.8.8.8”,
bypassing the system resolver. This is the diagnostic for
“is the resolver broken or is the system misconfigured”.
Reading dig output
; <<>> DiG 9.18.24 <<>> example.com A
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 512
;; QUESTION SECTION:
;example.com. IN A
;; ANSWER SECTION:
example.com. 300 IN A 93.184.216.34
;; Query time: 12 msec
;; SERVER: 127.0.0.53#53(127.0.0.53)
;; WHEN: ...
;; MSG SIZE rcvd: 56
Key fields:
- status: NOERROR (success), NXDOMAIN (name does not exist), SERVFAIL (server failure), REFUSED (policy refusal). Other statuses are rarely seen.
- flags:
qr= response (vs query).rd= recursion desired.ra= recursion available.aa= authoritative answer. - ANSWER SECTION: the records returned. Each line: name, TTL, class (IN), type, value.
- TTL: how long the answer can be cached. Stale caches are a frequent cause of “DNS was working yesterday”.
- SERVER: which resolver answered. 127.0.0.53 means systemd-resolved.
- OPT PSEUDOSECTION /
udp: 512: the EDNS buffer size this query advertised. It is the largest UDP response, in bytes, that the client says it is willing to receive. Anything bigger cannot come back over UDP intact. This one line explains a whole family of DNS incidents - see below. - MSG SIZE rcvd: how big the answer actually was. Compare it with the advertised buffer.
Common diagnostic queries
# Is this hostname resolvable at all?
dig example.com +short
# What does my resolver say?
dig @127.0.0.53 example.com # systemd-resolved
# What does Google\'s public resolver say?
dig @8.8.8.8 example.com
# What does the authoritative server say?
dig @ns1.example.com example.com
# Trace the resolution from the root
dig +trace example.com
# Reverse lookup (IP to name)
dig -x 8.8.8.8 +short
# Check the SOA (start of authority) record
dig example.com SOA +noall +answer
# Check all nameservers for the zone
dig example.com NS +noall +answer
If the system resolver returns one answer and a public resolver returns another, you have a stale cache, a split horizon, or a misconfigured authoritative server.
DNS over TCP and truncation
DNS is not a UDP-only protocol. It has always had a TCP transport, and it uses it routinely.
The mechanism is simple. A query advertises how large a UDP
response it can accept - that is the udp: 512 in the OPT
pseudosection above. If the answer does not fit, the server
returns a stub reply with the TC (truncated) flag set. The
client then retries the same question over TCP port 53. dig
prints ;; Truncated, retrying in TCP mode when this happens.
So the path from your host to a resolver has three requirements, not one:
- Small UDP responses must get through.
- Large UDP responses must get through - which often means fragmented UDP must survive the path.
- TCP/53 must be open.
Firewalls and middleboxes frequently satisfy the first and break one of the other two. The result is the most confusing DNS symptom there is: small answers work and large ones fail. A records resolve instantly, while DNSSEC-signed zones, long TXT/SPF records, or multi-record answers time out or SERVFAIL. Operators chase caches and resolver configuration for hours because “DNS works”.
The probe
Three queries isolate it. Run them against the same resolver, and change only the transport.
$ dig @10.0.0.1 example.com TXT +notcp +bufsize=512 # force UDP, small buffer
dig @10.0.0.1 example.com TXT +notcp +bufsize=4096 # force UDP, large buffer
dig @10.0.0.1 example.com TXT +tcp # force TCP/53Read the results as a table:
| UDP 512 | UDP 4096 | TCP | Conclusion |
|---|---|---|---|
| works | works | works | Transport is healthy. Look elsewhere. |
| works (TC set) | fails/timeout | works | Large or fragmented UDP is dropped in the path. The client falls back to TCP and recovers - slowly. |
| works | works | fails/timeout | TCP/53 is blocked by a firewall. Any answer needing fallback dies. |
| fails | fails | works | UDP/53 is blocked entirely. |
Two things to look for in the output:
flags: qr tc rd ra- thetcflag means the answer was truncated. With+notcpthe answer you get back is incomplete.;; Truncated, retrying in TCP mode-digtelling you the fallback happened. If you see this on ordinary queries and TCP is slow, that is your latency.
nslookup
nslookup is older and less scriptable than dig. It is
useful for interactive use because it has a prompt:
nslookup example.com
nslookup 8.8.8.8 # reverse
nslookup -type=MX example.com # specific record type
In an interactive session:
> server 8.8.8.8
> set type=MX
> example.com
host
host is the simplest tool. It returns a one-line answer
for most queries:
host example.com
host -t MX example.com
host 8.8.8.8 # reverse
Useful in scripts and quick sanity checks.
resolvectl
resolvectl is the systemd-resolved diagnostic tool:
resolvectl status # show all interfaces' DNS state
resolvectl statistics # show cache hit/miss statistics
resolvectl flush-caches # flush the cache
resolvectl query example.com # query through systemd-resolved
resolvectl domain example.com # show the search domain
resolvectl status is the first command to run on a host
using systemd-resolved. It shows:
- Which interfaces have which DNS configuration.
- Whether systemd-resolved is in use.
- The current cache statistics.
Common DNS failure modes
Stale cache: an answer was cached, but the authoritative
record changed. Symptom: some hosts see the new IP, others
see the old. Fix: resolvectl flush-caches or wait for the
TTL.
Wrong resolver: /etc/resolv.conf points to a DNS server
that cannot reach the authoritative zone. Symptom: NXDOMAIN
or SERVFAIL for some names. Fix: change the resolver.
Split horizon: external and internal resolvers return
different answers. Symptom: external hosts see one IP,
internal hosts see another. Diagnose by querying both
explicitly with @8.8.8.8 and @10.0.0.1.
DNSSEC validation failure: a chain of trust is broken.
Symptom: SERVFAIL with ad flag not set. Fix: check
DNSSEC chain, sometimes bypass with dig +cd (checking
disabled).
Reverse DNS missing: an IP has no PTR record. Symptom: applications that require rDNS (mail servers, some firewalls) reject the connection.
Small answers resolve, large ones time out: A records are
fine; DNSSEC-signed zones, long TXT/SPF records, or multi-record
answers hang or SERVFAIL. Cause: TCP/53 is blocked, or large and
fragmented UDP responses are dropped in the path. Diagnose by
comparing dig +notcp +bufsize=4096 with dig +tcp as shown
above. Fix: open TCP/53 both ways, or lower the advertised EDNS
buffer on the resolver so it truncates and falls back earlier.
Knowledge check
Knowledge check · 5 questions
Q1. What dig query shows the full resolution chain from the root?
Q2. A dig SERVFAIL status usually means the name does not exist.
Q3. Which of the following are DNS query tools on Linux? Select all that apply.
Q4. A firewall that permits udp/53 but not tcp/53 leaves ordinary A record lookups working while large answers fail.
Q5. Mail is failing SPF lookups from one site only. From that site, `dig example.com A` returns instantly, but `dig example.com TXT` times out. Both go to the same resolver. What do you run next, and what are you testing?
Passing score: 75%. Answers are checked in this browser.