Allowlist ng Android VpnService: bakit nag-hang pa rin ang mga pinapayagang pahina
Malamang ay maayos ang allowlist mo. Nag-hang ang mga pahina dahil sa DNS na sagot, talahanayan ng ruta, socket ng resolver, o MTU. Ito ang pagkakasunod-sunod ng pagsusuri.
Nagdagdag ka ng domain sa allowlist, umabot ang query sa app mo, ibinabalik ng tagatugma na pinapayagan, at hindi pa rin naglo-load ang pahina. Sa puntong iyon, karamihan ay nagsisimulang muling isulat ang tagatugma at nagdadagdag ng paghahambing na may wildcard. Sa aking karanasan, karaniwang tama ang tagatugma, at ang sira ay isang patong na mas malalim: sa DNS na sagot na ginawa mo, sa rutang inilagay mo, o sa socket na ginamit mo para ipasa ang query. Ang listahan ang madaling bahagi; ang landas ng packet ang lugar kung saan nasisira ang mga allowlist.
Bihirang ang tagatugma ang may kasalanan
Ang unang dapat ihiwalay ay ang naka-block sa sira. Ang naka-block na pangalan ay dapat mabigo nang mabilis at nakikita, dahil nakakakuha ang browser ng sagot na wala ang pangalan at tumitigil ito. Ang sirang pangalan ay nag-hang, nag-uulit sa IPv6, bumalik sa ibang transport, at iniiwan ka na may umiikot na indicator. Kung may nakita kang umiikot na indicator, malamang may sinasagot ang allowlist mo na hindi kayang pakialaman ng kliyente.
Ang walang laman na A record ang klasikong pagkakamali. Ang pagbabalik ng NOERROR na may zero na sagot ay mukhang valid na sagot, kaya tinatanggap ito ng stub resolver, nag-uulit ang browser, sinusubukan ang AAAA, sinusubukan ang ibang resolver, at sumusuko nang mas huli. Ang response code 3, o NXDOMAIN, na may paulit na question section at kinopyang transaction ID, ay agad na nagtatapos sa usapan. Gamitin ito sa bawat pangalang sinasadya mong tanggihan.
Ang IPv6 ay karapat-dapat sa parehong pasya at hindi sa default. Kung sumasagot ka ng NXDOMAIN sa A at hinahayaan ang AAAA, maaaring maabot ng kliyente ang naka-block na pangalan sa IPv6 at tumutulo ang filter. Ang ilang implementasyon ay sumasagot sa naka-block na AAAA query gamit ang loopback address upang agad mabigo ang koneksyon sa halip na bumalik sa alternatibo. Pumili ng isang patakaran, ilapat ito sa dalawang uri ng record, at i-log ang dalawa.
Ang rutang humuhuli sa lahat ay nagmamay-ari ng lahat
Ang disenyong DNS lamang ay hindi kailanman nagdadagdag ng addRoute("0.0.0.0", 0), kaya queries lang ang pumapasok sa TUN interface at lahat ng iba ay patuloy na gumagamit ng nasa ilalim na network. Iyon ang ligtas na hugis, at ipinapaliwanag din nito kung bakit ang ilang allowlist ay tila gumagana sa Wi-Fi at nabibigo sa cellular.
Sa sandaling may default route, bawat daloy ay sa iyo. Ang TCP packet na dumarating sa interface at hindi ipinapasa o sinasagot ay nakaupo sa pila hanggang maubos ang oras ng kliyente, at walang error na maitala dahil walang nabigo. Napanood ko ang isang taong gumugol ng isang hapon sa sirang allowlist na talagang kulang na forwarder para sa port 443. I-log ang protocol at destinasyon ng bawat packet na itinapon mo.
Kailangang lumabas ng tunnel ang socket ng resolver
Ang pagpapasa ang lugar ng susunod na bitag. Ang mga resolver ng carrier ay madalas nakatira sa pribadong address na hindi maabot ng tunnel, kaya ang query na ipinapasa mo ay walang pinupuntahan at nag-uulat ang app ng read timeout. Ipadala ang mga aprubadong query sa resolver na alam mong maabot, at ibigay muna ang socket na iyon sa VpnService.protect(). Ang hindi protektadong socket ay ibinabalik ang query sa sarili mong tunnel, kung saan muli itong umabot sa app at umiikot hanggang sumapit ang timeout.
Ang sira ay mukhang katulad ng pagkawala ng network, kaya tumatagal ito sa mga bug report. Magtago ng counters para sa mga ipinadala at natanggap: kung tumataas ang unang numero at nananatiling zero ang pangalawa, tinitingnan mo ang socket, hindi ang listahan.
Ang laki at checksum ay nabibigo nang walang mensahe
Ang tahimik na pagtatapon ay nagmumula rin sa laki. Ang DNS sagot na may malaking set ng sagot, o TCP handshake na may saganang opsyon, ay maaaring lumampas sa MTU ng landas na hindi mo kailanman tahasang itinakda; nawawala ang fragment sa itaas at ang kliyente ay nag-uulit nang mas maliit o tumitigil. Ang pagtatakda ng MTU ng interface sa 1280 ay konserbatibong pagpipilian na nakakalampas sa karamihan ng cellular na landas, at mas mabuti ang tahasang pagtatakda kaysa sa minanang default na walang sinumang nagsukat.
Kung ikaw mismo ang gumagawa ng packet, ang checksum ang isa pang tahimik na pumatay. Ang UDP checksum na kinalkula sa pseudo-header na iniiwan ang UDP haba o protocol field ay gumagawa ng packet na mukhang maayos sa iyo at itinatapon ng tatanggap nang walang bakas. Ihambing ang iyong pseudo-header sa spec field by field, at i-print ang kinalkulang checksum para sa isang kilalang daloy habang nagde-debug.
Ano ang hindi gagawin ng VpnService para sa iyo
Dalawang limitasyon ang dapat malaman bago ka magdisenyo sa paligid nito. Walang ordinaryong app ang makakapag-install ng system-wide proxy o PAC file sa labas ng Wi-Fi, at hindi nagbago ang bahaging iyon. Ang per-app na landas ay nagbago: bago ang API 29, hindi makakadala ng proxy ang VpnService.Builder kahit kaunti, at mula API 29, ang setHttpProxy(ProxyInfo.buildPacProxy(uri)) ay nagbibigay sa platform ng PAC script na susuriin para sa VPN network. Suriin ang mga patakaran sa sarili mong code kapag nagta-target ng mas lumang API o kapag hindi kayang ipahayag ng PAC model ang patakaran. Hindi rin libre ang UDP: TCP lang ang ipinapadala ng browser sa proxy na SOCKS, at karamihan ng SOCKS5 client ay hindi kailanman nagpapatupad ng UDP ASSOCIATE, kaya ang disenyong nakabatay sa proxy ay nagtatapon o nagtutulo ng UDP habang mukhang maayos ang TCP.
Ang ikalawang limitasyong iyon ang dahilan kung bakit ang protocol na nakabatay sa UDP ay gumagana sa ordinaryong network at nabibigo sa sandaling kumonekta ang VPN mo. Kung inaasahang magdadala ang tunnel ng UDP, kailangang ipatupad ng forwarder ang landas ng pagpapasa para dito, hindi lang ang TCP landas na may ibang uri ng socket.
Suriin sa ganitong pagkakasunod-sunod
Isa-isahin ang listahan at tumigil sa unang yugtong nabigo, dahil ang bawat susunod na pagsusuri ay ingay hangga't hindi tumatagal ang nauna.
- Ilista ang mga naka-install na ruta at tiyakin kung pumapasok talaga sa TUN interface ang mga packet na hindi DNS.
- I-log ang pangalan ng query, pasya at response code para sa isang naka-block at isang aprubadong pangalan.
- Tiyakin na protektado ang socket ng resolver at sumasagot ang piniling resolver mula sa loob ng tunnel.
- Tiyakin ang MTU ng interface at ang checksum ng isang sagot na ginawa mo mismo.
- Ulitin ang parehong pahina sa Wi-Fi at cellular, dahil naiiba ang resolver ng carrier at ang MTU ng landas.
Kung lahat ng lima ay tumatagal at nag-hang pa rin ang pahina, ang susunod na suspek ay ang forwarder mismo: ihambing ang nakuhang request sa nakuhang sagot at maghanap ng kulang na bilang ng byte o kalahating saradong socket. Saklaw ng VpnService.Builder reference ang mga kontrata sa ruta, DNS at MTU, at ang protect() ay hiwalay na tawag sa VpnService at hindi opsyon ng builder; ang nakakonektang interface ay nangangahulugan lamang na natupad ang unang kontrata.