Zbulimi i një VPN në Android: pse tun0 dhe ping mashtrojnë
Emri i ndërfaqes është një konventë; një ping provon që një host ishte i arritshëm. Pyetni NetworkCapabilities çfarë deklaron një rrjet, pastaj reagjoni ndaj callbacks.
Kontrolli që shumica e aplikacioneve Android përdorin për të zbuluar një VPN është një emër ndërfaqeje, dhe nuk ka qenë kurrë kontroll VPN. Ai raporton se ekziston një ndërfaqe me vargun që zhvilluesi priste, që në një pajisje do të thotë OpenVPN dhe në një tjetër do të thotë diçka krejt e palidhur. Një ping është i njëjti lloj prove: provon që një destinacion u përgjigj, jo që një tunel e transportoi paketën. Ajo që platforma ekspozon në të vërtetë është një grup rrjetesh dhe transportet që secili prej tyre deklaron, dhe kjo është një pyetje tjetër me një përgjigje tjetër.
Mit: nëse ekziston tun0, VPN është aktiv
Aplikacionet VPN për Android janë implementime të VpnService që i dorëzojnë sistemit një përshkrues skedari tun. Emri i ndërfaqes vjen nga ai që e krijoi: OpenVPN zakonisht prodhon tun0, PPTP dhe L2TP prodhojnë ppp0, WireGuard e emërton ndërfaqen sipas tunelit, dhe një tunel IPsec mund të mos paraqesë fare një emër konvencional. Prandaj leximi i /proc/net/dev ose numërimi i objekteve NetworkInterface kërkon një konventë, jo një fakt.
Të dy drejtimet e gabimit janë të gjalla. Një pajisje mund të ketë tun0 për një tunel lokal që nuk ka asnjë lidhje me VPN-në e përdoruesit, dhe një tunel WireGuard plotësisht i shëndoshë mund të jetë i padukshëm për një kontroll që njeh vetëm vargun tun0. Pozitivët e rremë dhe negativët e rremë në të njëjtin funksion e bëjnë atë të papërdorshëm si diagnostikim, sepse një tiketë mbështetjeje që thotë «asnjë VPN nuk u zbulua» nuk mund të besohet në asnjë drejtim.
Edhe aksesi është ngushtuar. Versionet më të reja të Android kufizojnë çfarë mund të lexojë një aplikacion i zakonshëm nga /proc, kështu që një kontroll i bazuar në emër që funksiononte në Android 8 mund të kthejë një listë bosh në një pajisje më të re pa asnjë ndryshim kodi. Kur kontrolli dështon në heshtje në anën e hapur, aplikacioni arrin në përfundimin se nuk ka VPN në harduerin ku tuneli është në rregull.
Mit: një ping i suksesshëm do të thotë që tuneli transporton trafik
Një ping drejt një hosti të brendshëm ka sukses sa herë që ekziston një rrugë drejt atij hosti. Me tunel të ndarë, hosti mund të jetë i arritshëm përmes Wi-Fi ndërsa tuneli është aktiv dhe bën diçka krejt tjetër. Me një VPN për çdo aplikacion, aplikacioni që bën ping mund të jetë i përjashtuar nga tuneli, kështu që jehona ICMP del jashtë tij dhe kthehet, gjë që provon të kundërtën e asaj që supozon kontrolli.
ICMP dhe TCP filtrohen gjithashtu veçmas. Një tunel që lejon kërkesat e jehonës por hedh portën TCP që i nevojitet një shërbimi do të kalojë testin e ping dhe do të dështojë në aplikacion, dhe ky është një rregull muri zjarri në anën tjetër, jo një veti e pajisjes. Leximi i vetëm i ndershëm i një ping të suksesshëm është se ky destinacion u përgjigj këtij protokolli në këtë moment.
Çfarë raporton në të vërtetë platforma
Nga API 21, ConnectivityManager.getAllNetworks() kthen çdo rrjet që sistemi njeh, dhe getNetworkCapabilities(network) raporton çfarë deklaron ai rrjet. Një rrjet VPN mban TRANSPORT_VPN. Kalimi nëpër të gjitha rrjetet përgjigjet një pyetjeje: a është aktiv ndonjë VPN në këtë pajisje tani?
Një pyetje e dytë, më e ngushtë kërkon një thirrje tjetër. getActiveNetwork() kthen rrjetin që trafiku i aplikacionit do të përdorte tani, dhe kontrollimi i të njëjtës aftësi në të përgjigjet: a do të kalonte trafiku im përmes një VPN? Të dyja mund të mos përputhen, dhe kjo mospërputhje është informuese. Një VPN aktiv por jo aktual tregon rrugëzim për çdo aplikacion ose një konfigurim tuneli të ndarë, jo një tunel që mungon.
Network active = cm.getActiveNetwork();
NetworkCapabilities caps = cm.getNetworkCapabilities(active);
boolean viaVpn = caps != null
&& caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
Mbrojini të dyja thirrjet. Aftësitë mund të jenë null për një rrjet që u zhduk midis listimit dhe pyetjes, dhe rrjeti aktiv mund të jetë null gjatë një kalimi. NET_CAPABILITY_NOT_VPN është i dobishëm në drejtimin tjetër, për të konfirmuar se një rrjet definitivisht nuk është tunel, në vend që thjesht t'i mungojë flamuri i transportit VPN.
NetworkInfo ishte i njëjti mit me një API
ConnectivityManager.TYPE_VPN me NetworkInfo është gjenerata e dytë e këtij kontrolli, dhe është vjetëruar për një arsye. Në versionet moderne objekti i kthyer për një VPN mund të jetë null ndërsa tuneli është i lidhur, kështu që kodi që e trajton null si «pa VPN» raporton në heshtje një negativ të rremë në pajisjet ku përgjigja ka më shumë rëndësi.
As transmetimi që zakonisht e shoqëron nuk është më i mirë. CONNECTIVITY_CHANGE ka një histori të dokumentuar të humbjes së kalimeve të VPN, duke përfshirë ndërtime ku ai shkëputej vetëm kur një VPN lidhej ose shkëputej në vend të çdo ndryshimi rrjeti. Një dëgjues i ndërtuar mbi të prodhon një variabël gjendjeje që largohet nga pikëpamja e platformës deri në rilidhjen e plotë të ardhshme.
Reagjoni ndaj callbacks në vend të sondimit
Regjistroni një NetworkRequest që kërkon TRANSPORT_VPN dhe heq NET_CAPABILITY_NOT_VPN, pastaj thirrni registerNetworkCallback me atë kërkesë. Atëherë onAvailable dhe onLost ju tregojnë kur ndryshon deklarata, dhe ky është ngjarja që ju intereson vërtet. Çregjistroni callback-un kur komponenti ndalon, përndryshe aplikacioni mban një referencë ndaj një ekrani të vdekur dhe callback-u vazhdon të aktivizohet.
NetworkRequest req = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(req, callback);
Kjo kërkon ACCESS_NETWORK_STATE, që është një leje normale: pa root, pa dialog pëlqimi të përdoruesit, pa leje VPN. Sondimi me një kohëmatës është alternativa të cilës njerëzit i drejtohen, dhe harxhon baterinë ndërsa vazhdon të humbasë një kalim më të shkurtër se intervali, dhe pikërisht ai është kalimi që raporton një përdorues.
Çfarë ende nuk mund t'ju thotë përgjigja
Asnjë prej këtyre API-ve nuk raporton nëse tuneli është i shëndoshë, në cilin server përfundon, ose nëse trafiku i një aplikacioni të caktuar është brenda tij. Një rrjet VPN mund të ekzistojë pa rrugë të përdorshme, dhe një tunel për çdo aplikacion mund të përjashtojë aplikacionin që bën pyetjen.
Prandaj regjistroni çfarë pa kontrolli, jo vetëm vlerën boolean. Regjistroni identifikuesin e rrjetit, transportet e deklaruara dhe nëse ai rrjet ishte aktiv. Një raport që thotë «asnjë VPN nuk u zbulua» është i papërdorshëm, ndërsa një që thotë se një rrjet deklaroi TRANSPORT_VPN por getActiveNetwork() ktheu Wi-Fi tregon drejtpërdrejt rrugëzimin ose një listë përjashtimesh, dhe ky është një korrigjim mbi të cilin dikush mund të punojë.