IPv6 link-local לא עובד דרך VPN: למה fe80 נעצר בקישור
כתובת fe80:: משמעותה רק בקישור אחד. ראו למה VPN מנותב לא יכול להעביר אותה, איך נראית התקלה, ואיזו כתובת להשתמש בה במקום.
אתם מעלים את המנהרה, עושים ping ל‑fe80::1 כשהמנהרה היא ממשק המקור, ולא חוזר כלום. זה לא כלל חומת אש ששכחתם. כתובת link-local משמעותה רק בקישור הבודד שבו היא נוצרה, ו‑VPN מנותב אינו אותו קישור. ה‑fe80::1 של הנתב המרוחק נמצא בסגמנט ה‑LAN המרוחק; אתם נמצאים במרחק קפיצה אחת בסגמנט אחר, ול‑IPv6 אין שום מנגנון שבו נתב מעביר מנות link-local בכלל.
קידומת fe80 מתארת היקף, לא טווח
Link-local unicast הוא fe80::/10, והתכונה המגדירה אינה המספר אלא ההיקף. הכתובת תקפה רק בקישור אחד, וכל ממשק יוצר אחת מהמזהה שלו, ולכן שתי מכונות לא קשורות בשתי רשתות לא קשורות יכולות שתיהן לענות ל‑fe80::1 בלי שום התנגשות. הקידומת בעצם אומרת “בקישור כלשהו”; הקישור עצמו מגיע מההקשר.
במארח, ההקשר הזה הוא ה‑zone, או scope ID, שמוסיפים אחרי סימן האחוז: fe80::1%eth0 ב‑Linux, fe80::1%3 או fe80::1%12 ב‑Windows ובכלים שחושפים אינדקסים של ממשקים. הגרעין מפענח את הכתובת יחד עם אינדקס הממשק ואז שולח. אם מסירים את ה‑zone, היעד אינו חד-משמעי, ולכן למחסנית אין דרך לבחור סגמנט.
למה מנהרה מנותבת לא יכולה להעביר אותה
VPN מנותב הוא ממשק נקודה-לנקודה שנושא כתובות משלו, בדרך כלל /64 של מרחב IPv6 ייחודי-מקומי או פרטי בתוך המנהרה. ה‑LAN המרוחק הוא קישור נפרד, שאליו מגיעים בכך שנקודת הקצה של המנהרה מנתבת ומעבירה בשמכם. אלה שני סגמנטים נפרדים, ולכן כתובת מאחד אינה יעד תקף בשני.
כלל ההעברה מפורש בתקן ולא מוזרות של הלקוח שלכם: נתבים אינם מעבירים מנות עם מקור או יעד link-local. זו הסיבה שהמנה מתה גם כשטבלת הניתוב נראית תקינה. אם מוסיפים מסלול ל‑fe80::/64 שמצביע על המנהרה, מחסנית תואמת או שדוחה אותו או שמקבלת אותו ומפילה כל מנה מתאימה: היקף היעד אומר “הקישור הזה בלבד”, וממשק היציאה אינו אותו קישור.
גילוי שכנים מחזק את אותו גבול. מארחים מפענחים קפיצות הבאות link-local בבקשת שכן שנשלחת ל‑multicast בהיקף הקישור עם מגבלת קפיצות של 255, כך שנתבים יכולים לדחות כל מה שמועבר. לעשות זאת דרך מנהרה פירושו לתווך גילוי עבור סגמנט מרוחק, וזה גישור Layer 2 בכובע אחר.
יש כשל שני שקט יותר, והוא תופס אנשים שמנסים לכפות את המסלול בכל זאת: ה‑zone. כל zone שתקלידו מקומית מציין את ממשק המנהרה, בעוד הכתובת שאתם רוצים קשורה לממשק ה‑LAN המרוחק. השניים לא יתאמו לעולם, ולכן לא ניתן לכוון את המנה לממשק הנכון בקצה המרוחק.
איך נראית התקלה בפועל
פלט כלים על טעות בהיקף נקרא כמו שגיאת ניתוב או חומת אש, וזו בדיוק הסיבה שאנשים מבלים אחר צהריים בשכבה הלא נכונה.
| What you run | What you see | What it means |
|---|---|---|
| ping fe80::1 with no zone | Invalid argument on Linux, or a transmit failure on Windows | The stack cannot pick an interface for an ambiguous destination |
| ping -6 -I tun0 fe80::1 | Destination unreachable, or a silent timeout | The address is not on the tunnel link, so there is nothing on-link to answer |
| ssh user@fe80::1 after the tunnel is up | Hangs, then no route to host | The SYN never left the machine in a deliverable form; the server logs nothing |
| ip -6 neigh show dev tun0 | Empty table | No neighbor entry can exist for a link-local host that is not on this link |
| fe80::/64 inside AllowedIPs or route-ipv6 | Config accepted, traffic still dropped | The tunnel carried the packet; the receiving stack refused to forward it |
השורה השלישית מבזבזת את הזמן הרב ביותר, כי לקוח ssh בלי פלט נראה כמו בעיה של שירות מאזין. אם יש לכם דרך להיכנס, בדקו את הצד המרוחק ואמתו אם sshd קשור לכל הכתובות או רק לאחת.
השתמשו בכתובת שנועדה לניתוב
לכל מה שאתם צריכים להגיע אליו דרך המנהרה, השתמשו בכתובת שניתנה לשירות למטרה הזו: כתובת unicast גלובלית, או כתובת unique-local מתוך fc00::/7, הטווח השמור בדיוק למקרה הפנימי הזה. אמתו שהמאזין אכן קושר אותה, ואמתו את נתיב החזרה וכל כלל חומת אש במארח.
הסתכלו על המארח המרוחק במקום לנחש. ip -6 addr show מציג את הכתובות שקיימות, ו‑ss -6 -ltn מציג על מה הדמון מאזין. שירות שקושר רק ל‑fe80:: נגיש רק מהסגמנט שלו, וזו בדרך כלל ברירת מחדל שאיש לא בחר בכוונה וניתן לשנותה בהסכמת המנהל.
כשהשירות באמת לא יכול להיקשר מחדש, העבירו את הגשר למעלה אל שכבת היישום במקום שכבת הרשת. ממסר במארח המרוחק שמאזין בכתובת נתיבה ומתחבר לזו של link-local פותר את הבעיה בלי להרחיב שום סגמנט:
socat TCP6-LISTEN:8080,bind=[fd00:1:2::10] TCP6:[fe80::1%eth0]:80כאן ה‑zone יושב בצד הנכון, במארח שבאמת יש לו eth0 בקישור הזה. הלקוח שלכם מדבר עם fd00:1:2::10, שמנותב כרגיל, והממסר עושה את קפיצת ה‑link-local מקומית. אותו טריק עובד עבור ממשק web של מכשיר או BMC ישן שמפרסם רק כתובת link-local.
כשגישור הוא באמת התשובה, ומה לבדוק
יש פריסות שבאמת זקוקות לסגמנט משותף אחד: מכשיר שמדבר רק גילוי link-local, מכשיר שתלוי ב‑multicast, מעבדה שמשחזרת LAN שטוח. זו בעיה של Layer 2 והיא דורשת תשובה של Layer 2, כמו התקן tap מגושר לממשק המרוחק או מוצר לקוח עם מצב גישור מפורש. זה עולה לכם בתעבורת broadcast ו‑multicast שחוצה את המנהרה וגם גילוי שכנים שחייב לעבוד מקצה לקצה.
אל תקרבו את זה על ידי הוספת fe80::/64 לפרופיל מנותב. זה יוצר את המצב הגרוע ביותר: התצורה נראית מוגמרת, טבלת הניתוב מציגה רשומה, וכל מנה עדיין נזרקת אי שם בין שתי מחסניות ששתיהן מתנהגות נכונה.
אמתו באמצעות הממשק ולא באמצעות ping. ip -6 addr show tun0 אומר לכם אם קישור המנהרה יצר כתובת link-local משלו, ו‑ip -6 route get fe80::1%tun0 אומר לכם מה הגרעין באמת יעשה עם יעד בעל היקף. כשהגרעין אומר שהיעד אינו נגיש בממשק הזה, שום הגדרת מנהרה לא תשנה את זה, והגיע הזמן להפסיק לערוך את הפרופיל.
רצף קצר שסוגר את השאלה:
- קראו את הכתובת במארח המרוחק ושים לב אם היא fe80:: או קידומת נתיבה.
- אם היא fe80::, קשרו מחדש את השירות, עשו ממסר במארח הזה, או גשרו את הסגמנט; אם היא נתיבה, תקנו את המסלול, חומת האש או כתובת הקישור.
- בדקו שוב את ה‑zone בכל פעם שאתם בודקים מחדש, כי פקודה שהועתקה בדרך כלל שומרת על הממשק הלא נכון.
מקורות: RFC 4291, ארכיטקטורת הכתובות של IPv6.