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

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

הוו כותב קובץ, לא ערך מוחזר

ההצהרה היא שתי שורות: script-security 2 כדי להתיר את הקריאה, ואז client-connect /etc/openvpn/server/assign-address.sh. כשקלקוח מאמת את עצמו, השרת מריץ את הסקריפט הזה עם נתיב הקובץ שנוצר כשהוא מצורף כארגומנט האחרון, שהוא $1 רק אם ההצהרה לא מעבירה ארגומנטים נוספים משלה. כל מה שמוחל על הלקוח הזה נכתב לקובץ הזה כהוראות רגילות, אחת לשורה, בדיוק כפי שהיו מופיעות בקונפיגורציה. עטיפה שמוסיפה פרמטרים משלה מזיזה את המיקום, והסימפטום הקלאסי הוא סקריפט שכותב לנתיב שנראה כמו --verbose.

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

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

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

מיפוי כתובות הוא מדיניות, לא אריתמטיקה

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

מי ששולט בשם שולט בכתובת, אז החליטו מה common_name באמת מייצג בפריסה הזו. כשמופעל username-as-common-name, הזהות היא ההתחברות ולא נושא האישור. לעולם אל תעבירו את הערך הזה להערכת מעטפת, ולעולם אל תתנו ללקוח להשפיע על נתיב קובץ.

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

הטופולוגיה קובעת מה ifconfig-push אומר

עם topology subnet על 10.77.0.0/24, ifconfig-push 10.77.0.20 255.255.255.0 הוא כתובת ועוד מסכת הרשת שלה. תחת topology net30 הארגומנט השני אינו מסכה כלל אלא כתובת העמית, ולכן העתקת צורת רשת המשנה לשרת net30 נותנת לקוח שמתחבר ולא יכול להעביר תעבורה. שנו את הטופולוגיה במכוון, לעולם לא כדי שדוגמה תיראה עקבית. לשרת שכבר מריץ net30 יש לקוחות חיים בכתובות הישנות, ולכן המעבר הוא הגירה עם חלון תחזוקה, לא עריכה של שורה אחת.

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

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

הריצו את אותן בדיקות על זהות ממופה, על לא ממופה, על חיבור מחדש ועל כשל רישום מדומה. openvpn --config client.ovpn --verb 4 מציג את הכתובת שהוקצתה בתגובת ה-push, ובשרת grep -A2 PUSH_REPLY /var/log/openvpn/openvpn.log מאשר מה נשלח בפועל. עבור הזהות הלא ממופה התוצאה הצפויה היא חיבור נדחה, לא כתובת מהמאגר.

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

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

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