Ko'pchilik Android ilovalari VPN aniqlash uchun ishlatadigan tekshiruv interfeys nomidir va u hech qachon VPN tekshiruvi bo'lmagan. U dasturchi kutgan satrga ega qandaydir interfeys borligini xabar qiladi, bu bir qurilmada OpenVPN ma'nosini, boshqasida esa mutlaqo aloqasiz narsani bildiradi. ping ham xuddi shunday dalil: u bitta manzil javob berganini isbotlaydi, tunnel paketni olib o'tganini emas. Platforma aslida nima taqdim etsa, bu tarmoqlar to'plami va har birining e'lon qilgan transportlari, va bu boshqa javobli boshqa savol.

Afsona: tun0 mavjud bo'lsa, VPN yoqilgan

Android VPN ilovalari tizimga tun fayl deskriptorini beradigan VpnService tatbiqlaridir. Interfeys nomi uni yaratgan tomondan keladi: OpenVPN odatda tun0 yaratadi, PPTP va L2TP ppp0 yaratadi, WireGuard interfeysini tunnel nomi bilan ataydi, IPsec tunneli esa umuman odatiy nom ko'rsatmasligi mumkin. Shuning uchun /proc/net/dev o'qish yoki NetworkInterface obyektlarini sanash faktni emas, kelishuvni qidiradi.

Xatoning ikkala yo'nalishi ham tirik. Qurilmada foydalanuvchi VPN'iga aloqasi yo'q mahalliy tunnel uchun tun0 bo'lishi mumkin, va butunlay sog'lom WireGuard tunneli faqat tun0 satrini biladigan tekshiruv uchun ko'rinmas bo'lishi mumkin. Bitta funksiyadagi yolg'on musbat va yolg'on manfiy natijalar uni diagnostika sifatida yaroqsiz qiladi, chunki «VPN topilmadi» degan qo'llab-quvvatlash chiptasiga hech bir yo'nalishda ishonib bo'lmaydi.

Kirish ham toraydi. Yangi Android versiyalari oddiy ilova /proc'dan nimani o'qiy olishini cheklaydi, shuning uchun Android 8'da ishlagan nomga asoslangan tekshiruv kod o'zgartirilmasdan keyingi qurilmada bo'sh ro'yxat qaytarishi mumkin. Tekshiruv jimgina ochiq tomonga muvaffaqiyatsiz bo'lsa, ilova tunnel joyida bo'lgan apparatda VPN yo'q degan xulosaga keladi.

Afsona: muvaffaqiyatli ping tunnel trafikni tashiydi degani

Ichki xostga ping o'sha xostga yo'l mavjud bo'lganda muvaffaqiyatli bo'ladi. Bo'lingan tunnelda xost Wi-Fi orqali yetib boriladigan bo'lishi mumkin, tunnel esa yoqilgan va butunlay boshqa ish qilmoqda. Har bir ilova uchun VPN'da ping qilayotgan ilova tunneldan chiqarib tashlanishi mumkin, shuning uchun ICMP aks sadosi uning tashqarisiga chiqib qaytadi, bu tekshiruv taxmin qilgan narsaning aksini isbotlaydi.

ICMP va TCP ham alohida filtrlanadi. Aks-sado so'rovlariga ruxsat berib, xizmatga kerak bo'lgan TCP portini tashlab yuboradigan tunnel ping sinovidan o'tib, ilovada muvaffaqiyatsiz bo'ladi, va bu qurilma xossasi emas, qarshi tomondagi xavfsizlik devori qoidasi. Muvaffaqiyatli pingning yagona halol o'qilishi — bu manzil shu lahzada shu protokolga javob berdi.

Platforma aslida nima xabar qiladi

API 21'dan boshlab ConnectivityManager.getAllNetworks() tizim bilgan har bir tarmoqni qaytaradi, getNetworkCapabilities(network) esa o'sha tarmoq nima e'lon qilishini xabar qiladi. VPN tarmog'i TRANSPORT_VPN'ni olib yuradi. Barcha tarmoqlar bo'ylab aylanish bitta savolga javob beradi: bu qurilmada hozir biron VPN yoqilganmi?

