ה-VPN פעיל, ממשק האינטרנט הפרטי עונה דרך IPv6 ממחשב נייד, והטלפון עם אנדרואיד עדיין פותח את אותו עמוד דרך IPv4 או מסרב לטעון אותו כלל. רשומת AAAA קיימת. המנהרה מדווחת כתובת IPv6. שום דבר בלקוח לא נראה שגוי. ארבע החלטות נפרדות קובעות את התוצאה: איזה מפענח ענה, מה VpnService הצהיר לאנדרואיד, איזו משפחת כתובות הדפדפן היה מוכן לנסות, והאם חבילה יכולה לבצע את המסע הלוך וחזור. עבדו עליהן בסדר הזה במקום להוסיף מסלול ברירת מחדל ולקוות שהתסמין יזוז.

שלב 1: הוכיחו איזה מפענח ענה לשאילתת AAAA

לאנדרואיד אין נתיב DNS יחיד. VPN יכול לדחוף שרת DNS לרשת שלו, המערכת יכולה להשתמש ב-Private DNS עבור שמות מארח שהיא מחשיבה ככשירים, ו-Chrome יכול להריץ מפענח מוצפן משלו מ-chrome://settings/security. בטלפון שבו המנהרה דוחפת 10.61.0.1 אך Private DNS מצביע על ספק ציבורי, השם בתוך האזור הפרטי שלכם אינו מפוענח על ידי המכונה שמחזיקה באזור. הדפדפן מקבל תשובה ממפענח שאין לו סמכות על אותו שם ומתייחס אליה כאל חסרה, וטקסט השגיאה אף פעם לא מזכיר DNS.

שאלו את המפענח של המנהרה ישירות לפני שתשנו משהו אחר. שתי הפקודות הראשונות מראות אילו שרתי 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 באמת הצהיר

הצד של אנדרואיד הוא מפורש ולא נגזר. VpnService.Builder מוסיף כתובות עם addAddress, מסלולים עם addRoute, שרתי DNS עם addDnsServer, ויכול להגביל את כל המנהרה למשפחת כתובות אחת עם allowFamily. בונה שקרא ל-allowFamily(AF_INET) ואחר כך הוסיף מסלול IPv6 אמר למערכת שני דברים סותרים, והגבלת המשפחה היא מה שהמערכת שומרת. מסלול שמכסה את fd00:61::/64 יחד עם כתובת ממשק בתחילית אחרת נכשל מאותה סיבה: הכתובת קיימת, אבל היא לא on-link עבור אותו מסלול.

קראו את ההצהרה במקום לסמוך על המתג באפליקציה. dumpsys netd מדפיס את הכתובות והמסלולים המחוברים לממשק tun, ו-LinkProperties לכל רשת בתוך dumpsys connectivity מציג את רשימת ה-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 מציג את התוצאות השמורות במטמון. פענוח שמחזיר רק רשומות A עבור שם שיש לו AAAA במפענח שלכם מצביע ישירות על השלב הזה.

שלב 4: ודאו שחבילה יכולה לבצע את המסע הלוך וחזור

בחירת כתובת אינה מסירה. אנדרואיד מחזיק טבלאות ניתוב וכללי מדיניות לכל רשת שבוחרים טבלה לפי 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 מגיעה מהמפענח שמחזיק באזור, קראו את מצב VpnService ו-netd עבור ממשק tun, תפסו עקבות net-export כדי לראות אם Chromium הפיל את המועמד, ואז בדקו את המסע הלוך וחזור עם ip -6 route get. תקנו את השכבה שבאמת כשלה והניחו למדיניות הפיצול. אם שמות פרטיים זקוקים לתשובות שונות מאלה של ציבוריים, בדיוק לכך נועד split tunneling.

רשמו את גרסת הבנייה של הטלפון, את גרסת הדפדפן ואת המפענח ששאלתם. שלוש העובדות האלה הופכות את "IPv6 is broken" למשהו שהאדם הבא יוכל לשחזר.

מאמרים קשורים