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

מצאו היכן נולדה החבילה

סדר ה-hooks של Netfilter מפריד בין שלושה מקרים, ורק אחד מהם כולל FORWARD:

OriginPathHook that sees it
Local processOUTPUT then POSTROUTINGOUTPUT, POSTROUTING
Addressed to a local servicePREROUTING then INPUTPREROUTING, INPUT
Received for another hostPREROUTING, FORWARD, POSTROUTINGFORWARD

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

שתי חבילות, סיפור אחד

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

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

מרחבי שמות מזיזים את הגבול

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

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

שאלו אם אתם בכלל צריכים סימון

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

סיווג נדרש כאשר ההחלטה תלויה במשהו שמסלול אינו יכול לבטא, כמו המקור, המשתמש או התהליך. לתעבורה נכנסת, סימון ב-PREROUTING עובד. לתעבורה מקומית, הסימון חייב לקרות בשלב פלט שיכול לעורר חיפוש מסלול חדש לאחר שהסימון נקבע. עם nftables זהו שרשרת מסוג route ב-hook הפלט; שרשרת סינון פלט רגילה תקבע את הערך ותשאיר את המסלול ללא שינוי.

עם iptables, המקבילה חיה בסידור mangle OUTPUT, ואותה דרישה חלה: יש לבחון מחדש את החלטת הניתוב לאחר שהסימון קיים. אחר כך כלל מדיניות חייב לצרוך את הסימון ולהצביע על טבלה שמכילה מסלול שמיש. קביעת סימון conntrack היא פעולה שלישית ונפרדת; היא שומרת ערך על הזרימה ואינה שמה בעצמה את הערך הזה על החבילה הנוכחית כדי שהניתוב יקרא אותו.

אמתו את החיפוש ואת המונה יחד

nft list ruleset
ip route get 198.51.100.25
ip route get 198.51.100.25 mark 0x1

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

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

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

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