Semakan yang digunakan oleh kebanyakan aplikasi Android untuk mengesan VPN ialah nama antara muka, dan ia tidak pernah menjadi semakan VPN. Ia melaporkan bahawa ada antara muka dengan rentetan yang dijangka oleh pembangun, yang pada satu peranti bermaksud OpenVPN dan pada peranti lain bermaksud sesuatu yang tidak berkaitan sama sekali. ping ialah jenis bukti yang sama: ia membuktikan satu destinasi menjawab, bukan bahawa terowong membawa paket itu. Apa yang sebenarnya didedahkan platform ialah satu set rangkaian dan pengangkutan yang diisytiharkan oleh setiap satu, dan itu soalan lain dengan jawapan lain.

Mitos: jika tun0 wujud, VPN sedang aktif

Aplikasi VPN Android ialah pelaksanaan VpnService yang menyerahkan deskriptor fail tun kepada sistem. Nama antara muka datang daripada sesiapa yang menciptanya: OpenVPN biasanya menghasilkan tun0, PPTP dan L2TP menghasilkan ppp0, WireGuard menamakan antara muka mengikut terowong, dan terowong IPsec mungkin tidak memaparkan nama konvensional langsung. Jadi membaca /proc/net/dev atau menyenaraikan objek NetworkInterface mencari konvensyen, bukan fakta.

Kedua-dua arah kesilapan masih hidup. Peranti boleh mempunyai tun0 untuk terowong tempatan yang tiada kaitan dengan VPN pengguna, dan terowong WireGuard yang sihat sepenuhnya boleh tidak kelihatan kepada semakan yang hanya mengenal rentetan tun0. Positif palsu dan negatif palsu dalam fungsi yang sama menjadikannya tidak berguna sebagai diagnostik, kerana tiket sokongan yang berkata «tiada VPN dikesan» tidak boleh dipercayai ke mana-mana arah.

Akses juga telah menyempit. Keluaran Android yang lebih baharu mengehadkan apa yang boleh dibaca oleh aplikasi biasa daripada /proc, jadi semakan berasaskan nama yang berfungsi pada Android 8 boleh mengembalikan senarai kosong pada peranti yang lebih kemudian tanpa sebarang perubahan kod. Apabila semakan gagal secara senyap ke arah terbuka, aplikasi membuat kesimpulan tiada VPN pada perkakasan yang terowongnya baik.

Mitos: ping yang berjaya bermaksud terowong membawa trafik

ping ke hos dalaman berjaya setiap kali ada laluan ke hos itu. Dengan terowong berpecah, hos itu mungkin boleh dicapai melalui Wi-Fi semasa terowong aktif dan melakukan sesuatu yang sama sekali lain. Dengan VPN setiap aplikasi, aplikasi yang melakukan ping mungkin dikecualikan daripada terowong, jadi gema ICMP keluar di luarnya dan kembali, yang membuktikan sebaliknya daripada apa yang diandaikan oleh semakan.

ICMP dan TCP juga ditapis secara berasingan. Terowong yang membenarkan permintaan gema tetapi menggugurkan port TCP yang diperlukan oleh perkhidmatan akan lulus ujian ping dan gagal dalam aplikasi, dan itu ialah peraturan firewall di sebelah sana, bukan sifat peranti. Satu-satunya bacaan jujur bagi ping yang berjaya ialah destinasi ini menjawab protokol ini pada saat ini.

Apa yang sebenarnya dilaporkan platform

Dari API 21, ConnectivityManager.getAllNetworks() mengembalikan setiap rangkaian yang diketahui sistem, dan getNetworkCapabilities(network) melaporkan apa yang diisytiharkan oleh rangkaian itu. Rangkaian VPN membawa TRANSPORT_VPN. Menggelung semua rangkaian menjawab satu soalan: adakah mana-mana VPN sedang aktif pada peranti ini sekarang?

