Zašto Android VpnService hvata dio prometa, a ne sav
Rute, DNS unosi i obuhvat po aplikacijama odlučuju koji paketi stižu do tun uređaja, zašto lokalni uređaji nestaju i šta graditelj odbija.
Ništa u VpnService ne presreće promet samo po sebi. On traži od sistema tun interfejs, daje tom interfejsu skup adresa i ruta, i od tog trenutka kernel kopira svaki paket koji odgovara tim rutama u datotečni deskriptor koji aplikacija može čitati. Kod aplikacije nikada ne vidi pakete koje rute nisu odabrale, pa je obuhvat tunela pitanje tablice rutiranja prije nego pitanje programiranja. Zato ista implementacija servisa može progutati svaki tok na jednom telefonu, a samo dio na drugom, i zato dodavanje rute ponekad popravi tunel koji je izgledao pokvaren. Ono što dobijete je ono što ste deklarisali, minus sve što je graditelj tiho odbio.
Rute odlučuju koji paketi stižu
Builder.addRoute(prefix, prefixLength) instalira prefiks u tablicu rutiranja VPN mreže. Sistem tu mrežu tretira kao zadanu za aplikacije u obuhvatu, pa se njeni unosi gledaju prije zadane rute fizičke mreže i odgovarajući prefiks je dovoljan da preusmjeri tok. Zato ruta za 0.0.0.0/0 preuzima IPv4 u cijelosti, uključujući pisač, cast odredište i admin stranicu rutera.
Klijenti koji žele to pokrivanje bez brisanja fizičkog zadanog unosa koriste umjesto toga par 0.0.0.0/1 i 128.0.0.0/1. Dvije specifičnije rute pobjeđuju zadanu rutu, zajedno pokrivaju cijeli adresni prostor, a vlastiti zadani unos telefona ostaje u tablici za sokete koji su još vezani za fizičku mrežu.
Adrese i DNS unosi dolaze od istog graditelja i odgovaraju na drugo pitanje. addAddress daje interfejsu adresu s dužinom prefiksa, a addDnsServer instalira razrješivač koji će aplikacije u obuhvatu pitati kroz interfejs. Obje familije mogu stajati na jednom interfejsu, pa je skup ruta samo za IPv4 uz adresu IPv6 konfiguracija koja se čita ispravno i ipak curi. Ako rutirate familiju u kojoj interfejs nema adresu, kernel nema izvornu adresu za te pakete i oni se nikada ne pojave na deskriptoru.
Šta vraća establish()
establish() vraća ParcelFileDescriptor ili null kada aplikacija nije ovlaštena. Null je stanje pristanka, a ne mrežna greška: VpnService.prepare() je već morao vratiti null ili je korisnik morao odobriti sistemski dijalog prije poziva. Pristanak se može povući dok servis radi, i interfejs se zatvara pod vama bez povratnog poziva u vašu petlju čitanja.
Deskriptor je neblokirajući osim ako ne kažete drugačije, pa čitanje vraća odmah bez podataka umjesto da parkira nit. Petlja napisana za blokirajući soket pali jedno jezgro, a petlja koja prazno čitanje smatra kobnim razdire tunel u jednoj praznoj sekundi. Builder.setBlocking(true) mijenja to ponašanje, a cijena je nit koja čeka unutar čitanja.
Argumenti rute i adrese provjeravaju se kao vrijednosti LinkAddress, a multicast odredišta poput 224.0.0.0/4 odbijaju se odmah. Tačka-na-tačku tun interfejs također nema broadcast domenu, pa multicast otkrivanje preko njega traži drugačiji dizajn, a ne još jednu rutu. Referenca VpnService.Builder je lista koju treba provjeriti prije nego zaključite da je poziv ignorisan.
Obuhvat po aplikacijama sužava skup, ne tunel
Od API 21 graditelj prihvata addAllowedApplication i addDisallowedApplication, a dvije liste se međusobno isključuju unutar jednog graditelja. Lista dopuštenih čini tunel postojećim za te pakete dok sve ostalo zadržava fizičku mrežu; lista zabranjenih hvata sve osim navedenih paketa, što klijent nudi kao razdvojeno tuneliranje. Prije API 21 nema platformskog mehanizma uopšte, a ponašanje po aplikacijama dolazilo je od klijenata trećih strana koji filtriraju po UID unutar vlastitog prosljeđivača. Razlika je važna pri otklanjanju grešaka, jer tunel po aplikacijama s listom dopuštenih od jedne aplikacije proizvodi gotovo nikakav promet i to je ispravno ponašanje, a ne pokvarena ruta.
Kakav god bio obuhvat, soket koji vaša aplikacija otvara prema VPN serveru ne smije putovati kroz tunel koji gradi. VpnService.protect(socket) veže taj soket za donju mrežu pa njegovi paketi preskaču tun uređaj. Preskočite poziv i rukovanje će progutati interfejs koji je rukovanje trebalo podići.
VpnService.setUnderlyingNetworks zatvara petlju govoreći sistemu koja fizička mreža nosi tunel. Ta vrijednost određuje kako VPN izvještava druge aplikacije o povezanosti, a null ili zastarjela vrijednost rutinski je uzrok povezanog tunela koji ostatak telefona smatra van mreže. Ažurirajte je kada se donja mreža promijeni, ne samo pri pokretanju.
Kontrolne sume i MTU: gdje ispravna ruta ipak pada
Kada paketi jednom stignu, dvije pojedinosti na nivou paketa odlučuju radi li išta od kraja do kraja. Prva je izvorna adresa: s nekoliko adresa interfejsa kernel može slati pakete s prvom, pa prosljeđivač koji prepisuje zaglavlja mora ispraviti adresu i kontrolnu sumu koja je pokriva.
Druga je obuhvat kontrolne sume. Kada aplikacija sama gradi TCP ili UDP pakete, kontrolna suma pokriva pseudo-zaglavlje s izvornom adresom, odredišnom adresom, brojem protokola i dužinom transporta, a izostavljanje bilo čega od toga daje pakete koji stignu i budu odbačeni. Taj kvar izgleda kao istek vremena nakon odgovora koji nikada ne dođe, što većinu ljudi vraća rutama. setMtu fiksira MTU interfejsa i svako čitanje vraća tačno jedan kompletan IP paket, pa će bafer napisan za tok bajtova fragmentisati vaše parsiranje, a ne paket.
Provjera koja razdvaja slojeve
Da biste našli gdje je obuhvat pogriješio, testirajte slojeve po redu. Pitajte uređaj koje rute VPN mreža stvarno drži, zatim provjerite pojavljuje li se tok prema poznatoj adresi kao čitanje na deskriptoru, zatim provjerite je li paket koji vaš prosljeđivač šalje dobro formiran. Problem rute ne pokazuje ništa na deskriptoru, dok problem kontrolne sume pokazuje paket koji stigne i nestane.
Ako ništa ne stigne do deskriptora, sumnjivac je skup ruta, a ne čitač: potvrdite prefikse, potvrdite da postoji adresa u istoj familiji i potvrdite da je aplikacija unutar obuhvata koji ste postavili. Ako paketi stižu do deskriptora ali ništa ne dolazi natrag, pregledajte protect() i vrijednost donje mreže prije nego ponovo dirate rutu. Ako daleka strana prijavljuje neispravne pakete, kontrolna suma i MTU su mjesta za pogledati. Jedna provjera po sloju štedi jedno poslijepodne nagađanja.