IPv6 Address Autoconfiguration — SLAAC and DHCPv6
“In IPv4, you either typed in your address or you asked a server. In IPv6, you can be told a prefix, ask for one, or compute your own — and the same host may do all three simultaneously.”
1. The Two Models
IPv6 gives a host three independent ways to acquire an address:
- Manual — operator-configured, identical in spirit to a static IPv4 address.
- SLAAC (StateLess Address AutoConfiguration, RFC 4862) — the host listens for Router Advertisements on the link, learns the prefix, and combines it with an interface identifier (IID) it generates locally. No server tracks the allocation; uniqueness is verified by DAD.
- DHCPv6 (RFC 8415, obsoletes RFC 3315) — a server explicitly leases an address or other configuration back to the requesting client. DHCPv6 has both stateful (server tracks lease) and stateless (server only hands out non-address options like DNS) modes.
The RA flags M and O (RFC 4861 §4.2) tell a host which combination to use:
| RA M-flag | RA O-flag | Host behaviour |
|---|---|---|
| 0 | 0 | SLAAC for address; assume DNS comes via RA’s RDNSS option (RFC 8106) |
| 0 | 1 | SLAAC for address; query DHCPv6 for DNS and other config only (stateless DHCPv6) |
| 1 | 0 | Use DHCPv6 for address and config (stateful) — operator disables SLAAC by setting A=0 on the prefix option |
| 1 | 1 | Use DHCPv6 for everything |
2. SLAAC — the stateless path
2.1 The mechanism
SLAAC is defined entirely in RFC 4862 and builds on RFC 4861 NDP. The complete sequence on a host that just came up on an Ethernet link:
Host boot
|
v
(1) Generate link-local: fe80:: + 64-bit interface identifier
|
v
(2) DAD on link-local (RFC 4861 §7.3)
|
v
(3) Send 3× RS to ff02::2 (All-Routers) at 4s intervals
|
v
(4) Router responds with RA containing one or more
Prefix Information options (PI):
prefix=2001:db8:0:1::/64
valid-lifetime=86400 s (24h, default)
preferred-lifetime=14400 s (4h, default)
A=1 (autonomous, SLAAC-eligible)
L=1 (on-link, prefix is reachable on this L2)
|
v
(5) For each PI with A=1, host forms a global address:
global = prefix(64) | interface_id(64)
|
v
(6) DAD on the new global
|
v
(7) Address becomes PREFERRED for preferred-lifetime seconds,
then DEPRECATED for the remainder of valid-lifetime,
then DELETED. RA refreshes lifetimes periodically.
2.2 Generating the Interface Identifier — three RFCs
The 64-bit IID can be generated by any of:
EUI-64 from a 48-bit MAC (RFC 4291 Appendix A, deprecated practice):
MAC: 00:1a:2b:3c:4d:5e
(1) Insert ff:fe in the middle:
00:1a:2b:ff:fe:3c:4d:5e
(2) Toggle the U/L bit (bit 1 of first octet):
02:1a:2b:ff:fe:3c:4d:5e
(3) Resulting IID: 021a:2bff:fe3c:4d5e
(4) Global address: 2001:db8:0:1:21a:2bff:fe3c:4d5e
The U/L bit (Universal/Local) is set so the IID is globally unique when the MAC was assigned by the IEEE (universal); the I/G (Individual/Group) bit must be 0 because the address is unicast.
EUI-64 has a known privacy problem: the IID never changes when the host moves networks, so the same MAC yields the same low 64 bits on every prefix, making the host trivially trackable across networks. RFC 7217 and RFC 4941 fix this.
RFC 7217 — stable, semantically opaque addresses:
A stable-per-network address that does not reveal the MAC. The host computes the IID as a hash (SHA-256 truncated to 64 bits) over the concatenation of:
Hash inputs:
- the prefix (so the IID differs per network)
- the network interface's stable secret (e.g., a per-host random key)
- the interface's hardware address (or other stable identifier)
- the DAD counter (so if a collision is detected, the host can recompute)
Output: 64-bit IID with U/L bit forced to "local"
The host keeps the same IID every time it rejoins the same prefix (useful for inbound connections to a stable server) but is a different IID on every other prefix. This is the recommended default in modern OSes (Linux addr_gen_mode 1, macOS, Windows 10+).
RFC 4941 — privacy extensions, temporary addresses:
For clients that want outbound-only anonymity, the host generates additional temporary IIDs with a fresh random value, rotating them frequently:
Stable addr: 2001:db8:0:1:021a:2bff:fe3c:4d5e (for inbound: SSH, servers)
Temp #1 addr: 2001:db8:0:1:7f4a:9b3c:8e1d:2a5f (for outbound: web browsing)
↑ regenerated every preferred-lifetime seconds
Temp #2 addr: 2001:db8:0:1:ab12:cd34:ef56:0123 (new one ready to take over)
The address-generation pseudocode (RFC 4941 §3.2.2) takes 5–7 random bytes and a token computed from the stable IID, and uses them to derive a new random IID each time the previous one expires its preferred lifetime. The deprecated temporary address is kept for the valid lifetime so existing TCP connections don’t break, but new connections use the new address.
Privacy extensions are the default in modern mobile OSes (Android 6+, iOS) and in Windows; they are enabled in Linux via sysctl net.ipv6.conf.*.use_tempaddr=2. The flip-side: when an operator expects the same address to come back (e.g., DNS reverse mapping, ACLs), they should deploy RFC 7217 stable privacy addresses instead, so inbound services work.
2.3 Lifetimes and address deprecation
Every address has two clocks running in parallel:
[assignment]
|
|<--- preferred-lifetime (default 4h) --->|
| |
| PREFERRED (active for new + old)|
| DEPRECATED (active for old connections only)
|<------------- valid-lifetime (default 24h) --------->|
DELETED
- A PREFERRED address is fair game for new outgoing connections;
getaddrinfo()will prefer it. - A DEPRECATED address may still be used for existing connections (so a TCP socket with that source continues to work) but not for new connections.
- After valid-lifetime elapses, the address is removed from the interface.
This dual-clock design means address rotation is graceful: by the time a temporary address is removed, every existing connection has had plenty of time to either close or migrate to a newer source. A long-lived TCP connection that outlives both the valid-lifetime and any successor address will still break — RFC 4941 recommends keeping at least one or two successors in the DEPRECATED state to make this rare.
3. DHCPv6 — the stateful path
DHCPv6 is specified by RFC 8415 (which obsoleted RFC 3315 and 3633). It uses UDP on ports 546 (client) and 547 (server) and shares many state-machine concepts with IPv4 DHCP (RFC 2131), but the wire format is different — DHCPv6 messages are typed, not option-tag-laden in the IPv4 way.
3.1 The classic 4-message exchange (stateful, address assignment)
Client Server
----- ------
(1) SOLICIT (multicast ff02::1:2) --> "Any DHCPv6 server out there?"
(server decides whether to reply)
(2) ADVERTISE <-- "I can give you this address"
(multiple servers can each ADVERTISE)
(3) REQUEST (multicast ff02::1:2) --> "I want the address you offered"
(server reserves the lease)
(4) REPLY <-- "Here's the address + DNS + lifetimes"
Both SOLICIT and REQUEST go to the All-DHCPv6-Relay-Agents-and-Servers multicast group ff02::1:2 — link-scoped, so a server on the same link sees it without a relay. When the server is off-link, a relay agent (typically a router) wraps the message in a Relay-Message envelope and forwards it to the server unicast; the reply is relayed back.
3.2 The stateless 2-message exchange
When the host already has an address (via SLAAC) and only wants other config (DNS, NTP, SIP), the host skips ADVERTISE and REQUEST, and only needs two messages:
(1) INFORMATION-REQUEST --> "I'm a SLAAC client, just give me DNS/NTP"
(2) REPLY <-- "Here: DNS=2001:db8::53, NTP=2001:db8::123"
This is what O=1 in the RA triggers. Many operators prefer stateless DHCPv6 to RDNSS because their DHCPv6 servers already integrate with IPAM (IP Address Management) and dynamic DNS updates.
3.3 The RAPID-COMMIT optimisation (2-message stateful)
RFC 8415 §5.1 defines a RAPID-COMMIT option that lets a SOLICIT/REPLY pair skip ADVERTISE/REQUEST. The client includes the option in SOLICIT; a server that supports RAPID-COMMIT and is willing to commit immediately sends REPLY directly. Operators typically enable RAPID-COMMIT on small subnets where contention is impossible; it is disabled on shared DHCPv6 servers because they need REQUEST/REPLY to coordinate allocation.
3.4 Prefix Delegation (PD)
DHCPv6 isn’t just for addresses; it can delegate prefixes to a downstream router. The CPE sends SOLICIT with an IA_PD option (Identity Association for Prefix Delegation, RFC 8415 §31); the operator’s DHCPv6-PD server delegates a /56 or /60 to the CPE, which then carves it into /64s on the customer LANs.
Operator DHCPv6-PD server
|
| REPLY: delegate 2001:db8:ab:cd00::/56 to CPE
v
Customer CPE
|
| +-- LAN1: 2001:db8:ab:cd00::/64 (SLAAC advertised on eth0)
| +-- LAN2: 2001:db8:ab:cd01::/64 (SLAAC advertised on eth1)
| +-- LAN3: 2001:db8:ab:cd02::/64
| ... 256 LANs maximum from /56
PD is how most residential operators (Comcast, BT, Free, KDDI) give customers enough IPv6 space for many subnets without per-host coordination.
3.5 Lifetimes and lease renewal
DHCPv6 leases use the same preferred/valid dual-clock model as SLAAC — the client must renew (T1) and rebind (T2) before the valid lifetime expires:
[lease acquired]
|
|<-- T1 (default = .5 * valid) -->| RENEW (unicast to original server)
| |
|<-- T2 (default = .8 * valid) -->| REBIND (multicast, in case original server is dead)
| |
|<-- valid lifetime -------------->| RELEASE or expiry
The server’s REPLY for RENEW/REPLY gives new T1, T2, and preferred/valid lifetimes — operators can shorten or extend leases without restarting clients.
4. SLAAC vs DHCPv6 — when to use which
| Property | SLAAC | DHCPv6 |
|---|---|---|
| Server required | No (only routers, which you have anyway) | Yes |
| Address tracking / audit | No (host picks IID) | Yes (operator logs every lease) |
| Static reverse DNS | Hard (host picks IID, may rotate) | Easy (DHCPv6 → dynamic DNS) |
| Stability across reattach | Depends on IID policy (RFC 7217 stable, RFC 4941 rotates) | Server-controlled, can be sticky |
| Android compatibility | Yes (Android ships SLAAC only) | Android does NOT do DHCPv6 address assignment |
| Prefix-Per-Host (PPH) routing | Trivial (host picks IID in delegated prefix) | Awkward (server must know per-host prefix) |
| Scalability | Unlimited — stateless | Server must track leases |
| Configuration besides address | RDNSS (RFC 8106), RA options (RFC 4191, 6106) | All of DHCPv4 + stateless options |
| Operator control of IID | None | Server picks address |
The Android DHCPv6 gap is operationally critical: Android does not implement RFC 8415 IA_NA (Identity Association for Non-temporary Address), only INFORMATION-REQUEST. So if you set M=1, O=1, A=0 on your RA to “force” DHCPv6-only addresses, every Android phone on the link will get only a link-local address and silently fail. The only portable configuration today is SLAAC + stateless DHCPv6 (M=0, O=1, A=1).
When to use SLAAC alone
- Public-access networks (cafés, hotels) where you don’t need to log IPs.
- Mobile carriers — every handset gets a /64 from the cellular prefix via SLAAC.
- IoT — most constrained stacks have an SLAAC implementation but not DHCPv6.
When to use DHCPv6 (stateful)
- Enterprises that need per-host audit logging (PCI DSS, regulated industries).
- Datacentres where the host address must match a DNS reverse-zone entry that operations controls.
- Hosts that don’t move networks (server farms).
When to use both
- A campus where SLAAC is for visitors (their IIDs are random, don’t pollute DNS) and DHCPv6 stateful is for managed workstations (with dynamic DNS).
5. Source Address Selection — RFC 6724
A host with multiple IPv6 addresses (link-local + several GUAs, some deprecated, some temporary, some stable) must pick one source per outgoing connection. RFC 6724 (which obsoleted RFC 3484) defines the algorithm:
Candidate source set, for destination D:
- all addresses on the outgoing interface
- EXCLUDE tentative, duplicate, deprecated unless no alternative
Sort by (in order):
1. Same-scope as destination (rule 1)
2. Prefer appropriate source scope (rule 2)
3. Avoid deprecated addresses (rule 3)
4. Prefer home addresses (rule 4, Mobile IPv6)
5. Prefer outgoing interface's address (rule 5)
6. Prefer matching label (rule 6) — labels from RFC 6724 §2.1
7. Prefer public over temporary (rule 7) — historically reversed by
privacy-conscious OSes to "prefer temporary"
8. Use longest matching prefix (rule 8)
Most modern OSes flip rule 7 to “prefer temporary” by policy (so RFC 4941 actually changes the address that gets used for outbound traffic). Operators should not rely on rule 8 — it’s the last tiebreaker, not the first.
6. Worked Example — host on an enterprise SLAAC + stateless DHCPv6 link
t=0 Host up. Interface eth0 has MAC 02:42:ac:11:00:02.
t=0.001 Host generates link-local IID via RFC 7217:
Hash(Prefix=fe80::/64, Secret=0x4a9b..., Iface=eth0) = 0x3c2a:1f5e:...
Link-local = fe80::3c2a:1f5e:abcd:1234
t=0.001 DAD on link-local → no reply in 1 s → link-local PREFERRED
t=1.000 Host sends 3× RS to ff02::2
t=1.100 Router RA:
Prefix=2001:db8:42:1::/64, valid=24h, pref=4h, A=1, L=1
M=0, O=1
RDNSS=2001:db8:42::53
t=1.101 Host assigns stable GUA (RFC 7217):
Hash(Prefix=2001:db8:42:1::/64, Secret, Iface) = 0x...
GUA-stable = 2001:db8:42:1:7f3a:9b1c:5d2e:1f4a
DAD → PREFERRED in 1 s
t=1.102 Host generates temporary GUA (RFC 4941):
random IID = 0xb1c2:d3e4:f5a6:0718
GUA-temp1 = 2001:db8:42:1:b1c2:d3e4:f5a6:0718
DAD → PREFERRED in 1 s
t=2.102 Host has 3 GUAs and a link-local. Opens a browser to https://example.com/
getaddrinfo() returns GUA-temp1 as source (per RFC 6724 rule 7,
inverted to prefer temporary)
t=2.200 Host also sends DHCPv6 INFORMATION-REQUEST to ff02::1:2
(RA said O=1)
t=2.300 DHCPv6 server REPLY:
DNS=2001:db8:42::53 (matches RDNSS, good)
NTP=2001:db8:42::123
Domain-search=corp.example.com
t=4h preferred-lifetime on GUA-temp1 expires → DEPRECATED
Host generates GUA-temp2 (new random IID), DADs, uses it for new connections
Existing TCP connections on GUA-temp1 keep working until 24h valid-lifetime
7. Common Pitfalls
- Forgetting O-flag when DNS lives in DHCPv6 — clients that don’t understand RDNSS will end up without DNS. Either set O=1 or deploy RDNSS (RFC 8106).
- Setting A=1 and M=1 — every host gets both a SLAAC address and a DHCPv6 address, doubling their address count for no benefit. Use A=0 if you want DHCPv6-only on a prefix.
- Hard-coding EUI-64 IIDs in ACLs — works until the NIC is replaced and breaks under RFC 4941.
- Telling Android to use DHCPv6-only — Android ignores IA_NA, you’ve just made every Android phone on the link unaddressable.
- Disabling RA’s periodic unsolicted broadcasts — RFC 7559 explicitly recommends RAs every ~7 minutes; longer intervals leave new hosts stranded for minutes if they miss the initial burst.
8. Summary
- SLAAC and DHCPv6 are complementary: SLAAC handles addresses (stateless, scale-invariant), DHCPv6 handles everything else (stateful or stateless).
- The IID policy is a separate decision from SLAAC-vs-DHCPv6: SLAAC with RFC 7217 stable privacy is the modern default for hosts that need a stable address; SLAAC with RFC 4941 temporaries is the default for clients that need outbound-only anonymity.
- Android’s lack of DHCPv6 IA_NA support means a portable configuration today is SLAAC + stateless DHCPv6 (RA: M=0, O=1, A=1).
- Operators get address auditing via IPAM/DNS for stateful DHCPv6; get scale via SLAAC; get both via the dual mode.
9. References
- RFC 4862 — IPv6 Stateless Address Autoconfiguration. https://www.rfc-editor.org/rfc/rfc4862
- RFC 8415 — Dynamic Host Configuration Protocol for IPv6 (DHCPv6). https://www.rfc-editor.org/rfc/rfc8415
- RFC 4941 — Privacy Extensions for Stateless Address Autoconfiguration. https://www.rfc-editor.org/rfc/rfc4941
- RFC 7217 — A Method for Generating Semantically Opaque Interface Identifiers with IPv6. https://www.rfc-editor.org/rfc/rfc7217
- RFC 6724 — Default Address Selection for IPv6. https://www.rfc-editor.org/rfc/rfc6724
- RFC 4291 — IPv6 Addressing Architecture (EUI-64). https://www.rfc-editor.org/rfc/rfc4291
- RFC 8106 — IPv6 Router Advertisement Options for DNS Configuration. https://www.rfc-editor.org/rfc/rfc8106
- RFC 7559 — Making IPv6-Only Networks Reliable with DHCPv6. https://www.rfc-editor.org/rfc/rfc7559
- RFC 6106 — IPv6 Router Advertisement Options for DNS Configuration (older, superseded by 8106). https://www.rfc-editor.org/rfc/rfc6106
- RFC 7078 — DHCPv6 Option for SRV RRs. https://www.rfc-editor.org/rfc/rfc7078
- RFC 8068 — DHCPv6 PD Per-Host. https://www.rfc-editor.org/rfc/rfc8068
Cross-References
- IPv6 Internals — header, addressing, extension headers
- ICMPv6 & NDP — the carrier of Router Advertisements
- IPv6 (overview) — high-level concepts
- DHCP — IPv4 DHCP, for comparison