שלוש קפיצות WireGuard מגיעות לרשת שאין לה כתובת ציבורית, ואז המכונה האמצעית מפסיקה לענות בפורט שהיא הייתה אמורה להאזין לו. המנהרה הלאה עדיין עובדת, המארח המרוחק עדיין מגיב, ורק השרת האמצעי עצמו שתק מבחוץ. השילוב הזה מבלבל דווקא מפני שהוא עצמי: הקפיצה האמצעית מצייתת לטבלת הניתוב של עצמה, והטבלה שולחת את התשובות שלה לכיוון הלא נכון.

שרשרת שעובדת עד שמדברים עם הקופסה האמצעית

קחו שרשרת להמחשה: הלקוח A מגיע לשרת B ב-UDP 500, ו-B ממשיך לשרת C ב-UDP 500. C מקבל תנועה רק מכתובת העמית היחיד שלו, מה שהופך אותו לעלה ושומר על התנהגותו פשוטה. B אינו עלה, וכל מה שמעניין בתקלה הזו קורה שם.

ההבחנה חשובה מפני שתפקידי העלה והאמצע מושכים לכיוונים מנוגדים. עלה יכול לשלוח הכול למנהרה אחת בלי תוצאות, מפני ששום דבר אחר אינו תלוי בו. קפיצה אמצעית היא בו-זמנית נקודת קצה ללקוחות ולקוח כלפי הצד המרוחק, ושתי העבודות האלה רוצות ניתוב שונה.

למה התשובה יוצאת דרך המנהרה

ב-B, הממשק הפונה ל-C נושא AllowedIPs = 0.0.0.0/0 יחד עם מסלול ברירת המחדל המתאים. לכן כל מקטע ש-B יוצר נכנס לאותה מנהרה, אלא אם משהו ספציפי יותר מקבל קדימות.

מקטע מ-A המיועד ל-B מגיע ומתקבל, מפני ש-B הוא היעד והמסירה המקומית מתרחשת ראשונה. התשובה היא מקטע חדש לגמרי שנוצר מקומית ומופנה לכתובת הציבורית של A, והיעד הזה תואם את מסלול ברירת המחדל לתוך המנהרה. C מקבל אותו, אינו בעלים של הכתובת הזו, ומפיל אותו.

התסמין נקרא כמו בעיית חומת אש או אי-התאמה של מפתח, ושני הדברים אינם נכונים כאן. לכידה על המנהרה לכיוון C מראה שהתשובות יוצאות לכיוון הלא נכון. התצפית האחת הזו חוסכת יותר זמן מכל כמות של קריאת תצורה, אז רשמו אותה לפני שמתחילים להחליף מפתחות. כל מי שלא ראה את הלכידה יניח שהמנהרה עצמה שבורה.

התיקון הצר: כללי מדיניות שמתאימים לפורט מקור

תשובות מהשקע המקשיב של B יוצאות עם פורט מקור 500. כלל מדיניות יכול להתאים לכך ולהחזיר את המקטעים האלה לטבלה הרגילה:

ip rule add sport 500 table main priority 100
ip rule add sport 8080 table main priority 101

כללי מדיניות נבדקים לפי סדר עדיפות, והטבלה הראשית נמצאת ב-32766, ולכן כלל ב-100 נשאל לפני שמסלול ברירת המחדל של המנהרה אומר את דברו. הוסיפו רשומה אחת לכל פורט שחייב להישאר נגיש מבחוץ ולא יותר, כדי שתנועה מועברת תמשיך להשתמש במנהרה שלמענה נבנתה.

דעו את הגבול של הטריק הזה. הבורר sport מתאים למקטעים שנוצרים מקומית, מה שמכסה בדיוק את מקרה התשובה ובמכוון אינו מכסה תנועה ש-B רק מעביר עבור מישהו אחר. שירות המתארח מאחורי B עדיין צריך תשובה משל עצמו, והעמדת פנים אחרת מייצרת תיקון שעובד לשירות הראשון ונכשל בשני.

תנו לכלל בעלים

כלל שהוקלד בשורת פקודה נעלם בפעם הבאה שהממשק נבנה מחדש. בהתקנת WireGuard, שימו אותו במקום שבו הממשק נוצר ומוסר:

PostUp = ip rule add sport 500 table main priority 100
PostDown = ip rule del sport 500 table main priority 100

אם NetworkManager, וו של הפצה או נקודת כניסה של מכולה הם הבעלים של הממשק, הזוג שייך לבעלים הזה ולא לקובץ שנערך ביד. בדקו את הכללים האפקטיביים אחרי התחברות מחדש, ולא רק אחרי ההתחלה הראשונה, כי ההתחלה הראשונה היא המקרה שתמיד עובד.

השוו את החלופות בכנות

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

ApproachWhat it costsWhere it breaks
Source-port policy ruleOne rule per exposed portAnything B forwards rather than originates
Destination exception routeA route pinned to specific client addressesClients whose address changes
Stop full-tunnelling on BLoses the catch-all path toward CDesigns that depend on it
Split into two tunnelsMore interfaces and more policyNothing, at the cost of complexity

אמתו משני הקצוות לאחר שבחרתם. מ-A, התחילו חיבור לפורט של B והחזיקו אותו עסוק לזמן מה. ב-B, גרמו לקרנל להצדיק את מסלול התשובה עם משהו כמו ip route get <address-of-A> sport 500, ואשרו שהוא מציין את ממשק ה-WAN ולא את המנהרה. לאחר מכן, בדקו שמשהו מאחורי C עדיין עונה דרך השרשרת, מה שמוכיח שהחריגה נשארה צרה במקום להפוך לעקיפה. לבסוף, רשמו את הפורטים בהערות העיצוב, אחרת המפעיל הבא יגלה זאת מחדש בשירות אחר.

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