Kontrola, ktorú väčšina aplikácií pre Android používa na zistenie VPN, je názov rozhrania a nikdy nebola kontrolou VPN. Hlási, že existuje nejaké rozhranie s reťazcom, ktorý vývojár očakával, čo na jednom zariadení znamená OpenVPN a na inom niečo úplne nesúvisiace. Ping je rovnaký druh dôkazu: dokazuje, že jedna destinácia odpovedala, nie že paket preniesol tunel. Čo platforma skutočne vystavuje, je množina sietí a transporty, ktoré každá z nich deklaruje, a to je iná otázka s inou odpoveďou.

Mýtus: ak existuje tun0, VPN je aktívna

Aplikácie VPN pre Android sú implementácie VpnService, ktoré systému odovzdávajú deskriptor súboru tun. Názov rozhrania pochádza od toho, kto ho vytvoril: OpenVPN zvyčajne vytvára tun0, PPTP a L2TP vytvárajú ppp0, WireGuard pomenúva rozhranie podľa tunela a tunel IPsec nemusí mať vôbec žiadny konvenčný názov. Čítanie /proc/net/dev alebo vymenúvanie objektov NetworkInterface teda hľadá konvenciu, nie fakt.

Oba smery chyby sú živé. Zariadenie môže mať tun0 pre lokálny tunel, ktorý nemá nič spoločné s VPN používateľa, a úplne zdravý tunel WireGuard môže byť neviditeľný pre kontrolu, ktorá pozná iba reťazec tun0. Falošne pozitívne a falošne negatívne výsledky v tej istej funkcii ju robia nepoužiteľnou ako diagnostiku, pretože tiketu podpory, ktorý hovorí „VPN sa nenašla“, nemožno veriť v žiadnom smere.

Prístup sa tiež zúžil. Novšie verzie Androidu obmedzujú, čo bežná aplikácia môže čítať z /proc, takže kontrola založená na názve, ktorá fungovala na Androide 8, môže na neskoršom zariadení vrátiť prázdny zoznam bez akejkoľvek zmeny kódu. Keď kontrola ticho zlyhá v otvorenom smere, aplikácia usúdi, že na hardvéri, kde je tunel v poriadku, žiadna VPN nie je.

Mýtus: úspešný ping znamená, že tunel prenáša prevádzku

Ping na interný host uspeje vždy, keď existuje trasa k tomuto hostu. Pri rozdelenom tunelovaní môže byť host dostupný cez Wi-Fi, zatiaľ čo tunel beží a robí niečo úplne iné. Pri VPN pre jednotlivé aplikácie môže byť aplikácia, ktorá ping vykonáva, z tunela vylúčená, takže ICMP echo vychádza mimo neho a vracia sa, čo dokazuje opak toho, čo kontrola predpokladá.

ICMP a TCP sa tiež filtrujú oddelene. Tunel, ktorý povoľuje echo požiadavky, ale zahadzuje TCP port, ktorý služba potrebuje, prejde testom ping a zlyhá v aplikácii, a to je pravidlo firewallu na druhej strane, nie vlastnosť zariadenia. Jediné čestné čítanie úspešného pingu je, že táto destinácia v tomto okamihu odpovedala tomuto protokolu.

Čo platforma skutočne hlási

Od API 21 vracia ConnectivityManager.getAllNetworks() každú sieť, ktorú systém pozná, a getNetworkCapabilities(network) hlási, čo tá sieť deklaruje. Sieť VPN nesie TRANSPORT_VPN. Prechádzanie všetkých sietí odpovedá na jednu otázku: je na tomto zariadení práve teraz aktívna nejaká VPN?

Druhá, užšia otázka vyžaduje iné volanie. getActiveNetwork() vracia sieť, ktorú by prevádzka aplikácie použila práve teraz, a kontrola tej istej schopnosti na nej odpovedá: išla by moja prevádzka cez VPN? Obe sa môžu rozchádzať a toto rozchádzanie je informatívne. VPN, ktorá beží, ale nie je aktuálna, ukazuje na smerovanie pre jednotlivé aplikácie alebo na konfiguráciu rozdeleného tunela, nie na chýbajúci tunel.

Network active = cm.getActiveNetwork();
NetworkCapabilities caps = cm.getNetworkCapabilities(active);
boolean viaVpn = caps != null
    && caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);

Chráňte obe volania. Schopnosti môžu byť null pre sieť, ktorá zmizla medzi vymenovaním a dopytom, a aktívna sieť môže byť null počas odovzdávania. NET_CAPABILITY_NOT_VPN je užitočná v opačnom smere — na potvrdenie, že sieť rozhodne nie je tunelom, namiesto toho, aby jej len chýbal príznak transportu VPN.

NetworkInfo bol ten istý mýtus s API

ConnectivityManager.TYPE_VPN s NetworkInfo je druhá generácia tejto kontroly a je zastaraná z dobrého dôvodu. V moderných verziách môže byť objekt vrátený pre VPN null, zatiaľ čo tunel je pripojený, takže kód, ktorý null považuje za „žiadna VPN“, ticho hlási falošne negatívny výsledok na zariadeniach, kde je odpoveď najdôležitejšia.

Ani vysielanie, ktoré ju zvyčajne sprevádza, nie je lepšie. CONNECTIVITY_CHANGE má zdokumentovanú históriu vynechaných prechodov VPN, vrátane zostavení, v ktorých sa spúšťalo len pri pripojení alebo odpojení VPN, a nie pri každej zmene siete. Poslucháč postavený na ňom vytvára stavovú premennú, ktorá sa odchyľuje od pohľadu platformy až do ďalšieho úplného opätovného pripojenia.

Reagujte na spätné volania namiesto dopytovania

Zaregistrujte NetworkRequest, ktorý vyžaduje TRANSPORT_VPN a odstraňuje NET_CAPABILITY_NOT_VPN, a potom zavolajte registerNetworkCallback s touto požiadavkou. Potom vám onAvailable a onLost povedia, kedy sa deklarácia zmení, a to je udalosť, ktorá vás skutočne zaujíma. Zrušte registráciu spätného volania, keď komponent skončí, inak si aplikácia drží odkaz na mŕtvu obrazovku a spätné volanie sa stále spúšťa.

NetworkRequest req = new NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();
cm.registerNetworkCallback(req, callback);

To vyžaduje ACCESS_NETWORK_STATE, čo je bežné povolenie: žiadny root, žiadny dialóg so súhlasom používateľa, žiadne povolenie VPN. Dopytovanie na časovači je alternatíva, ku ktorej sa ľudia uchyľujú, a spotrebúva batériu, pričom stále vynecháva prechod kratší ako interval, a to je presne ten prechod, ktorý používateľ hlási.

Čo vám odpoveď stále nemôže povedať

Žiadne z týchto API nehlási, či je tunel zdravý, na ktorom serveri končí a či je prevádzka určitej aplikácie v ňom. Sieť VPN môže existovať bez použiteľných trás a tunel pre jednotlivé aplikácie môže vylúčiť aplikáciu, ktorá kladie otázku.

Preto zaznamenajte, čo kontrola videla, nielen boolovskú hodnotu. Zaznamenajte identifikátor siete, deklarované transporty a to, či bola táto sieť aktívna. Správa, ktorá hovorí „VPN sa nenašla“, je nepoužiteľná, zatiaľ čo správa, že sieť deklarovala TRANSPORT_VPN, ale getActiveNetwork() vrátil Wi-Fi, ukazuje priamo na smerovanie alebo na zoznam vylúčení, a to je oprava, na ktorej môže niekto pracovať.

Súvisiace články