होइन, VpnService एपले फोनको VPN सक्रिय गर्न सक्दैन
एपले एउटा टनेल र त्यसको जीवनचक्रको स्वामित्व राख्छ, फोनको VPN स्विचको होइन। सहमति फिर्ता लिन सकिन्छ, एकै समयमा एउटै VPN चल्छ, र प्याकेट पार्स गर्ने काम तपाईंको हो।
गलत धारणा यो हो कि VpnService एपले सिस्टमको स्विच घुमाउँछ र त्यसपछि फोन सुरक्षित रहन्छ। वास्तवमा हुने कुरा अझ साँघुरो छ: एपले सहमति माग्छ, इन्टरफेस बनाउँछ, फाइल डिस्क्रिप्टरमार्फत प्याकेट पढ्छ र लेख्छ, र रोकिँदा इन्टरफेस फिर्ता दिन्छ। एकै समयमा यस्तो एउटै टनेल मात्र जीवित रहन सक्छ, र सिस्टमले नसोधी त्यो खोसेर लिन सक्छ। मानिसहरूले प्रोटोकलमाथि लगाउने भ्रमपूर्ण व्यवहारको ठूलो भाग यही स्वामित्व मोडेलबाट आउँछ।
प्रत्येक जीवनचक्र परिवर्तनलाई किनाराको अवस्था नभई डिजाइनको भाग मान्नुहोस्।
भ्रम: एपले फोनको VPN सक्रिय गर्छ
प्रवाह VpnService.prepare() बाट सुरु हुन्छ, जसले प्रयोगकर्ताले स्वीकार्नुपर्ने Intent फर्काउँछ, र establish() सँग अगाडि बढ्छ, जो पछि पनि एपले नियन्त्रण नगर्ने कारणले असफल हुन सक्छ। दोस्रो टनेल स्थापना गर्दा पहिलो इन्टरफेस निष्क्रिय हुन्छ र सिस्टम सूचना बदलिन्छ। त्यो क्रममा कतै पनि एपसँग पूरै यन्त्रको स्विच हुँदैन; उससँग दिइएको डिस्क्रिप्टर र त्यसमा आउने प्याकेटहरू हुन्छन्। स्थायी सूचना पनि एपको डिजाइनको नभई सिस्टमको हो।
इन्टरफेस खोसिने होइन, दिइने हुन्छ, त्यसैले अर्को क्लाइन्टले जुनसुकै बेला ठाउँ लिन सक्छ। एपले यो रिटर्न मानबाट होइन, कलब्याकबाट थाहा पाउँछ।
एप जबरजस्ती रोकिएको कुरा सूचना प्यानलमा देखिनुको कारण पनि त्यही हो: सिस्टमले आफूले के दियो भनेर जानकारी दिन्छ, एपले के देखाउने छान्यो भनेर होइन।
भ्रम: सहमति एक पटक मात्र दिइन्छ
सिस्टमले टनेल अर्को क्लाइन्टलाई सुम्पँदा, आधार वर्गले onBind() बाट फर्काउने binder मा रद्दीकरण कारोबार पठाउँछ। त्यो binder आफ्नैले प्रतिस्थापन गर्ने एपले रद्दीकरण कारोबार आफै अगाडि पठाउनुपर्छ, अन्यथा VpnService.onRevoke() कहिल्यै सक्रिय हुँदैन र सेवा अब नभएको डिस्क्रिप्टरमा लेखिरहन्छ। प्रयोगकर्ताले पनि स्वीकृति फिर्ता लिन सक्छ, र सिस्टमले पुनःसुरु वा सधैं-सक्रिय पुनःजडानका क्रममा सेवा रोक्न सक्छ।
यसलाई सम्हाल्नु लगको एक लाइन होइन, ठोस काम हो: डिस्क्रिप्टर पढ्न रोक्नुहोस्, बन्द गर्नुहोस्, जोडिएको झन्डा मेटाउनुहोस् र प्रयोगकर्तालाई कुन अवस्थामा छ भनेर बताउनुहोस्। त्यसपछि एपले पुनः स्थापना गर्ने, फेरि सोध्ने वा पर्खने निर्णय गर्नुहोस्, किनकि सधैं-सक्रिय कन्फिगरेसनमा सिस्टमले सेवा आफै फर्काउन सक्छ।
रद्दीकरणलाई अवस्था नभई अपवाद मान्ने एपले आफ्नो लेखिएको हरेक प्याकेट फालिँदा पनि जोडिएको भनी जानकारी दिन्छ, र गोपनीयता उपकरणका लागि यो सम्भव भएको सबैभन्दा नराम्रो असफलता मोड हो।
भ्रम: इन्टरफेसले तपाईंका लागि ट्राफिक छान्छ
आउने कुरा कच्चा IP हो। समात्नु वा छान्नु भनेको IP, TCP, UDP र IPv6 हेडर पार्स गर्नु, प्रवाह ट्र्याक गर्नु र जवाफ डिस्क्रिप्टरमा फर्काएर लेख्नु हो, जसले क्याप्चर एपलाई सिस्टम सुविधा नभई सानो नेटवर्क स्ट्याक बनाउँछ। protect() यसैका लागि छ कि एपको आफ्नै ट्रान्सपोर्ट सकेटले आफूलाई समात्नुको सट्टा आफ्नै टनेल छल्न सकोस्, र यसले टनेल उठेपछि बनाइने हरेक सकेटमा जाँच गर्न लायक बुलियन फर्काउँछ।
बिल्डरका अनुमति र निषेधित एप्लिकेसन सूचीहरूले कसको ट्राफिक इन्टरफेसमा पस्छ भनेर निर्धारण गर्छन्। तिनीहरूले इन्टरफेसले बोकेका IP प्याकेटभन्दा बाहिरको पेलोडमा पहुँच दिँदैनन्, र कुनै API ले अर्को क्लाइन्टको टनेल खुलाउँदैन वा सिस्टमका VPN प्रोफाइल सूचीबद्ध गर्छ। नेटवर्क क्षमताहरूले कुनै नेटवर्क VPN यातायात हो भन्न सक्छन्, तर टनेल कसको हो भन्न सक्दैनन्।
त्यसैले अरू एपका बारेमा सोधिएका स्थिति प्रश्नले विरोधाभासी उत्तर पाउँछन्: जानकारी तपाईंको प्रक्रियामा खुलाइएकै छैन।
जीवनचक्रले वास्तवमा के माग्छ
तपाईंले नियन्त्रण गर्ने अवस्थाहरू ट्र्याक गर्नुहोस्: तयार, स्थापित, रद्द, रोकिएको। पुनःजडान भनेको भत्काएर पुनः स्थापना गर्नु हो, डिस्क्रिप्टर र ट्रान्सपोर्ट सकेटको एउटै स्वामी राखेर, किनकि स्थापना गर्न प्रतिस्पर्धा गर्ने दुई घटक एउटै उपलब्ध ठाउँका लागि लड्छन्। आधुनिक Android मा पृष्ठभूमि सुरुवात सीमित छन्, त्यसैले बुट प्रसारण कुनै ग्यारेन्टी होइन; API स्तरले अनुमति दिने ठाउँमा यसको सूचनासहित अग्रभूमि सेवा प्रयोग गर्नुहोस्।
अन्तिम अवस्था मात्र होइन, परिवर्तन लग गर्नुहोस्, र हरेक मार्ग परीक्षण गर्न सकिने गरी अवस्था मेसिन सानो राख्नुहोस्। परीक्षणमा पुग्न नसकिने अवस्था लगबिना खेतमा भेटिने अवस्था हो।
यन्त्रामा जीवनचक्र परीक्षण गर्नुहोस्
इमुलेटरले जडान नक्कली बनाउन सक्छन्, तर सहमति र रद्दीकरणको मार्ग विश्वसनीय रूपमा होइन, त्यसैले यी काम ठाउँ चोर्न अर्को VPN क्लाइन्ट स्थापना गरिएको वास्तविक यन्त्रामा चलाउनुहोस्।
adb shell dumpsys connectivity | grep -i -A3 vpn
adb shell dumpsys activity services | grep -i -A2 vpnservice
adb logcat -s VpnService:V AndroidRuntime:E
adb shell am force-stop com.example.vpnapp
टनेल सुरु गर्नुहोस्, सूचना र इन्टरफेस पुष्टि गर्नुहोस्, त्यसपछि अर्को क्लाइन्ट जोड्नुहोस् र रद्दीकरण कलब्याक चल्छ कि अवस्था मेटिन्छ हेर्नुहोस्। एप जबरजस्ती रोक्नुहोस् र अझै जीवित डिस्क्रिप्टरको जानकारी कसैले दिन्छ कि जाँच्नुहोस्।
सधैं-सक्रिय पुनःसुरु पछि क्रम दोहोर्याउनुहोस्, किनकि त्यो मार्ग प्रयोगकर्ताले सुरु गरेको जडानभन्दा फरक हुन्छ। तपाईं हरियो चिन्ह होइन, एपले अब आफ्नो नभएको डिस्क्रिप्टर प्रयोग गर्न छाडेको प्रमाण खोजिरहनुभएको छ।