/dev/net/tun חסר למרות ש-tun טעון: תקנו את צומת ההתקן
מודול tun טעון אינו מוכיח שצומת ההתקן קיים. הפרידו את מנהל ההתקן מהצומת, בנו אותו מחדש לפי הסדר ואמתו אותו באמצעות ממשק.
OpenVPN נעצר עם תלונת errno 2 על /dev/net/tun בעוד lsmod מציג את מודול tun בלי בעיה. שתי העובדות נכונות בו-זמנית. המודול מספק מנהל התקן, והנתיב שהלקוח פותח הוא צומת התקן שמישהו אחר צריך ליצור. התייחסות לשניהם כאובייקט אחד היא הסיבה לכך שהתיקון המובן מאליו — טעינה מחדש של המודול — לא משנה דבר וחצי דבר.
שני אובייקטים, שני בעלים שונים
מודול ליבה וצומת התקן הם אובייקטים בלתי תלויים עם מחזורי חיים בלתי תלויים. טעינת המודול רושמת מנהל התקן, ובמערכת עם devtmpfs הליבה מבקשת ליצור את הצומת המתאים. במערכת בלי devtmpfs שום דבר לא יוצר דבר, ומנהל ההתקן יושב שם בלי נתיב שמצביע עליו. המודול יכול להיות טעון, תקין ובלתי נגיש לחלוטין דרך מערכת הקבצים באותו רגע.
לכן טקסט השגיאה ורשימת המודולים אינם סותרים זה את זה. הלקוח פותח נתיב, הנתיב אינו קיים, והליבה מחזירה ENOENT לפני שמנהל ההתקן tun נשאל בכלל. טעינה מחדש של המודול אינה יכולה לתקן נתיב חסר, ויצירת הנתיב אינה יכולה לתקן מנהל התקן חסר.
lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts
devtmpfs לעומת mknod מפורש
בדרך כלל שני מנגנונים יוצרים את הצומת הזה, וידיעה מי אמור להיות אחראי אומרת לכם מה לתקן. devtmpfs מאפשר לליבה ליצור צומתי התקן במופע מותקן, ו-udev מחיל בעלות והרשאות עליהם. mknod מפורש הוא הנתיב הידני עבור תמונות ומרחבי שמות שבהם אף אחד מהשניים אינו פועל באתחול.
השוו תוצאות ולא כוונות. אם devtmpfs מותקן על /dev והצומת עדיין חסר, מנהל ההתקן אינו זה שאתם מניחים, או שמשהו הסיר את הצומת אחרי האתחול. אם /dev הוא ספרייה רגילה בתוך rootfs שנפרש, אין מנגנון אוטומטי ומי שבונה את התמונה חייב ליצור את הצומת.
stat -c "%F major=%t minor=%T" /dev/net/tun
# expect: character special file major=a minor=c8
היכן שאף אחד מהמנגנונים אינו פועל, הצומת חייב להיעשות ביד, והסדר חשוב. צרו תחילה את ספריית האב, כי mknod אינו יכול להמציא אותה, אחר כך את התקן התו, ואחר כך מצב שמשאיר אותו ניתן לכתיבה רק ל-root. טענו את המודול מחדש לפני יצירת הצומת, והסירו נתיב קיים רק לאחר ש- ls הראה שמדובר בספרייה ולא בהתקן.
sudo modprobe tun
sudo mkdir -p /dev/net
sudo mknod /dev/net/tun c 10 200
sudo chmod 600 /dev/net/tun
ls -l /dev/net/tun
הסוג ש- stat מדווח עליו הוא המבחין המהיר ביותר, וספרייה בנתיב הזה היא ההפתעה הנפוצה ביותר בתמונות מינימליות. mkdir שנכתב בכוונה טובה ב-Dockerfile משאיר בדיוק את זה, ושום כמות של טעינת מודולים אינה מחליפה ספרייה בהתקן תו. Major 10 עם minor 200 הוא הזוג הרשום עבור tun, מבוטא בהקסדצימלי כ-a ו-c8.
ארבעה עקבות, ארבע סיבות
ארבע סיבות מסבירות כמעט כל מקרה, וכל אחת משאירה עקבות שונים ביומנים. התחילו בסביבת האתחול. תמונות בלי דיסק, לוחות משובצים ושלבי initramfs לרוב אינם מתקינים לא devtmpfs ולא /devבניהול udev, ולכן שום תהליך לא כותב את הצומת לעולם. אחר כך קראו את אפשרויות ההתקנה של כל מה שמארח את /dev, כי nodev מתיר לנתיב להתקיים אך מסרב לפותחו, והתקנת bind שנלקחה ממארח מוקשח נושאת את הדגל בלי להכריז על עצמה. התקנה לקריאה בלבד נכשלת מוקדם יותר ובקול רם יותר: mknod מחזיר שם EROFS, בעוד EPERM פירושו שלתהליך חסר היכולת ולא שמערכת הקבצים מגנה על עצמה. לבסוף, סביבת הרצה של מכולות עם /dev tmpfs משלה זקוקה לכך שהצומת יוזרק למרחב השמות שלה, וה-cgroup של ההתקנים שלה חייב להתיר את זוג ה-major וה-minor.
בדקו את שכבת המדיניות לפני ששוב משנים הרשאות. SELinux ו-AppArmor יכולים לסרב לפתיחה שכל מאפייני הקובץ מתירים, וסירוב כזה מופיע ביומן הביקורת ולא בפלט הלקוח. שינוי הרשאה שאף פעם אינו מופיע בסירוב הוא זמן שהושקע בשכבה הלא נכונה לגמרי.
sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5
הוכיחו זאת באמצעות ממשק, לא באמצעות רשימה
רשימה מוצלחת מוכיחה שנתיב קיים ולא יותר. פתחו צומת tun תקין לקריאה והקריאה חוזרת עם שגיאה, כי להתקן אין סמנטיקת קריאה והוא אינו קובץ רגיל. השגיאה הזו היא כאן אות ההצלחה, וזיהויה מונע מכם לרדוף אחריה כתקלה.
head -c 1 /dev/net/tun
head: error reading '/dev/net/tun': File descriptor in bad state
המבחן המכריע יוצר ממשק, כי הוא מפעיל את מנהל ההתקן, את הצומת ואת ההרשאות שלכם בצעד אחד. אם ההוספה מצליחה והקישור מופיע, שלושתם עובדים. כשזה נכשל, errno מפריד בין הסיבות: ENOENT פירושו שאין צומת שמיש, EPERM מצביע על יכולת, דגלי התקנה או מדיניות, ו-EBUSY פירושו שתהליך אחר כבר מחזיק בממשק.
sudo ip tuntap add dev tun7 mode tun
ip -brief link show tun7
sudo ip tuntap del dev tun7 mode tun
הריצו את המבחן הזה בהקשר שנכשל באמת, כי יחידת שירות, מכולה או משימה מתוזמנת יכולים לשאת סט יכולות שונה מזה של מעטפת הכניסה שלכם. מבחן שעובר בהקשר הלא נכון אינו מוכיח דבר על זה שנכשל.
כשההתקן אינו הבעיה
אם מבחן הממשק מצליח והלקוח עדיין נכשל, הבעיה שנותרה היא הפרופיל, הקשר השירות או המסלול, וההתקן תקין. זה הרגע להפסיק לערוך צומתי התקן, כי שינויים נוספים רק מוסיפים מרחק ממערכת עובדת.
הריצו את אותן חמש בדיקות בכל פעם במקום להמציא חדשה: האם המודול טעון בלי מודול מתחרה, האם הנתיב הוא התקן תו עם ה-major וה-minor הנכונים, האם אפשרויות ההתקנה נקיות, האם הקשר התהליך נושא את היכולת, והאם יש סירוב מדיניות בחתימת הזמן של הכשל. תקלה ששורדת את כל החמש אינה בעיית התקן, יהיה אשר יהיה מה שההודעה מזכירה.