Nie, aplikácia VpnService nedokáže zapnúť VPN telefónu
Aplikácia vlastní jeden tunel a jeho životný cyklus, nie prepínač VPN telefónu. Súhlas možno odvolať, naraz beží len jedna VPN a pakety rozoberáte vy.
Mylný predpoklad je, že aplikácia VpnService prepne systémový prepínač a od tej chvíle je telefón chránený. V skutočnosti sa deje niečo užšie: aplikácia požiada o súhlas, vytvorí rozhranie, číta a zapisuje pakety cez deskriptor súboru a po zastavení rozhranie vráti. Živý môže byť vždy len jeden takýto tunel a systém ho môže bez pýtania odobrať. Väčšina mätúceho správania, ktoré ľudia pripisujú protokolu, pochádza práve z tohto modelu vlastníctva.
Berte každý prechod životného cyklu ako súčasť návrhu, nie ako okrajový prípad.
Mýtus: aplikácia zapína VPN telefónu
Tok začína pri VpnService.prepare(), ktorý vracia Intent, ktorý musí používateľ prijať, a pokračuje pri establish(), ktorý potom ešte môže zlyhať z dôvodov, ktoré aplikácia neovláda. Nadviazanie druhého tunela deaktivuje prvé rozhranie a nahradí systémové oznámenie. Nikde v tomto slede aplikácia nevlastní prepínač pre celé zariadenie; vlastní deskriptor, ktorý jej bol pridelený, a pakety, ktoré naň dopadnú. Aj trvalé oznámenie patrí systému, nie návrhu aplikácie.
Keďže sa rozhranie prideľuje, a nie zaberá, môže iný klient miesto kedykoľvek zaujať. Aplikácia to zistí cez spätné volanie, nie cez návratovú hodnotu.
Vynútené zastavenie aplikácie je vidieť v oznamovacom paneli z rovnakého dôvodu: systém hlási, čo pridelil, nie čo sa aplikácia rozhodla zobraziť.
Mýtus: súhlas sa dáva raz
Keď systém odovzdá tunel inému klientovi, pošle transakciu odvolania po binderi, ktorý základná trieda vracia z onBind(). Aplikácia, ktorá tento binder nahradí vlastným, musí transakciu odvolania preposlať sama, inak VpnService.onRevoke() nikdy nevybehne a služba ďalej zapisuje do deskriptora, ktorý už neexistuje. Schválenie môže odvolať aj používateľ a systém môže službu zastaviť pri reštarte alebo pri opätovnom pripojení v režime stále zapnuté.
Riešiť to je konkrétna práca, nie riadok v logu: prestaňte čítať deskriptor, zatvorte ho, vymažte príznak pripojenia a povedzte používateľovi, v akom stave sa nachádza. Potom rozhodnite, či má aplikácia znova nadviazať, znova sa opýtať alebo počkať, pretože v konfigurácii stále zapnuté môže systém službu vrátiť sám.
Aplikácia, ktorá odvolanie berie ako výnimku, a nie ako stav, bude hlásiť pripojenie, zatiaľ čo každý paket, ktorý zapíše, sa zahodí, čo je najhorší možný režim zlyhania pre nástroj súkromia.
Mýtus: rozhranie za vás filtruje prevádzku
Prichádza surové IP. Zachytávanie alebo filtrovanie znamená parsovať hlavičky IP, TCP, UDP a IPv6, sledovať toky a zapisovať odpovede späť do deskriptora, čo robí zo zachytávacej aplikácie malý sieťový stack, nie systémovú funkciu. protect() existuje preto, aby vlastný transportný socket aplikácie obišiel jej tunel, namiesto toho aby zachytával sám seba, a vracia boolovskú hodnotu, ktorá si zaslúži kontrolu pri každom sockete vytvorenom po tom, čo tunel beží.
Zoznamy povolených a zakázaných aplikácií v builderi určujú, čí prevádzka do rozhrania vstúpi. Neposkytujú prístup k dátam za IP pakety, ktoré rozhranie nesie, a žiadne API neodhaľuje tunel iného klienta ani uvádza systémové profily VPN. Sieťové možnosti môžu povedať, že sieť je transport VPN, ale nie čí je to tunel.
Preto otázky na stav iných aplikácií dostávajú protichodné odpovede: informácia jednoducho nie je vášmu procesu vystavená.
Čo životný cyklus skutočne vyžaduje
Sledujte stavy, ktoré ovládate: pripravené, nadviazané, odvolané, zastavené. Opätovné pripojenie má byť rozobratie a potom nadviazanie, s jediným vlastníkom deskriptora a transportného socketu, pretože dve komponenty, ktoré sa predbiehajú v nadväzovaní, sa pobijú o jediné voľné miesto. Spúšťanie na pozadí je v modernom Androide obmedzené, takže broadcast pri štarte nie je záruka; použite službu v popredí s jej oznámením tam, kde to úroveň API dovolí.
Zaznamenávajte prechod, nie len konečný stav, a držte stavový stroj dosť malý, aby ste otestovali každú cestu. Stav, do ktorého sa v teste nedostanete, je stav, s ktorým sa v teréne stretnete bez logu.
Otestujte životný cyklus na zariadení
Emulátory vedia predstierať pripojenie, ale nie cestu súhlasu a odvolania presvedčivo, preto ich spúšťajte na skutočnom zariadení s nainštalovaným druhým VPN klientom, ktorý miesto ukradne.
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
Spustite tunel, potvrďte oznámenie a rozhranie, potom pripojte druhého klienta a sledujte, či sa spustí spätné volanie odvolania a či sa stav vyčistí. Vynútene zastavte aplikáciu a skontrolujte, či niečo stále hlási živý deskriptor.
Zopakujte sled po reštarte v režime stále zapnuté, pretože táto cesta sa líši od pripojenia začatého používateľom. Nehľadáte zelenú ikonu, ale dôkaz, že aplikácia prestala používať deskriptor, ktorý už nevlastnila.