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 देखने की जगहें हैं। हर स्तर पर एक जाँच आधे दिन का अनुमान बचाती है।