ההתחברות עובדת, PWD עובד, ואז LIST נתקע עד שהלקוח מתייאש או עובר למצב נתונים אחר. הפיצול הזה הוא החתימה: חיבור הבקרה לפורט 21 בריא, בעוד חיבור הנתונים נבנה מכתובת או מפורט שהצד השני לא יכול להגיע אליהם. מאחורי שער VPN שעושה גם NAT, האשם הרגיל הוא פקודת FTP שהמטען שלה נוקב בכתובת מנהרה כמו 10.8.0.6. תרגום הכותרות לא נוגע בערך הזה אף פעם.

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

מה שנשבר הוא המטען, לא המנהרה

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

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

שלושה מצבים, שלושה מטענים

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

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

ModeValue in the control streamWho dials whomHeader-only NAT leaves
Active (PORT)client address and portserver dials the clienta server dialing an unreachable tunnel address
Passive (227)server address and portclient dials the servera client dialing an address it cannot route to
FTPSthe same values, inside TLSas aboveciphertext, so no rewrite happens at all

שימו את העוזר במקום שבו מתרחש התרגום

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

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

modprobe nf_conntrack_ftp
lsmod | grep nf_conntrack_ftp
conntrack -L expect | grep ftp

לטעון את המודול זה לא אותו דבר כמו לחבר אותו. קרנלים מ-4.7 והלאה מגיעים עם net.netfilter.nf_conntrack_helper=0, ולכן העוזר ממתין לכלל מפורש, למשל iptables -t raw -A PREROUTING -p tcp --dport 21 -j CT --helper ftp. אם רשימת הציפיות נשארת ריקה בזמן שמנסים העברה, החיבור הוא מה שצריך לבדוק, לא המודול.

מצב פסיבי: אמרו לשרת מה לפרסם

קל יותר לעשות את המצב הפסיבי דטרמיניסטי כי אפשר לומר לשרת מה לשים בתשובת 227. ב-vsftpd זה pasv_address, יחד עם pasv_min_port ו-pasv_max_port; ProFTPD משתמש ב-MasqueradeAddress וב-PassivePorts. הגדירו אותם קודם, כי כתובת מפורסמת נכונה מסירה את הצורך לשכתב משהו בצד הזה.

אחר כך תנו בדיוק לטווח הפורטים הזה לעבור בשער, למשל -A FORWARD -i tun0 -p tcp --dport 30000:30100 -j ACCEPT, כדי שהכלל יתאים למה שהשרת מפרסם.

שתי ההגדרות חייבות להסכים. שרת שנאמר לו לפרסם 30000-30100 בזמן שהשער מתיר 40000-40100 נכשל בדרך הכי פחות מועילה: שיחת הבקרה נראית בריאה וכל חיבור נתונים מת. השוו את המספרים לפני שאתם מנסים לתקן משהו אחר.

שתי חתימות כשל, ומה FTPS מסיר

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

FTP מעל TLS מסיר את המטען שהעוזר קורא. תיבת ביניים לא יכולה לשכתב ערך PORT או PASV שהיא לא יכולה לפענח, ולכן האפשרויות שנותרו הן פרוקסי שמסיים TLS, שרת שמפרסם כתובת נגישה בתוך טווח תחום, או פרוטוקול העברה אחר.

סדר קצר של בדיקות

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

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

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