Ang pagsusuring ginagamit ng karamihang Android app upang matukoy ang VPN ay isang pangalan ng interface, at hindi ito kailanman naging pagsusuri ng VPN. Nag-uulat ito na may interface na may string na inaasahan ng developer, na sa isang device ay nangangahulugang OpenVPN at sa iba ay nangangahulugang isang bagay na walang kaugnayan. Ang ping ay parehong uri ng ebidensiya: pinapatunayan nitong may isang destinasyong sumagot, hindi na may tunnel na nagdala ng packet. Ang aktuwal na inilalantad ng platform ay isang set ng mga network at ang mga transport na idinedeklara ng bawat isa, at ibang tanong iyon na may ibang sagot.

Mito: kung may tun0, aktibo ang VPN

Ang mga VPN app sa Android ay mga implementasyon ng VpnService na nagbibigay sa system ng tun file descriptor. Ang pangalan ng interface ay nagmumula sa sinumang gumawa nito: karaniwang gumagawa ang OpenVPN ng tun0, gumagawa ang PPTP at L2TP ng ppp0, pinangalanan ng WireGuard ang interface nito ayon sa tunnel, at maaaring walang karaniwang pangalan ang isang IPsec tunnel. Kaya ang pagbasa ng /proc/net/dev o pag-enumerate ng mga NetworkInterface object ay naghahanap ng kombensiyon, hindi ng katotohanan.

Buhay ang dalawang direksiyon ng mali. Maaaring may tun0 ang isang device para sa lokal na tunnel na walang kaugnayan sa VPN ng user, at ang isang ganap na malusog na WireGuard tunnel ay maaaring hindi makita ng pagsusuring alam lamang ang string tun0. Ang mga false positive at false negative sa parehong function ay nagpapawalang-silbi rito bilang diagnostic, dahil ang support ticket na nagsasabing «walang VPN na natukoy» ay hindi mapagkakatiwalaan sa alinmang direksiyon.

Pumayat din ang access. Nililimitahan ng mga bagong release ng Android kung ano ang mababasa ng ordinaryong app mula sa /proc, kaya ang pagsusuring nakabatay sa pangalan na gumana sa Android 8 ay maaaring magbalik ng walang laman na listahan sa mas bagong device nang walang anumang pagbabago sa code. Kapag tahimik na nabigo ang pagsusuri sa bukas na panig, ipinapalagay ng app na walang VPN sa hardware kung saan maayos ang tunnel.

Mito: ang matagumpay na ping ay nangangahulugang nagdadala ng trapiko ang tunnel

Ang ping sa panloob na host ay nagtatagumpay sa tuwing may ruta papunta sa host na iyon. Sa split tunnelling, maaaring maabot ang host sa Wi-Fi habang aktibo ang tunnel at gumagawa ng ganap na ibang bagay. Sa VPN bawat app, maaaring hindi kasama sa tunnel ang app na nagpi-ping, kaya lumalabas ang ICMP echo sa labas nito at bumabalik, na nagpapatunay ng kabaligtaran ng ipinapalagay ng pagsusuri.

Hiwalay ding sinasala ang ICMP at TCP. Ang tunnel na nagpapahintulot ng mga echo request ngunit tinatanggihan ang TCP port na kailangan ng isang serbisyo ay papasa sa ping test at babagsak sa app, at iyon ay patakaran ng firewall sa kabilang panig, hindi katangian ng device. Ang tanging tapat na pagbasa ng matagumpay na ping ay sumagot ang destinasyong ito sa protocol na ito sa sandaling ito.

Ano ang aktuwal na iniuulat ng platform

Mula sa API 21, ibinabalik ng ConnectivityManager.getAllNetworks() ang bawat network na alam ng system, at iniuulat ng getNetworkCapabilities(network) kung ano ang idinedeklara ng network na iyon. Ang VPN network ay may TRANSPORT_VPN. Ang pag-ikot sa lahat ng network ay sumasagot sa isang tanong: may aktibong VPN ba sa device na ito ngayon?

