How to Fix DNS Resolution When Second Nameserver in /etc/resolv.conf Is Ignored by wget/curl


2 views
# 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 nameserver
  • rotate: 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
  1. Check resolver config:
    ldd $(which curl) | grep libresolv
    strace -e connect curl http://example.com 2>&1 | grep 'connect('
    
  2. 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:

  1. The resolver has a single-threaded retry mechanism
  2. Default timeout between retries is too long (5 seconds per RFC)
  3. 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 second
  • attempts:2 - Make 2 attempts per nameserver
  • rotate - 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.