Výchozí trasa IPv6 zmizela po zapnutí forwardování v Linuxu
Když zapnete IPv6 forwardování, jádro ignoruje router advertisements na uplinku a naučená výchozí trasa vyprší. Opravte to pomocí accept_ra.
Nastavil jsem net.ipv6.conf.all.forwarding=1 na Debian bráně, aby mohla předávat provoz VPN klientů, a asi za půl hodiny neměl stroj žádnou výchozí trasu IPv6. Upstream router byl v pořádku, link-local soused stále odpovídal a uplink si držel svou globální adresu. Co přestalo, byla ochota jádra nadále přijímat router advertisements na tom rozhraní. Trasa nezmizela ve chvíli, kdy jsem sysctl zadal; zmizela, když vypršela platnost výchozí trasy naučené z RA a nic ji neobnovilo.
Nic nevypadalo na první pohled rozbité. Forwardování fungovalo, klienti procházeli, dokud byla stará trasa v cache, a porucha přišla později než změna, která ji způsobila. Právě kvůli tomu zpoždění se to svádí na upstream nebo na pravidlo firewallu, které s tím nikdy nesouviselo.
Přečtěte si routovací tabulku, než se dotknete jakéhokoli sysctl
Začněte příkazem ip -6 route show default a čtěte atributy, ne jen bránu. Výchozí trasa naučená z RA je označená proto ra, nese preferenci a ukazuje odpočet expires. Trasa přidaná ručně nemá ani jedno, a ten rozdíl vám řekne, který mechanismus trasu vlastní.
$ ip -6 route show default
default via fe80::1 dev eth0 proto ra metric 1024 expires 1432sec hoplimit 64 pref mediumPak se podívejte na adresu: ip -6 addr show dev eth0. Globální adresa s preferovanou a platnou životností v hodinách přežije výchozí trasu, jejíž životnost routeru se měří v minutách. Adresa existuje a výchozí trasa chybí, to je podpis problému s ohlasy. Chybí-li i adresa, musíte nejdřív řešit link, informace o prefixu nebo detekci duplicitních adres.
Proč forwardování vypíná zpracování RA
RA je paket ICMPv6 typu 134, odeslaný z link-local zdroje s limitem skoku 255. Než ho jádro použije, prohlédne accept_ra rozhraní. Výchozí hodnota je 1 a 1 neznamená ano. Znamená: přijímej jen tehdy, dokud tento hostitel nepředává. Nastavte forwarding=1 a tato podmínka selže, takže se ohlás zahodí dřív, než se v něm zváží jakýkoli prefix nebo výchozí router.
Existují tři hodnoty a forwardování přežije jen ta třetí:
accept_ra | forwarding=0 | forwarding=1 |
|---|---|---|
| 0 | ignored | ignored |
| 1 (default) | accepted | ignored |
| 2 | accepted | accepted |
O dvou dalších příznacích rozhoduje, co se skutečně nainstaluje. accept_ra_defrtr řídí, zda se výchozí router z ohlásu stane trasou, a accept_ra_pinfo řídí, zda se informace o prefixu použijí pro konfiguraci adresy. Vypnutí accept_ra_defrtr je obvyklý způsob, jak na předávajícím hostiteli udržet adresy SLAAC, aniž byste se naučili výchozí trasu. Je to jiná páka než accept_ra a sáhnete po ní, když chcete adresy, ale ne trasu. Reference jádra k IP sysctl uvádí všechny tři.
Ověřte to třemi příkazy
Nejprve si přečtěte živé hodnoty místo souboru, o kterém si myslíte, že je načtený:
sysctl net.ipv6.conf.eth0.forwarding net.ipv6.conf.all.forwarding \
net.ipv6.conf.eth0.accept_ra net.ipv6.conf.eth0.accept_ra_defrtrZadruhé dokažte, že ohlasy stále přicházejí. Filtrování podle bajtu typu ICMPv6 stačí a ušetří vám čtení zdi provozu objevování sousedů:
tcpdump -ni eth0 'icmp6 and ip6[40] == 134'Pokud se během několika minut nic neobjeví, accept_ra není váš problém. Upstream přestal ohlašovat, něco na cestě filtruje ICMPv6, nebo to rozhraní ve skutečnosti není na segmentu, který si myslíte. Zatřetí si vyžádejte ohlás sami a přečtěte jeho pole:
rdisc6 eth0rdisc6 je v balíčku ndisc6 na Debianu a Ubuntu. Ve výstupu se podívejte na životnost routeru a preferenci, než cokoli dalšího změníte. Ohlás s životností routeru 0 je pokyn k odstranění výchozího routeru a žádná hodnota accept_ra z toho neudělá použitelnou trasu. Také tak zachytíte upstream CPE v režimu mostu, které rozdává prefixy, ale nikdy se nenabídne jako router.
Udělejte z uplinku jediné povolující rozhraní
Pokud má být upstream výchozím routerem, přijímejte tam ohlasy i přes forwardování, a nikde jinde:
# /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 = 1Omezení je důležité, protože IPv6 forwardování je v Linuxu jeden globální přepínač, ne jeden na link. Zapište 1 do net.ipv6.conf.wg0.forwarding a pak přečtěte net.ipv6.conf.all.forwarding: globální hodnota se překlopí a každé rozhraní začne předávat. Nemůžete být router na tunelu a obyčejný hostitel na LAN. Omezit můžete přijímání. Držte accept_ra=2 na uplinku a rozhraní tunelu a LAN nechte na 1 nebo 0, aby zbloudilý ohlás, který dorazí tunelem, nemohl nainstalovat výchozí trasu ukazující do něj.
Dočasné sysctl -w nepřežije další restart a jak systemd-networkd, tak NetworkManager zapisují tyto hodnoty ze své vlastní konfigurace. V networkd nastavte IPv6Forwarding=yes a IPv6AcceptRA=yes v souboru .network uplinku; networkd dokumentuje IPv6Forwarding jako globální ze stejného důvodu v jádru. U NetworkManageru je ipv6.method=auto na uplinku to, co řídí hodnotu accept_ra, takže po nmcli connection up čtěte sysctl znovu, místo abyste věřili první kontrole.
Statická alternativa, ip -6 route add default via fe80::1 dev eth0, opravdu funguje a je rozumnou odpovědí, když má upstream router stabilní link-local adresu. Buďte si jasní v tom, co obětujete. Statická výchozí trasa se nikdy neobnovuje a nikdy neodvolává, takže po výměně upstreamu dál ukazuje na mrtvého souseda. Trasa z RA selhává bezpečně; statická selhává tiše.
Testujte předávaný paket, ne ten od brány
Vlastní pingy brány mohou uspět na trase, kterou žádný klient nemůže použít, a mohou uspět i proto, že brána je zdrojem. Testujte z připojeného klienta, a pak se brány zeptejte, co by udělala pro adresu toho 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::2Pak počkejte jednu životnost routeru a podívejte se znovu. Stabilní stav, který chcete, je výchozí trasa označená proto ra, jejíž hodnota expires se stále obnovuje, plus all.forwarding=1. Pokud expires jen odpočítává, ohlasy se někde stále zahazují a obvyklým viníkem je správce sítě, který přepíše accept_ra poté, co sysctl při startu už proběhl.
Než to uzavřete, ověřte čtyři věci: výchozí trasa je proto ra a obnovuje se, accept_ra=2 platí jen pro uplink, forwardování je po restartu a po restartu správce stále 1 a ping IPv6 dokončí klient, ne brána. Pokud klient se zdravou trasou stále selhává, dalším podezřelým je zpáteční cesta nebo upstream firewall, ne ohlás.