Pogrešna pretpostavka je da VpnService aplikacija okrene sistemski prekidač i da je telefon od tada zaštićen. Ono što se stvarno događa je uže: aplikacija traži saglasnost, gradi interfejs, čita i piše pakete kroz deskriptor datoteke i vraća interfejs kada se zaustavi. U isto vrijeme može biti živ samo jedan takav tunel, a sistem ga može oduzeti bez pitanja. Većina zbunjujućeg ponašanja koje ljudi pripisuju protokolu dolazi upravo iz tog modela vlasništva.

Tretirajte svaki prelaz životnog ciklusa kao dio dizajna, a ne kao rubni slučaj.

Mit: aplikacija uključuje VPN telefona

Tok počinje s VpnService.prepare(), koji vraća Intent koji korisnik mora prihvatiti, i nastavlja se s establish(), koji nakon toga i dalje može pasti zbog razloga koje aplikacija ne kontroliše. Uspostavljanje drugog tunela deaktivira prvi interfejs i zamjenjuje sistemsku obavijest. Nigdje u tom nizu aplikacija ne posjeduje prekidač na nivou uređaja; posjeduje deskriptor koji joj je dodijeljen i pakete koji na njega slete. Čak i trajna obavijest pripada sistemu, a ne dizajnu aplikacije.

Pošto se interfejs dodjeljuje, a ne otima, drugi klijent može zauzeti mjesto u svakom trenutku. Aplikacija to saznaje kroz povratni poziv, a ne kroz povratnu vrijednost.

Prisilno zaustavljanje aplikacije vidljivo je u panelu obavijesti iz istog razloga: sistem izvještava šta je dodijelio, a ne šta je aplikacija odlučila prikazati.

Mit: saglasnost se daje jednom

Kada sistem preda tunel drugom klijentu, šalje transakciju opoziva na binder koji bazna klasa vraća iz onBind(). Aplikacija koja taj binder zamijeni svojim mora sama proslijediti transakciju opoziva, inače VpnService.onRevoke() nikada neće biti pozvan i servis nastavlja pisati u deskriptor koji više ne postoji. Odobrenje korisnik takođe može povući, a sistem može zaustaviti servis tokom restarta ili ponovnog povezivanja u režimu stalno uključenog.

Bavljenje time je konkretan posao, a ne linija u logu: prestanite čitati deskriptor, zatvorite ga, očistite zastavicu povezanosti i recite korisniku u kojem je stanju. Zatim odlučite da li aplikacija treba ponovo uspostaviti vezu, ponovo pitati ili čekati, jer u konfiguraciji stalno uključenog sistem može sam vratiti servis.

Aplikacija koja opoziv tretira kao izuzetak, a ne kao stanje, izvještavat će da je povezana dok se svaki paket koji zapiše odbacuje, a to je najgori mogući način otkaza za alat za privatnost.

Mit: interfejs filtrira saobraćaj umjesto vas

Ono što stiže je sirovi IP. Hvatanje ili filtriranje znači raščlanjivanje IP, TCP, UDP i IPv6 zaglavlja, praćenje tokova i pisanje odgovora natrag u deskriptor, što aplikaciju za hvatanje čini malim mrežnim stekom, a ne sistemskom mogućnošću. protect() postoji da bi vlastiti transportni socket aplikacije zaobišao njen tunel umjesto da hvata sam sebe, i vraća logičku vrijednost koju treba provjeriti na svakom socketu stvorenom nakon što je tunel podignut.

Liste dozvoljenih i zabranjenih aplikacija u graditelju odlučuju čiji saobraćaj ulazi u interfejs. One ne daju pristup sadržaju izvan IP paketa koje interfejs nosi, i nijedan API ne otkriva tunel drugog klijenta niti navodi sistemske VPN profile. Mrežne mogućnosti mogu reći da je neka mreža VPN transport, ali ne i čiji je tunel.

Zato pitanja o stanju drugih aplikacija dobijaju protivrječne odgovore: informacija jednostavno nije izložena vašem procesu.

Šta životni ciklus zapravo zahtijeva

Pratite stanja koja kontrolišete: pripremljeno, uspostavljeno, opozvano, zaustavljeno. Ponovno povezivanje treba biti rastavljanje pa uspostavljanje, s jednim vlasnikom deskriptora i transportnog socketa, jer će se dvije komponente koje se utrkuju da uspostave vezu boriti za jedno dostupno mjesto. Pozadinska pokretanja su ograničena na modernom Androidu, pa emitovanje pri podizanju nije garancija; koristite uslugu u prvom planu s njenom obaviješću gdje nivo API-ja to dozvoljava.

Bilježite prelaz, a ne samo konačno stanje, i držite mašinu stanja dovoljno malom da testirate svaki put. Stanje u koje ne možete doći u testu je stanje koje ćete sresti na terenu bez loga.

Testirajte životni ciklus na uređaju

Emulatori mogu lažirati povezanost, ali ne i put saglasnosti i opoziva uvjerljivo, pa ovo pokrenite na stvarnom uređaju s instaliranim drugim VPN klijentom koji će zauzeti mjesto.

adb shell dumpsys connectivity | grep -i -A3 vpn
adb shell dumpsys activity services | grep -i -A2 vpnservice
adb logcat -s VpnService:V AndroidRuntime:E
adb shell am force-stop com.example.vpnapp

Pokrenite tunel, potvrdite obavijest i interfejs, zatim povežite drugi klijent i gledajte da li se povratni poziv opoziva izvršava i da li se stanje čisti. Prisilno zaustavite aplikaciju i provjerite da li nešto još izvještava o živom deskriptoru.

Ponovite slijed nakon restarta u režimu stalno uključenog, jer se taj put razlikuje od korisnički pokrenutog povezivanja. Ono što tražite nije zelena ikona, nego dokaz da je aplikacija prestala koristiti deskriptor koji više ne posjeduje.

Povezani članci