When debugging DNS issues, we often use multiple tools for verification, but sometimes they don't agree. Here's what we observed:
$ host someserver
someserver.somenet.internal has address 192.168.0.252
$ dig someserver
;; status: SERVFAIL
These tools handle DNS queries differently:
// host/nslookup behavior:
1. Appends search domains from resolv.conf automatically
2. Uses system's resolver libraries
// dig behavior:
1. Sends queries exactly as typed (unless +search option is used)
2. Bypasses some system library features
The smoking gun is in the query patterns:
$ strace -e trace=network host someserver
... sendto(3, "\\310\\0\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\nsomeserver\\tsomenet\\7internal\\0\\0\\1\\0\\1", ...
$ strace -e trace=network dig someserver
... sendto(3, "\\227^\\1\\0\\0\\1\\0\\0\\0\\0\\0\\0\\nsomeserver\\0\\0\\1\\0\\1", ...
Several ways to make dig behave like other tools:
// Method 1: Enable search domains
$ dig +search someserver
// Method 2: Specify FQDN explicitly
$ dig someserver.somenet.internal
// Method 3: Use @nameserver with search suffix
$ dig @192.168.0.253 someserver.somenet.internal
Your configuration shows why this happens:
# /etc/resolv.conf
nameserver 192.168.0.253
search somenet.internal
Tools interpret this differently:
// host/nslookup: Will append .somenet.internal
// dig: Won't append unless +search is specified
Using tcpdump reveals the raw DNS packets:
$ sudo tcpdump -i any -n port 53
# host output shows query for "someserver.somenet.internal"
# dig output shows query for just "someserver"
For consistent behavior across tools:
// Best practice for scripts:
FQDN="someserver.somenet.internal"
dig ${FQDN} @192.168.0.253
// Debugging template:
dig +trace +all ${HOST}.${SEARCH_DOMAIN}
PTR records use special in-addr.arpa domain:
$ dig -x 192.168.0.252
;; QUESTION SECTION:
;252.0.168.192.in-addr.arpa. IN PTR
This standardized format avoids search domain ambiguity.
For production systems, consider standardizing on either:
- Always using FQDNs in scripts
- Configuring dig defaults in ~/.digrc
# Sample .digrc configuration
+search
+time=3
+tries=2
When troubleshooting DNS resolution, the inconsistent behavior between different tools can be puzzling. Let's examine what each command is doing differently:
# host command output
$ host someserver
someserver.somenet.internal has address 192.168.0.252
# nslookup output
$ nslookup someserver
Server: 192.168.0.253
Address: 192.168.0.253#53
Name: someserver.somenet.internal
Address: 192.168.0.252
# problematic dig output
$ dig someserver
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 55306
;; QUESTION SECTION:
;someserver. IN A
The key difference lies in how each tool handles the search domain specified in /etc/resolv.conf
:
nameserver 192.168.0.253
search somenet.internal
host
and nslookup
automatically append the search domain when the name doesn't contain dots, while dig
sends the query exactly as typed.
To get consistent results across all tools, you have several options:
# Option 1: Use FQDN
$ dig someserver.somenet.internal
# Option 2: Use +search flag
$ dig +search someserver
# Option 3: Specify search domain manually
$ dig @192.168.0.253 someserver.somenet.internal
# Option 4: Use ndots option
$ dig +ndots=1 someserver
Let's examine the actual DNS packets being sent using tcpdump
:
# For host/nslookup:
$ sudo tcpdump -i any port 53
15:47:38.123456 IP 192.168.0.1.42321 > 192.168.0.253.53: 12345+ A? someserver.somenet.internal. (42)
# For dig:
15:47:38.123457 IP 192.168.0.1.42322 > 192.168.0.253.53: 54321+ A? someserver. (27)
When writing scripts or automated tests, consider these approaches:
# In Bash scripts:
resolve_host() {
local host=$1
# Try FQDN first, then with search domain
dig +short "$host" || dig +short "$host.somenet.internal"
}
# Python example:
import socket
def resolve(host):
try:
return socket.gethostbyname(host)
except socket.gaierror:
return socket.gethostbyname(f"{host}.somenet.internal")
For comprehensive troubleshooting, use these diagnostic commands:
# Check search domains being used
$ grep ^search /etc/resolv.conf
# Verify resolver behavior
$ getent hosts someserver
# Check DNS server responses
$ drill someserver @192.168.0.253