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 पाहण्याची ठिकाणे आहेत। प्रत्येक स्तरावर एक तपासणी अर्धा दिवसाचा अंदाज वाचवते।