Android always-on VPN: чаму імя канчатковага пункта вырашаецца першым
Android блакуе трафік яшчэ да таго, як тунель існуе, але кліент усё роўна павінен вырашыць імя свайго канчатковага пункта. Вось парадак дзеянняў і месца, дзе ўзнікае тупік.
Тэлефон перазагружаецца, always-on уключаны, «block connections without VPN» актыўны, а тунель так і не ўздымаецца. Нічога не наладжана няправільна: блакаванне робіць сваю працу, і спроба самога кліента дасягнуць свайго канчатковага пункта падпадае пад яго. Імя канчатковага пункта трэба вырашыць да таго, як тунель існуе, і робіць гэта кліент, якому дазволена размаўляць з сеткай, пакуль усе астатнія праграмы не могуць. Разуменне таго, які кампанент гэта робіць і ў якім парадку, ператварае загадку ў пытанне канфігурацыі.
Што насамрэч запытвае будаўнік VPN
Праграма Android VPN не перадае платформе адрас сервера. Яна будуе лакальны інтэрфейс: адрасы і маршруты для тунеля, рэзалверы, якія праграмы павінны выкарыстоўваць унутры яго, а затым establish() вяртае файлавы дэскрыптар, які праграма чытае і запісвае як сырыя IP-пакеты. Аддалены канчатковы пункт у гэтым будаўніку зусім не з'яўляецца.
Гэта ключавы структурны факт. Платформа стварае інтэрфейс tun і прымяняе палітыку на ім; праграма рэалізуе транспарт у прасторы карыстальніка, гэта значыць, што яна сама вырашае імя свайго канчатковага пункта і адкрывае зашыфраванае злучэнне. Канчатковы пункт у выглядзе імя такім чынам магчымы — не таму, што платформа падтрымлівае імёны, а таму, што платформа ніколі не бачыць канчатковы пункт.
Адно поле будаўніка ўсё ж прымае адрасы: DNS-серверы. Яны павінны быць лікавымі адрасамі рэзалвераў, звычайна тымі, якія аператар хоча апытваць праз тунель. Гэтае поле апісвае, куды праграмы адпраўляюць запыты пасля ўздыму тунеля. Яно нічога не кажа пра тое, як кліент знаходзіць канчатковы пункт, і менавіта змяшэнне гэтых двух налад стварае блытаніну.
Два пытанні DNS, а не адно
Першае пытанне: куды праграмы адпраўляюць запыты, калі тунель ужо ўзняты? Адказ — адрас рэзалвера ўнутры тунеля, дасяжны праз інтэрфейс tun, лікавы па сваёй прыродзе.
Другое пытанне: як кліент знаходзіць свой уласны канчатковы пункт да таго, як гэты тунель існуе? Гэты пошук адбываецца па-за тунелем, у базавай сетцы, у працэсе кліента. Ён можа выкарыстоўваць імя і павінен выкарыстоўваць рэзалвер, дасяжны для прылады без VPN.
| Stage | Who resolves | Path | Failure looks like |
|---|---|---|---|
| Endpoint lookup | The VPN app | Underlying network, protected socket | Never connects; no tunnel interface traffic |
| Peer authentication | Client and server | Tunnel transport | Connects then drops; certificate or key error |
| Private name lookup | Apps via the tunnel | Resolver inside the tun | Tunnel up, internal sites do not resolve |
Тры этапы — тры розныя сімптомы. Адно паведамленне пра памылку, якое кажа «немагчыма падлучыцца», злівае іх разам, і таму людзі пачынаюць правіць поле DNS-сервера, каб выправіць праблему, якая ўзнікае яшчэ да таго, як гэтае поле ўвогуле чытаецца.
Чаму bootstrap можа зайсці ў тупік
Always-on з уключаным блакаваннем азначае, што трафік па-за VPN адкідаецца, уключаючы трафік праграмы, якой належыць VPN. Выключэнне зроблена яўна: праграма выклікае protect() на сокеце, што прывязвае яго да базавай сеткі, таму ён абыходзіць тунель і выпускаецца. Кожны VPN-кліент павінен рабіць гэта для свайго транспарту, інакш ён ніколі не дасягне сервера.
Цяпер разгледзім разгортванне, дзе адзіны рэзалвер, які ведае імя канчатковага пункта, знаходзіцца ўнутры тунеля. Кліенту патрэбен тунель, каб вырашыць імя, і імя, каб пабудаваць тунель. Гэта сапраўдная цыклічная залежнасць, і ніякая канфігурацыя кліента яе не вырашае. Гэта памылка праектавання, а не баг.
Час выяўляе тую ж залежнасць у больш мяккіх формах. Пры загрузцы да першага разблакавання прылада можа яшчэ не мець прыдатнай сеткі; на captive portal сетка ёсць, але блакуе ўсё, акрамя партала; пры пераключэнні з Wi-Fi на мабільную сетку базавая сетка абароненага сокета змяняецца, і кліент павінен гэта заўважыць і паўторна вырашыць імя. Кожнае з гэтага — падзея bootstrap, і кожнае варта тэставаць свядома, а не выяўляць у 3 гадзіны ночы.
Чаму замацаванне адказу не з'яўляецца рашэннем
Спакуслівы абыход — вырашыць імя адзін раз і ўставіць атрыманы адрас у лікавае поле або замацаваць яго ў спецыяльнай зборцы. Гэта выглядае працаздольным і ператварае імя ў здымак. Калі аператар перамяшчае канчатковы пункт — міграцыя, змена anycast, новы рэгіянальны адрас — кліент працягвае набіраць стары, і нішто ў інтэрфейсе не тлумачыць чаму.
DNS-запісы маюць час жыцця менавіта для таго, каб адказы маглі змяняцца; кэшаванне вызначаецца гэтым тэрмінам, а не назаўсёды. Замацаванне адказу адкідвае механізм, які робіць імя лепшым за адрас, захоўваючы пры гэтым аперацыйныя выдаткі выкарыстання імя.
Замацаванне звычайна ідзе побач з другой дрэннай звычкай: паслабленнем праверкі ідэнтычнасці, бо злучэнне цяпер падае інакш. Праверка ідэнтычнасці сервера не ўваходзіць у праблему bootstrap, і яе паслабленне абменьвае нязручнасць DNS на рызыку перахопу.
Рашэнні, якія вытрымліваюць перазагрузку
Трывалае рашэнне непрыгожае. Выкарыстоўвайце кліент, які правільна рэалізуе абароненыя сокеты і вырашае свой канчатковы пункт у базавай сетцы, і дайце яму імя канчатковага пункта, якое вырашаецца публічна або праз рэзалвер, дасяжны да тунеля. Пакіньце блакаванне ўключаным; поўнае адключэнне, каб DNS запрацаваў, прыбірае ўласцівасць, дзеля якой існуе разгортванне.
Там, дзе канчатковы пункт павінен заставацца прыватным, забяспечце яўны шлях bootstrap, які можа выкарыстоўваць платформа — рэзалвер, дасяжны без тунеля, або кіраўніцкае злучэнне, якое падтрымлівае аператар — і трымайце гэта выключэнне вузкім і належным палітыцы, а не пераключальніку карыстальніка. Дакументацыя Android VpnService — гэта даведнік пра тое, што платформа гарантуе адносна абароны і жыццёвага цыклу, а даведнік VpnService.Builder пацвярджае, што поле DNS прымае лікавыя адрасы.
Затым праверце тры этапы па парадку на свежым злучэнні пасля перазагрузкі: імя канчатковага пункта вырашаецца, тунель усталёўваецца і апанент аўтэнтыфікуецца, а прыватнае імя вырашаецца праз рэзалвер тунеля. Калі першы этап не праходзіць, нішто наступнае не можа працаваць, і выпраўленне належыць шляху bootstrap — ніколі ў поле рэзалвера.
- Вырашэнне канчатковага пункта адбываецца ў праграме, па-за тунелем, на абароненым сокеце.
- Поле DNS у будаўніку прызначана для праграм унутры тунеля, а не для ўласнага канчатковага пункта кліента.
- Рэзалвер, дасяжны толькі праз тунель, — гэта тупік, а не павольны старт.
- Тэстуйце канчатковы пункт, аўтэнтыфікацыю і прыватны пошук асобна пасля перазагрузкі.