Android VPN IPv6 पर चलता है, फिर भी ब्राउज़र IPv4 चुनता है
उन चार चरणों को ट्रेस करें जहाँ निजी IPv6 पता गायब हो जाता है: रिज़ॉल्वर, VpnService की घोषणा, ब्राउज़र की उम्मीदवार जाँच और रूट की डिलीवरी।
VPN चालू है, निजी वेब UI लैपटॉप से IPv6 पर जवाब देता है, और Android फ़ोन वही पेज अब भी IPv4 पर खोलता है या उसे लोड करने से इनकार कर देता है। AAAA रिकॉर्ड मौजूद है। टनल IPv6 पता बताती है। क्लाइंट में कुछ भी गलत नहीं दिखता। नतीजा चार अलग फ़ैसले तय करते हैं: किस रिज़ॉल्वर ने जवाब दिया, VpnService ने Android को क्या बताया, ब्राउज़र किस पता-परिवार को आज़माने को तैयार था, और क्या कोई पैकेट आने-जाने की यात्रा कर सकता है। डिफ़ॉल्ट रूट जोड़कर लक्षण के खिसकने की उम्मीद करने के बजाय इन्हें इसी क्रम में करें।
चरण 1: साबित करें कि AAAA क्वेरी का जवाब किस रिज़ॉल्वर ने दिया
Android के पास एक ही DNS रास्ता नहीं है। VPN अपने नेटवर्क के लिए DNS सर्वर धकेल सकता है, सिस्टम उन होस्टनामों के लिए Private DNS इस्तेमाल कर सकता है जिन्हें वह योग्य मानता है, और Chrome chrome://settings/security से अपना खुद का एन्क्रिप्टेड रिज़ॉल्वर चला सकता है। ऐसे फ़ोन पर जहाँ टनल 10.61.0.1 धकेलती है पर Private DNS किसी सार्वजनिक प्रदाता की ओर इशारा करता है, आपके निजी ज़ोन के अंदर का नाम उस मशीन द्वारा हल नहीं होता जो ज़ोन की मालिक है। ब्राउज़र को ऐसे रिज़ॉल्वर से जवाब मिलता है जिसके पास उस नाम पर अधिकार नहीं है और वह उसे अनुपस्थित मान लेता है, और त्रुटि के पाठ में DNS का ज़िक्र कभी नहीं होता।
कुछ और बदलने से पहले टनल के रिज़ॉल्वर से सीधे पूछें। पहले दो कमांड दिखाते हैं कि Android ने सक्रिय नेटवर्क से कौन-से DNS सर्वर जोड़े और Private DNS स्वचालित या सख़्त मोड में है; तीसरा टनल के अंदर किसी भी क्लाइंट से चलता है, फ़ोन से नहीं।
adb shell dumpsys connectivity | grep -A3 "DnsAddresses"
adb shell settings get global private_dns_mode
nslookup -type=AAAA nas.lan 10.61.0.1
चरण 2: पढ़ें कि VpnService ने असल में क्या घोषित किया
Android की तरफ़ स्पष्ट है, अनुमानित नहीं। VpnService.Builder addAddress से पते जोड़ता है, addRoute से रूट, addDnsServer से DNS सर्वर, और allowFamily से पूरी टनल को एक पता-परिवार तक सीमित कर सकता है। जिस बिल्डर ने allowFamily(AF_INET) कॉल किया और बाद में IPv6 रूट जोड़ा, उसने सिस्टम को दो विरोधाभासी बातें कही हैं, और सिस्टम परिवार-प्रतिबंध ही रखता है। fd00:61::/64 को कवर करने वाला रूट किसी दूसरे प्रीफ़िक्स के इंटरफ़ेस पते के साथ मिलकर इसी तरह विफल होता है: पता मौजूद है, पर वह उस रूट के लिए on-link नहीं है।
ऐप के टॉगल पर भरोसा करने के बजाय घोषणा पढ़ें। dumpsys netd tun इंटरफ़ेस से जुड़े पते और रूट छापता है, और dumpsys connectivity के अंदर प्रति-नेटवर्क LinkProperties नेटवर्क के दावे वाले परिवारों के बगल में DNS सूची दिखाता है।
adb shell ip -6 addr show tun0
adb shell ip -6 route show table all | grep tun0
adb shell dumpsys connectivity | grep -E "LinkAddresses|Routes"
अगर tun इंटरफ़ेस पर IPv6 पता है पर कोई रूट सेवा के प्रीफ़िक्स से मेल नहीं खाता, तो ब्राउज़र आने से पहले ही IPv6 डिलीवरी टूटी हुई है। यह आज़माने से इनकार करने वाले ब्राउज़र से अलग बग है, और इसके लिए अलग सुधार चाहिए।
चरण 3: IPv6 आज़माना है या नहीं, यह ब्राउज़र तय करता है
Chromium अपने पास आने वाला हर AAAA रिकॉर्ड इस्तेमाल नहीं करता। इसके होस्ट रिज़ॉल्वर में IPv6 पहुँच-जाँच और उम्मीदवार फ़िल्टरिंग है जो नेटवर्क को इसे ढोने में अक्षम माने जाने पर IPv6 को गिरा या उसकी प्राथमिकता घटा सकती है, और रिज़ॉल्वर का स्रोत उस प्रोब को उसके आसपास की शर्तों के साथ दिखाता है। तर्क संस्करण और फ़्लैग पर निर्भर है, और ठीक इसी वजह से एक ही टनल पर दो फ़ोन अलग व्यवहार कर सकते हैं। उम्मीदवार बन जाने के बाद Happy Eyeballs हर कनेक्शन के लिए परिवारों के बीच दौड़ लगाता है, इसलिए धीरे जवाब देने वाला IPv6 रास्ता तेज़ जवाब देने वाले IPv4 से हार सकता है।
फ़ैसले को अनुमानित करने के बजाय देखें। chrome://net-export से रिकॉर्ड किया गया और netlog व्यूअर में दोबारा चलाया गया सत्र हर रिज़ॉल्यूशन और चुना गया परिवार दिखाता है; chrome://net-internals/#dns कैश किए नतीजे दिखाता है। ऐसा रिज़ॉल्यूशन जो आपके अपने रिज़ॉल्वर पर AAAA वाले नाम के लिए सिर्फ़ A रिकॉर्ड लौटाए, सीधे इसी चरण की ओर इशारा करता है।
चरण 4: जाँचें कि पैकेट आने-जाने की यात्रा कर सकता है
पता चुनना डिलीवरी नहीं है। Android प्रति-नेटवर्क रूटिंग टेबल और नीति नियम रखता है जो fwmark से टेबल चुनते हैं, इसलिए मुख्य टेबल में दिखने वाला रूट अपने आप वह रूट नहीं है जो सॉकेट इस्तेमाल करता है। नियम पढ़ना और कर्नेल से स्रोत पते के लिए गंतव्य हल करने को कहना इन दोनों को अलग करता है।
adb shell ip -6 rule show
adb shell ip -6 route get fd00:61::20 from fd00:61::10
route get का आउटपुट ही सवाल का जवाब देता है। अगर वह tun0 बताता है और पैकेट फिर भी मरते हैं, तो फ़ोन पर लौटने के बजाय टनल के MTU और गेटवे के IPv6 फ़ॉर्वर्डिंग की ओर बढ़ें।
::/0 जोड़ने से आम तौर पर हालत बदतर क्यों होती है
::/0 जोड़ने से टनल का दावा एक प्रीफ़िक्स से हर IPv6 गंतव्य पर बदल जाता है। फ़ोन पर यह पहुँच-जाँच संतुष्ट कर सकता है, क्योंकि आपके प्रीफ़िक्स के बाहर का परीक्षण पता अब रूटेबल दिखता है। यह गेटवे पर IPv6 अपस्ट्रीम क्षमता नहीं बनाता, और कई घरेलू गेटवे में काम करने वाला IPv6 अपलिंक ही नहीं है। नतीजा सार्वजनिक IPv6 के लिए ब्लैक होल है: जो नाम पहले IPv4 पर लौटते थे वे अब अटक जाते हैं, और निजी पेज शायद इसलिए बेहतर दिखे क्योंकि प्रोब कुछ और माप रहा है।
नीति की कीमत भी है। टनल में ::/0 होने पर सारा IPv6 ट्रैफ़िक VPN से बाहर जाता है, उस ट्रैफ़िक सहित जिसे ढोने के लिए नेटवर्क मालिक ने कभी सहमति नहीं दी। इसे नामित मालिक वाला परिनियोजन निर्णय मानें, रात 1 बजे लिया जाने वाला डिबगिंग कदम नहीं।
वह कार्य-क्रम जो इसे खत्म करता है
पुष्टि करें कि AAAA जवाब उसी रिज़ॉल्वर से आता है जिसके पास ज़ोन है, tun इंटरफ़ेस के लिए VpnService और netd स्थिति पढ़ें, Chromium ने उम्मीदवार गिराया या नहीं यह देखने के लिए net-export ट्रेस लें, फिर ip -6 route get से आने-जाने की जाँच करें। जो परत असल में विफल हुई उसे ठीक करें और स्प्लिट नीति को छेड़ें नहीं। अगर निजी नामों को सार्वजनिक नामों से अलग जवाब चाहिए, तो split tunneling ठीक इसी के लिए है।
फ़ोन का बिल्ड, ब्राउज़र का संस्करण और जिस रिज़ॉल्वर से आपने पूछा, उसे लिख लें। ये तीन तथ्य "IPv6 is broken" को ऐसी चीज़ में बदल देते हैं जिसे अगला व्यक्ति दोहरा सके।