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 vreme 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 deo dizajna, a ne kao rubni slučaj.

Mit: aplikacija uključuje VPN telefona

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

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

Prisilno zaustavljanje aplikacije vidljivo je u panelu obavesti iz istog razloga: sistem izveštava šta je dodelio, 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 zameni svojim mora sama proslediti 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, izveštavać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 umesto 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 sopstveni transportni socket aplikacije zaobišao njen tunel umesto da hvata sam sebe, i vraća logičku vrednost koju treba proveriti 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 protivrečne odgovore: informacija jednostavno nije izložena vašem procesu.

Šta životni ciklus zapravo zahteva

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 dve komponente koje se utrkuju da uspostave vezu boriti za jedno dostupno mesto. Pozadinska pokretanja su ograničena na modernom Androidu, pa emitovanje pri podizanju nije garancija; koristite uslugu u prvom planu s njenom obavešću gde nivo API-ja to dozvoljava.

Belež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 uverljivo, pa ovo pokrenite na stvarnom uređaju sa instaliranim drugim VPN klijentom koji će zauzeti mesto.

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 obavest 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 proverite da li nešto još izveštava o živom deskriptoru.

Ponovite sled 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 da koristi deskriptor koji više nije posedovala.

Povezani članci