When a dual-stack client resolves a name to both IPv6 and IPv4 addresses, how does Happy Eyeballs decide which one it connects over?
answer
- race, but with a head start
- AAAA first, short wait for it
- staggered attempts, not sequential
- first completed connection wins
basics
~10 sHappy Eyeballs v2 (RFC 8305) queries AAAA and A together, gives IPv6 a short head start, and then starts staggered connection attempts every ~250 ms across interleaved addresses, keeping the first that completes.
solid answer
~40 sA dual-stack client (RFC 4213) could try IPv6 first and fall back, but if the IPv6 path is broken it waits a whole connection timeout. Happy Eyeballs v2 (RFC 8305, which obsoletes RFC 6555) avoids that. It sends the AAAA query, then the A query, without waiting for both. If the A answer arrives first it waits a **Resolution Delay** (recommended 50 ms) for the AAAA. It sorts addresses by RFC 6724 destination selection and interleaves the families. Then it starts the first attempt, and if nothing has connected after a **Connection Attempt Delay** (recommended 250 ms) it starts the next one **in parallel, without cancelling** the first. The first connection to complete wins; the rest are abandoned.
go deeper
Recall that a dual-stack client tries IPv6 and IPv4 almost together, with IPv6 slightly ahead, and keeps whichever connects first.
Walk through RFC 8305's steps — AAAA then A, the 50 ms Resolution Delay, interleaving, 250 ms staggered attempts that are not cancelled — and say why sequential fallback was not enough.
Explain the operational side effect: broken IPv6 is masked, so monitoring, rate limiting and allow lists must treat the two families separately.
Weigh how much an organisation can rely on clients' Happy Eyeballs when deciding to publish AAAA records, versus investing in IPv6 path monitoring before it does.
## The problem dual stack creates RFC 4213 calls a host that runs both protocols an **IPv6/IPv4 node** — the dual-stack host. When it looks up a name it may get several **AAAA** (IPv6) and **A** (IPv4) records and must pick a destination. The naive approach is sequential: try the preferred address, wait for the connection to fail, try the next. That works when IPv6 either works or fails fast. It fails badly when the IPv6 path silently **black-holes** packets: the client waits for its connect timeout — an implementation value that can run to tens of seconds — before falling back. RFC 7526 records one consequence: the high failure rates of anycast 6to4 led some users to disable IPv6 and made some content providers reluctant to serve content over IPv6. Happy Eyeballs replaces "try then fall back" with a **staggered race** that still favours IPv6. Version 2 is RFC 8305 (2017), which obsoletes the first version, RFC 6555. ## The algorithm, step by step 1. **Query both families at once.** The client sends the AAAA query first, immediately followed by the A query, and treats resolution as asynchronous — it SHOULD NOT wait for both answers before acting. 2. **Give IPv6 a head start.** If a positive AAAA answer arrives first, the first IPv6 attempt starts at once. If the A answer arrives first, the client waits the **Resolution Delay** for the AAAA answer before using IPv4. 3. **Sort and interleave.** The addresses are ordered with RFC 6724 destination address selection and then interleaved by family, so that one failing family cannot hold up the other for long. The **First Address Family Count** says how many addresses of the preferred family go first. 4. **Start staggered attempts.** The client starts one connection attempt; if none has succeeded when the **Connection Attempt Delay** expires, it starts the next address's attempt *while the earlier ones keep running*. 5. **Keep the winner.** The first connection to complete is used; the others are cancelled. If more AAAA answers arrive while attempts are already running, they are folded into the candidate list rather than ignored. ## The timers RFC 8305 recommends | Parameter | Recommended value | Purpose | |---|---|---| | Resolution Delay | 50 ms | How long to wait for AAAA after A has arrived | | First Address Family Count | 1 (2 to favour a family harder) | Addresses of the first family tried before switching | | Connection Attempt Delay | 250 ms | Gap between attempts when no RTT data exists | | Minimum Connection Attempt Delay | 100 ms, never below 10 ms | Floor, so attempts do not flood the network | | Maximum Connection Attempt Delay | 2 s | Ceiling for implementations that adapt the delay to measured RTT | These are the RFC's recommended defaults, not wire values; implementations may tune them, and a more nuanced client can derive the attempt delay from historical round-trip times. ## What it changes in a running system - **IPv6 is used whenever it works.** Because IPv6 gets the head start and the first slot, a healthy IPv6 path carries the traffic. RFC 6724's default policy table pushes the same way: native IPv6 (precedence 40) ranks above IPv4-mapped (35), with 6to4 (30) and Teredo (5) below IPv4. - **Broken IPv6 becomes slow-ish, not broken.** A black-holed IPv6 path costs a fraction of a second per new connection instead of a full timeout. - **That also hides the breakage.** A service whose IPv6 is down still "works" for dual-stack clients, so monitoring must probe IPv6 and IPv4 **separately**; a combined health check will stay green. - **Logs show a mix.** The same user may arrive over IPv6 on one connection and IPv4 on the next, which matters for rate limits and address-based allow lists. - **Servers see extra half-open attempts.** Losing attempts are abandoned, so a server may log connections that were opened and dropped. ## On IPv6-only networks RFC 8305 also covers clients behind NAT64 and DNS64. When an application hands the library an **IPv4 literal** instead of a name, the engine discovers the network's translation prefix and synthesises an IPv6 address for it (RFC 6052 encoding), then races it like any DNS result. That is how a Happy Eyeballs client survives IPv4 literals on an IPv6-only network without a device-side translator.
- Why does Happy Eyeballs start the next attempt in parallel instead of cancelling the slow one?A slow attempt may simply be on a long path and about to succeed; cancelling it would throw that away and could leave the client cycling through addresses. Running attempts in parallel means the client keeps whichever completes first, so a slow-but-working IPv6 path is not discarded just because the 250 ms delay expired.
- Your service's IPv6 endpoint has been unreachable for a day, yet no user has complained. How is that possible?Dual-stack clients running Happy Eyeballs fall back to IPv4 after a few hundred milliseconds, so the outage shows only as slightly slower connection setup. The fix is monitoring that probes the IPv6 and IPv4 endpoints separately, since an end-to-end check from a dual-stack client will keep succeeding over IPv4.
saying these in an interview costs you the question
- Happy Eyeballs uses whichever DNS answer, A or AAAA, arrives first.
- The client waits for both A and AAAA answers before connecting.
- Starting the next attempt cancels the one already in progress.
- Happy Eyeballs repairs broken IPv6, so it needs no separate monitoring.
- A dual-stack client always connects over IPv6 when a AAAA record exists.