Understanding and controlling how your system prioritizes IPv6 versus IPv4 connections is crucial for optimizing network performance in dual-stack environments. This guide explains the mechanisms that govern address selection and provides practical configurations for prioritizing IPv6 across different operating systems and applications.
When a hostname has both IPv4 (A record) and IPv6 (AAAA record) DNS entries, your system must decide which protocol to use. This decision involves multiple layers:
DNS resolvers typically send both A and AAAA queries simultaneously or with minimal delay. The responses may arrive in any order depending on network conditions.
Two key RFCs govern how systems handle dual-stack connections:
RFC 6724 - Default Address Selection
This specification defines how systems sort and select from multiple available addresses. It establishes a policy table with precedence values that determine which address families are preferred. By default, IPv6 addresses receive higher precedence than IPv4.
RFC 8305 - Happy Eyeballs Version 2
Modern applications implement the "Happy Eyeballs" algorithm to provide fast connections while preferring IPv6. The algorithm works as follows:
This approach ensures users don't experience delays if IPv6 is broken, while still preferring IPv6 when it works properly.
Linux systems use the getaddrinfo() function for address resolution, which can be configured via /etc/gai.conf to control IPv6 preference.
By default, Linux follows RFC 6724 with these precedence values:
Precedence Prefix
50 ::1/128 # Loopback
40 ::/0 # IPv6 default
35 ::ffff:0:0/96 # IPv4-mapped IPv6
30 2002::/16 # 6to4
5 2001::/32 # Teredo
10 fc00::/7 # Unique Local Addresses
1 fec0::/10 # Site-local (deprecated)
The higher the precedence value, the more preferred the address family. The default configuration gives IPv6 (::/0 with precedence 40) priority over IPv4-mapped addresses (::ffff:0:0/96 with precedence 35).
To explicitly ensure IPv6 is prioritized, edit /etc/gai.conf:
# Uncomment or add these lines to /etc/gai.conf
# Prefer IPv6 over IPv4
precedence ::ffff:0:0/96 35
precedence ::/0 40
# Full RFC 6724 default table (recommended to include all entries)
precedence ::1/128 50
precedence ::/0 40
precedence 2002::/16 30
precedence ::/96 20
precedence ::ffff:0:0/96 10
Important: When you add any precedence entry to gai.conf, it disables the default rules. You should include the complete policy table to avoid unexpected behavior.
For environments where you want to strongly prefer IPv6:
# Edit /etc/gai.conf
precedence ::1/128 50
precedence ::/0 100 # Very high priority for all IPv6
precedence ::ffff:0:0/96 10 # Low priority for IPv4
If you need to prefer IPv4 temporarily for troubleshooting:
# Edit /etc/gai.conf
precedence ::ffff:0:0/96 100 # High priority for IPv4
precedence ::/0 10 # Low priority for IPv6
Changes to /etc/gai.conf take effect immediately for new connections:
# Edit the file
sudo nano /etc/gai.conf
# Test the configuration
getent ahosts www.google.com
The order of addresses returned by getent ahosts reflects your precedence settings.
Windows uses a prefix policy table similar to Linux's gai.conf, configured via the netsh command.
Display your current IPv6 prefix policy table:
netsh interface ipv6 show prefixpolicies
Output example:
Precedence Label Prefix
---------- ----- ------
50 0 ::1/128
40 1 ::/0
35 4 ::ffff:0:0/96
30 2 2002::/16
5 5 2001::/32
3 13 fc00::/7
1 11 fec0::/10
By default, Windows prefers IPv6 (precedence 40) over IPv4-mapped addresses (precedence 35).
Windows 7 and later versions prefer IPv6 by default. To restore default behavior:
# Reset to default IPv6 preference
netsh interface ipv6 reset
# Or manually set precedence
netsh interface ipv6 set prefixpolicy ::1/128 50 0
netsh interface ipv6 set prefixpolicy ::/0 40 1
netsh interface ipv6 set prefixpolicy ::ffff:0:0/96 35 4
netsh interface ipv6 set prefixpolicy 2002::/16 30 2
netsh interface ipv6 set prefixpolicy 2001::/32 5 5
To further emphasize IPv6 preference:
# Increase IPv6 precedence significantly
netsh interface ipv6 set prefixpolicy ::/0 50 1
netsh interface ipv6 set prefixpolicy ::ffff:0:0/96 25 4
If you must prefer IPv4 for compatibility testing:
# Set IPv4 higher precedence than IPv6
netsh interface ipv6 set prefixpolicy ::ffff:0:0/96 46 4
netsh interface ipv6 set prefixpolicy ::/0 35 1
Note: Microsoft recommends adjusting prefix policies rather than disabling IPv6 entirely.
Changes take effect immediately. Test with:
# Test DNS resolution order
nslookup www.google.com
# Test connectivity
ping www.google.com
macOS follows BSD conventions and generally prefers IPv6 by default when available.
macOS implements RFC 6724 address selection automatically. IPv6 is preferred when:
macOS doesn't provide a direct equivalent to Linux's gai.conf or Windows' netsh prefix policy commands. The system-level address selection is built into the network stack.
# Check which protocol is used
dscacheutil -q host -a name www.google.com
# Test IPv6 connectivity
ping6 www.google.com
# Force IPv6 in curl
curl -6 https://ipv6.icanhazip.com
While you cannot directly configure address precedence, you can influence behavior by setting network service order in System Preferences > Network > Set Service Order.
Modern browsers implement Happy Eyeballs (RFC 8305) but with varying implementations.
Firefox has built-in IPv6 support enabled by default:
Configuration via about:config:
about:config in the address barnetwork.dns.disableIPv6false (IPv6 enabled and preferred)Note: Recent Firefox versions use "fast fallback" - if IPv6 connections are slower than one-third of a second, IPv4 is attempted in parallel. This behavior cannot be disabled via settings.
Chrome implements Happy Eyeballs with automatic protocol selection:
Chrome will prefer IPv6 if:
Safari follows macOS system defaults and implements address selection according to the underlying network stack. There are no Safari-specific IPv6 preference controls.
Edge on Windows follows the OS prefix policy table and implements Happy Eyeballs similar to Chrome.
Applications that don't implement Happy Eyeballs rely entirely on the OS-level address selection from getaddrinfo().
Many command-line tools provide flags to force protocol selection:
# curl - force IPv6
curl -6 https://api6.ipify.org
# wget - prefer IPv6
wget --prefer-family=IPv6 https://example.com
# ssh - force IPv6
ssh -6 user@example.com
# ping - IPv6 only
ping6 google.com
Applications can influence address selection in code:
Python:
import socket
# Get all addresses (respects gai.conf)
addrs = socket.getaddrinfo('www.google.com', 443)
# Filter for IPv6 only
ipv6_addrs = [a for a in addrs if a[0] == socket.AF_INET6]
Node.js:
const dns = require('dns');
// Set IPv6 preference
dns.setDefaultResultOrder('ipv6first');
// Or use options per lookup
dns.lookup('www.google.com', { family: 6 }, callback);
Docker requires explicit IPv6 configuration:
// /etc/docker/daemon.json
{
"ipv6": true,
"fixed-cidr-v6": "2001:db8:1::/64"
}
Restart Docker after configuration changes.
The DNS server communication itself can be prioritized for IPv6.
Linux (systemd-resolved):
# Edit /etc/systemd/resolved.conf
[Resolve]
DNS=2001:4860:4860::8888 2001:4860:4860::8844
FallbackDNS=8.8.8.8 8.8.4.4
Windows:
# Set IPv6 DNS servers
netsh interface ipv6 set dns "Ethernet" static 2001:4860:4860::8888
netsh interface ipv6 add dns "Ethernet" 2001:4860:4860::8844 index=2
macOS:
Configure via System Preferences > Network > Advanced > DNS and add IPv6 DNS server addresses.
For SLAAC environments, routers can advertise DNS servers via Router Advertisement (RA) messages using RDNSS (Recursive DNS Server) option.
After configuring IPv6 prioritization, verify your setup works correctly.
# Linux: Test which protocol is used
getent ahosts www.google.com
# Check resolved addresses in order
nslookup www.google.com
# Test IPv6 connectivity
ping6 -c 4 www.google.com
# Trace routing
traceroute6 www.google.com
# Check your public IP addresses
curl https://api.ipify.org # Should return IPv4
curl https://api6.ipify.org # Should return IPv6
curl https://api64.ipify.org # Returns whichever protocol is used
Visit test-ipv6.run for comprehensive testing. The site evaluates:
The testing runs entirely in your browser and provides real-time diagnostics, making it ideal for verifying that your IPv6 prioritization settings work as expected.
# Linux: Monitor active IPv6 connections
ss -6 -t
# Windows: Display IPv6 connections
netstat -an -p tcpv6
# View connection statistics
netstat -s -p ipv6
If your system prefers IPv6 but connections are slow or failing:
Test basic IPv6 connectivity:
ping6 2001:4860:4860::8888
Check for broken IPv6 - Visit test-ipv6.run and check for "broken IPv6" status (score 0/10 with red indicators)
Verify firewall rules - Ensure ICMPv6 and TCP/UDP over IPv6 are allowed
Check router configuration - Confirm your gateway supports IPv6 and has proper upstream connectivity
If IPv4 and IPv6 work individually but dual-stack tests fail:
To confirm Happy Eyeballs is working:
For most users wanting to prioritize IPv6:
For organizations deploying IPv6:
Prioritizing IPv6 DNS queries involves multiple layers - from DNS resolution timing to address selection algorithms to application-level connection handling. Modern operating systems and browsers generally prefer IPv6 by default when both protocols are available, implementing smart fallback mechanisms like Happy Eyeballs to ensure optimal user experience.
For most users, the default configurations are optimal. System administrators can fine-tune behavior using /etc/gai.conf on Linux or netsh interface ipv6 commands on Windows to influence address selection precedence. However, the key to successful IPv6 prioritization isn't just configuration - it's ensuring your IPv6 connectivity is reliable and performant.
Always verify your configuration changes with comprehensive testing tools like test-ipv6.run, which provides detailed diagnostics of your dual-stack connectivity, protocol preference, and overall IPv6 readiness. A high IPv6 readiness score (9-10/10) indicates that your system is correctly prioritizing and successfully using IPv6 connections.