Android VpnService ले केही ट्राफिक मात्र किन समात्छ, सबै किन होइन
रुट, DNS प्रविष्टि र प्रत्येक एपको दायराले कुन प्याकेट tun यन्त्रसम्म पुग्छन्, स्थानीय यन्त्र किन हराउँछन् र निर्माताले के अस्वीकार गर्छ भनेर निर्धारण गर्छ।
VpnService मा केही पनि आफैं ट्राफिक समात्दैन। यसले प्रणालीसँग tun इन्टरफेस माग्छ, त्यस इन्टरफेसलाई ठेगाना र रुटको समूह दिन्छ, र त्यही क्षणदेखि कर्नेलले ती रुटसँग मिल्ने हरेक प्याकेट एपले पढ्न सक्ने फाइल डिस्क्रिप्टरमा प्रतिलिपि गर्छ। एपको कोडले रुटले नछानिएका प्याकेट कहिल्यै देख्दैन, त्यसैले टनेलको दायरा प्रोग्रामिङको प्रश्न हुनुअघि राउटिङ तालिकाको प्रश्न हो। यसैले एउटै सेवा कार्यान्वयनले एउटा फोनमा सबै प्रवाह निल्न सक्छ र अर्कोमा एउटा भाग मात्र, र यसैले रुट थप्दा कहिलेकाहीँ बिग्रिएको देखिने टनेल सुधारिन्छ। तपाईंले पाउने भनेको तपाईंले घोषणा गरेको नै हो, निर्माताले चुपचाप अस्वीकार गरेको सबै घटाएर।
कुन प्याकेट आउने भन्ने रुटले निर्धारण गर्छ
Builder.addRoute(prefix, prefixLength) ले VPN सञ्जालको राउटिङ तालिकामा प्रिफिक्स स्थापना गर्छ। प्रणालीले त्यो सञ्जाललाई दायराभित्रका एपका लागि पूर्वनिर्धारित मान्छ, त्यसैले यसका प्रविष्टि भौतिक सञ्जालको पूर्वनिर्धारित रुटभन्दा अघि हेरिन्छ र मिल्ने प्रिफिक्सले प्रवाह मोड्न पर्याप्त हुन्छ। त्यसैले 0.0.0.0/0 का लागि रुटले IPv4 पूरै लिन्छ, प्रिन्टर, cast लक्ष्य र राउटरको एडमिन पृष्ठ सहित।
भौतिक पूर्वनिर्धारित प्रविष्टि नमेटी त्यो कभरेज चाहने ग्राहकहरूले यसको सट्टा 0.0.0.0/1 र 128.0.0.0/1 जोडी प्रयोग गर्छन्। दुई बढी विशिष्ट रुटले पूर्वनिर्धारित रुटलाई हराउँछन्, सँगै तिनीहरूले सम्पूर्ण ठेगाना क्षेत्र ढाक्छन्, र फोनको आफ्नै पूर्वनिर्धारित प्रविष्टि भौतिक सञ्जालमा बाँधिएका सकेटका लागि तालिकामा रहन्छ।
ठेगाना र DNS प्रविष्टि एउटै निर्माताबाट आउँछन् र अर्को प्रश्नको जवाफ दिन्छन्। addAddress ले इन्टरफेसलाई प्रिफिक्स लम्बाइसहित ठेगाना दिन्छ, र addDnsServer ले दायराभित्रका एपहरूले इन्टरफेसबाट सोध्ने समाधानकर्ता स्थापना गर्छ। दुवै परिवार एउटै इन्टरफेसमा बस्न सक्छन्, त्यसैले IPv6 ठेगानाको छेउमा IPv4 मात्र रुटको समूह ठीक पढिने र तैपनि चुहिने कन्फिगरेसन हो। इन्टरफेसमा ठेगाना नभएको परिवार रुट गरेमा कर्नेलसँग ती प्याकेटका लागि स्रोत ठेगाना हुँदैन र ती डिस्क्रिप्टरमा कहिल्यै देखिँदैनन्।
establish() ले के फर्काउँछ
establish() ले ParcelFileDescriptor फर्काउँछ, वा एप अधिकृत नभएमा null फर्काउँछ। null सञ्जाल त्रुटि होइन, सहमतिको स्थिति हो: VpnService.prepare() ले पहिले नै null फर्काइसकेको हुनुपर्छ, वा प्रयोगकर्ताले कलअघि प्रणाली संवाद स्वीकृत गरेको हुनुपर्छ। सेवा चलिरहँदा सहमति फिर्ता लिन सकिन्छ, र इन्टरफेस तपाईंको पढाइ लुपमा कुनै कलब्याक बिना तपाईंको खुट्टामुनि बन्द हुन्छ।
तपाईंले अन्यथा नभनेसम्म डिस्क्रिप्टर ब्लक गर्दैन, त्यसैले पढाइ थ्रेड रोक्नुको सट्टा डेटाबिना तुरुन्तै फर्कन्छ। ब्लकिङ सकेटका लागि लेखिएको लुपले एउटा कोर जलाउँछ, र खाली पढाइलाई घातक मान्ने लुपले निष्क्रिय सेकेन्डमा टनेल च्यात्छ। Builder.setBlocking(true) ले त्यो व्यवहार बदल्छ, र मूल्य पढाइभित्र पर्खने थ्रेड हो।
रुट र ठेगाना तर्कहरू LinkAddress मानका रूपमा प्रमाणित हुन्छन्, र 224.0.0.0/4 जस्ता मल्टिकास्ट गन्तव्य सिधै अस्वीकार गरिन्छन्। पोइन्ट-टु-पोइन्ट tun इन्टरफेसमा पनि ब्रोडकास्ट डोमेन हुँदैन, त्यसैले यसबाट मल्टिकास्ट पत्ता लगाउन अर्को रुट होइन, फरक डिजाइन चाहिन्छ। जाँच्ने सूची VpnService.Builder हो, कुनै कल बेवास्ता गरियो भन्ने निष्कर्षमा पुग्नुअघि।
एपअनुसारको दायराले समूह साँघुरो बनाउँछ, टनेल होइन
API 21 देखि निर्माताले addAllowedApplication र addDisallowedApplication स्वीकार गर्छ, र दुवै सूची एउटै निर्मातामा परस्पर विशिष्ट छन्। अनुमति सूचीले ती प्याकेटका लागि टनेल राख्छ जबकि बाँकी सबै भौतिक सञ्जाल राख्छ; निषेध सूचीले नाम दिइएका प्याकेटबाहेक सबै समात्छ, जसलाई ग्राहकले विभाजित टनेलिङका रूपमा दिन्छ। API 21 अघि प्लेटफर्मको कुनै संयन्त्र हुँदैन, र एपअनुसारको व्यवहार आफ्नै फर्वार्डरभित्र UID अनुसार फिल्टर गर्ने तेस्रो पक्षका ग्राहकबाट आएको थियो। डिबग गर्दा यो भिन्नता महत्त्वपूर्ण छ, किनकि एउटा प्याकेटको अनुमति सूचीसहितको एपअनुसारको टनेलले लगभग ट्राफिक उत्पादन गर्दैन र त्यो सही व्यवहार हो, बिग्रिएको रुट होइन।
दायरा जे भए पनि, तपाईंको एपले VPN सर्भरतर्फ खोल्ने सकेटले आफूले बनाइरहेको टनेलबाट जानु हुँदैन। VpnService.protect(socket) ले त्यो सकेटलाई अन्तर्निहित सञ्जालसँग बाँध्छ ताकि यसका प्याकेटले tun यन्त्र छोड्छन्। कल छोडिदिनुभयो भने ह्यान्डसेकलाई त्यो इन्टरफेसले निल्छ जसले यसलाई उठाउनुपर्ने थियो।
VpnService.setUnderlyingNetworks ले कुन भौतिक सञ्जालले टनेल बोक्छ भनी प्रणालीलाई भनेर वृत्त बन्द गर्छ। त्यो मानले VPN ले अन्य एपलाई जडानबारे कसरी रिपोर्ट गर्छ भन्ने निर्धारण गर्छ, र null वा पुरानो मान फोनको बाँकी भागले अफलाइन ठान्ने जडिएको टनेलको सामान्य कारण हो। अन्तर्निहित सञ्जाल बदलिँदा यसलाई अद्यावधिक गर्नुहोस्, सुरुमा मात्र होइन।
चेकसम र MTU: जहाँ सही रुट पनि असफल हुन्छ
प्याकेट आएपछि प्याकेट तहका दुई विवरणले केही कुरा टुप्पोदेखि टुप्पोसम्म चल्छ कि भन्ने निर्धारण गर्छन्। पहिलो स्रोत ठेगाना हो: धेरै इन्टरफेस ठेगाना भएमा कर्नेलले पहिलो बोक्ने प्याकेट पठाउन सक्छ, त्यसैले हेडर पुनर्लेखन गर्ने फर्वार्डरले ठेगाना र त्यसलाई ढाक्ने चेकसम सुधार्नुपर्छ।
दोस्रो चेकसमको दायरा हो। एपले आफैं TCP वा UDP प्याकेट बनाउँदा चेकसमले स्रोत ठेगाना, गन्तव्य ठेगाना, प्रोटोकल नम्बर र यातायात लम्बाइ भएको स्युडो-हेडर ढाक्छ, र तीमध्ये कुनै पनि छोड्दा आएर फालिने प्याकेट प्राप्त हुन्छ। त्यो असफलता कहिल्यै नआउने जवाफपछिको समय-सीमाजस्तो देखिन्छ, र यसले धेरैलाई रुटतर्फ फर्काउँछ। setMtu ले इन्टरफेसको MTU निर्धारण गर्छ, र प्रत्येक पढाइले ठ्याक्कै एउटा पूर्ण IP प्याकेट फर्काउँछ, त्यसैले बाइट प्रवाहका लागि लेखिएको बफरले प्याकेट होइन, तपाईंको पार्सिङ टुक्र्याउँछ।
तहहरू अलग्याउने प्रमाणीकरण चक्र
दायरा कहाँ बिग्रियो भनेर पत्ता लगाउन तहहरू क्रममा परीक्षण गर्नुहोस्। VPN सञ्जालले वास्तवमै कुन रुट राख्छ भनी यन्त्रलाई सोध्नुहोस्, त्यसपछि ज्ञात ठेगानातर्फको प्रवाह डिस्क्रिप्टरमा पढाइका रूपमा देखिन्छ कि भनी जाँच्नुहोस्, त्यसपछि तपाईंको फर्वार्डरले पठाउने प्याकेट राम्रोसँग बनेको छ कि भनी जाँच्नुहोस्। रुटको समस्याले डिस्क्रिप्टरमा केही देखाउँदैन, जबकि चेकसमको समस्याले आएर हराउने प्याकेट देखाउँछ।
डिस्क्रिप्टरसम्म केही पुगेन भने शंकास्पद पढ्ने होइन, रुटको समूह हो: प्रिफिक्स पुष्टि गर्नुहोस्, एउटै परिवारमा ठेगाना छ भनी पुष्टि गर्नुहोस्, र एप तपाईंले तोकेको दायराभित्र छ भनी पुष्टि गर्नुहोस्। प्याकेट डिस्क्रिप्टरसम्म पुग्छन् तर केही फर्कँदैन भने फेरि रुट छुनुअघि protect() र अन्तर्निहित सञ्जालको मान जाँच्नुहोस्। टाढाको पक्षले विकृत प्याकेट रिपोर्ट गरेमा चेकसम र MTU हेर्ने ठाउँ हुन्। प्रत्येक तहमा एउटा परीक्षणले आधा दिनको अनुमान बचाउँछ।