Jou program roep VpnService.prepare, kry ’n null terug, bou ’n tonnel, en die descriptor lyk geldig, tog bereik niks die bediener nie. Of prepare gee ’n Intent terug, die gebruiker keur dit goed, en establish misluk steeds. Albei uitkomste beteken gewoonlik dieselfde ding: ’n ander program besit reeds die VPN-koppelvlak vir hierdie gebruiker, en jou protect-oproepe merk sockets wat jou tonnel nie kan gebruik nie. Werk die kontroles hieronder in volgorde deur en stop by die eerste een wat misluk, want ’n latere stap kan nie ’n vroeëre een herstel nie.

Kontroleer die VPN-gleuf voordat jy protect aanraak

Android gee aan elke gebruiker presies een aktiewe VPN-koppelvlak. Dit is ’n platformreël, nie ’n toestemming wat jou program kan aanvra nie, so twee kliënte wat albei die tonnel wil wees, kan nie saam bestaan nie.

’n Altyd-aan-VPN wat vir ’n ander program gestel is, is die moeilikste geval, want die stelsel hou daardie program gekoppel en weier ’n oorname. ’n Verkeersfilter soos AdGuard, ’n korporatiewe kliënt of ’n verbruiker-VPN kan die gleuf hou terwyl die gebruiker vergeet het dat dit geïnstalleer is. Vra die gebruiker om Instellings oop te maak en die inskrywing onder VPN te lees; die naam daar is die eienaar met wie jy meeding. Totdat daardie inskrywing ontkoppel word of die altyd-aan-instelling skoongemaak word, kan jou VpnService nie die koppelvlak word nie.

Stap 1: lees wat prepare teruggee

VpnService.prepare beantwoord ’n enkele vraag: mag hierdie program die VPN word? Dit gee null terug wanneer toestemming reeds bestaan, en ’n Intent wanneer die gebruiker dit nog moet goedkeur, wat jy met startActivityForResult moet begin. Behandel ’n null-teruggawe as toestemming om voort te gaan, nie as bewys dat establish sal slaag nie.

Intent intent = VpnService.prepare(context);
if (intent != null) {
    startActivityForResult(intent, REQUEST_VPN);
}

As die Intent-pad terugkeer en die gebruiker het geweier, sal prepare by die volgende poging weer ’n Intent gee. Teken die resultaatkode aan eerder as om in ’n lus te herprobeer, want ’n geweierde toestemming is ’n gebruikersbesluit, nie ’n tydelike fout nie.

Stap 2: bevestig die koppelvlak behoort aan jou program

Ná establish is die ParcelFileDescriptor wat jy ontvang jou bewys van eienaarskap, en dit is die moeite werd om dit voor enige socket-werk na te gaan. ’n Descriptor wat null is of reeds gesluit is, beteken die koppelvlak is nooit geskep nie, selfs al het geen uitsondering opgeduik nie. Vergelyk die koppelvlaknaam van die bouer met die een wat die stelsel vir die aktiewe VPN rapporteer, met dumpsys op ’n toestel. As hulle verskil, is die tonnel wat jy gebou het nie die tonnel wat verkeer dra nie.

adb shell dumpsys connectivity

Dieselfde wanverhouding verklaar ’n gekoppelde ikoon met dooie verkeer. Die stelsel wys die ander program se tonnel, terwyl jou kode ’n descriptor hou vir ’n koppelvlak wat dit nie besit nie.

Stap 3: roep protect voor connect

Sodra die koppelvlak bestaan, word sockets wat jou program oopmaak, by verstek in die tonnel in gelei. Die buitenste transport kan nie daardie reël volg nie, anders sou die ingekapselde pakket terug in die koppelvlak kring, daarom VpnService se protect merk ’n socket om die VPN te omseil en die onderliggende netwerk te gebruik. Die oproep gee ’n boolean terug, en om dit te ignoreer is hoe jy eindig met ’n socket wat gesond lyk en niks dra nie.

Roep protect voor connect of bind, nooit daarna nie. Beskerming moet in plek wees voordat die socket gekoppel of gebind word, want ’n gekoppelde socket het reeds sy roete gekies en ’n latere protect skuif dit nie betroubaar nie. As protect false teruggee, stop en hersien eienaarskap: dit misluk wanneer die koppelvlak nie aan jou program behoort nie, wat presies die toestand is wat ’n ander VPN agterlaat. ’n Valse teruggawe is ’n teken om terug te gaan na Stap 1, nie om dieselfde socket te herprobeer nie.

DatagramSocket socket = new DatagramSocket();
if (!vpnService.protect(socket)) {
    return;
}
socket.connect(serverAddress, serverPort);

Stap 4: bind ’n proses wanneer ’n socket ongemaklik is

Sommige transporte is nie ’n enkele socket nie: ’n biblioteek mag verskeie oopmaak, of jy wil hê elke verbinding in ’n hulpproses moet dieselfde uitgang gebruik. ConnectivityManager.bindProcessToNetwork bind die proses aan ’n gekose netwerk, en die ouer setProcessDefaultNetwork het dieselfde gedoen voordat dit uitgefaseer is. Vra die onderliggende verbinding met NET_CAPABILITY_NOT_VPN aan sodat die binding die netwerk onder jou tonnel kies eerder as die tonnel self.

NetworkRequest request = new NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();

’n Proses bind is nie ’n tweede VPN nie. Dit kies ’n uitgang vir daardie proses, wat nuttig is vir jou transport en nutteloos vir die gelyktydige bestuur van twee tonnels.

Maak die gebruiker se toestel reg, nie die kode nie

Daar is geen API wat twee programme die VPN-gleuf laat deel nie, so die regstelling hoort by die toestelstand. Bied die gebruiker twee konkrete paaie: ontkoppel of vee altyd-aan vir die ander program uit sodat jou prepare kan oorneem, of maak daardie program se per-program-instellings oop en sluit jou program van sy tonnel uit. Die uitsluiting hou die filter vir alles anders aan die gang en laat jou program die gewone verbinding gebruik, wat dikwels die uitkoms is wat die gebruiker eintlik wil hê.

Skryf albei paaie in jou ondersteuningsdokumentasie, want gebruikers weet selde watter program die VPN besit. Vra hulle om die aktiewe VPN-naam uit Instellings en die resultate van prepare, establish en protect uit jou logs te stuur, en jy kan binne ’n minuut sien watter stap gefaal het. Verifieer dan met regte verkeer: ’n naamsoektog, ’n TCP-verbinding en een versoek deur die tonnel, nie net ’n gekoppelde ikoon nie. ’n Geldige descriptor en ’n groen aanduiding bewys op sy beste eienaarskap, nooit dat die transport die roetereëls oorleef het nie.

As al vier kontroles slaag en verkeer sterf steeds, is eienaarskap nie meer jou probleem nie. Gaan voort na roetering en bedienerbereikbaarheid, en toets dieselfde geloofsbriewe vanaf ’n toestel sonder ’n VPN-program.

Verwante artikels