Стандартны маршрут IPv6 знік пасля ўключэння перасылкі ў Linux
Калі ўключыць перасылку IPv6, ядро ігнаруе router advertisements на uplink, і вывучаны стандартны маршрут сканчаецца. Выпраўце гэта праз accept_ra.
Я ўсталяваў net.ipv6.conf.all.forwarding=1 на шлюзе Debian, каб ён мог перасылаць трафік VPN-кліентаў, і прыкладна праз паўгадзіны машына ўжо не мела стандартнага маршруту IPv6. Верхні маршрутызатар працаваў, link-local сусед усё яшчэ адказваў, і uplink па-ранейшаму меў свой глабальны адрас. Спынілася тое, што ядро больш не хацела прымаць router advertisements на гэтым інтэрфейсе. Маршрут не знік у момант, калі я ўвёў sysctl; ён знік, калі скончыўся тэрмін жыцця стандартнага маршруту, вывучанага з RA, і нішто яго не абнавіла.
На першы погляд нічога не выглядала зламаным. Перасылка працавала, кліенты праходзілі, пакуль стары маршрут яшчэ быў у кэшы, а збой прыйшоў пазней за змену, якая яго выклікала. Менавіта праз гэтую затрымку вінавацяць верхні бок або правіла філтра, якое ніколі не было задзейнічана.
Прачытайце табліцу маршрутаў, перш чым чапаць любы sysctl
Пачніце з ip -6 route show default і чытайце атрыбуты, а не толькі шлюз. Стандартны маршрут, вывучаны з RA, пазначаны proto ra, нясе перавагу і паказвае адваротны адлік expires. Маршрут, дададзены ўручную, не мае ні таго, ні іншага, і гэтая розніца кажа, які механізм валодае маршрутам.
$ ip -6 route show default
default via fe80::1 dev eth0 proto ra metric 1024 expires 1432sec hoplimit 64 pref mediumЗатым паглядзіце на адрас: ip -6 addr show dev eth0. Глабальны адрас з пераважнымі і сапраўднымі тэрмінамі жыцця ў гадзінах перажыве стандартны маршрут, тэрмін жыцця маршрутызатара якога вымяраецца ў хвілінах. Адрас ёсць, а стандартнага маршруту няма, гэта подпіс праблемы з абвяшчэннямі. Калі няма і адраса, спачатку трэба гнацца за злучэннем, інфармацыяй аб прэфіксе або выяўленнем дублікатаў адрасоў.
Чаму перасылка выключае апрацоўку RA
RA, гэта пакет ICMPv6 тыпу 134, адпраўлены з link-local крыніцы з абмежаваннем скоку 255. Перш чым ядро яго выкарыстае, яно правярае accept_ra інтэрфейса. Значэнне па змаўчанні, гэта 1, і 1 не азначае так. Яно азначае: прымаць толькі пакуль гэты хост не перасылае. Пастаўце forwarding=1, і гэтая ўмова не выконваецца, таму абвяшчэнне адкідваецца яшчэ да таго, як у ім разгледзяць любы прэфікс або стандартны маршрутызатар.
Існуюць тры значэнні, і перасылку перажывае толькі трэцяе:
accept_ra | forwarding=0 | forwarding=1 |
|---|---|---|
| 0 | ignored | ignored |
| 1 (default) | accepted | ignored |
| 2 | accepted | accepted |
Два іншыя сцягі вырашаюць, што ўрэшце ўсталюецца. accept_ra_defrtr кіруе тым, ці стане стандартны маршрутызатар з абвяшчэння маршрутам, а accept_ra_pinfo кіруе тым, ці выкарыстоўваюцца звесткі аб прэфіксе для канфігурацыі адраса. Выключэнне accept_ra_defrtr, звычайны спосаб захаваць адрасы SLAAC на хосце, які перасылае, не вывучаючы стандартны маршрут. Гэта іншы рычаг, чым accept_ra, і па яго бяруць, калі патрэбны адрасы, але не маршрут. Даведнік ядра па IP sysctl пералічвае ўсе тры.
Пацвердзіце гэта трыма камандамі
Спачатку прачытайце жывыя значэнні замест файла, які, на вашу думку, загружаны:
sysctl net.ipv6.conf.eth0.forwarding net.ipv6.conf.all.forwarding \
net.ipv6.conf.eth0.accept_ra net.ipv6.conf.eth0.accept_ra_defrtrПа-другое, дакажыце, што абвяшчэнні ўсё яшчэ прыходзяць. Фільтраванне па байце тыпу ICMPv6 дастатковае і пазбаўляе ад чытання сцяны трафіку выяўлення суседзяў:
tcpdump -ni eth0 'icmp6 and ip6[40] == 134'Калі за некалькі хвілін нічога не з'явіцца, accept_ra не ваша праблема. Верхні бок спыніў абвяшчаць, нешта на шляху фільтруе ICMPv6, або гэты інтэрфейс насамрэч не ў тым сегменце, пра які вы думаеце. Па-трэцяе, запытайце абвяшчэнне самі і прачытайце яго палі:
rdisc6 eth0rdisc6 пастаўляецца ў пакеце ndisc6 на Debian і Ubuntu. У вывадзе паглядзіце на тэрмін жыцця маршрутызатара і перавагу, перш чым нешта іншае змяніць. Абвяшчэнне з тэрмінам жыцця маршрутызатара 0, гэта загад выдаліць стандартны маршрутызатар, і ніякае значэнне accept_ra не робіць з гэтага прыдатны маршрут. Так вы таксама зловіце верхні CPE у рэжыме моста, які раздае прэфіксы, але ніколі не прапануе сябе як маршрутызатар.
Зрабіце uplink адзіным падатлівым інтэрфейсам
Калі верхні бок павінен быць стандартным маршрутызатарам, прымайце там абвяшчэнні нягледзячы на перасылку, і больш нідзе:
# /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Абмежаванне важнае, бо перасылка IPv6 у Linux, гэта адзін глабальны перамыкач, а не адзін на злучэнне. Запішыце 1 у net.ipv6.conf.wg0.forwarding і затым прачытайце net.ipv6.conf.all.forwarding: глабальнае значэнне перакульваецца, і кожны інтэрфейс пачынае перасылаць. Вы не можаце быць маршрутызатарам у тунелі і звычайным хостам у LAN. Абмежаваць можна прыём. Трымайце accept_ra=2 на uplink, а інтэрфейсы тунеля і LAN пакіньце на 1 або 0, каб заблуканае абвяшчэнне, якое прыйдзе праз тунель, не магло ўсталяваць стандартны маршрут, што паказвае ў яго.
Часовы sysctl -w не перажыве наступны запуск, і як systemd-networkd, так і NetworkManager запісваюць гэтыя значэнні са сваёй канфігурацыі. У networkd пастаўце IPv6Forwarding=yes і IPv6AcceptRA=yes у файле .network для uplink; networkd апісвае IPv6Forwarding як глабальнае з той жа прычыны ў ядры. У NetworkManager менавіта ipv6.method=auto на uplink кіруе значэннем accept_ra, таму пасля nmcli connection up прачытайце sysctl зноў, замест таго каб давяраць першай праверцы.
Статычная альтэрнатыва, ip -6 route add default via fe80::1 dev eth0, сапраўды працуе і з'яўляецца разумным адказам, калі верхні маршрутызатар мае стабільны link-local адрас. Будзьце ясныя ў тым, чым ахвяруеце. Статычны стандартны маршрут ніколі не абнаўляецца і ніколі не адклікаецца, таму пасля замены верхняга боку ён працягвае паказваць на мёртвага суседа. Маршрут з RA адмаўляе бяспечна; статычны адмаўляе ціха.
Тэстуйце перасланы пакет, а не ўласны пакет шлюза
Уласныя пінгі шлюза могуць паспяхова прайсці па маршруце, якім не можа скарыстацца ніводны кліент, і могуць прайсці таксама таму, што шлюз з'яўляецца крыніцай. Тэстуйце з падключанага кліента, а затым спытайце шлюз, што ён зрабіў бы для адраса гэтага кліента:
# 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Затым пачакайце адзін тэрмін жыцця маршрутызатара і паглядзіце зноў. Стабільны стан, які вы хочаце, гэта стандартны маршрут з пазнакай proto ra, значэнне expires якога ўвесь час скідваецца, плюс all.forwarding=1. Калі expires толькі адлічвае, абвяшчэнні ўсё яшчэ недзе адкідваюцца, і звычайны вінаваты, гэта кіраўнік сеткі, які перазапісвае accept_ra пасля таго, як sysctl пры загрузцы ўжо выканаўся.
Перш чым закрыць гэта, пацвердзіце чатыры рэчы: стандартны маршрут, гэта proto ra і ён абнаўляецца, accept_ra=2 дзейнічае толькі для uplink, перасылка па-ранейшаму 1 пасля перазапуску і пасля перазапуску кіраўніка, і IPv6-пінг завяршае кліент, а не шлюз. Калі кліент з здаровым маршрутам усё яшчэ не працуе, наступны падазроны, гэта зваротны шлях або верхні філтр, а не абвяшчэнне.