VPN на Android працуе з IPv6, але браўзер усё яшчэ выбірае IPv4
Прасочыце чатыры этапы, на якіх знікае прыватны адрас IPv6: рэзалвер, дэкларацыя VpnService, праверка кандыдатаў у браўзеры і дастаўка маршруту.
VPN уключаны, прыватны вэб-інтэрфейс адказвае праз IPv6 з ноўтбука, а тэлефон Android усё яшчэ адкрывае тую ж старонку праз IPv4 або зусім адмаўляецца яе загружаць. Запіс AAAA існуе. Тунель паведамляе адрас IPv6. У кліенце нішто не выглядае няправільным. Вынік вызначаюць чатыры асобныя рашэнні: які рэзалвер адказаў, што VpnService абвясціў Android, якую сям'ю адрасоў браўзер быў гатовы паспрабаваць і ці можа пакет здзейсніць паездку туды і назад. Праходзьце іх менавіта ў гэтым парадку, замест таго каб дадаваць маршрут па змаўчанні і спадзявацца, што сімптом пераедзе.
Крок 1: дакажыце, які рэзалвер адказаў на запыт AAAA
У Android няма аднаго шляху DNS. VPN можа праштурхнуць DNS-сервер для сваёй сеткі, сістэма можа выкарыстоўваць Private DNS для тых імёнаў хостаў, якія яна лічыць прыдатнымі, а Chrome можа запускаць уласны зашыфраваны рэзалвер з chrome://settings/security. На тэлефоне, дзе тунель праштурхвае 10.61.0.1, але Private DNS паказвае на публічнага пастаўшчыка, імя ўнутры вашай прыватнай зоны не развязаецца машынай, якая валодае зонай. Браўзер атрымлівае адказ ад рэзалвера без паўнамоцтваў на гэтае імя і лічыць яго адсутным, а тэкст памылкі ніколі не згадвае DNS.
Спытайце рэзалвер тунеля напрамую, перш чым нешта змяняць. Першыя дзве каманды паказваюць, якія DNS-серверы Android далучыў да актыўнай сеткі і ці знаходзіцца Private DNS у аўтаматычным або строгім рэжыме; трэцяя выконваецца з любога кліента ўнутры тунеля, а не з тэлефона.
adb shell dumpsys connectivity | grep -A3 "DnsAddresses"
adb shell settings get global private_dns_mode
nslookup -type=AAAA nas.lan 10.61.0.1
Крок 2: прачытайце, што VpnService фактычна абвясціў
Бок Android — гэта яўная дэкларацыя, а не здагадка. VpnService.Builder дадае адрасы праз addAddress, маршруты праз addRoute, DNS-серверы праз addDnsServer і можа абмежаваць увесь тунель адной сям'ёй адрасоў праз allowFamily. Будаўнік, які выклікаў allowFamily(AF_INET) і пазней дадаў маршрут IPv6, паведаміў сістэме дзве супярэчлівыя рэчы, і менавіта абмежаванне сям'і сістэма пакідае. Маршрут, які пакрывае fd00:61::/64, у спалучэнні з адрасам інтэрфейса ў іншым прэфіксе правальваецца па падобнай прычыне: адрас існуе, але ён не on-link для гэтага маршруту.
Чытайце дэкларацыю, а не давярайце пераключальніку ў праграме. dumpsys netd друкуе адрасы і маршруты, далучаныя да інтэрфейса tun, а LinkProperties для кожнай сеткі ў dumpsys connectivity паказвае спіс DNS побач з сям'ямі, якія сетка заяўляе.
adb shell ip -6 addr show tun0
adb shell ip -6 route show table all | grep tun0
adb shell dumpsys connectivity | grep -E "LinkAddresses|Routes"
Калі інтэрфейс tun трымае адрас IPv6, але ні адзін маршрут не адпавядае прэфіксу сэрвісу, дастаўка IPv6 ужо зламаная да таго, як у справу ўступае браўзер. Гэта іншая памылка, чым браўзер, які адмаўляецца спрабаваць, і яна патрабуе іншага выпраўлення.
Крок 3: браўзер вырашае, ці спрабаваць IPv6 наогул
Chromium выкарыстоўвае не кожны атрыманы запіс AAAA. Яго рэзалвер хостаў нясе праверкі дасяжнасці IPv6 і фільтрацыю кандыдатаў, якія могуць адкінуць або панізіць прыярытэт IPv6, калі сетка прызнаная няздольнай яго несці, і зыходнік рэзалвера паказвае гэтую праверку разам з умовамі вакол яе. Логіка залежыць ад версіі і сцягоў — менавіта таму два тэлефоны на адным тунелі могуць паводзіць сябе па-рознаму. Калі кандыдаты ўжо ёсць, Happy Eyeballs уладкоўвае спаборніцтва паміж сям'ямі для кожнага злучэння, таму шлях IPv6, які адказвае павольна, можа ўсё яшчэ прайграць IPv4, які адказвае хутка.
Назірайце за рашэннем, а не выводзьце яго. Сесія, запісаная праз chrome://net-export і прайграная ў праглядніку netlog, паказвае кожнае развязанне і выбраную сям'ю; chrome://net-internals/#dns паказвае кэшаваныя вынікі. Развязанне, якое вяртае толькі запісы A для імя, што мае AAAA у вашым уласным рэзалверы, паказвае прама на гэты этап.
Крок 4: праверце, што пакет можа здзейсніць паездку туды і назад
Выбар адраса — гэта не дастаўка. Android трымае табліцы маршрутызацыі і правілы палітыкі для кожнай сеткі, якія выбіраюць табліцу па fwmark, таму маршрут, бачны ў асноўнай табліцы, не абавязкова той маршрут, які выкарыстоўвае сокет. Чытанне правілаў і просьба да ядра развязаць пункт прызначэння для адраса крыніцы раздзяляюць гэтыя два.
adb shell ip -6 rule show
adb shell ip -6 route get fd00:61::20 from fd00:61::10
Менавіта вывад route get адказвае на пытанне. Калі ён называе tun0, а пакеты ўсё яшчэ гінуць, пераходзьце да MTU тунеля і фарвардынгу IPv6 на шлюзе, а не назад да тэлефона.
Чаму даданне ::/0 звычайна робіць горш
Даданне ::/0 змяняе заяву тунеля з аднаго прэфікса на кожны пункт прызначэння IPv6. На тэлефоне гэта можа задаволіць праверку дасяжнасці, бо тэставы адрас па-за вашым прэфіксам цяпер выглядае маршрутызуемым. Гэта не стварае прапускную здольнасць IPv6 уверх на шлюзе, а ў многіх хатніх шлюзаў зусім няма працоўнага ўзыходнага канала IPv6. Вынік — чорная дзірка для публічнага IPv6: імёны, якія раней адкочваліся на IPv4, цяпер вісяць, а прыватная старонка можа выглядаць лепш толькі таму, што праверка вымярае нешта іншае.
Ёсць і цана для палітыкі. З ::/0 у тунелі ўвесь трафік IPv6 выходзіць праз VPN, уключаючы трафік, які ўласнік сеткі ніколі не пагаджаўся несці. Стаўцеся да гэтага як да рашэння аб разгортванні з названым уласнікам, а не як да кроку адладкі, які вы робіце ў 1 гадзіну ночы.
Парадак працы, які гэта завяршае
Пацвердзіце, што адказ AAAA прыходзіць ад рэзалвера, які трымае зону, прачытайце стан VpnService і netd для інтэрфейса tun, здыміце трасоўку net-export, каб убачыць, ці адкінуў Chromium кандыдата, затым праверце паездку туды і назад з ip -6 route get. Выпраўце той узровень, які сапраўды праваліўся, і не чапайце палітыку раздзялення. Калі прыватныя імёны патрабуюць іншых адказаў, чым публічныя, для гэтага і існуе split tunneling.
Запішыце зборку тэлефона, версію браўзера і рэзалвер, які вы апытвалі. Гэтыя тры факты ператвараюць "IPv6 is broken" у нешта, што наступны чалавек зможа прайграць.