How Happy Eyeballs Works: Fast Fallback for Dual-Stack Connections
Happy Eyeballs is the algorithm that makes dual-stack internet connectivity work without making users wait. When a client needs to connect to a host that has both IPv4 and IPv6 addresses, it races connection attempts over both address families simultaneously, using whichever succeeds first. The current specification is RFC 8305 (Happy Eyeballs Version 2), which replaced the original RFC 6555. Without this algorithm, a broken or slow IPv6 path would cause users to wait for a full TCP timeout — often 20 to 75 seconds — before falling back to IPv4. Happy Eyeballs cuts that penalty to around 250 milliseconds.
The name "Happy Eyeballs" comes from the goal: keeping the human user happy (their eyeballs content) rather than making them stare at a loading spinner while one protocol family times out. The algorithm is implemented in every major browser, operating system, and HTTP client library. If you have ever connected to a dual-stack website and it "just worked" despite having a broken IPv6 path, Happy Eyeballs was the reason.
The Problem: Dual-Stack Breakage
The internet is in the middle of a decades-long transition from IPv4 to IPv6. During this transition, many hosts are dual-stacked — they have both an A record (IPv4) and an AAAA record (IPv6) in DNS. A naive client implementation would query DNS, get both record types, prefer IPv6 (as recommended by RFC 6724), and attempt to connect over IPv6 first. If that works, great. If it does not, the client waits for the connection to time out before trying IPv4.
The problem is that IPv6 connectivity is frequently broken in subtle ways. Common failure modes include:
- IPv6 blackholing — A router advertises an IPv6 route but silently drops packets. The client sends a SYN and never gets a SYN-ACK. There is no ICMP unreachable, no RST — just silence. The TCP stack retransmits the SYN with exponential backoff, waiting 1, 2, 4, 8 seconds before giving up.
- Broken 6to4 or Teredo tunnels — Early IPv6 transition mechanisms like 6to4 (RFC 3056) and Teredo (RFC 4380) automatically configured IPv6 addresses on hosts, but the tunnel endpoints were unreliable. The host appeared to have IPv6 connectivity but could not actually reach most destinations.
- Middlebox interference — Firewalls, NAT devices, or carrier-grade NAT (CGNAT) that do not properly handle IPv6, or that block ICMPv6 messages required for Path MTU Discovery, causing connections to stall after the handshake.
- Asymmetric failures — IPv6 works to some destinations but not others, because the routing path differs. A user might reach Google over IPv6 fine but have a broken path to a smaller hosting provider.
- Higher latency — In some networks, the IPv6 path is routed through a tunnel or a less optimal path, adding tens or hundreds of milliseconds compared to native IPv4.
Without Happy Eyeballs, these failures translate directly into user-visible delays. A 2010 study by Google found that approximately 0.1% of users experienced significantly degraded performance when IPv6 was preferred, with connection setup times exceeding 20 seconds. While 0.1% sounds small, at Google's scale that meant millions of affected page loads per day. This finding directly motivated the development of Happy Eyeballs.
RFC 6555 (Version 1) vs RFC 8305 (Version 2)
The original Happy Eyeballs specification, RFC 6555 (2012), established the core idea: start a connection attempt over the preferred address family, and if it has not succeeded within a short timeout, start a parallel attempt over the other family. Use whichever connection completes first and discard the other.
RFC 6555 had several limitations. It did not specify how to handle DNS resolution ordering. It recommended a timeout of 150-250ms but left the exact value as an implementation choice. It did not address the case where a host has multiple addresses within the same family. And it predated QUIC, so it only covered TCP.
RFC 8305 (2017), "Happy Eyeballs Version 2: Better Connectivity Using Concurrency," is a comprehensive rewrite that addresses all of these gaps:
- DNS resolution ordering — Specifies that AAAA and A queries should be sent in parallel, and that the client should start connection attempts as soon as the first response arrives, not waiting for both.
- Address interleaving — When multiple addresses are available, they should be sorted with IPv6 and IPv4 addresses interleaved (first IPv6, first IPv4, second IPv6, second IPv4, etc.) rather than all IPv6 addresses followed by all IPv4.
- Connection attempt pacing — A fixed 250ms delay between successive connection attempts, giving each address a fair chance without opening too many connections simultaneously.
- Statefulness — Recommends caching which address family and specific addresses worked for a destination, so subsequent connections can skip the racing and go directly to the known-good address.
- Signal-based sorting — Incorporates signals like network interface availability (no point trying IPv6 if the device has no IPv6 address) and historical success rates into address selection.
The Connection Racing Algorithm
Here is how RFC 8305's algorithm works, step by step. This is the core of Happy Eyeballs.
Step 1: Parallel DNS Resolution
The client sends both a AAAA query (IPv6) and an A query (IPv4) simultaneously. It does not wait for both responses before proceeding. As soon as the first DNS response arrives, the client can begin connection attempts with whatever addresses it has. If the AAAA response arrives first, the client starts connecting over IPv6 immediately. If the A response arrives first but the AAAA response has not arrived within a short delay (RFC 8305 recommends 50ms), the client should start trying IPv4 addresses without waiting further for IPv6.
This 50ms "Resolution Delay" prevents a slow DNS resolver for one record type from delaying connection setup entirely. In practice, most resolvers respond to both queries within a few milliseconds of each other since they are usually sent to the same recursive resolver.
Step 2: Address Sorting and Interleaving
Once addresses arrive from DNS, they are sorted. The default preference order gives IPv6 addresses priority (following RFC 6724 source/destination address selection), but the key innovation of RFC 8305 is interleaving: the sorted list alternates between address families.
If DNS returns three IPv6 addresses (2001:db8::1, 2001:db8::2, 2001:db8::3) and two IPv4 addresses (192.0.2.1, 198.51.100.1), the interleaved list looks like:
2001:db8::1(IPv6 — first preference)192.0.2.1(IPv4 — first of the other family)2001:db8::2(IPv6)198.51.100.1(IPv4)2001:db8::3(IPv6 — remaining)
This interleaving ensures that even if all IPv6 addresses are broken, an IPv4 address is tried after just one 250ms delay (the second entry in the list), rather than after all IPv6 addresses have been exhausted.
Step 3: Connection Attempt Racing with Pacing
The client works through the interleaved list, starting one connection attempt every 250 milliseconds. It does not wait for each attempt to fail before starting the next — it simply fires off a new attempt every 250ms, letting them race in parallel.
The sequence proceeds like this:
- t=0ms — Start a connection attempt to the first address (IPv6
2001:db8::1). Send a TCP SYN. - t=250ms — The first attempt has not completed (SYN-ACK not received). Start a second attempt to the next address in the interleaved list (IPv4
192.0.2.1). The first attempt continues in parallel. - t=440ms — The IPv4 SYN-ACK arrives. The IPv4 connection wins. Cancel the pending IPv6 attempt (send RST or just abandon the socket). Proceed with the IPv4 connection.
- t=500ms — Would have started attempt 3, but a connection is already established. No further attempts needed.
The critical property: the user experienced at most 440ms of connection setup time (250ms pacing delay + 190ms for the IPv4 handshake), instead of the 20+ seconds they would have waited for the IPv6 attempt to time out under a naive sequential implementation.
Step 4: Winner Selection and Cleanup
As soon as any connection attempt completes successfully (TCP SYN-ACK received), it is declared the winner. All other pending connection attempts are cancelled. If TLS is required (which it almost always is for HTTPS), the TLS handshake proceeds over the winning TCP connection. Some implementations race TLS as well — they do not cancel the other TCP connections until the TLS handshake also completes, guarding against the rare case where TCP connects but TLS fails.
Why 250 Milliseconds?
The 250ms connection attempt delay is the most important constant in Happy Eyeballs. It represents a tradeoff between three competing concerns:
- Too short (e.g., 25ms) — On high-latency paths (satellite, intercontinental), a perfectly healthy IPv6 connection might take 150ms+ for the SYN-ACK round trip. A 25ms timer would trigger unnecessary IPv4 attempts for nearly every connection, doubling server load and wasting client sockets.
- Too long (e.g., 2 seconds) — If IPv6 is broken, the user waits 2 seconds before any fallback begins. This is noticeable and annoying.
- Just right (250ms) — Long enough that most healthy connections complete before the fallback fires. Short enough that broken paths are detected quickly. The original RFC 6555 recommended 150-250ms. RFC 8305 standardized on 250ms.
The 250ms value was informed by latency measurements across the internet. The vast majority of TCP connections complete their handshake in well under 200ms — even across continents. According to measurements from major CDN providers, the 95th percentile TCP handshake time for most destinations is under 150ms. Setting the timer at 250ms means that fewer than 1% of healthy connections would trigger an unnecessary fallback attempt.
Some implementations deviate from 250ms based on local conditions. Apple's implementation uses adaptive timing informed by historical connection data. Chrome has experimented with shorter values. But 250ms remains the recommended default.
Browser Implementations
Every major browser implements Happy Eyeballs, but each has distinct quirks.
Chrome / Chromium
Chrome's network stack implements Happy Eyeballs v2 in its TransportConnectJob class. Chrome sends AAAA and A queries in parallel, interleaves the results, and uses a 250ms connection attempt delay. Chrome also maintains a per-host cache of which address family succeeded, so subsequent connections to the same host skip the racing and go directly to the previously successful address. This cache is flushed when the network interface changes (e.g., switching from Wi-Fi to cellular).
Chrome's implementation has an additional optimization: if the host's AAAA lookup returns no results (no IPv6 addresses), it skips Happy Eyeballs entirely and connects using IPv4 only. Similarly, if the device has no IPv6 address on any interface, AAAA lookups may be skipped entirely to avoid unnecessary DNS traffic.
Firefox
Firefox implements Happy Eyeballs in its nsSocketTransport layer. Firefox's default connection attempt delay is 250ms, configurable via the preference network.http.connection-timeout. Firefox also implements address family caching and respects the system's address selection policy (RFC 6724).
Firefox has a notable behavior: it implements "pessimistic" Happy Eyeballs for HTTPS connections. Because TLS handshake failure after a successful TCP connect can indicate a different class of problem (e.g., certificate mismatch, not a network path issue), Firefox waits for the full TLS handshake to complete before declaring a winner, not just the TCP SYN-ACK.
Safari / WebKit
Safari delegates Happy Eyeballs to Apple's Network.framework (previously CFNetwork), which implements it at the OS level rather than in the browser. This means all apps on macOS and iOS get Happy Eyeballs behavior automatically. Apple's implementation is notably aggressive about preferring IPv6 — it uses adaptive timing based on historical success rates and adjusts the connection attempt delay dynamically. On networks where IPv6 has consistently worked, Apple's stack may wait longer before trying IPv4; on networks with a history of IPv6 failures, it may start IPv4 attempts earlier or even in parallel with no delay.
Operating System Implementations
Address Selection: RFC 6724 and getaddrinfo
Happy Eyeballs interacts closely with the operating system's address selection policy, defined in RFC 6724. When an application calls getaddrinfo() to resolve a hostname, the OS returns a sorted list of addresses. The sorting considers:
- Source address availability — Prefer destinations for which the host has a matching source address. If the host has no global IPv6 address, IPv4 destinations are ranked higher.
- Scope matching — Prefer same-scope addresses (global to global, link-local to link-local).
- Longest prefix matching — Prefer destinations whose address shares a longer common prefix with the source address.
- Label matching — A configurable label table maps address ranges to labels, allowing policy-based preferences.
- Precedence table — A configurable table assigns precedence values to address prefixes. By default, IPv6 native addresses have higher precedence than IPv4.
The address order returned by getaddrinfo() feeds into Happy Eyeballs. The algorithm takes this OS-sorted list and further interleaves address families, ensuring that even if the OS puts all IPv6 addresses first, an IPv4 address appears early in the connection attempt sequence.
macOS and iOS
Apple's Network.framework provides a complete Happy Eyeballs v2 implementation. Applications using NWConnection get Happy Eyeballs automatically. The framework also performs Multipath TCP (MPTCP) and can simultaneously use Wi-Fi and cellular paths. Apple's implementation is the most mature and aggressive about IPv6 adoption — Apple requires all apps submitted to the App Store to work in IPv6-only environments.
Linux
Linux's kernel does not implement Happy Eyeballs directly — it provides the primitives (non-blocking connect(), epoll/io_uring for multiplexing) and applications implement the racing logic themselves. The getaddrinfo() implementation in glibc sorts addresses according to RFC 6724, and applications that iterate through the returned addresses sequentially (without racing) get the OS's preferred ordering but no Happy Eyeballs behavior. Modern applications and libraries must implement the racing explicitly.
Windows
Windows implements Happy Eyeballs at the Winsock layer starting with Windows 8. The ConnectEx API and the newer WSAConnectByName function automatically race IPv4 and IPv6 connection attempts. Windows also maintains a "connection quality" cache that tracks which address families and specific addresses have worked for each destination, biasing future connection attempts toward known-good paths.
How curl Implements It
curl, the ubiquitous command-line HTTP client, has implemented Happy Eyeballs since version 7.59.0 (2018). Its implementation lives in the connection setup code and follows RFC 8305 closely. curl sends parallel DNS queries for A and AAAA records, interleaves the results, and races connections with a 250ms delay between attempts.
curl exposes several knobs for controlling Happy Eyeballs behavior:
--happy-eyeballs-timeout-ms— Sets the connection attempt delay (default 250ms).-4/--ipv4— Force IPv4 only (disable Happy Eyeballs).-6/--ipv6— Force IPv6 only.CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS— The libcurl C API equivalent.
When debugging connectivity issues, curl -v shows the Happy Eyeballs decision process: you can see both DNS queries being sent, the interleaved address list, each connection attempt starting, and which attempt wins. This makes curl an invaluable tool for diagnosing dual-stack problems.
Language and Library Support
Go: net.Dialer
Go's standard library implements Happy Eyeballs in net.Dialer. Since Go 1.12, the default dialer sends parallel DNS queries and races connections with a 300ms fallback delay (slightly longer than the RFC-recommended 250ms). The DualStack field on net.Dialer was deprecated in Go 1.12 because Happy Eyeballs is now always enabled — there is no reason to disable it.
Go's implementation uses FallbackDelay (default 300ms) as the connection attempt delay. You can tune it:
dialer := &net.Dialer{
Timeout: 30 * time.Second,
FallbackDelay: 250 * time.Millisecond, // Match RFC 8305
}
conn, err := dialer.DialContext(ctx, "tcp", "example.com:443")
Internally, Go spawns goroutines for each connection attempt and uses channels to coordinate the race. The first successful connection is returned; all others are closed.
Python: asyncio
Python's asyncio module has included Happy Eyeballs since Python 3.8, via loop.create_connection() with the happy_eyeballs_delay parameter (default 250ms). Python 3.11 added asyncio.staggered_race(), a general-purpose utility for racing coroutines with staggered start times, which is used internally by the connection logic.
reader, writer = await asyncio.open_connection(
'example.com', 443,
happy_eyeballs_delay=0.25 # seconds
)
The synchronous socket module does not implement Happy Eyeballs. Applications using blocking sockets must implement the racing logic manually or use a third-party library. This is a common gotcha: a Python application using urllib3 (which uses blocking sockets by default) does not get Happy Eyeballs unless it is configured to use an async transport.
Java
The JVM does not implement Happy Eyeballs by default. java.net.Socket and HttpURLConnection try addresses sequentially, using the order returned by InetAddress.getAllByName() (which respects the OS's RFC 6724 ordering). If IPv6 is preferred and broken, Java applications experience the full TCP timeout before falling back.
Java 17+ with the java.net.http.HttpClient introduced in Java 11 does not add Happy Eyeballs either. Third-party libraries like Netty and OkHttp implement their own Happy Eyeballs logic. OkHttp's implementation follows RFC 8305 with 250ms pacing and address interleaving. If you are writing a Java service that connects to dual-stack destinations, using OkHttp or Netty is strongly recommended over the standard library.
Rust
Rust's standard library std::net::TcpStream::connect() does not implement Happy Eyeballs. It resolves the hostname via getaddrinfo() and tries each address sequentially. The tokio async runtime's TcpStream::connect() similarly does not race connections by default.
Rust applications that need Happy Eyeballs should use the hyper HTTP library with the hyper-util crate, which implements connection racing. Alternatively, the hickory-resolver (formerly trust-dns-resolver) DNS library can be combined with manual connection racing using tokio::select! to implement the algorithm. The reqwest HTTP client, built on hyper, provides Happy Eyeballs behavior out of the box.
QUIC Happy Eyeballs: Racing Protocols
QUIC adds another dimension to Happy Eyeballs. When a client supports both HTTP/2 (over TCP+TLS) and HTTP/3 (over QUIC), it must decide which protocol to use for a new connection. This is sometimes called Happy Eyeballs v3 or QUIC Happy Eyeballs, though there is no formal RFC for it yet (as of 2025).
The client knows a server supports HTTP/3 through one of two mechanisms: the Alt-Svc HTTP header from a previous response, or the HTTPS DNS record (SVCB, RFC 9460) which advertises ALPN protocols including h3. Armed with this knowledge, the client can race a QUIC connection against a TCP+TLS connection.
The racing works similarly to address-family racing:
- Start a QUIC connection attempt (UDP). QUIC's 1-RTT handshake includes TLS 1.3 encryption, so a successful QUIC handshake means the connection is fully ready for HTTP/3.
- After 250ms (or a configured delay), if QUIC has not succeeded, start a TCP connection to the same server. This TCP connection will require a separate TLS handshake (2-RTT total for TCP + TLS 1.3).
- Whichever protocol completes its full handshake first wins.
This is critical because UDP (which QUIC runs on) is sometimes blocked by corporate firewalls, hotel captive portals, or misconfigured middleboxes. Without protocol racing, a client that knows the server supports HTTP/3 might try QUIC first and wait for a long timeout before falling back to TCP. Chrome implements this racing and tracks which networks block QUIC, temporarily disabling QUIC on networks where it consistently fails — a behavior called "QUIC broken" detection.
Interaction with DNS Prefetching and HTTP/2 Connection Coalescing
Happy Eyeballs does not operate in isolation. Several other optimization mechanisms interact with it:
DNS prefetching — Browsers speculatively resolve hostnames for links on the current page before the user clicks them. This means that by the time Happy Eyeballs starts its connection racing, the DNS results may already be cached. The 50ms Resolution Delay in RFC 8305 becomes irrelevant if both A and AAAA records are already available. DNS prefetching can also pre-warm the Happy Eyeballs address family cache: if a prefetched resolution reveals that a host only has A records, the browser knows to skip IPv6 entirely when the user navigates.
HTTP/2 connection coalescing — HTTP/2 allows multiple hostnames to share a single TCP connection if they resolve to the same IP address and present a valid certificate covering all hostnames. This means that Happy Eyeballs might run for the first hostname on a page (e.g., www.example.com) but subsequent hostnames that coalesce onto the same connection (e.g., api.example.com, static.example.com) skip connection setup entirely. The winning address family from the first connection effectively "wins" for all coalesced hostnames.
TCP Fast Open (TFO) — TFO (RFC 7413) allows data to be sent in the initial SYN packet, eliminating one round trip for repeat connections. Happy Eyeballs interacts with TFO in that the racing decision happens before TFO can provide any benefit — TFO only helps after the winning connection is selected. However, TFO cookies are address-specific, so switching address families between connections (which Happy Eyeballs might cause) means TFO cookies for the old address family are not usable.
Measuring Happy Eyeballs Behavior
Understanding how Happy Eyeballs is behaving on your network or for your users requires specific measurement approaches:
With curl:
# Show Happy Eyeballs in action
curl -v --trace-time https://example.com 2>&1 | grep -E "Trying|Connected"
# Force IPv4 only to compare timing
curl -4 -w "time_connect: %{time_connect}s\n" -o /dev/null -s https://example.com
# Force IPv6 only
curl -6 -w "time_connect: %{time_connect}s\n" -o /dev/null -s https://example.com
# Use Happy Eyeballs (default) and see which wins
curl -w "time_connect: %{time_connect}s\nremote_ip: %{remote_ip}\n" -o /dev/null -s https://example.com
With browser DevTools: The Network panel in Chrome DevTools shows the remote IP address for each connection. If it is an IPv6 address (contains colons), IPv6 won the race. The Timing tab shows connection setup time — if it is consistently ~250ms higher than expected, Happy Eyeballs is likely kicking in due to a slow or broken preferred address family.
With Wireshark: Filter for tcp.flags.syn == 1 and examine the timing between SYN packets. You should see SYN packets to different address families separated by approximately 250ms. If you see a SYN to an IPv6 address, then 250ms later a SYN to an IPv4 address, and the IPv4 connection completes first, Happy Eyeballs is working as designed.
Server-side: If you operate a dual-stack server, compare the ratio of IPv4 to IPv6 connections over time. A sudden shift toward IPv4 from clients that previously used IPv6 may indicate an IPv6 path degradation that Happy Eyeballs is silently working around. Check your BGP routes — a path change in the IPv6 routing table could be adding latency that causes IPv6 to consistently lose the race.
Pathological Cases
Happy Eyeballs is not a silver bullet. Several scenarios cause degraded behavior:
IPv6 Blackholing with Many Addresses
If a destination has many IPv6 addresses and all of them are blackholed, the interleaved list still means the client must wait 250ms before each IPv4 attempt. With 6 IPv6 addresses and 2 IPv4 addresses, the interleaved list might be: v6, v4, v6, v4, v6, v6, v6, v6. The first IPv4 attempt starts at t=250ms, which is fine. But if the first IPv4 address is also unreachable, the second IPv4 attempt does not start until t=750ms (fourth in the list). Most applications set an overall connection timeout (e.g., 30 seconds) that limits the total damage, but the per-address 250ms adds up.
Asymmetric DNS Response Times
If the AAAA response takes several seconds (due to a misbehaving authoritative DNS server for the ip6.arpa zone or DNSSEC validation delays), the client may have already connected over IPv4 before IPv6 addresses are even known. This is arguably correct behavior — the client connected successfully — but it means the user never benefits from IPv6 even if the IPv6 path would have been faster. The 50ms Resolution Delay mitigates this somewhat, but cannot help if one DNS response is drastically slower than the other.
Connection Success but High Latency
Happy Eyeballs optimizes for connection success, not connection quality. If IPv6 connects successfully in 80ms but IPv4 would have connected in 20ms, IPv6 wins the race — even though the IPv4 path might offer lower latency for data transfer. The algorithm has no mechanism for post-handshake quality comparison. Some implementations partially address this through historical timing data: if IPv4 consistently completes connections faster, the implementation may bias toward IPv4 in its address sorting.
Server Resource Waste
Every connection attempt that is eventually cancelled still consumed server resources: the server processed a SYN, allocated a socket, possibly performed a TLS handshake. Under heavy load, the extra connection attempts from Happy Eyeballs across thousands of clients can be significant. This is why the 250ms pacing delay exists (rather than starting all attempts simultaneously) — it limits the burst of speculative connections.
DNS Resolution Failures
If a host only has AAAA records (IPv6 only) but the client's DNS resolver has trouble with AAAA queries (some older resolvers did), the client might connect over an IPv4 fallback that does not exist, leading to complete connection failure. Modern DNS resolvers handle this correctly, but edge cases remain with split-horizon DNS, DNSSEC validation failures, or unusual resolver configurations.
Happy Eyeballs and the IPv6 Transition
Happy Eyeballs is fundamentally a transition technology. In a world where IPv6 deployment is complete and reliable everywhere, there would be no need to race address families — everything would just use IPv6. The algorithm exists precisely because the IPv6 transition is incomplete, uneven, and prone to partial failures.
Paradoxically, Happy Eyeballs both helps and hinders the transition. It helps by making IPv6 safe to deploy: network operators and content providers can enable IPv6 without fear that users with broken IPv6 paths will experience degraded performance. It hinders by hiding IPv6 problems: if Happy Eyeballs silently falls back to IPv4, the user never notices and never reports the IPv6 breakage, reducing the pressure to fix it.
The algorithm's preference for IPv6 (giving it the first attempt and a 250ms head start) creates a gentle pressure toward IPv6 adoption. On networks where IPv6 works correctly, connections will almost always use IPv6 because it gets to try first. This means more IPv6 traffic, more operational experience, and more incentive to maintain and improve IPv6 connectivity. As IPv6 deployment matures and IPv6 breakage becomes rarer, the 250ms fallback will fire less and less often, and eventually Happy Eyeballs will be a vestigial behavior — always attempting IPv6 first and always succeeding.
Until that day, Happy Eyeballs remains one of the most important algorithms most people have never heard of. It runs in every browser, every modern HTTP client, and most operating systems, silently making the dual-stack internet work despite its imperfections. You can see which protocol your connections use by looking up any dual-stack host in the looking glass — the result shows both IPv4 and IPv6 routes when they exist, and Happy Eyeballs ensures your browser connected over whichever one was fastest.
Related Articles
- IPv4 vs IPv6 — The two address families that Happy Eyeballs races between
- IPv6 Transition Technologies — Dual-stack, tunneling, and other approaches to the IPv4-to-IPv6 transition
- How TCP Works — The transport protocol whose handshake Happy Eyeballs races
- How QUIC and HTTP/3 Work — The protocol that adds a third dimension to connection racing
- What Is DNS? — How A and AAAA queries feed into address selection
- How TLS and HTTPS Work — The encryption handshake that follows the TCP connection
- What Is an IP Address? — The addresses that Happy Eyeballs sorts and races