तपाईंको एपले VpnService.prepare कल गर्छ, null पाउँछ, सुरुङ बनाउँछ, र डिस्क्रिप्टर मान्य देखिन्छ, तर सर्भरसम्म केही पुग्दैन। वा prepare ले Intent फर्काउँछ, प्रयोगकर्ताले त्यसलाई स्वीकृत गर्छ, र establish अझै असफल हुन्छ। दुवै नतिजाले सामान्यतया एउटै कुरा बुझाउँछन्: अर्को एपले यो प्रयोगकर्ताको VPN इन्टरफेस पहिले नै राखेको छ, र तपाईंका protect कलहरूले तपाईंको सुरुङले प्रयोग गर्न नसक्ने सकेटहरू चिन्ह लगाइरहेका छन्। तलका जाँचहरू क्रममा पूरा गर्नुहोस् र असफल हुने पहिलोमा रोक्नुहोस्, किनकि पछिको चरणले अघिल्लोलाई सुधार्न सक्दैन।

protect छुनु अघि VPN स्लट जाँच्नुहोस्

Android ले प्रत्येक प्रयोगकर्तालाई ठ्याक्कै एउटा सक्रिय VPN इन्टरफेस दिन्छ। यो प्लेटफर्मको नियम हो, तपाईंको एपले माग्न सक्ने अनुमति होइन, त्यसैले दुवै सुरुङ बन्न चाहने दुई क्लाइन्ट सँगै रहन सक्दैनन्।

अर्को एपका लागि सेट गरिएको सधैं-चालु VPN सबैभन्दा कठिन अवस्था हो, किनकि सिस्टमले त्यो एप जोडिएको राख्छ र अधिग्रहण अस्वीकार गर्छ। AdGuard जस्तो ट्राफिक फिल्टर, कर्पोरेट क्लाइन्ट वा उपभोक्ता VPN ले स्लट राख्न सक्छ, जब प्रयोगकर्ता यो इन्स्टल छ भन्ने बिर्सेको हुन्छ। प्रयोगकर्तालाई सेटिङ खोलेर VPN मुनि सूचीबद्ध प्रविष्टि पढ्न भन्नुहोस्; त्यहाँको नाम नै तपाईं प्रतिस्पर्धा गरिरहेको मालिक हो। त्यो प्रविष्टि डिस्कनेक्ट नभएसम्म वा सधैं-चालु सेटिङ मेटिएसम्म, तपाईंको VpnService इन्टरफेस बन्न सक्दैन।

चरण 1: prepare ले के फर्काउँछ पढ्नुहोस्

VpnService.prepare ले एउटै प्रश्नको उत्तर दिन्छ: के यो एप VPN बन्न सक्छ? सहमति पहिले नै भएमा यसले null फर्काउँछ, र प्रयोगकर्ताले अझै स्वीकृत गर्नुपर्ने भएमा Intent दिन्छ, जुन तपाईंले startActivityForResult सँग सुरु गर्नुपर्छ। null फिर्तीलाई अगाडि बढ्ने अनुमति मान्नुहोस्, establish सफल हुने प्रमाण होइन।

Intent intent = VpnService.prepare(context);
if (intent != null) {
    startActivityForResult(intent, REQUEST_VPN);
}

Intent मार्ग फर्किएर प्रयोगकर्ताले अस्वीकार गरेमा, अर्को प्रयासमा prepare ले फेरि Intent फर्काइरहन्छ। लुपमा फेरि प्रयास गर्नुको सट्टा नतिजा कोड लग गर्नुहोस्, किनकि अस्वीकृत सहमति प्रयोगकर्ताको निर्णय हो, क्षणिक त्रुटि होइन।

चरण 2: इन्टरफेस तपाईंको एपको हो भनी पुष्टि गर्नुहोस्

establish पछि प्राप्त ParcelFileDescriptor तपाईंको स्वामित्वको प्रमाण हो, र कुनै पनि सकेट काम अघि त्यो जाँच्नु उपयुक्त हुन्छ। null वा पहिले नै बन्द डिस्क्रिप्टर भन्नाको अर्थ इन्टरफेस कहिल्यै बनेन, कुनै अपवाद देखा नपरे पनि। builder को इन्टरफेस नाम सिस्टमले सक्रिय VPN का लागि बताउने नामसँग तुलना गर्नुहोस्, परीक्षण उपकरणमा dumpsys प्रयोग गरेर। यदि ती फरक छन् भने, तपाईंले बनाएको सुरुङ ट्राफिक बोक्ने सुरुङ होइन।

adb shell dumpsys connectivity

त्यही असंगतिले जोडिएको आइकनसँगै मृत ट्राफिकको व्याख्या गर्छ। सिस्टमले अर्को एपको सुरुङ देखाउँछ, जबकि तपाईंको कोडले आफ्नो नभएको इन्टरफेसको डिस्क्रिप्टर राख्छ।

चरण 3: connect अघि protect कल गर्नुहोस्

