Ich setzte net.ipv6.conf.all.forwarding=1 auf einem Debian-Gateway, damit es VPN-Client-Verkehr weiterleiten konnte, und etwa eine halbe Stunde später hatte die Kiste keine IPv6-Standardroute mehr. Der Upstream-Router war erreichbar, der link-lokale Nachbar antwortete weiterhin, und der Uplink hielt seine globale Adresse. Was aufgehört hatte, war die Bereitschaft des Kernels, auf dieser Schnittstelle weiterhin Router Advertisements anzunehmen. Die Route verschwand nicht, als ich das sysctl setzte; sie verschwand, als die Lebensdauer der RA-gelernten Standardroute ablief und nichts sie erneuerte.

Nichts sah auf den ersten Blick kaputt aus. Die Weiterleitung funktionierte, die Clients kamen weiter durch, solange die alte Route noch im Cache lag, und der Fehler trat später auf als die Änderung, die ihn verursacht hatte. Diese Verzögerung ist der Grund, warum man das dem Upstream oder einer Firewall-Regel zuschreibt, die nie beteiligt war.

Lies die Routentabelle, bevor du irgendein sysctl anfasst

Beginne mit ip -6 route show default und lies die Attribute, nicht nur das Gateway. Eine RA-gelernte Standardroute ist mit proto ra markiert, trägt eine Präferenz und zeigt einen expires-Countdown. Eine Route, die du von Hand hinzugefügt hast, hat beides nicht, und dieser Unterschied sagt dir, welcher Mechanismus die Route besitzt.

$ ip -6 route show default
default via fe80::1 dev eth0 proto ra metric 1024 expires 1432sec hoplimit 64 pref medium

Sieh dir dann die Adresse an: ip -6 addr show dev eth0. Eine globale Adresse mit bevorzugten und gültigen Lebensdauern in Stunden überlebt eine Standardroute, deren Router-Lebensdauer in Minuten gemessen wird. Adresse vorhanden und Standardroute fehlend ist die Signatur eines Advertisement-Problems. Fehlt auch die Adresse, musst du zuerst den Link, die Präfixinformationen oder die Duplicate Address Detection verfolgen.

Warum Weiterleitung die RA-Verarbeitung abschaltet

Ein RA ist ein ICMPv6-Paket vom Typ 134, gesendet von einer link-lokalen Quelle mit Hop Limit 255. Bevor der Kernel es nutzt, konsultiert er das accept_ra der Schnittstelle. Der Standardwert ist 1, und 1 bedeutet nicht ja. Es bedeutet: nur annehmen, solange dieser Host nicht weiterleitet. Setze forwarding=1, und diese Bedingung schlägt fehl, sodass das Advertisement verworfen wird, bevor ein Präfix oder ein Standardrouter darin berücksichtigt wird.

Es gibt drei Werte, und nur der dritte überlebt die Weiterleitung:

accept_raforwarding=0forwarding=1
0ignoredignored
1 (default)acceptedignored
2acceptedaccepted

Zwei weitere Flags entscheiden, was tatsächlich installiert wird. accept_ra_defrtr steuert, ob der Standardrouter im Advertisement zu einer Route wird, und accept_ra_pinfo steuert, ob Präfixinformationen für die Adresskonfiguration verwendet werden. accept_ra_defrtr abzuschalten ist der übliche Weg, SLAAC-Adressen auf einem weiterleitenden Host zu behalten, ohne eine Standardroute zu lernen. Das ist ein anderer Hebel als accept_ra, und man greift danach, wenn man Adressen, aber keine Route will. Die Kernel-IP-sysctl-Referenz listet alle drei auf.

Bestätige es mit drei Befehlen

Lies zuerst die laufenden Werte statt die Datei, von der du glaubst, dass sie geladen ist:

sysctl net.ipv6.conf.eth0.forwarding net.ipv6.conf.all.forwarding \
       net.ipv6.conf.eth0.accept_ra net.ipv6.conf.eth0.accept_ra_defrtr

Zweitens beweise, dass die Advertisements noch ankommen. Auf das ICMPv6-Typbyte zu filtern reicht, und es erspart dir eine Wand aus Neighbor-Discovery-Verkehr:

tcpdump -ni eth0 'icmp6 and ip6[40] == 134'

