Fire føresetnader om Android VpnService kosta meg ein gong mesteparten av ei veke, og ingen av dei handla om nettverksprotokollen. Appen sa tilkopla, nøkkelikonet sat i statuslinja, og trafikken gjekk framleis ut over den vanlege ruta. Eg heldt fram med å føresetje at tunnelen var min til eg stoppa han, at rutene eg la til var rutene eg fekk, og at eit kall til stopSelf ville ta grensesnittet ned med seg. Tenesta oppførte seg nøyaktig som dokumentert. Den mentale modellen min var den øydelagde delen.

Myte 1: tunnelen blir oppe til du stoppar han

Android held eitt VPN-grensesnitt om gongen. Set opp eit nummer to, og plattforma set det ikkje i kø: ho deaktiverer ditt og kallar onRevoke() på tenesta di. Viss koden din berre riv ned ved eit knappetrykk, etterlèt ei overtaking ein deskriptor og ein lesetråd, og neste oppstart arvar båe.

VpnService-referansen seier uttrykkeleg at prepare() returnerer null når appen alt har samtykke, og ein Intent når brukaren framleis må godkjenne. Det samtykket kjem berre fram viss du leverer intensjonen gjennom startActivityForResult(). Hoppar du over overleveringa, returnerer establish() null, som blir lese som ein stille feil snarare enn eit løyveproblem.

Always-on VPN legg til ein eigar du ikkje styrer. Systemet kan hente tunnelen tilbake etter oppstart eller etter ein krasj, og det fortrengjer ein VPN-app brukaren starta for hand. Bygg onRevoke() slik at han lukkar dei same ressursane som den vanlege nedstenginga di, og handsam han som ein primær stoppveg i staden for eit hjørnetilfelle. Brukarar byter VPN-app; koden din må tole det.

Myte 2: addRoute fangar nøyaktig det du lista opp

Rutene avgjer kva pakkar som når deskriptoren din, og ein feil i omfanget gjev det vanvettige tilfellet der noko av trafikken går gjennom tunnelen og noko ikkje. addRoute("0.0.0.0", 0) tek heile IPv4, noko som tyder at kvar pakke no kjem til deg og må videresendast eller droppast. Ein /32 for éin einaste vert tek nesten ingenting, og alt anna oppfører seg som om VPN-en aldri vart installert.

Familiane blir talde kvar for seg. Ei rute berre for IPv4 lèt IPv6 bli på det underliggjande nettverket, så ein dobbeltstakka vert kan framleis slå opp og kople til utanfor tunnelen medan han ser perfekt tilkopla ut inni.

DNS følgjer same logikk. Tenarar lagde til med addDnsServer() går til apper som brukar resolvaren til tunnelen, medan ein app med eige kryptert DNS-endepunkt eller Private DNS sett til eit vertsnamn ignorerer dei heilt. Når namn feilar for éin app og verkar for ein annan, sjekk resolvarstien før du rører ei einaste rute.

Myte 3: reglar per app er ein brytar du kan vippe båe vegar

addDisallowedApplication() og addAllowedApplication() er to modus, ikkje to filter. Byggjaren godtek éin modell per tunnel, så ein app som vil ha alt utanom tre pakkar brukar den forbodne lista og lèt den tillatne lista vere tom. Dei to er gjensidig utelukkjande, og folk finn det ut ved køyring etter at innstillingsskjermen alt har tilbode båe brytarane.

Pakkesynlegheit bit òg. På Android 11 og nyare kan du berre namngje pakkar du ser, så ei utelatingsliste bygd på ei spørjing appen din ikkje har lov til å køyre, vil stille miste oppføringar. Samanlikn lista med det pakkehandsamaren faktisk returnerer før du stolar på ho.

Arbeidsprofilar deler publikum igjen. Ein tunnel starta inne i profilen dekkjer den profilen og appane hans, medan den personlege sida held si eiga tilkopling. Det er eit omfangsval som blir teke éin gong, og det høyrer i grensesnittet, ikkje i ein støttebillett.

Myte 4: stopSelf avsluttar tunnelen

Det gjer han ikkje. Grensesnittet lever i deskriptoren som establish() returnerer, og tenesteobjektet kan døy medan den deskriptoren blir verande open. Lukk ParcelFileDescriptor først, slepp referansen, join eller avbryt lese- og skrivetrådane, og kall deretter stopForeground(true) og stopSelf() i den rekkjefølgja.

Ein gløymd deskriptor er den vanlege grunnen til at ei teneste ser ut til å overleve si eiga stoppførespurnad, og han forklarer ei utdatert rute som lever lengre enn appen som la ho til.

Den motsette feilen er like vanleg: å lukke deskriptoren medan ein lesetråd er midt i ei lesing, og deretter la den tråden handsame eit unntak ingen har skrive handsaming for. Hald nedstengingsrekkjefølgja på éin stad, og la både brukarhandlinga og onRevoke() kalle inn i ho.

Kva du bør sjekke når tunnelen ser død ut

Vern langliva sockets med protect() før tunnelen kjem opp. Utan det blir eigen transporten til tunnelen ruta tilbake i tunnelen, og sambandet stoppar på ein måte som ser nøyaktig ut som ein tenarfeil. Test mot ei adresse som berre finst bak det eksterne nettverket, ikkje ein offentleg nettstad som svarar frå hurtigbufferen eller frå den underliggjande vegen.

Logg resultatet av establish(), rutene, dei utelukka pakkane og årsaka til nedstenginga. Dei fire linjene skil eit samtykkeproblem frå eit omfangsproblem og frå eit livssyklusproblem utan pakkefangst.

Relaterte artiklar