Ikkinchi, torroq savol boshqa chaqiruvni talab qiladi. getActiveNetwork() ilova trafigi hozir ishlatadigan tarmoqni qaytaradi, va unda o'sha qobiliyatni tekshirish quyidagiga javob beradi: trafikim VPN orqali o'tadimi? Ikkalasi mos kelmasligi mumkin, va bu nomuvofiqlik ma'lumotlidir. Yoqilgan, lekin joriy bo'lmagan VPN har bir ilova uchun marshrutlashga yoki bo'lingan tunnel sozlamasiga ishora qiladi, yo'qolgan tunnelga emas.

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

Ikkala chaqiruvni himoya qiling. Qobiliyatlar ro'yxatlash va so'rash orasida yo'qolgan tarmoq uchun null bo'lishi mumkin, va faol tarmoq topshirish vaqtida null bo'lishi mumkin. NET_CAPABILITY_NOT_VPN qarama-qarshi yo'nalishda foydali — tarmoqda VPN transport bayrog'i yo'qligini emas, uning aniq tunnel emasligini tasdiqlash uchun.

NetworkInfo API bilan xuddi shu afsona edi

NetworkInfo bilan ConnectivityManager.TYPE_VPN bu tekshiruvning ikkinchi avlodi va u biron sababga ko'ra eskirgan. Zamonaviy versiyalarda tunnel ulangan bo'lsa ham VPN uchun qaytarilgan obyekt null bo'lishi mumkin, shuning uchun null'ni «VPN yo'q» deb qabul qiladigan kod javob eng muhim bo'lgan qurilmalarda jimgina yolg'on manfiy natija xabar qiladi.

Odatda u bilan birga keladigan eshittirish ham yaxshiroq emas. CONNECTIVITY_CHANGE'ning VPN o'tishlarini o'tkazib yuborish bo'yicha hujjatlashtirilgan tarixi bor, jumladan har bir tarmoq o'zgarishida emas, faqat VPN ulanganda yoki uzilganda ishga tushgan buildlar ham. Unga qurilgan tinglovchi keyingi to'liq qayta ulanishgacha platforma qarashidan uzoqlashadigan holat o'zgaruvchisini hosil qiladi.

So'rov o'rniga qayta qo'ng'iroqlarga javob bering

TRANSPORT_VPN talab qiladigan va NET_CAPABILITY_NOT_VPN'ni olib tashlaydigan NetworkRequest ro'yxatdan o'tkazing, so'ng o'sha so'rov bilan registerNetworkCallback'ni chaqiring. Shunda onAvailable va onLost e'lon qachon o'zgarishini aytadi, va bu sizni haqiqatan qiziqtiradigan hodisa. Komponent to'xtaganda qayta qo'ng'iroq ro'yxatini bekor qiling, aks holda ilova o'lik ekranga havola saqlaydi va qayta qo'ng'iroq davom etadi.

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

Bu ACCESS_NETWORK_STATE'ni talab qiladi, bu oddiy ruxsat: root yo'q, foydalanuvchi rozilik muloqoti yo'q, VPN ruxsati yo'q. Taymer bilan so'rov — odamlar murojaat qiladigan alternativa, u batareyani sarflaydi va intervaldan qisqa o'tishni baribir o'tkazib yuboradi, va bu foydalanuvchi xabar qiladigan o'tishning o'zi.

Javob hali sizga ayta olmaydigan narsa

Bu API'larning hech biri tunnel sog'lommi, qaysi serverda tugaydi yoki muayyan ilova trafigi uning ichidami, deb xabar qilmaydi. VPN tarmog'i foydali marshrutlarsiz mavjud bo'lishi mumkin, va har bir ilova uchun tunnel savol berayotgan ilovani chiqarib tashlashi mumkin.

Shuning uchun tekshiruv ko'rgan narsani yozib oling, faqat mantiqiy qiymatni emas. Tarmoq identifikatorini, e'lon qilingan transportlarni va o'sha tarmoq faol bo'lganini jurnalga yozing. «VPN topilmadi» degan hisobot yaroqsiz, ammo tarmoq TRANSPORT_VPN e'lon qildi, lekin getActiveNetwork() Wi-Fi qaytardi degan hisobot to'g'ridan-to'g'ri marshrutlashga yoki chiqarib tashlash ro'yxatiga ishora qiladi, va bu kimdir ishlashi mumkin bo'lgan tuzatish.

O'xshash maqolalar