Android VPN टनल से सबनेट को कैसे बाहर रखें
VpnService किसी रूट को बाहर नहीं कर सकता, इसलिए आप पूरक जोड़ते हैं: /8 के लिए आठ उत्पन्न प्रीफ़िक्स, साथ में IPv6, DNS और लुकअप जाँच जो बाकी को पकड़ती है।
Android के VpnService में कोई बहिष्करण रूट नहीं है, और API पढ़ने की कोई मात्रा एक भी नहीं बनाएगी। Builder.addRoute() टनल में हमेशा केवल गंतव्य जोड़ता है, इसलिए किसी LAN खंड को स्थानीय रखने का अर्थ है कि वह खंड कभी रूट सूची में नहीं आता। इसके बजाय आप खंड का पूरक जोड़ते हैं, जिसे सामान्य प्रीफ़िक्स के रूप में व्यक्त किया जाता है। काम अंकगणित है, और यह कुछ अनुमानित जगहों पर विफल होता है।
नीचे दी गई जाँचें क्रम से करें। हर एक मानती है कि पिछली टिकी, इसलिए नीचे लक्षणों को पैच करने के बजाय पहली विफलता पर रुकें।
टनल जो दावा करती है उसी से शुरू करें
0.0.0.0/0 को addRoute() में देना Android को बताता है कि हर IPv4 गंतव्य टनल का है। इसीलिए इतने सारे क्लाइंट विभाजित टनलिंग में अक्षम दिखते हैं: वे पूरा पता स्थान दावा करते हैं और फिर उसमें से घटाने की कोशिश करते हैं। बिल्डर में कुछ भी नहीं घटाता। जिस नेटवर्क को आप स्थानीय रखना चाहते थे उसके लिए अधिक विशिष्ट रूट लोगों की अपेक्षा के उलट करता है, क्योंकि सबसे लंबा मेल खाता प्रीफ़िक्स जीतता है और वह नेटवर्क टनल के अंदर पहुँच जाता है।
रूट सूची ही पूरी नीति है। इसके पीछे प्रति-गंतव्य वीटो नहीं है, और Builder संदर्भ ऐसी कोई विधि सूचीबद्ध नहीं करता जो एक दे।
प्रीफ़िक्स अंकगणित से पूरक बनाएँ
बहिष्कृत प्रीफ़िक्स का पूरक पता वृक्ष की जड़ तक के मार्ग पर उसके भाई-बहनों का समुच्चय है। 1 से बहिष्कृत लंबाई तक हर लंबाई के लिए, उस लंबाई का वह ब्लॉक लें जिसमें आपका प्रीफ़िक्स है, प्रीफ़िक्स के ठीक नीचे का बिट पलटें, और परिणाम दें। जब तक आप इसे चलाते नहीं, यह अमूर्त लगता है।
10.0.0.0/8 को बाहर रखने पर आठ रूट मिलते हैं: 128.0.0.0/1, 64.0.0.0/2, 32.0.0.0/3, 16.0.0.0/4, 0.0.0.0/5, 12.0.0.0/6, 8.0.0.0/7, 11.0.0.0/8। इनमें से कोई 10.0.0.0/8 नहीं रखता, और मिलकर वे बाकी सब कवर करते हैं।
आठ पंक्तियाँ किसी भी प्रीफ़िक्स के लिए वह सूची बनाती हैं:
import ipaddress
def complement(addr, length):
base = int(ipaddress.IPv4Address(addr))
out = []
for k in range(1, length + 1):
block = base & (0xFFFFFFFF << (32 - k))
sibling = block ^ (1 << (32 - k))
out.append(f"{ipaddress.IPv4Address(sibling)}/{k}")
return out
print(complement("10.0.0.0", 8))
रूट की संख्या प्रीफ़िक्स की लंबाई के बराबर होती है, और यही वह संख्या है जिस पर नज़र रखनी है। एक अकेला /21 बहिष्करण 21 रूट का खर्च लाता है और पठनीय रहता है। दस बहिष्करण कुछ सौ का खर्च ला सकते हैं, जिसका अर्थ आमतौर पर यह है कि नेटवर्क डिज़ाइन बदलना है, जनरेटर नहीं।
पता परिवार और टनल का दायरा जाँचें
IPv4 रूट IPv6 के लिए कुछ नहीं करते। अगर टनल IPv6 पता दावा करती है, तो IPv6 LAN प्रीफ़िक्स को अपना पूरक चाहिए, जो 128 बिट पर उसी अंकगणित से बनाया गया हो। कागज़ पर बहिष्करण काम करने और स्थानीय डिवाइस पहुँच से बाहर रहने का एक आम कारण यह है: होस्ट तक IPv6 से पहुँचा गया, और केवल IPv4 काटा गया था। अंकगणित गलत है यह निष्कर्ष निकालने से पहले दोनों परिवार जाँचें।
दायरा जाँच का दूसरा आधा है। Android नेटवर्क और ऐप के अनुसार रूटिंग ट्रैक करता है, इसलिए वही प्रीफ़िक्स एक ऐप के लिए टनल से जा सकता है और दूसरे के लिए सीधा, इस पर निर्भर करता है कि VPN कैसे घोषित किया गया।
DNS और प्रति-ऐप नियम सही जगह रखें
रूट बहिष्करण रिज़ॉल्वर नहीं बदलते। कोई स्थानीय होस्टनाम अब भी टनल के DNS सर्वर से उत्तर पा सकता है जबकि उसका पता स्थानीय रूप से रूट होता है, और असंगति ऐसे नाम के रूप में दिखती है जो ऐसी चीज़ पर हल होता है जहाँ LAN नहीं पहुँच सकता। रिज़ॉल्वर नीति जानबूझकर तय करें, खोज डोमेन या विभाजित-DNS नियम के साथ। यह न मानें कि रूट ने आपके लिए यह तय कर दिया।
addDisallowedApplication() एक ऐप को टनल से बाहर रखता है; अंदर रहने वाले ऐप्स के लिए यह गंतव्य को बाहर नहीं रखता। protect() आपके द्वारा खोले गए सॉकेट को टनल से बचने देता है, और इस तरह टनल अपनी ही ट्रांसपोर्ट पकड़ने से बचती है। दोनों में से कोई पूरक की जगह नहीं लेता।
अपनी सूची से नहीं, लुकअप से सत्यापित करें
टनल चालू होने के बाद, अपनी बनाई सूची दोबारा पढ़ने के बजाय डिवाइस से पूछें कि पता वास्तव में कहाँ जाता है। iproute2 के साथ आने वाले बिल्ड पर, adb shell ip route get 10.1.2.3 उस इंटरफ़ेस का नाम बताता है जिसे कर्नेल ने चुना। किसी सार्वजनिक पते के लिए वही कमांड चलाएँ और पुष्टि करें कि यह टनल का नाम बताता है।
दो और जाँचें चक्र बंद करती हैं। पहले कोई स्थानीय नाम हल करें, फिर हल किए गए पते पर adb shell ip route get चलाएँ और ऐसा इंटरफ़ेस माँगें जो टनल न हो, क्योंकि सफल adb shell ping -c 1 host.lan पहुँच सिद्ध करता है, मार्ग नहीं। अगर टनल एक दावा करे तो IPv6 पर पता-परिवार परीक्षण दोहराएँ। उसी API स्तर पर परीक्षण करें जो आप भेजते हैं, क्योंकि VPN नेटवर्क रूटिंग तालिका के सामने कैसे आते हैं यह रिलीज़ के साथ बदला है। कागज़ पर सही दिखने वाली रूट सूची और गलत इंटरफ़ेस चुनने वाला लुकअप अलग बग हैं, और केवल दूसरा उपयोगकर्ताओं तक पहुँचता है।
अगर बहिष्करण सूची बढ़ती रहे, तो रूट बनाना बंद करें और दूरस्थ नेटवर्क को फिर से क्रमांकित करें या इसके बजाय टनल को संकीर्ण करें। जनरेटर अनुपस्थित API के लिए एक उपाय है, डिज़ाइन उपकरण नहीं।