इन्टरफेस बनेपछि, तपाईंको एपले खोल्ने सकेटहरू पूर्वनिर्धारित रूपमा सुरुङमा रुट हुन्छन्। बाह्य ट्रान्सपोर्टले यो नियम पालना गर्न सक्दैन, नत्र इन्क्याप्सुलेटेड प्याकेट इन्टरफेसमा फर्केर आउँथ्यो, त्यसैले VpnService protect ले सकेटलाई VPN बाइपास गरी तल्लो नेटवर्क प्रयोग गर्न चिन्ह लगाउँछ। कलले boolean फर्काउँछ, र त्यसलाई बेवास्ता गर्नु नै स्वस्थ देखिने तर केही नबोक्ने सकेटसम्म पुग्ने बाटो हो।

connect वा bind अघि protect कल गर्नुहोस्, कहिल्यै पछि होइन। सकेट जोडिनु वा बाँधिनु अघि सुरक्षा ठाउँमा हुनुपर्छ, किनकि जोडिएको सकेटले आफ्नो मार्ग पहिले नै छानिसकेको हुन्छ र पछिको protect ले त्यसलाई भरपर्दो रूपमा सार्दैन। protect ले false फर्काएमा, रोक्नुहोस् र स्वामित्व फेरि जाँच्नुहोस्: इन्टरफेस तपाईंको एपको नभएमा यो असफल हुन्छ, र त्यही अवस्था अर्को VPN ले छोड्छ। false फिर्ती चरण 1 मा फर्कने सङ्केत हो, त्यही सकेट फेरि प्रयास गर्ने होइन।

DatagramSocket socket = new DatagramSocket();
if (!vpnService.protect(socket)) {
    return;
}
socket.connect(serverAddress, serverPort);

चरण 4: सकेट असहज हुँदा प्रक्रिया बाँध्नुहोस्

केही ट्रान्सपोर्ट एउटा सकेट हुँदैनन्: पुस्तकालयले धेरै खोल्न सक्छ, वा सहायक प्रक्रियाका हरेक जडानले एउटै निकास प्रयोग गरोस् भन्ने तपाईं चाहनुहुन सक्छ। ConnectivityManager.bindProcessToNetwork ले प्रक्रियालाई छानिएको नेटवर्कमा बाँध्छ, र पुरानो setProcessDefaultNetwork ले पनि त्यही काम गर्थ्यो, अप्रचलित हुनु अघि। तल्लो जडान NET_CAPABILITY_NOT_VPN सँग माग्नुहोस् ताकि बाँधाइले तपाईंको सुरुङमुनिको नेटवर्क छानोस्, सुरुङ आफैं होइन।

NetworkRequest request = new NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();

प्रक्रिया बाँध्नु दोस्रो VPN होइन। यसले त्यो प्रक्रियाका लागि निकास छान्छ, जुन तपाईंको ट्रान्सपोर्टका लागि उपयोगी छ र एकैचोटि दुई सुरुङ चलाउनका लागि अनुपयोगी।

कोडको मार्ग होइन, प्रयोगकर्ताको उपकरण सुधार्नुहोस्

दुई एपले VPN स्लट साझा गर्न दिने कुनै API छैन, त्यसैले सुधार उपकरणको अवस्थामा छ। प्रयोगकर्तालाई दुई ठोस मार्ग दिनुहोस्: अर्को एपको जडान काट्नुहोस् वा त्यसको सधैं-चालु मेट्नुहोस् ताकि तपाईंको prepare ले अधिग्रहण गर्न सकोस्, वा त्यो एपको प्रति-एप सेटिङ खोलेर तपाईंको एपलाई त्यसको सुरुङबाट बाहिर राख्नुहोस्। बहिष्करणले बाँकी सबैका लागि फिल्टर चलिराख्छ र तपाईंको एपलाई सामान्य जडान प्रयोग गर्न दिन्छ, जुन प्रायः प्रयोगकर्ताले साँच्चै चाहेको नतिजा हो।

दुवै मार्ग तपाईंको सहयोग कागजातमा लेख्नुहोस्, किनकि प्रयोगकर्तालाई कुन एप VPN को मालिक हो भन्ने विरलै थाहा हुन्छ। सेटिङबाट सक्रिय VPN नाम र तपाईंको लगबाट prepare, establish र protect का नतिजा पठाउन भन्नुहोस्, र एक मिनेटमै कुन चरण असफल भयो भन्न सक्नुहुन्छ। त्यसपछि वास्तविक ट्राफिकसँग प्रमाणित गर्नुहोस्: नाम खोज, TCP जडान र सुरुङबाट एउटा अनुरोध, केवल जोडिएको आइकन होइन। मान्य डिस्क्रिप्टर र हरियो सूचकले बढीमा स्वामित्व प्रमाणित गर्छन्, ट्रान्सपोर्ट रुटिङ नियमबाट बाँच्यो भन्ने कहिल्यै होइन।

चारै जाँच उत्तीर्ण भए र ट्राफिक अझै मर्छ भने, स्वामित्व अब तपाईंको समस्या होइन। रुटिङ र सर्भर पहुँचतर्फ जानुहोस्, र VPN एप इन्स्टल नभएको उपकरणबाट ती नै प्रमाणपत्रहरू जाँच्नुहोस्।

सम्बन्धित लेखहरू