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

קחו את הדוגמה של לקוחות מורשים ב-10.77.0.0/24 שמגיעים דרך wg0, שואלים את הכתובת המוכרזת 10.77.0.1 וזקוקים ל-resolver ב-203.0.113.53. כתובת המעלה היא מציין מקום לתיעוד ולא שירות פעיל.

הפניית שאילתה משנה רק את היעד שלה

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

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

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

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p udp --dport 53 -j DNAT --to-destination 203.0.113.53:53
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p tcp --dport 53 -j DNAT --to-destination 203.0.113.53:53

נתיב התשובה הוא החלטה נפרדת

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

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

הגבילו את התרגום הזה בדיוק כמו את ההפניה, אחרת הכלל הופך ל-NAT כללי לכל דבר שמתאים לו במקרה:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p udp --dport 53 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p tcp --dport 53 -j MASQUERADE

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

כתבו את הכללים צרים יותר ממה שהמשימה נראית

הרשאת העברה שייכת לאותו היקף. התירו את הזרימה מהלקוח אל ה-resolver ואת תעבורת החזור ש-conntrack כבר מזהה, במקום לקבל כל חיבור DNAT במכונה. קבלה גורפת מתירה גם העברות פורטים שאין להן שום קשר ל-DNS.

ה-resolver של השער עצמו הוא נתיב קוד אחר. שאילתה שנשלחת מקומית עוברת דרך OUTPUT, ולכן בדיקה ממעטפת השער אינה מתרגלת לא את כלל PREROUTING ולא את מדיניות ההעברה. לכן בדיקה מקומית יכולה לעבור בעוד כל לקוח נכשל, וההיפך נפוץ באותה מידה.

שום דבר כאן אינו מכסה DNS על HTTPS בפורט 443 או DNS על TLS בפורט 853, ושום דבר אינו מכסה IPv6. לקוח עם resolver IPv6 מוגדר יתעלם בשמחה מכל הסידור.

מה שאילתה טרייה מוכיחה

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

dig @10.77.0.1 example.com A +short
conntrack -L -p udp --dport 53 | head

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

ודאו שה-resolver מכיר את השמות שאתם מצפים להם לפני שמפנים משהו. תחליף שעונה על שמות ציבוריים אך לא על האזור הפרטי שלכם הופך חיפוש עובד ל-NXDOMAIN שנראה כמו מנהרה שבורה. בדקו את ה-resolver ישירות, מהשער, לפני שנתיב הלקוח מעורב. ואילו הפניה לתוספי iptables מתעד את סמנטיקת DNAT ו-masquerade שהכללים האלה תלויים בה.

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