הגעה לשירות בלקוח VPN: מנהרה הפוכה או DNAT
הגעה לשירות בלקוח OpenVPN בלי העברת פורט: השוו מנהרת SSH הפוכה מול DNAT בצד השרת ושלושת התנאים שקובעים את הבחירה.
אפילו מחשב נייד מאחורי NAT של הספק יכול לשרת עמית, כל עוד שרת ה-VPN משמש נקודת מפגש. שני מנגנונים מגיעים לשם: הלקוח מתחבר החוצה ומבקש מהשרת להחזיק פורט האזנה, או שהשרת מפרסם פורט ומתרגם אותו אל תוך המנהרה. שניהם פותרים את אותה בעיית נגישות ומתנהגים אחרת בתקלה, בפיקוח וברשומות. שלושה תנאים קובעים איזה מהם שייך להגדרה שלכם.
שתי צורות, נקודת מפגש אחת
בצורה הראשונה הלקוח פותח הפעלת SSH החוצה ומבקש מהשרת להאזין בפורט נבחר, ומחזיר כל חיבור דרך אותה הפעלה. בשרת לא מועבר דבר ולא מתרחש תרגום מנות, ולכן הדרישות היחידות הן חשבון SSH, העברה מורשית וכלל חומת אש לפורט. השירות נשאר כבול ל-loopback בלקוח, וזה בדרך כלל מה שרוצים.
ssh -N -R 8081:127.0.0.1:8080 -o ExitOnForwardFailure=yes -o ServerAliveInterval=30 [email protected]
בצורה השנייה השרת הוא הבעלים של הפורט הציבורי ו-כותב מחדש כל חיבור אל כתובת המנהרה של הלקוח. זה דורש העברת IP מופעלת, תרגום יעד בכניסה ותרגום מקור ביציאה, והוא ממשיך לעבוד כשאין הפעלת SSH. הפורט שייך לשרת ולא להפעלה, וזו התכונה שמכריעה את רוב המקרים האמיתיים.
אף אחת מהצורות אינה בטוחה יותר מכוח המבנה שלה. שתיהן חושפות פורט שירות אחד לכל מי שמגיע לכתובת הציבורית של השרת, ושתיהן עדיין תלויות באימות של השירות עצמו.
תנאי ראשון: האם הפורט חייב לחיות יותר מההפעלה
העברה הפוכה חיה בדיוק כמו הפעלת ה-SSH שיצרה אותה. כשהקישור נופל, המאזין נעלם והעמית רואה חיבור שנדחה במקום נתיב איטי. פיקוח על הפקודה באמצעות יחידת systemd ומדיניות הפעלה מחדש פותר זאת, ו-ExitOnForwardFailure=yes הופך כריכה שנכשלה לגלויה מיד במקום להשאיר הפעלה ללא העברה.
פורט מתורגם שורד אתחולים אם הכללים נשמרים, אבל הוא תלוי בכך שהלקוח ישמור על אותה כתובת מנהרה. מאגר דינמי שנותן למחשב הנייד כתובת אחרת לאחר התחברות מחדש מפנה את הכלל בשקט לשום מקום. הקצו קודם את כתובת המנהרה, אחר כך כתבו את הכלל, והתייחסו לשניים כשינוי אחד.
אם השירות חייב לענות בשלוש לפנות בוקר בלי שאף אחד מסתכל, הצורה עם הפורט שהשרת מפרסם היא בעלת המרכיבים הנעים המעטים ביותר, כי התהליך היחיד שחייב להישאר פעיל הוא המנהרה עצמה.
תנאי שני: למי שייכים חומת האש והרשומות
הצורה ההפוכה מחזיקה את כל המדיניות בשני מקומות. sshd קובע דרך AllowTcpForwarding אם העברות מרחוק מותרות בכלל, ו-GatewayPorts קובע אם המאזין נכרך ל-loopback או לכל כתובת. עם ברירת המחדל no עמית מחוץ לשרת לא יכול להגיע לפורט למרות שההעברה הצליחה, וזה נראה כמו מנהרה שבורה כשבעצם מדובר בכתובת כריכה.
sudo ss -ltn '( sport = :8081 )'
sudo grep -E '^(GatewayPorts|AllowTcpForwarding)' /etc/ssh/sshd_config
הצורה המתורגמת דורשת העברה מופעלת ושני כללים, והכלל השני הוא המקום שבו רוב המתכונים טועים. הגבלת תרגום המקור למצב conntrack DNAT פירושה שרק החיבורים שיצר כלל היעד נכתבים מחדש, במקום כל מנה שהשרת שולח אל המנהרה.
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 8081 -j DNAT --to-destination 10.88.0.6:8080
sudo iptables -t nat -A POSTROUTING -o tun0 -m conntrack --ctstate DNAT -j SNAT --to-source 10.88.0.1
הכתיבה מחדש הזו הורסת גם את הייחוס. אחריה הלקוח רואה כל מתקשר ככתובת המנהרה של השרת, מה שמאחד כל הגבלת קצב לפי כתובת לדלי אחד ומסתיר מי שלח מה. אם הייחוס חשוב, סיימו את החיבור בשרת או השאירו שם את החלטת ההיתר והעבירו זהות בכותרת שהשירות סומך עליה. הבחירה בין שני התיקונים הללו תלויה בשאלה אם השירות קורא כותרת פרוקסי בכלל.
תנאי שלישי: פורט אחד או רבים, ולמי שייך השם
שירות אחד בפורט אחד הוא המקרה שבו ההעברה ההפוכה מנצחת במאמץ. צריך פקודה אחת, חשבון אחד וכלל חומת אש אחד, והניקוי הוא הריגת ההפעלה. כמה שירותים על אותה כתובת ציבורית דוחפים אתכם לצורה שהשרת מפרסם, כי כל העברה הפוכה זקוקה לפורט שרת משלה והקבוצה גדלה עם כל שירות.
שמות מסבכים עוד יותר. העברה הפוכה יכולה לשבת מאחורי פרוקסי TCP שמנתב לפי SNI, בעוד שפורט מתורגם הוא בדרך כלל פורט אחד לשירות. אם השירות מסיים TLS בעצמו וזקוק לשם המארח המקורי, גישת הפרוקסי משמרת אותו וגישת ה-DNAT משמרת אותו רק אם השירות מקבל את השם הזה בפורט הזה.
רשמו איזה משלושת התנאים הכריע את הצורה. אחרת האדם הבא שיוסיף שירות שני יפתח מחדש את אותה השוואה עם פחות הקשר.
החליטו, ואז בדקו מבחוץ
בדקו את הנתיב מרשת שאין לה נתיב למחשב הנייד, וצפו במונים בשרת בזמן שהבקשה רצה. בדיקה מהשרת אל הכתובת הציבורית של עצמו לא מוכיחה כאן דבר, כי המנה נוצרת מקומית ולעולם אינה מגיעה לקרס תרגום הכניסה, כך שהבדיקה יכולה לעבור בעוד הנתיב האמיתי שבור.
sudo iptables -t nat -L PREROUTING -n -v
sudo tcpdump -ni any 'tcp port 8081' -c 20
מונים שנשארים שטוחים אומרים שהמנה לא הגיעה לכלל, מה שמצביע על הספק או על חומת האש של המארח. מונים שזזים בזמן שהשירות מסרב מצביעים על חומת האש של הלקוח עצמו או על הכתובת שהשירות מאזין בה. מנהרה שנושאת את המנה אך אינה מחזירה דבר היא בעיית ניתוב או נתיב חזור, ואף אחד משלושת התוצאות האלה לא צריך להיות מאובחן על ידי עריכת מתאם הלקוח. רשמו איזה מונה זז לפני שתשנו משהו, כי הבדיקה הבאה צריכה את קו הבסיס הזה.
כשהצורה עובדת, רשמו את הפורט, הבעלים ושיטת הפיקוח לצד תצורת המנהרה. תיקון נגישות שקיים רק בהיסטוריית ה-shell של מישהו נמצא אתחול אחד מתקרית חוזרת.