Split tunneling u Android VpnService-u: šta zapravo možete usmjeravati
VpnService prosljeđuje samo pakete koje builder pošalje svom deskriptoru. Provjerite prefikse, proxy autentifikaciju, DNS i liste aplikacija prije nego optužite split tunneling.
Split tunneling u aplikaciji s VpnService-om kvari se na nekoliko konkretnih mjesta, a popravka se razlikuje za svako. Klijent prikazuje samo jednu destinaciju koja ne prolazi, pa je prvi posao utvrditi na koju granicu nailazite: rute koje je builder dobio, proxy koji ne možete autentificirati, resolver koji ste samo najavili ili listu aplikacija koju platforma primjenjuje po korisniku. Zbog toga držim provjeru u četiri koraka. Ide redom ispod i zaustavlja se na prvom neuspjehu.
Potvrdite šta je builder predao platformi
VpnService.Builder je lista deklaracija. establish() vraća ParcelFileDescriptor za virtualno sučelje, a platforma u taj deskriptor šalje samo saobraćaj koji odgovara prefiksima iz addAddress i addRoute; addDnsServer govori klijentima koji resolver da pitaju. Destinacija izvan svih prefiksa koje ste dodali nikada ne stiže do vaše aplikacije, šta god sučelje obećavalo. Ta jedna činjenica objašnjava većinu prijava pokvarenog split tunnelinga prije ikakve promjene koda.
Zapišite u log liste adresa, ruta i DNS-a koje je builder sastavio, pa ih uporedite s destinacijama koje ne prolaze. Nedostajući /32 za upravljački host mnogo je češći od pokvarenog tunela. Ako je lista ispravna, idite dalje; ako nije, ostatak kontrolne liste je uzaludan trud.
excludeRoute postoji samo od API 33
Isključivanje po destinaciji je zahtjev koji najčešće završi kao tema podrške. builder.excludeRoute(IpPrefix) stigao je u API 33; prije toga jedina podržana aproksimacija je dodavanje ruta za sve osim isključenog prefiksa, što znači da komplementarne prefikse morate izračunati sami. Dva poziva nisu zrcalne slike: jedan oduzima od skupa ruta sučelja, drugi gradi skup od nule, a stariji uređaj će baciti izuzetak ili tiho ignorisati poziv koji ne poznaje. Granajte na Build.VERSION.SDK_INT i testirajte oba puta na stvarnom hardveru.
Kad računate komplemente, pazite na poravnanje prefiksa. Isključenje /24 unutar rute /16 traži pokrivajuće prefikse koji stvarno opisuju ostatak, a ne jedan nepravilan /8. Zapišite konačnu listu i provjerite da se isključeni host još razrješava putem izvan tunela.
Proxy akreditive se ne mogu izraziti
setHttpProxy(ProxyInfo) usmjerava sučelje na HTTP ili SOCKS proxy, a PAC URL može birati između njih po destinaciji. Ni ProxyInfo ni PAC format ne nose korisničko ime i lozinku, pa autentificirani proxy ostaje izvan API-ja platforme. Aplikacije kojima treba obično ugrađuju korisnički stek, tun2socks ili sličan motor i same odgovaraju na izazov 407.
Ta odluka ima posljedice. Korisnički stek vidi samo saobraćaj koji mu usmjerite, pa mora živjeti unutar istih granica deskriptora i nasljeđuje isti zahtjev za protect() za vlastiti uplink socket. Preskočite protect() i tunel hvata vlastiti transport, što se vidi kao rukovanje koje stane nakon prvog paketa. Testirajte na proxyju koji traži akreditive, jer otvoreni proxy prolazi na putu platforme i ništa ne dokazuje.
Liste aplikacija i DNS su također deklaracije
Builder ima i addAllowedApplication i addDisallowedApplication, a međusobno se isključuju: poziv oba baca izuzetak. U svakom slučaju lista se primjenjuje po korisniku pri postavljanju sučelja, pa aplikacijom radnog profila upravlja tunel radnog profila, a ne vaš. Nijedan API vam ne daje kontrolu nad odlukom druge aplikacije: ne možete spolja ugurati paket u svoj tunel i ne možete zatvoriti ili rekonfigurisati VPN koji je već aktivan.
DNS slijedi isti obrazac. addDnsServer objavljuje adresu resolvera; ne dopušta vašoj aplikaciji da odgovara na upite. Ako želite sami razrješavati imena, pokrenite resolver i usmjerite njegovu adresu u tunel. Aplikacije koje koriste DoT ili DoH prema fiksnom imenu hosta mogu zaobići adresu koju ste objavili, pa razrješavanje imena tretirajte kao najbolji pokušaj osim ako presrećete i put upita.
Manifest, always-on i test u četiri koraka
Prihvatljivost se deklarira u manifestu: BIND_VPN_SERVICE, intent filter android.net.VpnService i foreground servis ako tunel mora preživjeti u pozadini. Always-on VPN dodatno traži čist onRevoke, jer ga sistem poziva kad korisnik promijeni postavke ili druga aplikacija preuzme kontrolu.
Izvršite provjere redom i zaustavite se na prvom neuspjehu. Prvo, ispišite liste adresa, ruta i DNS-a predate builderu. Drugo, potvrdite da je establish() vratio deskriptor i da je transportni socket zaštićen. Treće, zatražite jednu destinaciju unutar uključenog prefiksa i jednu unutar isključenog. Četvrto, provjerite koji je resolver stvarno odgovorio pitajući ime hosta koje samo vaš resolver može razriješiti.
Završeno rukovanje ne dokazuje nijedan kasniji korak. Svaka provjera izolira jedan sloj, pa prolaz na drugom koraku ne govori ništa o četvrtom.
Referenca za VpnService.Builder navodi cijelu površinu buildera. Sve što vam treba izvan nje je drugi API, druga aplikacija ili vaš vlastiti korisnički stek, a to je dizajnerska odluka, ne greška split tunnelinga.