אירועי hook של OpenVPN: למה שם וחותמת זמן אינם מפתח
hook לניתוק מדווח על זמן ההתחברות, לא על זמן הניתוק. בצירוף שם המשתמש הוא עלול לסגור את הסשן הלא נכון; החזיקו זהות במקום.
רשומת ניתוק מגיעה אחרי שכבר החלה התחברות שנייה תחת אותו שם, ומטפל שמעדכן את השורה החדשה ביותר של אותו משתמש סוגר את הסשן הלא נכון. הטעות אינה השוואת חותמות הזמן. היא ההנחה ששם ועוד שנייה שלמה מזהים סשן אחד. אירועי hook מתארים חיבורים, וחיבור זקוק למפתח ששייך רק לו.
התחילו במה שמשתני הניתוק באמת אומרים. רק אז לבחירת המזהה יש היגיון.
מה ה-hook לניתוק באמת נושא
ב-Community OpenVPN 2.6, מסמך ה-hook time_unix מגדיר אותו כרגע שבו הלקוח התחבר; הוא נקבע לפני שה-hook להתחברות רץ, והוא אינו מוגדר מחדש כאשר ה-hook לניתוק מופעל מאוחר יותר. time_duration נותן את אורך הסשן הזה בשניות, כך שהסוף הוא בערך זמן ההתחברות ועוד המשך. שניהם שניות שלמות, ואף אחד מהם אינו הרגע שבו מסד הנתונים שלכם עיבד את האירוע. דווקא החזקת שלושת הזמנים האלה בנפרד היא מה שמאפשר למתאם להחזיק מעמד, במקום רק להיראות נכון בזמן הבדיקות.
החשבון הזה ראוי להירשם, כי זהו זמן הסיום היחיד שה-hook עצמו מציע. עיכוב העיבוד והבדלי שעונים בין מארחים עדיין נמצאים מחוצה לו.
למה הזוג המובן מאליו אינו ייחודי
הצמדת השם לזמן ההתחברות מצמצמת את החיפוש ועדיין אינה מזהה סשן. לקוח יכול להתחבר מחדש בתוך אותה שנייה, כך ששני סשנים יכולים לחלוק את שני הערכים. שני מופעי דמון, או החלפת שרת ששומרת על אותה תצורה, יכולים להפיק את הזוג הזה מתהליכים שונים. כתובות המנהרה מוחזרות לשימוש מאותה סיבה, מה שהופך אותן לתכונות של סשן ולא למזהים שלו.
מצב הכשל שקט. ניתוק מאוחר של הסשן הראשון תואם את השורה החדשה ביותר ומסיים הקצאה שהסשן השני עדיין משתמש בה, כך שהמשתמש חווה אובדן גישה אקראי שהוא לא גרם לו. מספר שורות שנראה נכון לאחר מכן הופך את הבעיה לקשה יותר לאיתור.
מאיפה מגיעה זהות יציבה
ממשק הניהול מקצה לכל לקוח מזהה מופע לקוח, ומזהה זה מוגבל למופע הדמון שהנפיק אותו. מפתח חיצוני שמיש משלב מזהה שרת יציב, תקופה שמשתנה כשהדמון מתחיל, ומזהה הלקוח הזה. התקופה חשובה כי מזהים מתחילים מחדש עם התהליך, ומזהה תהליך חשוף יכול לשמש מאוחר יותר מחדש על ידי משהו לא קשור.
משתני סביבה שנקבעים בתוך סקריפט התחברות בן אינם עוברים לסקריפט הניתוק המאוחר של דמון האב, כי הסקריפטים האלה רצים כתהליכים נפרדים עם סביבות משלהם. לכן יצירת UUID בזמן ההתחברות היא חצי פתרון. צד הניתוק חייב להיות מסוגל לנקוב באותו UUID, כלומר הזהות חייבת לחיות במקום ששני האירועים יכולים להגיע אליו.
הפכו את הפרישה למותנית ולאידמפוטנטית
פרשו לפי בעל הסשן, לא לפי משתמש. מטפל שמוחק כל הקצאה ששייכת כרגע לשם ימחק בסופו של דבר את הלא נכונה, וההגנה היחידה היא לבדוק שהרשומה שמוסרת היא הרשומה שהאירוע הזה מתאר.
ממשק הניהול מקבל לקוח ניהול מחובר אחד בכל פעם, אז השתלבו עם מי שכבר מחזיק בו במקום לחבר צופה שני שמתחרה על אותו socket.
טפלו באירועים חוזרים בלי לשנות את התוצאה פעמיים, ושמרו אירועים לא מותאמים לפיוס במקום לזרוק אותם. לקריאת חזרה של ניתוק יש תנאי מחזור חיים מתועדים והיא עשויה לעולם לא להגיע אחרי קריסה או עצירה קשה, לכן התכנון צריך דרך לייצג סשן שאירוע הסיום שלו חסר.
בדקו את המקרים המסורבלים בכוונה: שני חיבורים מחדש בתוך שנייה אחת, שני מופעי דמון, התחברות שעיבודה נכשל, והפעלה מחדש של דמון באמצע סשן. מפתח ששורד את כל הארבעה הוא מפתח שראוי לאמון.