IPv6 routeren tussen twee locaties over een bestaand VPN
Een WAN met alleen IPv4 kan nog steeds innerlijk IPv6 vervoeren. Volg selectors, kernelroutes, forwarding en het retourprefix dat antwoorden stil laat vallen.
Wanneer je een IPv6-prefix aan een site-naar-site-tunnel toevoegt, reist het packet niet zoals het diagram suggereert. De lokale gateway neemt het hele IPv6-packet, versleutelt het en plaatst er een buitenste IP-header voor, waarvan de adressenfamilie door de endpointadressen wordt bepaald, niet door wat er binnenin zit. De verre gateway verwijdert die buitenste header en stuurt het oorspronkelijke packet door naar zijn LAN, waar het weer een gewoon IPv6-packet is. Buitenste tunnel en binnenste verkeer zijn twee afzonderlijke gesprekken die een sleutel, een endpointpaar en verder niets delen.
Twee headers, twee adressenfamilies
In IPsec-tunnelmodus wordt het binnenste IPv6-packet de payload achter een ESP-header. De buitenste header die dat ESP-packet draagt, kan IPv4 of IPv6 zijn, en volgt local_addrs en remote_addrs. WireGuard doet hetzelfde met minder ceremonie: het binnenste packet is de payload van een UDP-datagram naar het endpoint van de peer. Beide laten de binnenste header ongemoeid, waardoor de andere zijde hem na decapsulatie kan routeren.
Het pad tussen de locaties ziet alleen UDP 4500 wanneer IPsec NAT-traversal gebruikt, of UDP 51820 voor een standaard WireGuard-listener. Elke router onderweg kan alleen IPv4 spreken en het IPv6-verkeer gaat er toch doorheen, omdat het op dat pad nooit als IPv6-packet verschijnt. Dat geeft een schone eerste splitsing: tcpdump -ni eth0 udp port 51820 toont het versleutelde pad, tcpdump -ni wg0 ip6 het binnenste verkeer. Een drukke buitenste opname met een stille binnenste betekent dat de kernel geen IPv6 in de tunnel legt; dat is routing of beleid, niet linkstatus.
De gateway verlaagt ook de binnenste Hop Limit bij het doorsturen, dus de endpoints gelden als routers op het IPv6-pad. Buitenste hopcount en binnenste Hop Limit bewegen onafhankelijk, en een packet dat bij de verre gateway sterft, stierf in het doorsturen, niet in de versleuteling.
Selectors en AllowedIPs zijn de toegangslijst
IKEv2 onderhandelt welke binnenste prefixes een child-SA mag dragen. Op strongSwan 5.9 en later ziet het uitschrijven ervan in swanctl.conf er zo uit:
children {
net6 {
local_ts = 2001:db8:aa::/48
remote_ts = 2001:db8:bb::/48
mode = tunnel
esp_proposals = aes256gcm16-prfsha384-ecp384
start_action = trap
}
}
Laat local_ts en remote_ts weg en strongSwan leidt ze af uit de subnetten van de interface die het kiest. Op een dual-stackhost levert die snelweg vaak een paar met alleen IPv4 op: de SA komt op en IPv6 wordt geweigerd voordat het de ESP-code bereikt. Beide prefixes uitschrijven maakt de SA geschikt om ze te dragen, en start_action = trap brengt hem op bij het eerste passende packet.
WireGuard heeft één lijst met twee taken. In het peer-blok is AllowedIPs = 2001:db8:bb::/48, fd00:bb::/48 zowel de route die bij verzenden wordt geïnstalleerd als het filter dat bij ontvangen wordt toegepast: een ontsleuteld packet waarvan de binnenste bron buiten de lijst van die peer valt, wordt stil weggeworpen. wg-quick voegt per vermelding een route toe, dus het peer-blok hieronder heeft geen aparte ip -6 route-opdracht nodig.
[Interface]
Address = 2001:db8:aa:ff::1/64, fd00:aa:ff::1/64
ListenPort = 51820
[Peer]
PublicKey = <site-b-public-key>
Endpoint = 203.0.113.20:51820
AllowedIPs = 2001:db8:bb::/48, fd00:bb::/48
Beide lijsten moeten gespiegeld zijn: locatie B accepteert het prefix van locatie A als extern selectiecriterium en routeert het terug, en de tunnel werkt alleen wanneer de twee richtingen overeenkomen. Een asymmetrische lijst geeft het symptoom dat de meeste tijd kost — een gezonde handshake, tellers die op één zijde lopen, en een ping van A naar B die slaagt terwijl niets van B de A bereikt.
Doorsturen, routes en het retourprefix
Linux stuurt IPv6 pas door wanneer je dat zegt, en de instelling geldt per namespace, niet per interface:
sysctl -w net.ipv6.conf.all.forwarding=1
ip -6 route add 2001:db8:bb::/48 dev wg0
ip -6 route get 2001:db8:bb::10 from 2001:db8:aa::10
De tweede regel is degene die mensen bij op route gebaseerde ontwerpen vergeten. Beleidmatig IPsec installeert een XFRM-beleid dat op de prefixes past, maar een op routes gebaseerde opzet met vti6 of WireGuard heeft een echte IPv6-route nodig die naar dat apparaat wijst. Bewaar de sysctl onder /etc/sysctl.d/; een herstart zet het doorsturen anders stil terug op uit.
Doorsturen heeft een kanttekening die je moet kennen: de kernel negeert dan router advertisements tenzij net.ipv6.conf.<wan>.accept_ra 2 is, dus een gateway waarvan het WAN-adres via SLAAC binnenkomt, kan zijn standaardroute verliezen op het moment dat je doorsturen aanzet. Zet accept_ra = 2 op die interface in hetzelfde bestand en de route overleeft. De core van locatie B moet 2001:db8:aa::/48 ook van de tunnelgateway leren, via een statische route of een routingprotocol over de tunnel, anders sterft de reactie in het eigen netwerk van B.
Een vierstappencontrole die de breuk lokaliseert
Werk in deze volgorde en stop bij de eerste stap die faalt, omdat elke latere stap van de eerdere afhangt.
- Selectors:
swanctl --list-sasmoet het IPv6-prefixpaar op de child-SA tonen, ofwg show wg0 allowed-ipshet externe prefix met een recentelatest-handshakes. - Kernelroute:
ip -6 route get 2001:db8:bb::10moet antwoorden met het tunnelapparaat, niet met de WAN-interface. - Binnenste opname:
tcpdump -ni wg0 ip6terwijl je tussen echte LAN-hosts pingt. Packets die weggaan maar niet terugkomen wijzen op de route of firewall van B; helemaal geen packets wijzen terug op stap 1 of 2. - Bestemming: op de B-host bevestigt
ss -6 -ltndat de dienst op IPv6 luistert, en de lokale firewaltellers tonen of het packet is geaccepteerd of weggeworpen.
MTU hoort in dezelfde ronde. IPv6-routers fragmenteren niet, dus een te groot packet wordt weggeworpen en Packet Too Big komt bij de afzender terug. Als handshakes en kleine pings werken maar een bestandsoverdracht vastloopt, verklein dan de payload tot het doorkomt: ping -6 -s 1400 -c 3 2001:db8:bb::10. WireGuard-interfaces hebben standaard een MTU van 1420 bytes en IPsec over IPv4 trekt er meer af, dus de binnenste MTU instellen is beter dan hopen op pad-MTU-ontdekking door een firewall die ICMPv6 laat vallen.
Faalmodi die op firewallproblemen lijken
De meest voorkomende is helemaal geen firewall: de dienst bindt aan 0.0.0.0 in plaats van ::, het AAAA-record bestaat, en de client krijgt een snelle weigering over IPv6 die een dual-stackbrowser verbergt door terug te vallen op IPv4. Als alleen sommige toepassingen falen, controleer dan de luisterende familie voordat je een regelset aanraakt.
Ten tweede is dat ICMPv6-filtering. Neighbor Discovery en Packet Too Big horen bij normaal bedrijf, niet bij diagnostiek, en een beleid dat al het ICMPv6 laat vallen levert een tunnel op die verbindt, authenticeert en dan stokt bij alles groter dan een klein packet. Laat de types toe waarvan het pad afhangt en laat tellers aan zodat een drop zichtbaar is.
Ten derde een prefix dat aan de tunnel wordt toegevoegd maar nooit in het adresplan van de locatie die er eigenaar van is, zodat geen router het aankondigt en geen host eruit kan antwoorden. Begin met één prefix en één hostpaar, bewijs beide richtingen met de vier stappen en voeg daarna de rest toe; een kapot prefix blijft één regel in een configuratie in plaats van een herontwerp. De ene officiële referentie die het waard is open te houden is RFC 8200, die de header definieert die de tunnel draagt.