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 medium

Potem 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_raforwarding=0forwarding=1
0ignoredignored
1 (default)acceptedignored
2acceptedaccepted

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_defrtr

Po 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 eth0

rdisc6 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 = 1

Ograniczenie 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::2

Potem 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.

Powiązane artykuły