אינכם יכולים לפטור תוכנית ממארח WireGuard עם מנהרה מלאה על ידי עריכת מסלולים. מסלולים בוחרים נתיב לפי יעד, ומה שאתם רוצים לפטור הוא תהליך, ולכן לליבה אין מה להתאים. הגישה הישימה היא לתת לאותו תהליך הקשר רשת משלו: מרחב שמות עם ממשק, כתובות ומסלול ברירת מחדל משלו, המחובר למארח באמצעות זוג veth. הרצתי זאת ב-Ubuntu 24.04 עם wireguard-tools 1.0.20210914, ומרחב השמות מעולם לא היה הבעיה — מדיניות ההעברה של המארח וכללי הסימון של המנהרה היו הבעיה.

בחרו תחילה את סוג ההקשר שאתם צריכים

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

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

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

בנו את ההקשר השני וחברו אותו למארח

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

ip netns add clearnet
ip link add veth-clear-out type veth peer name veth-clear-in
ip addr add 192.168.100.1/24 dev veth-clear-out
ip link set veth-clear-out up
ip link set veth-clear-in netns clearnet
ip netns exec clearnet ip addr add 192.168.100.2/24 dev veth-clear-in
ip netns exec clearnet ip link set veth-clear-in up
ip netns exec clearnet ip route add default via 192.168.100.1

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

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o <wan-interface> -j MASQUERADE

ודאו את צד מרחב השמות לפני שתמשיכו.ip netns exec clearnet ip route אמור להציג את מסלול veth ואת מסלול ברירת המחדל דרך 192.168.100.1, ופינג לכתובת הזו אמור לענות. אם הפינג לכתובת המארח נכשל, הכתובות או מצב הקישור שגויים ואף כלל חומת אש לא יעזור.

כששמות נפתרים אבל שום דבר לא חוזר, קראו את FORWARD

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

קראו את השרשרת לפני שמוסיפים משהו:

iptables -S FORWARD
nft list chain inet filter forward

אחר כך התירו את התעבורה בשני הכיוונים, עם מונים, כדי שתדעו אם הכלל אי פעם התאים:

iptables -A FORWARD -i veth-clear-out -o <wan-interface> -j ACCEPT
iptables -A FORWARD -i <wan-interface> -o veth-clear-out -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
watch -n1 'iptables -L FORWARD -v -n'

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

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

הרחיקו את כללי הסימון של המנהרה מהנתיב החדש

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

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

iptables -t mangle -I PREROUTING -s 192.168.100.0/24 -j RETURN
ip rule add from 192.168.100.0/24 lookup main priority 100

עדיפות 100 מסתדרת לפני כללי המנהרה במארח שלי, ולכן הטבלה הרגילה מכריעה עבור אותו מקור. אל תעתיקו את המספר בעיוורון: העדיפויות ש-wg-quick מתקין שונות בין גרסאות ובין התקנות IPv4 ו-IPv6, לכן הריצו ip rule show ובחרו עדיפות שנופלת לפני כללי המנהרה במחשב שלכם.

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

ip route get 1.1.1.1 from 192.168.100.2
ip netns exec clearnet ip route get 1.1.1.1

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

הפעילו את התהליך שפותח את החיבור

הפעלת הפקודה היא שורה אחת, אבל הפעילו את התהליך שבאמת יוצר את השקע.ip netns exec clearnet curl -s https://ifconfig.me היא המבחן הישר הקטן ביותר: היא מציגה את הכתובת שמרחב השמות מציג לעולם, לא זו שהמארח היה משתמש בה.

עבור שירות, חברו את מרחב השמות לפי נתיב כדי שהתהליך יישאר בו כל חייו:

[Service]
NetworkNamespacePath=/run/netns/clearnet

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

readlink /proc/$(pgrep -f clearnet-profile | head -1)/ns/net
readlink /run/netns/clearnet

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

פתרון שמות צריך החלטה משלו. יצירת מרחב שמות אינה נותנת לו תצורת פותר; קבצים לכל מרחב שמות נתמכים דרך /etc/netns/<name>/resolv.conf ובלי אחד אתם יורשים התנהגות שקל לקרוא אותה לא נכון. IPv6 צריך את אותו יחס: אם למרחב השמות אין מסלול ברירת מחדל v6 בעוד היישום מעדיף v6, בקשות עלולות להיתקע לפני נסיגה, וזה נראה כמו מנהרה שבורה.

בדקו את המסגור, לא רק את כתובת היציאה

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

  • ip netns exec clearnet ip route get 1.1.1.1 מציג את מסלול ברירת המחדל של veth, לא את ממשק WireGuard.
  • מוני FORWARD בשני הכללים גדלים בזמן שבקשה פועלת.
  • תהליך היישום מדווח על ה-inode של מרחב השמות שאתם מצפים לו.
  • לאחר אתחול מרחב השמות קיים לפני שהשירות מתחיל; יחידה שרצה מוקדם יותר נכשלת או, גרוע מכך, רצה מחוץ למרחב השמות.

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

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