העברה דינמית של SSH כפרוקסי SOCKS מעל ה-VPN שלכם
לאפליקציה שמדברת רק SOCKS אין נקודת קצה של פרוקסי ב-VPN רגיל. שתי קפיצות, מאזין loopback אחד וחיפוש שם שעל שרת ה-SSH לעשות בעצמו.
לאפליקציה שמדברת רק SOCKS אין עם מה לדבר ב-VPN רגיל, כי המנהרה נושאת מנות והאפליקציה רוצה נקודת קצה של פרוקסי. OpenSSH יכול לספק את נקודת הקצה הזאת כשבעל הגישה מתיר זאת, כי העברה דינמית הופכת סשן SSH אחד לפרוקסי מקומי. אחר כך יש שתי קפיצות שצריך להחזיק בנפרד: המנהרה שמגיעה למארח ה-SSH, והחיבור שהמארח הזה פותח הלאה. ההפרדה ביניהן מסבירה גם למה הסידור עובד וגם מה הוא לעולם לא יעשה.
למה מאזין ה-SSH הופך ולמה לא
העברה דינמית גורמת ללקוח ה-SSH להאזין מקומית ולדבר SOCKS4 או SOCKS5 עם כל מה שמתחבר. כל בקשה נוקבת ביעד ושרת ה-SSH פותח את החיבור שלהלן, ולכן חיפוש היעד יכול להתבצע בצד הרחוק. זוהי העברת TCP ברמת האפליקציה, לא VPN לכל המכשיר. היא אינה נושאת שיוך UDP, לא ICMP, ולא דבר לאפליקציות שמתעלמות לגמרי מהגדרות פרוקסי. גם הקפיצה משרת ה-SSH לאפליקציה אינה בתוך המנהרה שלכם, וזה חשוב כשהיעד מקבל תעבורה רק מרשתות מוכרות.
התנאים המוקדמים אמיתיים: מסלול למארח ה-SSH, חשבון מורשה, מפתח מארח מאומת של השרת והרשאה להעביר. אף אחד מהם לא נוצר על ידי הפרוקסי, והאחרון הוא בדרך כלל הראשון שחסר. אמתו את כל הארבעה לפני שאתם מנתחים משהו אחר, כי מהצד של הלקוח הכשל נראה זהה, לא משנה מה חסר.
הפעילו אותו על loopback עם פורט מפורש
בחרו פורט מקומי שאינו בשימוש וקשרו אותו במפורש ל-loopback במקום להשאיר את הכתובת חסרה. שלוש האפשרויות שלהלן קיימות כל אחת מסיבה אחת.
ssh -D 127.0.0.1:1080 -NT -o ControlPath=none -o ExitOnForwardFailure=yes \
[email protected]
-N מדלג על הפקודה המרוחקת ו--T מדלג על הפסאודו-טרמינל, כך שהסשן קיים רק כדי להעביר. ExitOnForwardFailure גורם ללקוח לצאת כאשר לא ניתן ליצור את המאזין, במקום לרוץ בלי ההעברה שביקשתם. ControlPath=none מרחיק את הסשן מחיבור מרובה קיים שעלול להוסיף העברות משלו. loopback מרחיק את המאזין מה-LAN, אבל במחשב משותף זה לא גבול הרשאה, כי גם תהליכים מקומיים אחרים יכולים להגיע אליו. תיעוד לקוח OpenSSH מתעד את כל הדגלים האלה, והאזהרה לגבי loopback נובעת ממה שהוא socket מאזין.
שלחו שמות דרך הפרוקסי, לא סביבו
לקוח SOCKS5 יכול לפתור את היעד בעצמו או לבקש מהפרוקסי לעשות זאת, והבחירה הזאת קובעת איזה פותר עונה. עם socks5h curl שולח את שם המארח דרך הפרוקסי, כך שהחיפוש מתבצע בשרת ה-SSH. עם socks5 רגיל המחשב הנייד פותר קודם ורק החיבור נוסע, מה שמאיין בשקט את המטרה כשהשם פנימי. הבקשה שלהלן גם מנקה את רשימת היעדים ללא פרוקסי, כך שערך NO_PROXY שעבר בירושה לא יוכל להסיט אותה סביב הפרוקסי.
curl -sS --noproxy '' --proxy socks5h://127.0.0.1:1080 https://app.corp.example/health
אימות התעודה והכניסה של האפליקציה עצמה עדיין חלים, כי הפרוקסי לא מחליף אף אחד מהם. נשארים שני חיפושים: המחשב הנייד חייב להגיע למארח ה-SSH דרך מסלול ה-VPN וה-DNS המותר, ושרת ה-SSH חייב לפתור בעצמו את שם האפליקציה. את השני אפשר לבדוק בנפרד לפני שתעבורה כלשהי עוברת דרך הפרוקסי.
ssh [email protected] getent hosts app.corp.example
הוכיחו יעד מורשה אחד, ואז סגרו את הסשן
בדקו יעד שהמדיניות מתירה ויעד שהיא אמורה לסרב לו, כי העברה שעובדת מוכיחה רק שהמאזין עובד ולא יותר. האפליקציה רואה את כתובת המקור ששרת ה-SSH בוחר, וזו אינה כתובת המנהרה של המחשב הנייד שלכם. כשהצד הרחוק רושם חיבורים לפי מקור, ההבדל הזה הוא הדבר הראשון לבדוק כשבקשה נדחית.
עצרו את הסשן דרך התהליך שבבעלותו ולא על ידי הריגת shell לא קשור. אחר כך ודאו שהמאזין נעלם, כי פורט שעדיין עונה הוא סשן שלא סגרתם באמת. הסירו רק את הגדרת הפרוקסי שהתרגיל הזה הכניס, והשאירו את שאר תצורת האפליקציה בשקט. מסוף ללא השגחה שמחזיק בכלל העברה אינו שירות, ו-פרוקסי קבוע דורש מחזור חיים מאושר, לא חלון נשכח.
ss -ltn | grep 1080
כשלים שהסידור הזה לא יכול לתקן
כמה תסמינים מצביעים ישר על המגבלות שלמעלה, וזיהוי מוקדם שלהם חוסך אחר צהריים של ניפוי פרוקסי. הטבלה ממפה את מה שאתם רואים למה שזה בדרך כלל אומר. כל דבר בעמודה האחרונה הוא שאלת תכנון ולא טעות תצורה.
| What you see | What it usually means | Where to look |
|---|---|---|
| The app connects and nothing follows | It ignores proxy settings entirely | Its own network settings, not the SSH session |
| A name resolution error for the destination | The SSH server cannot resolve it | Server resolver and search domains |
| A UDP-only application fails | Dynamic forwarding carries TCP only | This arrangement cannot serve it |
| curl works, the browser does not | The browser is not using the socks5h endpoint | Browser proxy configuration |
| The listener answers after the session ended | Another process owns port 1080 | The ss output, then the owning process |
שלוש השורות הראשונות הן אלה שאנשים מאבחנים לא נכון, כי כל אחת מהן מייצרת ניסיון חיבור ולא שגיאה על הפרוקסי עצמו. שם שנפתר במחשב הנייד לא אומר דבר על הפותר של השרת, והכשל נקרא במקום זאת כבעיית תעודה או פסק זמן. אפליקציות UDP בלבד עומדות מחוץ לתכנון, לא שבורות בתוכו, ושום אפשרות ssh נוספת לא משנה זאת. שורת הדפדפן היא התזכורת הרגילה לכך שהגדרות פרוקסי הן לפי אפליקציה. השורה האחרונה היא הסיבה לכך שבדיקת הסגירה קיימת: פורט שעדיין מאזין פירושו שעכשיו משהו אחר מחזיק בו.