Algorithmic Selection of IP Addresses in DNS Response Handling: RFC Standards vs. Implementation Choices


1 views

When dealing with multiple DNS responses, the selection process occurs at two distinct levels:

  1. DNS server selection during recursive resolution
  2. IP address selection from the final response

The core specifications are covered in several RFCs:

  • RFC 1034: Defines DNS concepts and suggests round-robin for load balancing
  • RFC 1794: Discusses DNS round-robin scheduling
  • RFC 3484 (obsoleted by RFC 6724): Address selection algorithms
  • RFC 6724: Current standard for destination address selection

Most implementations follow these selection patterns:

// Pseudocode for common selection logic
function selectIP(addresses) {
  // 1. Filter by reachability (if known)
  let candidates = addresses.filter(addr => isReachable(addr));
  
  // 2. Apply RFC 6724 sorting if implemented
  if (supportsRFC6724) {
    return sortByRFC6724(candidates)[0];
  }
  
  // 3. Fallback to simple round-robin or random selection
  return candidates[lastIndex++ % candidates.length];
}

Linux glibc implementation:

/* From glibc's getaddrinfo.c */
static int
rfc3484_sort (const struct addrinfo *results)
{
  // Implementation of RFC 6724 rules
  // Including:
  // - Prefer same address family
  // - Avoid deprecated addresses
  // - Prefer smaller scope
  // - Use longest matching prefix
}

Windows DNS Client behavior:

  • Implements RFC 6724 with additional heuristics
  • Caches reachability information
  • Includes subnet prioritization for local networks

When building applications that handle DNS:

// Python example with explicit selection control
import socket

def get_ordered_ips(hostname):
    try:
        info = socket.getaddrinfo(hostname, None)
        # Apply custom sorting here
        return sorted([item[4][0] for item in info], 
                     key=lambda x: (x.count('.'), x))
    except socket.gaierror:
        return []

Common issues and verification techniques:

  • Use dig +short example.com to see raw DNS responses
  • Check /etc/gai.conf on Linux for RFC 6724 overrides
  • Windows: netsh interface ipv4 show addresses reveals priority settings

For systems requiring custom behavior:

# Linux /etc/gai.conf example
# Prefer IPv4 over IPv6
precedence ::ffff:0:0/96  100

# macOS equivalent (requires root)
sudo sysctl -w net.inet6.ip6.precedence=0

When dealing with DNS resolution, professionals often encounter scenarios where:

  1. DNS servers receive multiple nameserver options during recursive resolution
  2. Clients obtain multiple IP addresses for a single hostname

RFC 1034 and RFC 1035 establish the foundation, while later RFCs like 2181 provide clarifications:


// Pseudo-code for nameserver selection
function selectNameserver(availableServers) {
    // 1. Prefer servers with lowest RTT (measured from previous queries)
    // 2. If equal, use server with successful query history
    // 3. Fall back to round-robin if no metrics available
    return sortedServers[0];
}

Modern implementations typically follow these steps:

  • RFC 6724 (Default Address Selection) defines the current standard
  • Most clients implement a variation of this algorithm

Here's how a resolver might implement RFC-compliant selection in Python:


import socket
import random

def sort_addresses(hostname):
    try:
        # Get all addresses
        addrinfo = socket.getaddrinfo(hostname, None)
        ips = [info[4][0] for info in addrinfo]
        
        # Basic RFC 6724-inspired sorting
        ipv6_addrs = [ip for ip in ips if ':' in ip]
        ipv4_addrs = [ip for ip in ips if '.' in ip]
        
        # Prefer IPv6 per RFC (unless configured otherwise)
        sorted_ips = ipv6_addrs + ipv4_addrs
        
        # Implement round-robin for load balancing
        return sorted_ips[1:] + sorted_ips[:1] if sorted_ips else []
    except socket.gaierror:
        return []

Consider these production scenarios:

Scenario Typical Behavior
Cloud load balancers Round-robin with health checks
CDN endpoints Geo-based priority sorting
Dual-stack hosts Happy Eyeballs algorithm (RFC 8305)

For specialized applications, you might override default behavior:


// JavaScript example using DNS-over-HTTPS
async function customResolver(domain) {
    const response = await fetch(https://cloudflare-dns.com/dns-query?name=${domain}, {
        headers: { 'Accept': 'application/dns-json' }
    });
    const data = await response.json();
    
    // Custom sorting:
    // 1. Prefer low-latency DCs
    // 2. Avoid previously failed IPs
    // 3. Filter by protocol preference
    return sortByLatency(data.Answer);
}

Debugging techniques include:

  • Using dig +short example.com to see raw responses
  • Checking TTL values for cache behavior
  • Verifying client-side sorting with packet captures