ווי PHP של OpenVPN: trusted_ip מול ifconfig_pool_remote_ip
שתי כתובות עם שני משמעויות שונות, שנקראות על ידי תהליך שלא אתה הפעלת. מה הם משתני הוו, ולמה $_ENV ריק לא מוכיח דבר.
מערך $_ENV ריק בסקריפט ווי נראה כמו הוכחה ש־OpenVPN לא העביר דבר. בדרך כלל זו הוכחה למשהו אחר לגמרי: PHP הוגדר לא לאכלס את המשתנה העל-גלובלי ההוא, והערכים ישבו בסביבת התהליך כל הזמן. המסקנה השגויה השנייה עדינה יותר, מפני ששני משתני הכתובת בוו חיבור מתכוונים לדברים שונים ומשמשים לסירוגין. שתי הטעויות עולות אחר צהריים שלם אם מתחילים מהשגויה.
שתי כתובות, שתי טענות שונות
קצה החוץ הוא מה שהשרת צפה בו כשהלקוח התחבר, זמין כ-trusted_ip עבור IPv4 וכ-trusted_ip6 עבור IPv6. הכתובת הווירטואלית היא מה שהמאגר הקצה לסשן הזה, זמינה כ-ifconfig_pool_remote_ip.
הן עונות על שאלות שונות, ורשומה בדרך כלל צריכה אחת מהן ולא את שתיהן. הראשונה היא מהיכן הגיע החיבור, שיכול להיות כתובת NAT משותפת שמשתמשים בה מאות אנשים. השנייה היא היכן הסשן הזה חי בתוך המנהרה, והיא יכולה להיות מוקצית מחדש לסשן אחר מאוחר יותר. ערבוב בין השתיים מייצר רשומות שנראות סבירות והן שגויות.
קריאה מינימלית נראית כך.
$outer4 = getenv('trusted_ip');
$outer6 = getenv('trusted_ip6');
$inner = getenv('ifconfig_pool_remote_ip');
$outer = $outer4 !== false ? $outer4 : $outer6;אף אחד משני הערכים אינו מזהה אדם. האחד הוא תצפית רשת, השני הוא חכירה, ורשומה שמתייחסת לאחד מהם כמזהה מכשיר יציב תהיה שגויה בפעם הראשונה שלקוח מתחבר מחדש מרשת אחרת או מקבל כתובת מאגר אחרת. בחרו את השדה לפי השאלה שהרשומה חייבת לענות עליה, ואז כתבו את השאלה הזו לצד העמודה.
בדקו איך הופעל PHP, ולא את מעטפת הפקודות שלכם
הוו רץ כבן של דמון ה-VPN עם סביבה שהדמון בונה. למעטפת האינטראקטיבית שלכם יש סביבה אחרת, והרצת הסקריפט ביד בודקת את סביבת המעטפת ולא את זו של הוו.
התחילו באימות שהוו אכן הופעל בשלב שציפיתם לו. סקריפט שמחובר לשלב שגוי, או כזה שמעולם לא רץ מפני שההנחיה מצביעה על נתיב אחר, נותן בדיוק את אותו סימפטום כמו משתנה חסר. הוסיפו שורת סמן מכוונת בראש הסקריפט ואמתו שהיא מופיעה לפני שתבדקו משהו אחר. שורה אחת עם חתימת זמן ביומן מפרידה בין «מעולם לא רץ» לבין «רץ בלי הערך».
אחר כך אמתו איזה מפרש ואיזה קובץ תצורה משתמש באותה קריאה. עריכת תצורת PHP של שרת אינטרנט לא משנה דבר בתהליך CLI שהופעל על ידי OpenVPN, ושניהם יכולים לטעון קבצי php.ini שונים לגמרי.
למה $_ENV ריק לא מוכיח דבר
התיעוד של getenv ב-PHP מתאר קריאה ישירה של סביבת התהליך, שמחזירה false כשהשם חסר. המשתנה העל-גלובלי $_ENV מאוכלס בנפרד, וההנחיה variables_order קובעת אילו משתנים על-גלובליים יאוכלסו.
אם ההנחיה הזו משמיטה את E, $_ENV נשאר ריק בלי קשר למה שהסביבה מכילה. קוד שמאנדקס אותו מדווח אז על משתנה חסר שלמעשה קיים, והחקירה פונה לעבר OpenVPN כשהתשובה נמצאת ב-php.ini. בדקו את ההנחיה במיוחד עבור תצורת ה-CLI, לא עבור שרת האינטרנט.
קריאה עם getenv נמנעת מכל מחלקת הבלבול הזו, וסקריפט עוטף שמנקה את הסביבה לפני קריאה למפרש מחזיר אותה בצורה אחרת.
אחסנו קשר, לא עדכון שורה
החליטו איזה ערך הרשומה צריכה לפני שכותבים אותו. אם המטרה היא לציין מהיכן הגיע סשן, אחסנו את קצה החוץ ותייגו אותו כתצפית. אם המטרה היא למפות סשן לכתובת מנהרה למשך חיבור, אחסנו את כתובת המאגר וקשרו אותה לסשן.
עדכנו לפי הזהות המאומתת והסשן הנוכחי ולא לפי כל שורה שחולקת כתובת מנהרה, מפני שכתובות מאגר נמצאות בשימוש חוזר ואירוע ניתוק מאוחר יכול אחרת לדרוס את הנתונים של חיבור חדש יותר. טפלו ב-IPv6 במפורש במקום לכתוב בשקט רק את ערך ה-IPv4. שורה עם כתובת חוץ NULL עדיפה על שורה עם הכתובת השגויה, מפני שהראשונה גלויה כחסרה.
קשרו את הכתיבה למזהה הסשן ש-OpenVPN מספק כדי שחיבור מחדש ייצור רשומה חדשה ולא יערוך את הישנה. השתמשו בהצהרות עם פרמטרים ובחשבון עם רק ההרשאות שהפעולה צריכה. ווי רץ בסמכות הדמון, ולכן שאילתה רשלנית היא בעיה רחבה יותר משורת יומן שגויה.
אבחנו בלי לשפוך את הסביבה
תעדו אילו שמות היו נוכחים, איזה שלב רץ ואיזה מפרש שימש. אל תדפיסו את כל הסביבה, מפני שתהליך ווי יכול לרשת ערכים לא קשורים שאסור שיגיעו לקובץ יומן.
אמתו חיבור אחד מקצה לקצה: קראו את קצה החוץ, קראו את הכתובת שהוקצתה, ואמתו את שניהם מול התצוגה של השרת עצמו על אותו סשן. לאחר שהזוג אומת עבור לקוח אחד, אפשר לתת אמון בקשר במקומות אחרים.