Skip to main content
RunBook Academy

LinuxXXI · Advanced Linux NetworkingIPv6 advanced

IPv6 advanced - privacy, SLAAC details, and operational gotchas

Advanced⏱ ~10 minipsysctl

What you'll learn

  • Explain how SLAAC generates the interface identifier
  • Recognise privacy extension addresses and their trade-offs
  • Configure IPv6 on Linux with predictable addressing
  • Avoid the common IPv6 operational gotchas

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

A Linux host’s IPv6 address is often more complex than its IPv4 address. It has a link-local address (automatic), a global address (from SLAAC or DHCPv6), and possibly temporary addresses (privacy extensions). Understanding what each is for - and how to control them - is essential for production.

SLAAC and the interface identifier

SLAAC generates an interface identifier (IID, the lower 64 bits of the IPv6 address) from one of three sources:

  1. Modified EUI-64: derived from the MAC address. The 48-bit MAC is split down the middle, the two bytes ff:fe are inserted between the halves (48 + 16 = 64 bits), and the universal/local bit — 0x02 of the first octet — is flipped.
  2. RFC 7217 opaque: stable but random, derived from a hash of network-specific values.
  3. RFC 4941 privacy extensions: temporary addresses that rotate periodically.

A MAC address aa:bb:cc:00:00:01 produces a Modified EUI-64 IID of a8bb:ccff:fe00:0001. Prefixed with the SLAAC prefix, this becomes the global IPv6 address.

Privacy concerns: the EUI-64 IID embeds the MAC address, which is also the interface’s link-local IID. An observer on the same LAN can correlate the MAC with the IPv6 address across networks, breaking some privacy assumptions.

Privacy extensions (RFC 4941)

Privacy extensions generate temporary addresses in addition to the SLAAC address. The temporary addresses rotate (default 24 hours on Linux), making it harder to track a host across networks.

sysctl net.ipv6.conf.eth0.use_tempaddr
sysctl net.ipv6.conf.eth0.temp_valid_lft
sysctl net.ipv6.conf.eth0.temp_prefered_lft

A value of 2 for use_tempaddr means “use temporary addresses for outgoing connections, but also keep the publicly-known stable address”. This is the right setting for most hosts.

For servers, privacy extensions are usually undesirable: the address is the host’s identity and should be stable. Disable them:

sudo sysctl -w net.ipv6.conf.eth0.use_tempaddr=0

For clients, privacy extensions are usually the right choice.

Configure a stable IPv6 address

Predictable addressing matters for servers. The recommended approach is to disable SLAAC and configure the address explicitly:

# /etc/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
Address=2001:db8:85a3:1::10/64
Gateway=2001:db8:85a3:1::1
IPv6AcceptRA=false

Setting IPv6AcceptRA=false prevents the kernel from auto-configuring addresses from router advertisements. With SLAAC disabled, the host’s IPv6 address is exactly what the configuration says.

The gateway is not optional

Gateway= is the line operators forget, and the omission is silent. In IPv4 you get a default route from DHCP or you configure it by hand, and its absence is obvious immediately. In IPv6 the default route normally arrives inside a Router Advertisement, not with the address. Turning off RA acceptance therefore turns off the only source of your IPv6 default route.

A host configured with Address= but no Gateway= and IPv6AcceptRA=false ends up in the worst possible state: it holds a global IPv6 address, it publishes an AAAA record, it answers inbound IPv6 connections perfectly, and it cannot originate a single off-link IPv6 connection. Outbound calls to dual-stack destinations stall until Happy Eyeballs times out and retries over IPv4, so package mirrors, DNS resolvers, telemetry and inter-service calls all pick up intermittent multi-second delays. It presents as packet loss. It is a missing route.

Verify explicitly after every change:

Read-only / Safethe route must be there before you call the change done
$ ip -6 route show default
default via 2001:db8:85a3:1::1 dev eth0 proto static metric 1024 pref medium

Illustrative output

An empty result from ip -6 route show default means IPv6 egress is broken, whatever the address list says.

