Domyślna trasa IPv6 zniknęła po włączeniu przekazywania w Linuksie
Włączenie przekazywania IPv6 sprawia, że jądro ignoruje router advertisements na uplinku, a nauczona trasa domyślna wygasa. Napraw to przez accept_ra.
Ustawiłem net.ipv6.conf.all.forwarding=1 na bramie Debiana, żeby mogła przekazywać ruch klientów VPN, i po około pół godzinie maszyna nie miała już żadnej domyślnej trasy IPv6. Router nadrzędny działał, sąsiad link-local nadal odpowiadał, a uplink wciąż miał swój adres globalny. To, co się zatrzymało, to gotowość jądra do dalszego przyjmowania router advertisements na tym interfejsie. Trasa nie zniknęła w chwili wpisania sysctl; zniknęła, gdy wygasł czas życia trasy domyślnej nauczonej z RA i nic jej nie odświeżyło.
Na pierwszy rzut oka nic nie wyglądało na zepsute. Przekazywanie działało, klienci przechodzili, dopóki stara trasa była w cache, a awaria przyszła później niż zmiana, która ją spowodowała. To opóźnienie jest powodem, dla którego zwala się to na uplink albo na regułę firewalla, która nigdy nie była w to zamieszana.
Przeczytaj tablicę tras, zanim dotkniesz jakiegokolwiek sysctl
Zacznij od ip -6 route show default i czytaj atrybuty, nie tylko bramę. Trasa domyślna nauczona z RA jest oznaczona proto ra, niesie preferencję i pokazuje odliczanie expires. Trasa dodana ręcznie nie ma ani jednego, ani drugiego, a ta różnica mówi, który mechanizm jest właścicielem trasy.
$ ip -6 route show default
default via fe80::1 dev eth0 proto ra metric 1024 expires 1432sec hoplimit 64 pref mediumPotem spójrz na adres: ip -6 addr show dev eth0. Adres globalny z preferowanym i ważnym czasem życia mierzonym w godzinach przeżyje trasę domyślną, której czas życia routera mierzy się w minutach. Adres jest, a trasy domyślnej brak, to sygnatura problemu z ogłoszeniami. Gdy brakuje też adresu, najpierw trzeba ścigać łącze, informacje o prefiksie albo wykrywanie zduplikowanych adresów.
Dlaczego przekazywanie wyłącza przetwarzanie RA
RA to pakiet ICMPv6 typu 134, wysłany ze źródła link-local z limitem skoku 255. Zanim jądro go użyje, sprawdza accept_ra interfejsu. Wartość domyślna to 1, a 1 nie znaczy tak. Znaczy: przyjmuj tylko wtedy, gdy ten host nie przekazuje. Ustaw forwarding=1 i ten warunek przestaje być spełniony, więc ogłoszenie jest odrzucane, zanim rozważy się w nim jakikolwiek prefiks czy router domyślny.
Istnieją trzy wartości i tylko trzecia przeżywa przekazywanie:
accept_ra | forwarding=0 | forwarding=1 |
|---|---|---|
| 0 | ignored | ignored |
| 1 (default) | accepted | ignored |
| 2 | accepted | accepted |
Dwa inne znaczniki decydują, co faktycznie zostanie zainstalowane. accept_ra_defrtr steruje tym, czy router domyślny z ogłoszenia stanie się trasą, a accept_ra_pinfo tym, czy informacje o prefiksie posłużą do konfiguracji adresu. Wyłączenie accept_ra_defrtr to zwykły sposób utrzymania adresów SLAAC na przekazującym hoście bez uczenia się trasy domyślnej. To inna dźwignia niż accept_ra i sięga się po nią, gdy chce się adresów, ale nie trasy. Dokumentacja jądra dotycząca IP sysctl wymienia wszystkie trzy.
Potwierdź to trzema poleceniami
Najpierw przeczytaj wartości na żywo, a nie plik, który uważasz za wczytany:
sysctl net.ipv6.conf.eth0.forwarding net.ipv6.conf.all.forwarding \
net.ipv6.conf.eth0.accept_ra net.ipv6.conf.eth0.accept_ra_defrtrPo drugie udowodnij, że ogłoszenia nadal przychodzą. Filtrowanie po bajcie typu ICMPv6 wystarczy i oszczędza czytanie ściany ruchu odkrywania sąsiadów:
tcpdump -ni eth0 'icmp6 and ip6[40] == 134'Jeśli przez kilka minut nic się nie pojawi, accept_ra nie jest twoim problemem. Strona nadrzędna przestała ogłaszać, coś na drodze filtruje ICMPv6 albo ten interfejs naprawdę nie leży w segmencie, o którym myślisz. Po trzecie sam poproś o ogłoszenie i przeczytaj jego pola:
rdisc6 eth0rdisc6 jest w pakiecie ndisc6 na Debianie i Ubuntu. W wyniku popatrz na czas życia routera i preferencję, zanim cokolwiek innego zmienisz. Ogłoszenie z czasem życia routera 0 to polecenie usunięcia routera domyślnego i żadna wartość accept_ra nie zamieni tego w użyteczną trasę. Tak też wyłapiesz nadrzędne CPE w trybie mostu, które rozdaje prefiksy, ale nigdy nie oferuje się jako router.
Uczyń uplink jedynym pobłażliwym interfejsem
Jeśli strona nadrzędna ma być routerem domyślnym, przyjmuj tam ogłoszenia mimo przekazywania i nigdzie indziej:
# /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 = 1Ograniczenie ma znaczenie, bo przekazywanie IPv6 to w Linuksie jeden globalny przełącznik, a nie jeden na łącze. Wpisz 1 do net.ipv6.conf.wg0.forwarding, a potem przeczytaj net.ipv6.conf.all.forwarding: wartość globalna się przełącza i każdy interfejs zaczyna przekazywać. Nie możesz być routerem na tunelu i zwykłym hostem w sieci LAN. Ograniczyć można przyjmowanie. Trzymaj accept_ra=2 na uplinku, a interfejsy tunelu i LAN zostaw na 1 albo 0, żeby zabłąkane ogłoszenie przychodzące tunelem nie mogło zainstalować trasy domyślnej wskazującej do niego.
Tymczasowe sysctl -w nie przetrwa następnego rozruchu, a zarówno systemd-networkd, jak i NetworkManager zapisują te wartości ze swojej konfiguracji. W networkd ustaw IPv6Forwarding=yes i IPv6AcceptRA=yes w pliku .network uplinku; networkd opisuje IPv6Forwarding jako globalne z tego samego powodu w jądrze. W NetworkManagerze to ipv6.method=auto na uplinku steruje wartością accept_ra, więc po nmcli connection up przeczytaj sysctl ponownie, zamiast ufać pierwszemu sprawdzeniu.
Statyczna alternatywa, ip -6 route add default via fe80::1 dev eth0, naprawdę działa i jest rozsądną odpowiedzią, gdy router nadrzędny ma stabilny adres link-local. Bądź świadomy, z czego rezygnujesz. Statyczna trasa domyślna nigdy się nie odświeża i nigdy nie jest wycofywana, więc dalej wskazuje martwego sąsiada po wymianie urządzenia nadrzędnego. Trasa z RA zawodzi bezpiecznie; statyczna zawodzi cicho.
Testuj pakiet przekazywany, a nie ten z bramy
Własne pingi bramy mogą się udać na trasie, której żaden klient nie może użyć, i mogą się udać także dlatego, że brama jest źródłem. Testuj z podłączonego klienta, a potem zapytaj bramę, co zrobiłaby dla adresu tego klienta:
# 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::2Potem odczekaj jeden czas życia routera i spójrz ponownie. Stabilny stan, którego chcesz, to trasa domyślna oznaczona proto ra, której wartość expires stale się odświeża, plus all.forwarding=1. Jeśli expires tylko odlicza, ogłoszenia są nadal gdzieś odrzucane, a zwykłym winowajcą jest menedżer sieci nadpisujący accept_ra po tym, jak sysctl przy starcie już się wykonał.
Zanim to zamkniesz, potwierdź cztery rzeczy: trasa domyślna jest proto ra i się odświeża, accept_ra=2 dotyczy tylko uplinku, przekazywanie nadal wynosi 1 po restarcie i po restarcie menedżera, oraz to klient, a nie brama, kończy ping IPv6. Jeśli klient nadal zawodzi przy zdrowej trasie, następnym podejrzanym jest droga powrotna albo firewall nadrzędny, nie ogłoszenie.