Erscheint über mehrere Minuten nichts, ist accept_ra nicht dein Problem. Der Upstream hat das Advertisieren eingestellt, etwas auf dem Pfad filtert ICMPv6, oder diese Schnittstelle liegt nicht wirklich auf dem Segment, das du denkst. Drittens fordere selbst ein Advertisement an und lies seine Felder:

rdisc6 eth0

rdisc6 steckt im Paket ndisc6 auf Debian und Ubuntu. Sieh in der Ausgabe auf die Router-Lebensdauer und die Präferenz, bevor du sonst etwas änderst. Ein Advertisement mit Router-Lebensdauer 0 ist die Anweisung, den Standardrouter zu entfernen, und kein accept_ra-Wert macht daraus eine nutzbare Route. So erwischst du auch ein Upstream-CPE im Bridge-Modus, das Präfixe verteilt, sich aber nie selbst als Router anbietet.

Mach den Uplink zur einzigen erlaubenden Schnittstelle

Wenn der Upstream der Standardrouter sein soll, nimm Advertisements dort trotz Weiterleitung an, und sonst nirgends:

# /etc/sysctl.d/60-ipv6-router.conf
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.eth0.accept_ra = 2
net.ipv6.conf.eth0.accept_ra_defrtr = 1

Die Eingrenzung ist wichtig, weil IPv6-Weiterleitung in Linux ein globaler Schalter ist, nicht einer pro Link. Schreibe 1 nach net.ipv6.conf.wg0.forwarding und lies dann net.ipv6.conf.all.forwarding: der globale Wert kippt, und jede Schnittstelle beginnt weiterzuleiten. Du kannst nicht Router am Tunnel und normaler Host im LAN sein. Eingrenzen lässt sich nur die Annahme. Halte accept_ra=2 am Uplink und lass Tunnel- und LAN-Schnittstellen auf 1 oder 0, damit ein verirrtes Advertisement über den Tunnel keine Standardroute installieren kann, die in ihn hineinzeigt.

Ein temporäres sysctl -w überlebt den nächsten Neustart nicht, und sowohl systemd-networkd als auch NetworkManager schreiben diese Werte aus ihrer eigenen Konfiguration. Setze in networkd IPv6Forwarding=yes und IPv6AcceptRA=yes in der .network-Datei des Uplinks; networkd dokumentiert IPv6Forwarding aus demselben Kernel-Grund als global. Bei NetworkManager ist ipv6.method=auto am Uplink das, was den accept_ra-Wert treibt, also lies das sysctl nach nmcli connection up erneut, statt der ersten Prüfung zu vertrauen.

Die statische Alternative, ip -6 route add default via fe80::1 dev eth0, funktioniert, und sie ist eine vernünftige Antwort, wenn der Upstream-Router eine stabile link-lokale Adresse hat. Sei dir klar darüber, was du aufgibst. Eine statische Standardroute wird nie erneuert und nie zurückgezogen, sie zeigt also nach dem Austausch des Upstreams weiter auf einen toten Nachbarn. Die RA-Route scheitert sicher; die statische scheitert still.

Teste ein weitergeleitetes Paket, nicht das des Gateways

Die eigenen Pings des Gateways können auf einer Route gelingen, die kein Client nutzen kann, und sie können auch gelingen, weil das Gateway die Quelle ist. Teste von einem verbundenen Client aus und frage dann das Gateway, was es für die Adresse dieses Clients tun würde:

# on the VPN client
ping -6 -c 3 2001:4860:4860::8888

# on the gateway, using a client address
ip -6 route get 2001:4860:4860::8888 from fd42:20::2

Warte dann eine Router-Lebensdauer und sieh erneut nach. Der gewünschte stabile Zustand ist eine Standardroute mit proto ra, deren expires-Wert sich immer wieder zurücksetzt, plus all.forwarding=1. Zählt expires nur herunter, werden Advertisements noch irgendwo verworfen, und der übliche Übeltäter ist ein Netzwerkmanager, der accept_ra überschreibt, nachdem das sysctl beim Booten schon gelaufen ist.

Bevor du das abschließt, bestätige vier Dinge: die Standardroute ist proto ra und wird erneuert, accept_ra=2 gilt nur für den Uplink, die Weiterleitung ist nach einem Neustart und nach einem Manager-Neustart noch 1, und ein Client statt des Gateways schließt einen IPv6-Ping ab. Scheitert der Client bei gesunder Route weiterhin, ist der nächste Verdächtige der Rückweg oder eine Upstream-Firewall, nicht das Advertisement.

Ähnliche Artikel