# Sample resolv.conf showing the issue
; generated by /sbin/dhclient-script
search mcdc
nameserver 10.0.4.48 # Primary (failing) DNS
nameserver 8.8.8.8 # Secondary (working) DNS
When applications like wget
or curl
fail to use fallback nameservers specified in /etc/resolv.conf
, it typically indicates one of these scenarios:
- The glibc resolver isn't properly cycling through nameservers
- DNS timeout thresholds are too aggressive
- The application implements its own DNS resolution logic
First verify resolver behavior using different tools:
# Using getent (uses glibc resolver)
getent hosts google.com
# Using dig (bypasses local resolver)
dig @8.8.8.8 google.com +short
# Timeout simulation
time curl --connect-timeout 5 http://google.com
Create /etc/resolv.conf
with proper timeout and attempts:
options timeout:1 attempts:5 rotate
nameserver 10.0.4.48
nameserver 8.8.8.8
Key parameters:
timeout
: Wait time per query (seconds)attempts
: Retries per nameserverrotate
: Round-robin nameserver selection
For applications using glibc resolver, set environment variables:
export RES_OPTIONS="rotate timeout:1 attempts:2"
curl http://example.com
For curl specifically:
curl --dns-servers 8.8.8.8,10.0.4.48 http://example.com
- Check resolver config:
ldd $(which curl) | grep libresolv strace -e connect curl http://example.com 2>&1 | grep 'connect('
- Test with different DNS libraries:
# Using c-ares (alternative DNS library) curl --dns-interface eth0 http://example.com
For production systems, consider:
- Setting up local DNS caching (dnsmasq/unbound)
- Implementing DNS failover at network level
- Using /etc/nsswitch.conf to control resolution order
# Example nsswitch.conf modification
hosts: files dns [NOTFOUND=return] mdns4_minimal
html
When troubleshooting DNS resolution in Linux, I recently encountered a puzzling behavior where network utilities like wget
and curl
would only use the first nameserver entry in /etc/resolv.conf
, ignoring subsequent entries even when the primary server fails. Here's a deep dive into the problem and solutions.
Here's what my /etc/resolv.conf
looks like:
; generated by /sbin/dhclient-script search mcdc nameserver 10.0.4.48 nameserver 8.8.8.8
Testing with nslookup
works as expected - it properly falls back to Google's DNS (8.8.8.8) when the primary server fails:
nslookup www.google.com ;; Got SERVFAIL reply from 10.0.4.48, trying next server Server: 8.8.8.8 Address: 8.8.8.8#53 Non-authoritative answer: www.google.com canonical name = www.l.google.com.
However, when using curl
or wget
:
curl www.google.com curl: (6) Could not resolve host: www.google.com
Using strace
revealed these tools only attempt the first nameserver:
strace -e trace=network curl www.google.com [...] connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("10.0.4.48")}, 16) = 0
This behavior stems from how the glibc resolver works:
- The resolver has a single-threaded retry mechanism
- Default timeout between retries is too long (5 seconds per RFC)
- Many applications don't implement proper fallback logic
1. Using getaddrinfo() with Proper Timeouts
For programmers developing network applications, always implement proper timeout handling:
#include <netdb.h> #include <stdio.h> struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM }; struct addrinfo *result; int status = getaddrinfo("www.google.com", "80", &hints, &result); if (status != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(status)); return 1; }
2. System-wide Configuration Changes
Modify /etc/resolv.conf
options:
options timeout:1 attempts:2 rotate nameserver 10.0.4.48 nameserver 8.8.8.8
Key parameters:
timeout:1
- Reduce timeout to 1 secondattempts:2
- Make 2 attempts per nameserverrotate
- Round-robin between nameservers
3. Using Alternative DNS Utilities
For scripting, consider using tools with better DNS handling:
# Using dig with explicit nameserver dig @8.8.8.8 www.google.com +short # Using DNS cache daemon like nscd sudo apt install nscd sudo service nscd restart
For critical applications, you might want to implement custom DNS resolution:
import socket import dns.resolver def resolve_host(hostname): resolvers = ['10.0.4.48', '8.8.8.8'] for resolver in resolvers: try: dns_resolver = dns.resolver.Resolver() dns_resolver.nameservers = [resolver] answer = dns_resolver.resolve(hostname) return str(answer[0]) except: continue raise Exception("All DNS servers failed") print(resolve_host("www.google.com"))
Based on my testing, the most reliable approach is to combine:
- System-wide
/etc/resolv.conf
configuration with proper timeout settings - Application-level retry logic
- Consider using local DNS caching daemon
Remember that DNS resolution behavior can vary between different Linux distributions and glibc versions, so always test your specific environment.