ניתוב VPN ב-Android: כללי מדיניות לפני טבלת main
Android בוחר טבלת ניתוב באמצעות כללי uid וסימון לפני כל חיפוש יעד, ולכן מסלול שמתווסף ל-main עלול לא להיבדק כלל.
מסלול שמתווסף לטבלה main ב-Android נראה תקין בכל רשימה ובכל זאת אינו נושא את התעבורה. הסיבה היא שטבלת main היא אחת מכמה אפשרויות, והיא אינה נבדקת ראשונה. שירות הרשת של Android בונה כללי מדיניות שבוחרים טבלת ניתוב באמצעות מידע שכתובת היעד אינה מכילה — ה-uid של היישום, סימון על החבילה, הממשק שממנו הגיעה — וחיפוש היעד מתרחש אחר כך, בתוך הטבלה שאותם כללים בחרו.
שלוש החלטות בסדר קבוע
חבילה שיוצאת מקבלת שלוש החלטות נפרדות. ראשית, כלל מדיניות קובע איזו טבלת ניתוב חלה. שנית, מסלול בתוך אותה טבלה קובע את הקפיצה הבאה ואת ממשק היציאה. שלישית, ווי netfilter קובעים אם החבילה שורדת, משתנה או מופנית מחדש.
הסדר חשוב משום שכל שלב יכול לענות רק על השאלה שלו. כלל חומת אש שמקבל חבילה אינו בוחר טבלה, ומסלול שמתווסף לטבלה שאין כלל שבוחר אותה אינו פעיל. חלק ניכר מהבלבול סביב VPN ב-Android נובע מתיקון אחד מהשלושה ואי-ראיית שינוי, משום שהתקלה הייתה באחר.
| Stage | Selector | What it cannot decide |
|---|---|---|
| Policy rule | uid range, mark, incoming interface | Which route exists inside the table |
| Route lookup | Destination prefix, longest match | Whether the packet is allowed out |
| Netfilter hook | Chain position, match conditions | Which table was selected |
סימונים הם שדה ארוז, לא תווית שבבעלותך
Android אורז כמה עובדות באותו ערך סימון: איזו רשת נבחרה, אם יישום בחר רשת במפורש, אם socket מוגן מפני ה-VPN, וביטים הקשורים להרשאות. כותרת ה-fwmark של AOSP מגדירה את הפריסה הזו עבור העץ הנוכחי, והפריסה היא פנים-פלטפורמי שמשתנה בין מהדורות.
לכן כתיבת ערך סימון שלם עם iptables -j MARK --set-mark מסוכנת ב-Android. היא אינה מוסיפה תג; היא מחליפה את בחירת הרשת שהמערכת כבר עשתה. החבילה תואמת אז כללים אחרים, מה שיכול להיראות כאילו ה-VPN התחיל לעבוד, או כאילו יישום לא קשור איבד את הקישוריות, בהתאם לביטים שנדרסו.
אם חייבים לגעת בסימונים, קראו קודם את הערך הנוכחי והשתמשו במסיכה כך שרק הביטים שאתם מבינים ישתנו:
ip rule show
ip route show table all | head -40
ip route get 10.20.4.11סימון חיבור הוא אובייקט נפרד מסימון חבילה, ואף אחד מהם אינו מסלול. שחזור הסימון על חבילות תשובה הוא שלב נפרד מבחירת טבלה ביציאה, ולכן תיקונים חד-כיווניים יוצרים חיבורים שנפתחים ואז נתקעים.
מי הבעלים של הכללים והטבלאות
שירות הרשת של Android, netd, יוצר את הכללים ואת הטבלאות לכל רשת. AOSP RouteController הוא המקום שבו הכללים האלה מורכבים עבור VPN, רשתות פיזיות וטווחי uid, ומחזור החיים שלו קשור לאירועי רשת ולא לקובץ תצורה.
שתי השלכות נובעות מכך. ראשית, עדיפויות ומספרי טבלאות שתמצאו במכשיר אחד הן פנים-בנייה, לא ממשק: מספרים שנראים זהים בגרסת Android אחרת יכולים לומר משהו אחר לגמרי. שנית, המצב נבנה מחדש כשהרשתות משתנות, כך שכלל שהוכנס היום מ-root shell עלול להיעלם לאחר מעבר ה-Wi-Fi הבא.
היעלמות זו מדווחת לעתים קרובות כמערכת שמתעלמת ממסלול. מה שקרה בפועל הוא שהכלל שבחר את הטבלה אינו קיים עוד, והמסלול בתוך הטבלה אינו נגיש כעת מנקודת המבט של החבילה. בדקו את רשימת הכללים, לא את רשימת המסלולים, כאשר תצורה שעובדת מפסיקה לעבוד לאחר התחברות מחדש.
לשאלות על סדר הווים אין תשובה אוניברסלית
לשאלה אם iptables רץ לפני ניתוב ה-VPN אין תשובה בלי לנקוב בנתיב החבילה. חבילה שנוצרת מקומית עוברת דרך ווי output, שם שינוי סימון מפעיל בדיקת ניתוב מחדש — חיפוש שני, לא עריכה רטרואקטיבית של הראשון. חבילה שמגיעה מלקוח ב-tether עוברת בנתיב prerouting ומועברת הלאה במקום, והשרשראות שרואות אותה אחרות.
לכן אותו כלל יכול להיות יעיל לתעבורה של יישום ובלתי נראה לתעבורת tether, ומונה שנשאר באפס אומר לכם איזה נתיב החבילה לקחה, לא אם הכלל שגוי. השתמשו במונים כדי לקבוע את הנתיב לפני שינוי תנאי התאמה.
זה גם השלב שבו טעות בניתוב מדיניות הופכת לקשה לראייה. ניתוב לטבלה שקיימת אך אינה מכילה את היעד מייצר רשת בלתי נגישה שנראית כמו נפילה של חומת אש, בעוד שנפילה של חומת אש מייצרת פסק זמן שנראה כמו חור שחור בניתוב.
אבחנו בתוך המערכת, או הניחו לה
לבדיקה מורשית, קבעו ארבע עובדות לפני שנוגעים במשהו: ה-uid והפרופיל של היישום, הרשת ש-Android בחר עבורו, אם ה-VPN כולל את היישום הזה בכלל, ואם הבעיה קיימת בשתי משפחות הכתובות. החרגה לפי יישום מסבירה דיווחים רבים של VPN לא עובד בלי שום תקלת ניתוב.
לאחר מכן קראו את הכללים, המסכות והטבלאות שבאמת בתוקף, והשאירו החלפת רשת בתוך חלון התצפית. אם ההתנהגות משתנה לאורך התחברות מחדש, אתם מסתכלים על מחזור חיים מנוהל, לא על מסלול חסר.
לדרישות רגילות השתמשו בבקרות הנתמכות: הכללה והחרגה לפי יישום ביישום ה-VPN, ובבחירת הרשת של הפלטפורמה עצמה לכל דבר שדורש נתיב מסוים. אם אינטגרציה עם הרשאות באמת חייבת לשתף פעולה עם מנגנון הניתוב, כוונו למימוש של גרסת ה-Android המדויקת שאתם תומכים בה ותחזקו את מחזור החיים שלה דרך הרכיב שבבעלותו היא. שטיפת שרשראות פלטפורמה או הכנסת כלל בעדיפות גבוהה הופכת אבחון למנהל רשת שני, והטלפון יתנהג בהתאם.