/dev/net/tun chybí, i když je tun načtený: opravte uzel zařízení
Načtený modul tun nedokazuje, že uzel zařízení existuje. Oddělte ovladač od uzlu, znovu jej sestavte v pořadí a ověřte jej rozhraním.
OpenVPN se zastaví se stížností errno 2 na /dev/net/tun zatímco lsmod bez problémů vypisuje modul tun. Obě skutečnosti platí zároveň. Modul poskytuje ovladač a cesta, kterou klient otevírá, je uzel zařízení, který musí vytvořit něco jiného. Považovat je za jeden objekt je důvod, proč zjevná oprava v podobě znovunačtení modulu nezmění vůbec nic.
Dva objekty, dva různí vlastníci
Modul jádra a uzel zařízení jsou nezávislé objekty s nezávislými životními cykly. Načtení modulu zaregistruje ovladač a v systému s devtmpfs jádro požádá o vytvoření odpovídajícího uzlu. V systému bez devtmpfs nic nic nevytváří a ovladač tam zůstává bez cesty, která by na něj ukazovala. Modul může být načtený, zdravý a zároveň zcela nedostupný přes souborový systém.
Proto si text chyby a výpis modulů neodporují. Klient otevírá cestu, cesta neexistuje a jádro vrátí ENOENT dřív, než je ovladač tun vůbec dotázán. Znovunačtení modulu nemůže opravit chybějící cestu a vytvoření cesty nemůže opravit chybějící ovladač.
lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts
devtmpfs versus explicitní mknod
Ten uzel obvykle vytvářejí dva mechanismy a znalost toho, který má být odpovědný, vám řekne, co opravit. devtmpfs nechává jádro vytvářet uzly zařízení v připojené instanci a udev na ně navrchu aplikuje vlastnictví a oprávnění. Explicitní mknod je ruční cesta pro obrazy a jmenné prostory, kde při bootu neběží ani jeden z nich.
Porovnávejte výsledky, ne úmysly. Pokud je devtmpfs připojen v /dev a uzel stále chybí, ovladač není ten, který předpokládáte, nebo něco uzel po bootu odstranilo. Pokud je /dev obyčejný adresář v rozbaleném rootfs, neexistuje žádný automatický mechanismus a ten, kdo obraz staví, musí uzel vytvořit.
stat -c "%F major=%t minor=%T" /dev/net/tun
# expect: character special file major=a minor=c8
Tam, kde neběží ani jeden mechanismus, musí se uzel vytvořit ručně a na pořadí záleží. Nejprve vytvořte nadřazený adresář, protože mknod ho nedokáže vymyslet, pak znakové zařízení, pak režim, který ho nechá zapisovatelný jen pro root. Před vytvořením uzlu znovu načtěte modul a existující cestu odstraňujte jen poté, co ls ukázal, že jde o adresář, a ne o zařízení.
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, který hlásí stat je nejrychlejší rozlišovač a adresář na této cestě je nejčastější překvapení v minimálních obrazech. Dobře míněný mkdir v Dockerfile zanechá přesně to a žádné načítání modulů nenahradí adresář znakovým zařízením. Major 10 s minor 200 je registrovaná dvojice pro tun, vyjádřená hexadecimálně jako a a c8.
Čtyři stopy, čtyři příčiny
Čtyři příčiny vysvětlují téměř každý případ a každá zanechává v logech jinou stopu. Začněte u bootovacího prostředí. Obrazy bez disku, vestavěné desky a fáze initramfs často nepřipojují ani devtmpfs, ani /devspravovaný udev, takže žádný proces nikdy uzel nezapíše. Potom si přečtěte možnosti připojení toho, co hostuje /dev, protože nodev dovoluje, aby cesta existovala, ale odmítá ji otevřít, a bind mount převzatý z očvrhlého hostitele nese tento příznak, aniž by se ohlásil. Připojení pouze pro čtení selhává dřív a hlasitěji: mknod tam vrací EROFS, zatímco EPERM znamená, že procesu chybí schopnost, a ne že se souborový systém chrání. Nakonec kontejnerový runtime s vlastním /dev tmpfs potřebuje uzel vložit do svého vlastního jmenného prostoru a jeho device cgroup musí povolit dvojici major a minor.
Než znovu změníte oprávnění, zkontrolujte vrstvu politiky. SELinux a AppArmor mohou odmítnout otevření, které všechny atributy souboru povolují, a toto odmítnutí se objeví v auditním logu, ne ve výstupu klienta. Změna oprávnění, která se nikdy neobjeví v odepření, je čas strávený zcela na špatné vrstvě.
sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5
Dokažte to rozhraním, ne výpisem
Úspěšný výpis dokazuje, že cesta existuje a nic víc. Otevřete zdravý uzel tun pro čtení a volání se vrátí s chybou, protože zařízení nemá sémantiku čtení a není běžný soubor. Tato chyba je zde signálem úspěchu a její rozpoznání vám zabrání honit ji jako závadu.
head -c 1 /dev/net/tun
head: error reading '/dev/net/tun': File descriptor in bad state
Rozhodující test vytvoří rozhraní, protože procvičí ovladač, uzel i vaše oprávnění v jediném kroku. Pokud přidání uspěje a spoj se objeví, všechny tři fungují. Když selže, errno oddělí příčiny: ENOENT znamená, že není použitelný uzel, EPERM ukazuje na schopnost, příznaky připojení nebo politiku a EBUSY znamená, že rozhraní už vlastní jiný proces.
sudo ip tuntap add dev tun7 mode tun
ip -brief link show tun7
sudo ip tuntap del dev tun7 mode tun
Spusťte tento test v kontextu, který skutečně selhává, protože service unit, kontejner nebo naplánovaná úloha mohou nést jinou sadu schopností než váš přihlašovací shell. Test, který projde ve špatném kontextu, nic nedokazuje o tom selhávajícím.
Když zařízení není problém
Pokud test rozhraní uspěje a klient stále selhává, zbývající problém je profil, kontext služby nebo trasa a zařízení je v pořádku. To je okamžik přestat editovat uzly zařízení, protože další změny jen přidávají vzdálenost od funkčního systému.
Spouštějte stejných pět kontrol pokaždé, místo abyste vymýšleli novou: je modul načtený bez konkurenčního modulu, je cesta znakovým zařízením se správným major a minor, jsou možnosti připojení čisté, nese kontext procesu schopnost a existuje odepření politiky v časovém razítku selhání. Závada, která přežije všech pět, není problém zařízení, ať zpráva zmiňuje cokoli.