IPv6 durch einen OpenVPN-Tunnel: eine Anleitung für den Heimrouter
IPv6 stirbt oder leakt, wenn der Tunnel ein Präfix ausgibt, das der Router nicht weiterleiten kann. Arbeite Client, Pool, Forwarding, Proxy-NDP und Rückweg der Reihe nach ab.
Der Laptop hat eine IPv6-Adresse, der Tunnel läuft über IPv4, und trotzdem scheitert jeder IPv6-Test. Schlimmer noch: Der Test gelingt, und der Verkehr hat den ISP-Pfad genommen, ohne je in den Tunnel zu gelangen. Beide Ergebnisse führen auf dieselbe fehlende Entscheidung zurück: Niemand hat dem Router ein Präfix gegeben, das er zu den Clients hin routen kann. Wer den Weg vom Client nach außen abgeht, findet das fehlende Teil.
Zuerst beim Client ansetzen
Sieh dir den Client an, bevor du den Server anfasst. ip -6 addr sollte eine Tunneladresse aus dem Pool zeigen, und ip -6 route sollte das gepushte Präfix zeigen, das auf das Tunnelgerät verweist. Wenn die Adresse da ist, aber keine Route, fehlt der Push oder der Client hat ihn ignoriert. Wenn beides fehlt, hat der Server überhaupt nichts zugewiesen.
Dann prüfe, was der Client über die Außenwelt glaubt. Eine Default-Route über den Tunnel beansprucht den gesamten IPv6-Verkehr, während eine Route für 2000::/3 nur globales Unicast beansprucht. Beides kann richtig sein, und beide beantworten unterschiedliche Fragen zum Leaken.
Ein Client ganz ohne IPv6-Default scheitert an jedem öffentlichen Test, obwohl der Tunnel selbst völlig gesund ist. Das ist eine Lücke in der Policy und kein kaputter Tunnel.
Den Pool prüfen, den der Server wirklich routen kann
Ein Server kann nur aus einem Präfix zuweisen, das er tatsächlich kontrolliert. Wenn der ISP ein /56 delegiert, reserviere ein /64 für den Tunnel und lass den Rest für das LAN. Wo der ISP am WAN nur ein einziges /64 übergibt und nichts weiter routet, lass das LAN-Präfix in Ruhe und gib dem Tunnel einen eindeutigen lokalen Bereich, wobei du akzeptierst, dass die Clients keinen globalen Ausgang haben.
Pool und Push gehören zusammen. server-ipv6 2001:db8:80:10::/64 weist Adressen zu, und push "route-ipv6 2000::/3" sagt den Clients, was sie in den Tunnel schicken sollen. Das Pushen von 2000::/3 deckt globales Unicast ab und lässt Link-Local- und Multicast-Bereiche aus dem Tunnel heraus.
Halte das gewählte Präfix im Inbetriebnahmeprotokoll fest. Wer als Nächstes die ISP-Übergabe ändert, muss wissen, welches /64 der Tunnel bereits belegt.
Forwarding für die zweite Familie einschalten
IPv4-Forwarding bedeutet nicht automatisch IPv6-Forwarding. Setze net.ipv6.conf.all.forwarding=1 und spiegle alles, was die IPv4-FORWARD-Policy bereits erlaubt. Auf einem Router, dessen FORWARD-Kette standardmäßig verwirft, sieht ein fehlendes Regelwerk genauso aus wie ein toter Tunnel.
Der Handshake gelingt, der Client bekommt eine Adresse, und zurück kommt nichts. Füge Regeln für beide Richtungen und für den WAN-Abschnitt hinzu, denn ein Tunnel, der das LAN erreicht, aber nicht das Internet, scheitert am dritten Test. Prüfe nach einem Fehlversuch die Zähler der Ketten, denn eine Regel, die nie gegriffen hat, ist ein anderes Problem als eine, die gegriffen und verworfen hat.
ip6tables -A FORWARD -i br0 -o tun0 -j ACCEPT
ip6tables -A FORWARD -i tun0 -o br0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ip6tables -A FORWARD -i tun0 -o wan0 -j ACCEPT
Ein Nebeneffekt erwischt die Leute, die am Ende den Tunnel beschuldigen. Schaltet man Forwarding ein, überspringt der Kernel die Adresskonfiguration per Router Advertisement, sofern man ihm nichts anderes sagt, und eine so gelernte Default-Route verschwindet mit ihr. Entweder setzt du eine ausdrückliche Default-Route auf dem WAN-Interface, oder du stellst accept_ra dort bewusst auf 2. Prüfe nach beiden Änderungen, ob der Router noch einen nutzbaren IPv6-Pfad nach außen hat, bevor du die Clients erneut testest.
Nachbarschaftserkennung beantworten, wenn das Upstream nicht routet
Upstream-Geräte behandeln das delegierte /64 manchmal als zu ihrem eigenen Link gehörend und weigern sich, ein Unterpräfix an die VPN-Box zu routen. Wenn das passiert, muss etwas die Neighbour Solicitations für jede Clientadresse einzeln beantworten.
OpenVPN reicht die zugewiesene Adresse an einen client-connect-Hook weiter, sodass Einträge dem echten Pool folgen können statt einer von Hand gepflegten Liste. Der Hook fügt ip -6 neigh add proxy $ifconfig_pool_remote_ip6 dev eth0 hinzu, und ein passender client-disconnect-Hook entfernt ihn wieder. Ohne das Entfernen veraltet die Proxy-Tabelle, und ein späterer Client kann einen Eintrag für eine Adresse erben, die er nie bekommen hat. Prüfe den Zustand mit ip -6 neigh show proxy.
Betrachte das Proxying als Notlösung. Eine statische Route für das Tunnel-/64, die auf den Router zeigt, übersteht Client-Wechsel und braucht überhaupt keinen privilegierten Shell-Hook.
Den Weg nach außen verfolgen, Hop für Hop
Teste nach außen in drei Schritten: zuerst die Tunneladresse des Routers, dann einen LAN-Host und drittens ein öffentliches Ziel per traceroute6. Den Pool beweist der erste Schritt, Forwarding und die LAN-Firewall der zweite, und den Rückweg über das Upstream der dritte. Jeder Fehlschlag verengt die Suche auf ein Gerät, statt das ganze Design neu aufzumachen.
Achte auf die Tunnel-MTU, denn die IPv6-Router auf dem Weg fragmentieren nicht für dich. Eine zu große MTU zeigt sich als Packet-Too-Big-Fehler und stockendes TLS statt als sauberer Fehlschlag. Setze sie ausdrücklich und teste mit einer Nutzlast nahe dem Grenzwert.