Soalan kedua yang lebih sempit memerlukan panggilan lain. getActiveNetwork() mengembalikan rangkaian yang akan digunakan oleh trafik aplikasi sekarang, dan menyemak keupayaan yang sama padanya menjawab: adakah trafik saya akan melalui VPN? Kedua-duanya boleh tidak bersetuju, dan ketidaksetujuan itu bermaklumat. VPN yang aktif tetapi bukan semasa menunjukkan penghalaan setiap aplikasi atau konfigurasi terowong berpecah, bukan terowong yang hilang.

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

Lindungi kedua-dua panggilan. Keupayaan boleh menjadi null untuk rangkaian yang hilang antara penyenaraian dan pertanyaan, dan rangkaian aktif boleh menjadi null semasa pemindahan. NET_CAPABILITY_NOT_VPN berguna ke arah lain, untuk mengesahkan rangkaian itu pasti bukan terowong dan bukannya hanya kekurangan bendera pengangkutan VPN.

NetworkInfo ialah mitos yang sama dengan API

ConnectivityManager.TYPE_VPN dengan NetworkInfo ialah generasi kedua semakan ini, dan ia usang atas sebab. Pada keluaran moden objek yang dikembalikan untuk VPN boleh menjadi null semasa terowong disambungkan, jadi kod yang menganggap null sebagai «tiada VPN» secara senyap melaporkan negatif palsu pada peranti yang jawapannya paling penting.

Siaran yang biasanya mengiringinya juga tidak lebih baik. CONNECTIVITY_CHANGE mempunyai sejarah terdokumentasi terlepas peralihan VPN, termasuk binaan yang hanya dicetuskan apabila VPN disambungkan atau diputuskan dan bukannya pada setiap perubahan rangkaian. Pendengar yang dibina di atasnya menghasilkan pemboleh ubah keadaan yang menjauh daripada pandangan platform sehingga penyambungan semula penuh seterusnya.

Bertindak balas terhadap callback dan bukannya melakukan tinjauan

Daftarkan NetworkRequest yang memerlukan TRANSPORT_VPN dan membuang NET_CAPABILITY_NOT_VPN, kemudian panggil registerNetworkCallback dengan permintaan itu. Kemudian onAvailable dan onLost memberitahu anda bila pengisytiharan berubah, dan itulah peristiwa yang benar-benar anda pedulikan. Nyahdaftar callback apabila komponen berhenti, jika tidak aplikasi menyimpan rujukan kepada skrin mati dan callback terus dicetuskan.

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

Ini memerlukan ACCESS_NETWORK_STATE, yang merupakan kebenaran biasa: tiada root, tiada dialog persetujuan pengguna, tiada kebenaran VPN. Tinjauan dengan pemasa ialah alternatif yang orang gunakan, dan ia membakar bateri sambil masih terlepas peralihan yang lebih pendek daripada selang, yang merupakan peralihan yang dilaporkan oleh pengguna.

Apa yang jawapannya masih tidak dapat memberitahu anda

Tiada satu pun API ini melaporkan sama ada terowong sihat, di pelayan mana ia berakhir, atau sama ada trafik aplikasi tertentu berada di dalamnya. Rangkaian VPN boleh wujud tanpa laluan yang boleh digunakan, dan terowong setiap aplikasi boleh mengecualikan aplikasi yang bertanya soalan itu.

Jadi rekod apa yang dilihat oleh semakan, bukan hanya boolean. Rekod pengecam rangkaian, pengangkutan yang diisytiharkan dan sama ada rangkaian itu aktif. Laporan yang berkata «tiada VPN dikesan» tidak berguna, manakala laporan yang berkata sesuatu rangkaian mengisytiharkan TRANSPORT_VPN tetapi getActiveNetwork() mengembalikan Wi-Fi menunjuk terus kepada penghalaan atau senarai pengecualian, dan itu ialah pembetulan yang boleh diusahakan oleh seseorang.

Artikel berkaitan