Android मा VPN पत्ता लगाउने: tun0 र ping किन भ्रमित गर्छन्
इन्टरफेसको नाम एउटा परम्परा हो; ping ले एउटा होस्ट पुग्न सकिने थियो भनी प्रमाणित गर्छ। नेटवर्कले के घोषणा गर्छ भनी NetworkCapabilities लाई सोध्नुहोस्, त्यसपछि कलब्याकमा प्रतिक्रिया दिनुहोस्।
अधिकांश 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 फर्कायो भन्ने रिपोर्टले सिधै राउटिङ वा बहिष्करण सूचीतर्फ संकेत गर्छ, र त्यो यस्तो सुधार हो जसमा कसैले काम गर्न सक्छ।