IPv6 in Practice: SLAAC Autoconfiguration, NDP, Dual-Stack & ICMPv6 Firewalling
Created: 2026-11-08 · Last updated: 2026-11-08 · Nejat Hakan
Executive Summary: IPv6 is not merely IPv4 with longer addresses; it represents a fundamental modernization of the internet protocol suite. Broadcast traffic and ARP have been eliminated in favor of multicast-driven Neighbor Discovery Protocol (NDP). Rather than relying solely on centralized DHCP daemons, nodes can configure their own addresses dynamically via Stateless Address Autoconfiguration (SLAAC). This guide details 128-bit address scoping, NDP message mechanics, deploying a Debian Linux IPv6 router using
radvd, configuring dual-stacksystemd-networkd, and crafting resilientnftablesrules that do not break Path MTU Discovery.
-
128-Bit Address Scopes
Understand the structural difference between Link-Local (
fe80::/10), Unique Local (fc00::/7), and Global Unicast (2000::/3) prefixes. -
NDP Replaces ARP
Trace how ICMPv6 Router Solicitations (RS), Router Advertisements (RA), and Neighbor Solicitations (NS) resolve L2 MAC addresses without broadcasts.
-
Linux Router &
radvd
Turn a Debian server into an autonomous IPv6 router: enable kernel forwarding, configure the Router Advertisement Daemon (
radvd), and distribute RDNSS. -
ICMPv6 Firewalling
Avoid the catastrophic mistake of blocking all ICMP in IPv6: configure stateful
nftablesrules to permit Path MTU Discovery and Neighbor Discovery.
1. 128-Bit Address Architecture & Scoping
An IPv6 address comprises 128 binary bits, represented as eight groups of four hexadecimal digits separated by colons:
The Two Golden Compression Rules (RFC 5952)
- Omit Leading Zeros:
0042becomes42;0000becomes0. - Double Colon (
::) Substitution: A contiguous run of all-zero groups can be replaced with::exactly once per address to prevent ambiguity.
Standard Subnet Sizing: The Universal /64 Prefix
In IPv6, individual subnets are almost universally allocated with a prefix length of /64:
* Network Prefix (Leading 64 bits): Routed by ISPs, enterprise firewalls, and data centers.
* Interface Identifier (Trailing 64 bits): Uniquely identifies the host interface (2^64 addresses per subnet).
+------------------------------------+------------------------------------+
| 64-bit Network Routing Prefix | 64-bit Interface Identifier |
| (Assigned by ISP / Router) | (EUI-64 or RFC 7217 Stable-Priv) |
+------------------------------------+------------------------------------+
Essential Address Scopes & Well-Known Prefixes
| IPv6 Scope | Prefix Range | IPv4 Equivalent | Scope & Routing Behavior |
|---|---|---|---|
| Loopback | ::1/128 |
127.0.0.1 |
Local host only; never transmitted across physical links. |
| Link-Local | fe80::/10 |
169.254.0.0/16 |
Mandatory on every IPv6 interface. Non-routable; valid only on the local physical link. Requires a scope ID (e.g., fe80::1%eth0). |
| Unique Local (ULA) | fc00::/7 (fd00::/8) |
RFC 1918 Private | Routable across private corporate WANs, site-to-site VPNs, and homelabs. Not routable on the public internet (RFC 4193). |
| Global Unicast (GUA) | 2000::/3 |
Public IPv4 | Globally unique and publicly routable across the global internet. |
| Multicast | ff00::/8 |
224.0.0.0/4 |
One-to-many communication. Subsumes all legacy broadcast functions. |
2. Neighbor Discovery Protocol (NDP): The Modern Replacement for ARP
IPv6 completely eliminates Layer-2 broadcast storms. There is no such thing as an ARP request in IPv6. Instead, the Neighbor Discovery Protocol (NDP) operates using dedicated ICMPv6 messages sent over efficient multicast groups:
%%{init: {'flowchart': {'wrappingWidth': 600}}}%%
flowchart TB
A["Host A joins Network"] --> B["1. Router Solicitation (RS)<br/>ICMPv6 Type 133 sent to ff02::2 (All Routers)"]
B --> C["2. Router Advertisement (RA)<br/>ICMPv6 Type 134 replied by Router with /64 Prefix"]
C --> D["3. SLAAC Autoconfiguration<br/>Host combines /64 Prefix + Interface ID"]
D --> E["4. Duplicate Address Detection (DAD)<br/>Sends Neighbor Solicitation (NS) Type 135 to verify uniqueness"]
E --> F["5. L2 MAC Address Resolution<br/>Neighbor Solicitation (NS) & Neighbor Advertisement (NA) Type 136"]
Core ICMPv6 NDP Message Types
- Router Solicitation (RS - Type 133): Sent by hosts upon link startup to prompt local routers to advertise themselves immediately.
- Router Advertisement (RA - Type 134): Sent periodically (and in response to RS) by routers. Announces the
/64prefix, default gateway lifetime, MTU, and DNS servers. - Neighbor Solicitation (NS - Type 135): Replaces ARP Request. Sent to the target's Solicited-Node Multicast Address (
ff02::1:ffxx:xxxx) to discover its MAC address or verify reachability. - Neighbor Advertisement (NA - Type 136): Replaces ARP Reply. Informs the requesting node of the target MAC address.
- Redirect (Type 137): Informs a host of a better first-hop router for a specific destination.
3. Autoconfiguration: SLAAC vs. DHCPv6
IPv6 provides two distinct mechanisms for dynamic address assignment:
%%{init: {'flowchart': {'wrappingWidth': 600}}}%%
flowchart TB
RA["Router Advertisement (RA) Received"] --> FLAG{"Check M and O Flags in RA"}
FLAG -->|"M=0, O=0: Pure SLAAC"| SLAAC["Host configures IP autonomously from /64 prefix.<br/>Uses RDNSS (RFC 8106) for DNS."]
FLAG -->|"M=0, O=1: Stateless DHCPv6"| STATEL["Host configures IP via SLAAC.<br/>Queries DHCPv6 server for DNS/NTP options."]
FLAG -->|"M=1: Stateful DHCPv6"| STATEF["Host requests IP and options<br/>directly from DHCPv6 server (like IPv4)."]
- SLAAC (Stateless Address Autoconfiguration): The router does not maintain a database of assigned IPs. Hosts generate their own 64-bit host IDs (either randomly via RFC 7217 Stable Privacy to prevent hardware MAC tracking, or via legacy EUI-64).
- DHCPv6 (Stateful): A central server leases individual addresses and tracks MAC-to-IP bindings.
4. Deploying an Autonomous Linux IPv6 Router (radvd)
You can easily configure a Debian Linux server to serve as an IPv6 router and announce network prefixes to all client machines on eth1.
Step 1: Enable IPv6 Forwarding in the Linux Kernel
Create /etc/sysctl.d/70-ipv6-routing.conf:
# File: /etc/sysctl.d/70-ipv6-routing.conf
# Enable IPv6 packet forwarding across all network interfaces
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.default.forwarding = 1
# Accept Router Advertisements even if forwarding is enabled on WAN interface
net.ipv6.conf.eth0.accept_ra = 2
Apply changes immediately:
Step 2: Install and Configure radvd
Install the Router Advertisement Daemon:
Edit /etc/radvd.conf:
# File: /etc/radvd.conf
interface eth1 {
# Send periodic Router Advertisements (every 200-600 seconds)
AdvSendAdvert on;
MinRtrAdvInterval 60;
MaxRtrAdvInterval 200;
# M-Flag = off (Use SLAAC), O-Flag = off (No DHCPv6 needed)
AdvManagedFlag off;
AdvOtherConfigFlag off;
# Advertise local /64 prefix for SLAAC autoconfiguration
prefix 2001:db8:cafe:1::/64 {
AdvOnLink on;
AdvAutonomous on;
AdvRouterAddr on;
};
# Distribute recursive DNS servers via RDNSS (RFC 8106)
RDNSS 2001:4860:4860::8888 2606:4700:4700::1111 {
AdvRDNSSLifetime 600;
};
};
Enable and start the daemon:
5. Dual-Stack Host Configuration with systemd-networkd
Configure a robust dual-stack Debian server supporting both static IPv4 and automated SLAAC IPv6:
# File: /etc/systemd/network/10-dualstack-eth0.network
[Match]
Name=eth0
[Network]
# Static IPv4 Configuration
Address=192.168.1.50/24
Gateway=192.168.1.1
DNS=192.168.1.1
# IPv6 Configuration: Enable SLAAC & Accept Router Advertisements
IPv6AcceptRA=yes
DHCP=no
# Optional: Assign a static ULA address for internal communications
Address=fd00:dead:beef:1::50/64
[IPv6AcceptRA]
# Accept DNS servers advertised in Router Advertisements
UseDNS=yes
UseAutonomousPrefix=yes
Reload the network configuration:
6. Stateful nftables Firewalling for IPv6: The ICMPv6 Imperative
CRITICAL WARNING: Never Drop All ICMPv6
In legacy IPv4, security guides often recklessly advised DROP icmp. Doing this in IPv6 will completely destroy network connectivity.
Without ICMPv6, Neighbor Discovery (NDP) fails (hosts cannot resolve MACs) and Path MTU Discovery (PMTUD) breaks (packets larger than the path MTU are silently dropped, causing TCP connections to hang indefinitely during TLS handshakes).
Here is a hardened, production-grade /etc/nftables.conf for a dual-stack Debian server:
# File: /etc/nftables.conf
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
# 1. Allow established and related connections
ct state established,related accept
# 2. Drop invalid packets
ct state invalid drop
# 3. Allow all loopback traffic
iif "lo" accept
# 4. ESSENTIAL: Permit essential ICMPv6 types
ip6 nexthdr icmpv6 icmpv6 type {
destination-unreachable, # Type 1: Required for error reporting
packet-too-big, # Type 2: MANDATORY for Path MTU Discovery
time-exceeded, # Type 3: Traceroute and TTL expiration
parameter-problem, # Type 4: Protocol syntax errors
echo-request, # Type 128: Ping diagnostic
nd-router-advert, # Type 134: SLAAC Router Advertisements
nd-neighbor-solicit, # Type 135: NDP MAC resolution
nd-neighbor-advert # Type 136: NDP MAC resolution reply
} accept
# 5. Allow inbound SSH on port 22 (IPv4 & IPv6)
tcp dport 22 accept
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Apply and verify the ruleset:
7. Practical IPv6 CLI Diagnostics
Always use the -6 flag with standard iproute2 commands:
# 1. Inspect all IPv6 addresses (look for GUA 'global' and Link-Local 'fe80')
ip -6 -br addr show
# 2. Inspect the IPv6 routing table (verify default gateway via fe80::...)
ip -6 route show
# 3. Inspect the Neighbor Cache (replaces 'arp -n')
ip -6 neigh show
# 4. Verify end-to-end IPv6 connectivity and Path MTU
ping -6 -c 3 2606:4700:4700::1111
mtr -6 google.com
8. Next Steps
With your foundational understanding of IPv4 subnetting and IPv6 protocol mechanics in place, master the unified Linux administration suite:
-
The Modern
iproute2Suite in Daily Operations
Replace legacy
ifconfig,netstat, androutecommands with Netlink-poweredip addr,ip link,ip route, andss.