OpenVPN sa zastaví so sťažnosťou errno 2 na /dev/net/tun zatiaľ čo lsmod bez problémov vypisuje modul tun. Obe skutočnosti platia súčasne. Modul poskytuje ovládač a cesta, ktorú klient otvára, je uzol zariadenia, ktorý musí vytvoriť niečo iné. Považovať ich za jeden objekt je dôvod, prečo zjavná oprava v podobe opätovného načítania modulu nezmení vôbec nič.

Dva objekty, dvaja rôzni vlastníci

Modul jadra a uzol zariadenia sú nezávislé objekty s nezávislými životnými cyklami. Načítanie modulu zaregistruje ovládač a v systéme s devtmpfs jadro požiada o vytvorenie zodpovedajúceho uzla. V systéme bez devtmpfs nič nič nevytvára a ovládač tam zostáva bez cesty, ktorá by naň ukazovala. Modul môže byť načítaný, zdravý a zároveň úplne nedostupný cez súborový systém.

Preto si text chyby a výpis modulov neodporujú. Klient otvára cestu, cesta neexistuje a jadro vráti ENOENT skôr, než sa ovládač tun vôbec opýta. Opätovné načítanie modulu nemôže opraviť chýbajúcu cestu a vytvorenie cesty nemôže opraviť chýbajúci ovládač.

lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts

devtmpfs verzus explicitný mknod

Ten uzol zvyčajne vytvárajú dva mechanizmy a znalosť toho, ktorý má byť zodpovedný, vám povie, čo opraviť. devtmpfs necháva jadro vytvárať uzly zariadení v pripojenej inštancii a udev na ne navrchu aplikuje vlastníctvo a oprávnenia. Explicitný mknod je ručná cesta pre obrazy a menné priestory, kde pri boote nebeží ani jeden z nich.

Porovnávajte výsledky, nie úmysly. Ak je devtmpfs pripojený v /dev a uzol stále chýba, ovládač nie je ten, ktorý predpokladáte, alebo niečo uzol po boote odstránilo. Ak je /dev obyčajný adresár v rozbalenom rootfs, neexistuje žiadny automatický mechanizmus a ten, kto obraz stavia, musí uzol vytvoriť.

stat -c "%F major=%t minor=%T" /dev/net/tun
# expect: character special file major=a minor=c8

Tam, kde nebeží ani jeden mechanizmus, musí sa uzol vytvoriť ručne a na poradí záleží. Najprv vytvorte nadradený adresár, pretože mknod ho nedokáže vymyslieť, potom znakové zariadenie, potom režim, ktorý ho nechá zapisovateľný len pre root. Pred vytvorením uzla znova načítajte modul a existujúcu cestu odstraňujte len potom, čo ls ukázal, že ide o adresár a nie o zariadenie.

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

Typ, ktorý hlási stat je najrýchlejší rozlišovač a adresár na tejto ceste je najčastejšie prekvapenie v minimálnych obrazoch. Dobre mienený mkdir v Dockerfile zanechá presne to a žiadne načítanie modulov nenahradí adresár znakovým zariadením. Major 10 s minor 200 je registrovaná dvojica pre tun, vyjadrená hexadecimálne ako a a c8.

Štyri stopy, štyri príčiny

Štyri príčiny vysvetľujú takmer každý prípad a každá zanecháva v logoch inú stopu. Začnite u bootovacieho prostredia. Obrazy bez disku, vstavané dosky a fázy initramfs často nepripájajú ani devtmpfs, ani /devspravovaný udev, takže žiadny proces nikdy uzol nezapíše. Potom si prečítajte možnosti pripojenia toho, čo hostuje /dev, pretože nodev dovoľuje, aby cesta existovala, ale odmieta ju otvoriť, a bind mount prevzatý z očvrsnutého hostiteľa nesie túto príznak, bez toho aby sa ohlásil. Pripojenie iba na čítanie zlyháva skôr a hlasnejšie: mknod tam vracia EROFS, zatiaľ čo EPERM znamená, že procesu chýba schopnosť, a nie že sa súborový systém chráni. Nakoniec kontajnerový runtime s vlastným /dev tmpfs potrebuje uzol vložiť do svojho vlastného menného priestoru a jeho device cgroup musí povoliť dvojicu major a minor.

Pred ďalšou zmenou oprávnení skontrolujte vrstvu politiky. SELinux a AppArmor môžu odmietnuť otvorenie, ktoré všetky atribúty súboru povoľujú, a toto odmietnutie sa objaví v audítnom logu, nie vo výstupe klienta. Zmena oprávnení, ktorá sa nikdy neobjaví v odmietnutí, je čas strávený úplne na nesprávnej vrstve.

sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5

Dokážte to rozhraním, nie výpisom

Úspešný výpis dokazuje, že cesta existuje a nič viac. Otvorte zdravý uzol tun na čítanie a volanie sa vráti s chybou, pretože zariadenie nemá sémantiku čítania a nie je bežný súbor. Táto chyba je tu signálom úspechu a jej rozpoznanie vám zabráni hnať sa za ňou ako za poruchou.

head -c 1 /dev/net/tun
head: error reading '/dev/net/tun': File descriptor in bad state

Rozhodujúci test vytvorí rozhranie, pretože precvičí ovládač, uzol aj vaše oprávnenia v jedinom kroku. Ak pridanie uspeje a spoj sa objaví, všetky tri fungujú. Keď zlyhá, errno oddelí príčiny: ENOENT znamená, že nie je použiteľný uzol, EPERM ukazuje na schopnosť, príznaky pripojenia alebo politiku a EBUSY znamená, že rozhranie už vlastní iný proces.

sudo ip tuntap add dev tun7 mode tun
ip -brief link show tun7
sudo ip tuntap del dev tun7 mode tun

Spustite tento test v kontexte, ktorý skutočne zlyháva, pretože service unit, kontajner alebo naplánovaná úloha môžu niesť inú sadu schopností než váš prihlasovací shell. Test, ktorý prejde v nesprávnom kontexte, nič nedokazuje o tom zlyhávajúcom.

Keď zariadenie nie je problém

Ak test rozhrania uspeje a klient stále zlyháva, zostávajúci problém je profil, kontext služby alebo trasa a zariadenie je v poriadku. To je okamih prestať upravovať uzly zariadení, pretože ďalšie zmeny len pridávajú vzdialenosť od funkčného systému.

Spúšťajte rovnakých päť kontrol zakaždým, namiesto vymýšľania novej: je modul načítaný bez konkurenčného modulu, je cesta znakovým zariadením so správnym major a minor, sú možnosti pripojenia čisté, nesie kontext procesu schopnosť a existuje odmietnutie politiky v časovej značke zlyhania. Porucha, ktorá prežije všetkých päť, nie je problém zariadenia, nech správa spomína čokoľvek.

Súvisiace články