Nei, en VpnService-app kan ikke slå på telefonens VPN
Appen eier én tunnel og livssyklusen dens, ikke VPN-bryteren på telefonen. Samtykket kan trekkes tilbake, bare én VPN kjører om gangen, og pakkene må du analysere selv.
Den gale antakelsen er at en VpnService-app vipper en systembryter, og at telefonen fra da av er beskyttet. Det som faktisk skjer, er smalere: appen ber om samtykke, bygger et grensesnitt, leser og skriver pakker gjennom en filbeskrivelse, og gir grensesnittet tilbake når den stopper. Bare én slik tunnel kan være levende om gangen, og systemet kan ta den uten å spørre. Det meste av den forvirrende atferden folk gir protokollen skylden for, kommer fra den eierskapsmodellen.
Behandle hver livssyklusovergang som en del av designet og ikke som et randtilfelle.
Myte: appen slår på telefonens VPN
Flyten starter med VpnService.prepare(), som returnerer et Intent brukeren må godta, og fortsetter med establish(), som fortsatt kan feile etterpå av årsaker appen ikke kontrollerer. Å opprette en ny tunnel deaktiverer det første grensesnittet og erstatter systemvarselet. Ingen steder i den sekvensen eier appen en enhetsomfattende bryter; den eier beskrivelsen den fikk, og pakkene som lander på den. Selv det vedvarende varselet tilhører systemet og ikke appens design.
Fordi grensesnittet blir gitt og ikke grepet, kan en annen klient ta plassen når som helst. Appen får vite det gjennom et tilbakeringing, ikke gjennom en returverdi.
At appen blir tvangsstoppet, vises i varselspanelet av samme grunn: systemet rapporterer hva det har gitt, ikke hva appen valgte å vise.
Myte: samtykket gis én gang
Når systemet overleverer tunnelen til en annen klient, sender det en tilbakekallingstransaksjon på binderen som basisklassen returnerer fra onBind(). En app som erstatter den binderen med sin egen, må videresende tilbakekallingstransaksjonen selv, ellers utløses aldri VpnService.onRevoke(), og tjenesten fortsetter å skrive til en beskrivelse som ikke finnes lenger. Godkjenningen kan også trekkes tilbake av brukeren, og systemet kan stoppe tjenesten under en omstart eller en alltid-på-gjenoppkobling.
Å håndtere det er konkret arbeid og ikke en logglinje: slutt å lese beskrivelsen, lukk den, tøm tilkoblet-flagget og fortell brukeren hvilken tilstand den er i. Deretter avgjør om appen skal gjenopprette, spørre igjen eller vente, for i en alltid-på-konfigurasjon kan systemet bringe tjenesten tilbake selv.
En app som behandler tilbakekalling som et unntak og ikke som en tilstand, vil rapportere tilkoblet mens hver pakke den skriver blir forkastet, og det er den verste feilmodusen som finnes for et personvernverktøy.
Myte: grensesnittet filtrerer trafikk for deg
Det som kommer inn, er rå IP. Å fange eller filtrere betyr å parse IP-, TCP-, UDP- og IPv6-hoder, følge strømmer og skrive svar tilbake til beskrivelsen, noe som gjør en fangeapp til en liten nettverksstakk og ikke en systemfasilitet. protect() finnes for at appens egen transportssokkel skal gå utenom tunnelen sin i stedet for å fange seg selv, og den returnerer en boolsk verdi som fortjener en sjekk på hver sokkel som opprettes etter at tunnelen er oppe.
Byggerens lister over tillatte og forbudte apper avgjør hvis trafikk som kommer inn i grensesnittet. De gir ikke tilgang til nyttelast utover IP-pakkene grensesnittet bærer, og ingen API eksponerer en annen klients tunnel eller lister systemets VPN-profiler. Nettverksfunksjoner kan si at et nettverk er VPN-transport, men ikke hvis tunnel det er.
Derfor får statusspørsmål om andre apper motstridende svar: informasjonen er rett og slett ikke eksponert for prosessen din.
Hva livssyklusen faktisk krever
Følg tilstandene du kontrollerer: forberedt, opprettet, tilbakekalt, stoppet. Gjenoppkobling bør være nedriving etterfulgt av oppretting, med én eier av beskrivelsen og transportssokkelen, fordi to komponenter som kappes om å opprette, vil slåss om den ene ledige plassen. Bakgrunnsstarter er begrenset på moderne Android, så en oppstartsbroadcast er ingen garanti; bruk en forgrunnstjeneste med varselet sitt der API-nivået tillater det.
Logg overgangen og ikke bare sluttilstanden, og hold tilstandsmaskinen liten nok til å teste hver vei. En tilstand du ikke kan nå i en test, er en tilstand du møter i felt uten en logg.
Test livssyklusen på en enhet
Emulatorer kan etterligne tilkobling, men ikke samtykke- og tilbakekallingsveien overbevisende, så kjør disse på en ekte enhet med en annen VPN-klient installert for å stjele plassen.
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
Start tunnelen, bekreft varselet og grensesnittet, koble deretter til den andre klienten og se om tilbakekallingstilbakeringingen kjører og tilstanden tømmes. Tvangsstopp appen og sjekk om noe fortsatt rapporterer en levende beskrivelse.
Gjenta sekvensen etter en alltid-på-omstart, fordi den veien er forskjellig fra en brukerstartet tilkobling. Det du leter etter, er ikke et grønt ikon, men bevis på at appen sluttet å bruke en beskrivelse den ikke lenger eide.