Split tunneling sa Android VpnService: ano ang talagang maaaring i-route
Ipapasa lang ng VpnService ang mga packet na inilalagay ng builder sa deskriptor nito. Suriin ang mga prefix, pagpapatotoo ng proxy, DNS at listahan ng app bago sisihin ang split tunneling.
Ang split tunneling sa isang app na VpnService ay nasisira sa ilang partikular na lugar, at iba ang pag-aayos sa bawat isa. Isang destination lang ang ipinapakita ng client na nabigo, kaya ang unang gawain ay alamin kung aling hangganan ang tinatamaan mo: ang mga ruta na natanggap ng builder, ang proxy na hindi mo ma-authenticate, ang resolver na inihayag mo lang, o ang listahan ng app na ipinapataw ng platform sa bawat user. Kaya naman mayroon akong apat na hakbang na pagsusuri. Dumadaan ito sa pagkakasunod-sunod sa ibaba at humihinto sa unang pagpalya.
Kumpirmahin ang ibinigay ng builder sa platform
Ang VpnService.Builder ay isang listahan ng mga deklarasyon. Nagbabalik ang establish() ng ParcelFileDescriptor para sa virtual na interface, at ipinapadala lang ng platform sa deskriptor na iyon ang trapikong tumutugma sa mga prefix ng addAddress at addRoute; sinasabi ng addDnsServer sa mga client kung aling resolver ang tatanungin. Ang destination sa labas ng lahat ng prefix na idinagdag mo ay hindi kailanman nakakarating sa app mo, anuman ang ipangako ng interface. Ang nag-iisang katotohanang ito ang nagpapaliwanag sa karamihan ng ulat ng sirang split tunneling bago pa magbago ang code.
I-log ang mga listahan ng address, ruta at DNS na binuo ng builder mo, pagkatapos ihambing ang mga ito sa mga destination na nabibigo. Ang kulang na /32 para sa management host ay mas karaniwan kaysa sa sirang tunnel. Kung tama ang listahan, magpatuloy; kung mali, sayang ang natitirang checklist.
Ang excludeRoute ay umiiral lamang mula sa API 33
Ang pagbubukod batay sa destination ang kahilingang pinakamadalas maging support thread. Dumating ang builder.excludeRoute(IpPrefix) sa API 33; bago iyon, ang tanging sinusuportahang paraan ay magdagdag ng ruta para sa lahat maliban sa ibinukod na prefix, ibig sabihin kailangan mong kalkulahin mismo ang mga komplementaryong prefix. Hindi magkasalamin ang dalawang tawag: ang isa ay nagbabawas mula sa set ng ruta ng interface, ang isa ay nagtatayo ng set mula sa zero, at ang lumang device ay magtatapon o tahimik na hindi papansinin ang tawag na hindi nito kilala. Mag-branch sa Build.VERSION.SDK_INT at subukan ang parehong landas sa totoong hardware.
Kapag nagkalkula ng komplemento, pansinin ang pagkakahanay ng prefix. Ang pagbubukod na /24 sa loob ng rutang /16 ay nangangailangan ng mga sumasaklaw na prefix na tunay na naglalarawan sa natitira, hindi isang pilipit na /8. I-log ang huling listahan at tiyaking nareresolba pa rin ang ibinukod na host sa landas sa labas ng tunnel.
Hindi maipapahayag ang mga kredensyal ng proxy
Itinuturo ng setHttpProxy(ProxyInfo) ang interface sa isang HTTP o SOCKS proxy, at ang PAC URL ay makakapili sa pagitan nila sa bawat destination. Ni ProxyInfo o ang format na PAC ay walang dalang username at password, kaya ang proxy na nangangailangan ng pagpapatotoo ay nananatili sa labas ng API ng platform. Ang mga app na nangangailangan nito ay karaniwang naglalagay ng userspace stack, tun2socks o katulad na engine, at sila mismo ang sumasagot sa hamon na 407.
May mga kahihinatnan ang pagpiling iyon. Ang userspace stack ay nakikita lamang ang trapikong iruruta mo papunta rito, kaya kailangan nitong manirahan sa loob ng parehong hangganan ng deskriptor, at namamana nito ang parehong pangangailangan ng protect() para sa sarili nitong uplink socket. Kung lalaktawan mo ang protect(), mahuhuli ng tunnel ang sarili nitong transport, na lumalabas bilang handshake na tumitigil pagkatapos ng unang packet. Subukan laban sa proxy na humihingi ng kredensyal, dahil ang bukas na proxy ay dumadaan sa landas ng platform at walang pinapatunayan.
Ang listahan per app at DNS ay mga deklarasyon din
May addAllowedApplication at addDisallowedApplication ang Builder, at hindi sila maaaring pagsamahin: ang pagtawag sa dalawa ay nagtatapon ng exception. Alinman, inilalapat ang listahan sa bawat user sa pag-set up ng interface, kaya ang app sa work profile ay pinamamahalaan ng tunnel ng work profile at hindi ng sa iyo. Ang hindi ibinibigay ng anumang API ay kontrol sa desisyon ng ibang app: hindi mo maipapasok ang packet sa tunnel mo mula sa labas, at hindi mo maisasara o maisasaayos muli ang VPN na aktibo na.
Sumusunod ang DNS sa parehong pattern. Naghahayag ang addDnsServer ng address ng resolver; hindi nito pinapayagan ang app mo na sumagot sa mga query. Kung gusto mong ikaw mismo ang magresolba ng mga pangalan, magpatakbo ng resolver at iruta ang address nito sa tunnel. Ang mga app na gumagamit ng DoT o DoH patungo sa fixed hostname ay maaaring lumampas sa address na inihayag mo, kaya ituring na best effort ang resolution ng pangalan maliban kung naharang mo rin ang landas ng query.
Manifest, always-on at ang apat na hakbang na pagsubok
Ang pagiging karapat-dapat ay idinedeklara sa manifest: BIND_VPN_SERVICE, ang intent filter na android.net.VpnService at foreground service kung kailangang mabuhay ang tunnel sa background. Ang always-on VPN ay nangangailangan din ng malinis na onRevoke, dahil tinatawag ito ng system kapag binago ng user ang mga setting o may ibang app na pumalit sa kontrol.
Patakbuhin ang mga pagsusuri sa pagkakasunod-sunod at huminto sa unang pagpalya. Una, ilabas ang mga listahan ng address, ruta at DNS na ibinigay sa builder. Pangalawa, kumpirmahin na nagbalik ang establish() ng deskriptor at protektado ang transport socket. Pangatlo, humingi ng isang destination sa loob ng kasamang prefix at isa sa loob ng ibinukod na prefix. Pang-apat, tingnan kung aling resolver ang tunay na sumagot sa pamamagitan ng pagtatanong ng hostname na tanging resolver mo lang ang makakaresolba.
Ang natapos na handshake ay walang pinapatunayang alinman sa mga susunod na hakbang. Ihinihiwalay ng bawat pagsusuri ang isang layer, kaya ang tagumpay sa ikalawang hakbang ay walang sinasabi tungkol sa ikaapat.
Ang reference ng VpnService.Builder ay naglilista ng buong ibabaw ng builder. Anumang kailangan mo sa labas nito ay ibang API, ibang app o sarili mong userspace stack, at iyon ay desisyon sa disenyo, hindi bug ng split tunnel.