बहुतेक Android ॲप्स VPN ओळखण्यासाठी जी तपासणी वापरतात ती इंटरफेसचे नाव आहे, आणि ती कधीही VPN तपासणी नव्हती. विकसकाने अपेक्षित असलेल्या स्ट्रिंगसह काही इंटरफेस अस्तित्वात आहे असे ती नोंदवते, ज्याचा एका उपकरणावर अर्थ OpenVPN आणि दुसऱ्यावर पूर्णपणे असंबंधित गोष्ट असा होतो. ping हा त्याच प्रकारचा पुरावा आहे: एक गंतव्यस्थानाने उत्तर दिले हे तो सिद्ध करतो, टनेलने पॅकेट नेले हे नाही. प्लॅटफॉर्म प्रत्यक्षात जे उघड करते ते म्हणजे नेटवर्कचा संच आणि प्रत्येकाने घोषित केलेले ट्रान्सपोर्ट, आणि हा वेगळ्या उत्तरासह वेगळा प्रश्न आहे.

गैरसमज: tun0 असेल तर VPN सुरू आहे

Android VPN ॲप्स ही VpnService अंमलबजावणी आहेत जी सिस्टमला tun फाइल डिस्क्रिप्टर देतात. इंटरफेसचे नाव ते तयार करणाऱ्याकडून येते: OpenVPN सामान्यतः tun0 तयार करते, PPTP आणि L2TP ppp0 तयार करतात, WireGuard आपल्या इंटरफेसला टनेलचे नाव देतो, आणि IPsec टनेल पारंपरिक नावच देत नाही असे होऊ शकते. म्हणून /proc/net/dev वाचणे किंवा NetworkInterface ऑब्जेक्ट मोजणे हे तथ्य नाही, परंपरा शोधते.

चुकीच्या दोन्ही दिशा जिवंत आहेत. उपकरणात वापरकर्त्याच्या VPN शी काहीही संबंध नसलेल्या स्थानिक टनेलसाठी tun0 असू शकतो, आणि पूर्णपणे निरोगी WireGuard टनेल फक्त tun0 स्ट्रिंग ओळखणाऱ्या तपासणीला अदृश्य असू शकते. एकाच फंक्शनमध्ये खोटे सकारात्मक आणि खोटे नकारात्मक परिणाम त्याला निदान म्हणून निरुपयोगी बनवतात, कारण «VPN आढळला नाही» असे म्हणणाऱ्या सपोर्ट तिकिटावर कोणत्याही दिशेने विश्वास ठेवता येत नाही.

प्रवेशही अरुंद झाला आहे. नवीन Android आवृत्त्या सामान्य ॲप /proc मधून काय वाचू शकते हे मर्यादित करतात, त्यामुळे Android 8 वर चालणारी नाव-आधारित तपासणी कोड न बदलता नंतरच्या उपकरणावर रिकामी यादी परत करू शकते. तपासणी शांतपणे खुल्या बाजूला अयशस्वी झाल्यास, टनेल ठीक असलेल्या हार्डवेअरवर VPN नाही असा ॲपचा निष्कर्ष निघतो.

गैरसमज: यशस्वी ping म्हणजे टनेल ट्रॅफिक वाहत आहे

अंतर्गत होस्टला ping त्या होस्टकडे मार्ग असेल तेव्हाच यशस्वी होतो. विभाजित टनेलिंगमध्ये टनेल सुरू असून पूर्णपणे दुसरे काही करत असताना होस्ट Wi-Fi द्वारे पोहोचण्यायोग्य असू शकतो. प्रति-ॲप VPN मध्ये ping करणारे ॲप टनेलमधून वगळले जाऊ शकते, त्यामुळे ICMP प्रतिध्वनी त्याच्या बाहेर जाऊन परत येतो, जे तपासणी गृहीत धरते त्याच्या उलट सिद्ध करते.

ICMP आणि TCP देखील स्वतंत्रपणे फिल्टर होतात. प्रतिध्वनी विनंत्या अनुमत करणारे पण सेवेला आवश्यक असलेला TCP पोर्ट सोडणारे टनेल ping चाचणी उत्तीर्ण होईल आणि ॲपमध्ये अयशस्वी होईल, आणि हा उपकरणाचा गुणधर्म नसून पलीकडचा फायरवॉल नियम आहे. यशस्वी ping चा एकमेव प्रामाणिक अर्थ म्हणजे हे गंतव्यस्थान या क्षणी या प्रोटोकॉलला उत्तर दिले.

प्लॅटफॉर्म प्रत्यक्षात काय नोंदवते

API 21 पासून ConnectivityManager.getAllNetworks() सिस्टमला माहीत असलेले प्रत्येक नेटवर्क परत करते, आणि getNetworkCapabilities(network) ते नेटवर्क काय घोषित करते ते नोंदवते. VPN नेटवर्क TRANSPORT_VPN धारण करते. सर्व नेटवर्कवर फिरून एका प्रश्नाचे उत्तर मिळते: या उपकरणावर सध्या कोणतेही VPN सुरू आहे का?

