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

התאימו את גרסת SOCKS לפני החומת אש

OpenVPN הקהילתי מדבר SOCKS5 עבור socks-proxy. כוונו אותו ל-proxy שמציע רק SOCKS4 והחיבור ב-TCP נפתח ואז נתקע, כי הלקוח ממתין לתשובה לברכה שהצד השני לעולם לא מפענח. מבחוץ, התקיעה הזו נראית בדיוק כמו פורט מסונן, ולכן שאלת הגרסה באה לפני כל כלל חומת אש. שליפה מודעת SOCKS מכריעה את זה בפקודה אחת.

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example

בקשה שהושלמה מוכיחה שני דברים בו-זמנית: הפרוקסי קיבל את בקשת SOCKS והוא פתר את השם. אין צורך בסכימת URL, כי curl מתייחס למארח חשוף כ-HTTP, וזה מספיק לבדיקה הזו.

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

התעבורה חייבת להיות TCP בשני הצדדים

SOCKS5 נושא כאן זרם TCP, ולכן המנהרה עצמה צריכה proto tcp-client. פרופיל שעדיין מוגדר ל-UDP לא יעבוד דרך הנתיב הזה, כי הלקוח לא משתמש במצב שיוך ה-UDP של הפרוטוקול. היפוך הפרופיל הוא שינוי אמיתי ולא פורמלי: הקצה המרוחק חייב להאזין ב-TCP באותו פורט. אז המטען הופך ל-TCP בתוך TCP, שם סגמנט שאבד נשלח מחדש פעמיים והקצב נפגע, מה שסשנים אינטראקטיביים מרגישים הרבה יותר מהעברות גדולות.

proto tcp-client
remote gw.lab.example 8443
socks-proxy 127.0.0.1 9050

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

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

עשיית השרשרת על המארח פירושה השתלטות על נתיב ברירת המחדל שלו והשארת ה-resolver במצב שאיש לא יוכל להסביר אחר כך. מרחב שמות או קונטיינר מגביל אותה במקום, כך שהמארח שומר על הנתיב שלו בזמן שקפיצת SOCKS והמנהרה חיות יחד. שום דבר לא עולה בתוכו בלי התקן מנהרה, בלי הזכויות להגדיר את ההתקן הזה ובלי פרוקסי נגיש. שירות Compose מקבל זאת עם cap_add: NET_ADMIN ו-/dev/net/tun שמותקן ב-bind.

cap_add:
  - NET_ADMIN
devices:
  - /dev/net/tun:/dev/net/tun

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

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

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

docker compose exec vpn cat /etc/resolv.conf
docker compose exec vpn getent hosts internal.lab.example

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

הוכיחו כל קפיצה לפי הסדר

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

curl --socks5-hostname 127.0.0.1:9050 gw.lab.example
docker compose exec vpn ip route get 203.0.113.10
docker compose exec vpn getent hosts internal.lab.example

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

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

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