Ang ikalawa, mas makitid na tanong ay nangangailangan ng ibang tawag. Ibinabalik ng getActiveNetwork() ang network na gagamitin ng trapiko ng app ngayon, at ang pagsuri ng parehong kakayahan doon ay sumasagot: dadaan ba ang trapiko ko sa VPN? Maaaring hindi magkasundo ang dalawa, at ang pagkakaibang iyon ay may impormasyon. Ang VPN na aktibo ngunit hindi kasalukuyan ay tumuturo sa routing bawat app o sa split-tunnel configuration, hindi sa nawawalang tunnel.

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

Protektahan ang dalawang tawag. Maaaring null ang mga kakayahan para sa network na nawala sa pagitan ng paglilista at pagtatanong, at maaaring null ang aktibong network habang naglilipat. Ang NET_CAPABILITY_NOT_VPN ay kapaki-pakinabang sa kabilang direksiyon, upang kumpirmahin na ang isang network ay talagang hindi tunnel kaysa kulang lamang sa flag ng transport na VPN.

Ang NetworkInfo ay ang parehong mito na may API

Ang ConnectivityManager.TYPE_VPN kasama ang NetworkInfo ay ang ikalawang henerasyon ng pagsusuring ito, at lipas na ito sa isang dahilan. Sa mga modernong release, ang object na ibinabalik para sa VPN ay maaaring null habang nakakonekta ang tunnel, kaya ang code na itinuturing na «walang VPN» ang null ay tahimik na nag-uulat ng false negative sa mga device kung saan pinakamahalaga ang sagot.

Hindi rin mas mabuti ang broadcast na karaniwang kasama nito. Ang CONNECTIVITY_CHANGE ay may dokumentadong kasaysayan ng pagmimintis ng mga pagbabago ng VPN, kabilang ang mga build kung saan nag-trigger lamang ito kapag kumonekta o nadiskonekta ang VPN sa halip na sa bawat pagbabago ng network. Ang listener na itinayo rito ay gumagawa ng state variable na lumalayo sa pananaw ng platform hanggang sa susunod na buong muling pagkonekta.

Tumugon sa mga callback sa halip na mag-poll

Magrehistro ng NetworkRequest na nangangailangan ng TRANSPORT_VPN at nag-aalis ng NET_CAPABILITY_NOT_VPN, pagkatapos ay tawagin ang registerNetworkCallback gamit ang kahilingang iyon. Pagkatapos ay sasabihin sa iyo ng onAvailable at onLost kung kailan nagbabago ang deklarasyon, at iyon ang event na talagang mahalaga sa iyo. I-unregister ang callback kapag huminto ang component, kung hindi ay may hawak na reference ang app sa patay na screen at patuloy na nag-trigger ang callback.

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

Nangangailangan ito ng ACCESS_NETWORK_STATE, na isang normal na pahintulot: walang root, walang dialog ng pahintulot ng user, walang pahintulot sa VPN. Ang pag-poll gamit ang timer ang alternatibong hinahawakan ng mga tao, at ito ay kumakain ng baterya habang namimintis pa rin ng pagbabagong mas maikli kaysa sa agwat, at iyon mismo ang pagbabagong iniuulat ng user.

Ano ang hindi pa masasabi ng sagot

Wala sa mga API na ito ang nag-uulat kung malusog ang tunnel, sa aling server ito nagtatapos, o kung nasa loob nito ang trapiko ng isang partikular na app. Maaaring umiral ang VPN network nang walang magagamit na ruta, at ang tunnel bawat app ay maaaring mag-alis sa app na nagtatanong.

Kaya itala kung ano ang nakita ng pagsusuri, hindi lamang ang boolean. Itala ang identifier ng network, ang mga idineklarang transport at kung aktibo ang network na iyon. Ang ulat na nagsasabing «walang VPN na natukoy» ay walang gamit, samantalang ang ulat na nagsasabing nagdeklara ang isang network ng TRANSPORT_VPN ngunit nagbalik ang getActiveNetwork() ng Wi-Fi ay direktang tumuturo sa routing o sa listahan ng pagbubukod, at iyon ay pagwawastong maaaring pagtrabahuhan ng isang tao.

Kaugnay na mga artikulo