दुसऱ्या, अधिक अरुंद प्रश्नासाठी वेगळा कॉल आवश्यक आहे. getActiveNetwork() ॲपचा ट्रॅफिक सध्या वापरणारे नेटवर्क परत करते, आणि त्यावर तीच क्षमता तपासल्यास उत्तर मिळते: माझा ट्रॅफिक VPN मधून जाईल का? दोन्ही जुळण्याची गरज नाही, आणि तो फरक माहितीपूर्ण आहे. सुरू असलेला पण सध्याचा नसलेला VPN प्रति-ॲप राउटिंग किंवा विभाजित-टनेल कॉन्फिगरेशनकडे निर्देश करतो, गहाळ टनेलकडे नाही.

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

दोन्ही कॉलचे संरक्षण करा. यादी करणे आणि विचारणे यामध्ये गायब झालेल्या नेटवर्कसाठी क्षमता null असू शकतात, आणि हस्तांतरणादरम्यान सक्रिय नेटवर्क null असू शकते. NET_CAPABILITY_NOT_VPN विरुद्ध दिशेने उपयुक्त आहे, नेटवर्कमध्ये VPN ट्रान्सपोर्ट ध्वज नाही एवढेच नाही तर ते निश्चितपणे टनेल नाही याची पुष्टी करण्यासाठी.

NetworkInfo API सह तोच गैरसमज होता

NetworkInfo सह ConnectivityManager.TYPE_VPN या तपासणीची दुसरी पिढी आहे, आणि ती कारणाने अप्रचलित झाली आहे. आधुनिक आवृत्त्यांमध्ये टनेल जोडलेले असतानाही VPN साठी परत केलेला ऑब्जेक्ट null असू शकतो, त्यामुळे null ला «VPN नाही» असे मानणारा कोड उत्तर सर्वाधिक महत्त्वाचे असलेल्या उपकरणांवर शांतपणे खोटे नकारात्मक नोंदवतो.

सहसा त्यासोबत येणारा प्रसारणही चांगला नाही. CONNECTIVITY_CHANGE ला VPN संक्रमण चुकवण्याचा दस्तऐवजी इतिहास आहे, ज्यात प्रत्येक नेटवर्क बदलावर नव्हे तर फक्त VPN जोडल्यावर किंवा तुटल्यावर सक्रिय होणाऱ्या बिल्डचाही समावेश आहे. त्यावर बांधलेला श्रोता पुढील पूर्ण पुनर्जोडणीपर्यंत प्लॅटफॉर्मच्या दृष्टिकोनापासून दूर जाणारे स्थिती चल तयार करतो.

पोलिंगऐवजी कॉलबॅकवर प्रतिक्रिया द्या

TRANSPORT_VPN आवश्यक असलेली आणि NET_CAPABILITY_NOT_VPN काढून टाकणारी NetworkRequest नोंदवा, नंतर त्या विनंतीसह registerNetworkCallback कॉल करा. मग onAvailable आणि onLost घोषणा कधी बदलते ते सांगतात, आणि तीच घटना तुम्हाला खरोखर महत्त्वाची आहे. घटक थांबल्यावर कॉलबॅकची नोंदणी रद्द करा, अन्यथा ॲप मृत स्क्रीनचा संदर्भ ठेवते आणि कॉलबॅक सुरूच राहतो.

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

यासाठी ACCESS_NETWORK_STATE आवश्यक आहे, जी सामान्य परवानगी आहे: root नाही, वापरकर्ता संमती संवाद नाही, VPN परवानगी नाही. टाइमरवर पोलिंग हा लोक आश्रय घेतात तो पर्याय आहे, आणि तो बॅटरी जाळतो आणि तरीही अंतरापेक्षा लहान संक्रमण चुकवतो, आणि तेच वापरकर्ता नोंदवतो ते संक्रमण.

उत्तर अजूनही तुम्हाला काय सांगू शकत नाही

यापैकी कोणतेही API टनेल निरोगी आहे का, कोणत्या सर्व्हरवर संपते, किंवा विशिष्ट ॲपचा ट्रॅफिक त्यात आहे का हे नोंदवत नाही. VPN नेटवर्क उपयुक्त मार्गांशिवाय अस्तित्वात असू शकते, आणि प्रति-ॲप टनेल प्रश्न विचारणाऱ्या ॲपला वगळू शकते.

म्हणून तपासणीने काय पाहिले ते नोंदवा, फक्त बुलियन नाही. नेटवर्क ओळखकर्ता, घोषित ट्रान्सपोर्ट आणि ते नेटवर्क सक्रिय होते का हे लॉग करा. «VPN आढळला नाही» असे म्हणणारा अहवाल निरुपयोगी आहे, तर नेटवर्कने TRANSPORT_VPN घोषित केले पण getActiveNetwork() ने Wi-Fi परत केले असे म्हणणारा अहवाल थेट राउटिंगकडे किंवा वगळण्याच्या यादीकडे निर्देश करतो, आणि ती अशी दुरुस्ती आहे ज्यावर कोणी काम करू शकते.

संबंधित लेख