Many routers only offer a link-local next hop. That is normal and correct for IPv6, and Gateway= accepts it:

[Network]
Address=2001:db8:85a3:1::10/64
Gateway=fe80::1
IPv6AcceptRA=false

A link-local address is only unique per link, so the next hop is meaningless without an interface. In a systemd-networkd file the interface comes from the [Match] stanza. On the command line you must supply it yourself, or the command fails: ip -6 route add default via fe80::1 dev eth0.

Disable SLAAC per interface

sudo sysctl -w net.ipv6.conf.eth0.autoconf=0
sudo sysctl -w net.ipv6.conf.eth0.accept_ra=0

autoconf=0 disables SLAAC for that interface. accept_ra=0 prevents accepting router advertisements.

accept_ra=0 also stops the kernel installing the default route it learned from those advertisements. The trap is that routes already installed do not vanish the moment you set the sysctl; they persist until their RA lifetime expires. So the host keeps working, the change looks safe, and IPv6 egress breaks hours later or at the next reboot. Set the sysctl, then immediately confirm you still have a route you configured yourself with ip -6 route show default.

For DHCPv6-only addressing you still want the RAs - they carry the default route and the M/O flags that tell the host to ask DHCPv6 in the first place. What you turn off is SLAAC address generation, not RA acceptance:

sudo sysctl -w net.ipv6.conf.eth0.autoconf=0
sudo sysctl -w net.ipv6.conf.eth0.accept_ra=1

accept_ra=2 means something entirely different, and the name misleads people into using it here. The values are:

ValueMeaning
0Do not accept Router Advertisements
1Accept RAs if forwarding is disabled (the functional default)
2Overrule forwarding behaviour - accept RAs even if forwarding is enabled

None of them suppresses address autoconfiguration; that is autoconf=0 alone.

Operational gotchas

  1. Two addresses, one hostname: a host has both a stable and a temporary IPv6 address. A DNS AAAA record points to the stable address; outgoing connections may use the temporary one. Reverse the priority with temp_prefered_lft=0 on servers.

  2. RA-driven configuration surprise: a guest network or test rig accepts RAs and configures itself automatically. This is convenient but can override your static configuration. Disable with accept_ra=0.

  3. Multicast listener exhaustion: a host that joins many multicast groups (IPv6 heavily uses multicast for ND) may exhaust the multicast listener table on a router. This is rare but documented.

  4. Dual-stack listeners: :: and [::] are the same address. The brackets are only notation for writing an IPv6 address next to a port, which is why ss prints [::]:443 and 0.0.0.0:443. Whether a socket bound to :: also accepts IPv4 is decided by the IPV6_V6ONLY socket option, whose system default comes from net.ipv6.bindv6only (0 = dual-stack, the Linux default). Most applications set it themselves - nginx listen [::]:443 ipv6only=on, the JVM’s -Djava.net.preferIPv4Stack - so when a service is reachable over one family and not the other, read the application’s own setting first, then sysctl net.ipv6.bindv6only.

  5. Ping6 zone identifier: pinging a link-local address requires a zone identifier: ping6 fe80::1%eth0. Forgetting %eth0 produces “no route to host” errors.

  6. RA flooding: a misbehaving router may flood RAs and reconfigure hosts. Disable RA acceptance on servers.

Knowledge check

Knowledge check · 5 questions

  1. Q1. What is the right sysctl to disable SLAAC on eth0?

  2. Q2. A server with privacy extensions enabled has a stable, predictable IPv6 address.

  3. Q3. Which of the following are operational IPv6 gotchas? Select all that apply.

  4. Q4. A server is configured with Address=2001:db8:85a3:1::10/64 and IPv6AcceptRA=false, and no Gateway=. Users report intermittent multi-second stalls on outbound calls to dual-stack services. What is the fault?

  5. Q5. Setting net.ipv6.conf.eth0.accept_ra=0 on a running host immediately removes the IPv6 default route it learned from Router Advertisements.

Passing score: 75%. Answers are checked in this browser.