/dev/net/tun brakuje mimo wczytanego tun: napraw węzeł urządzenia
Wczytany moduł tun nie dowodzi, że węzeł urządzenia istnieje. Oddziel sterownik od węzła, odtwórz go po kolei i zweryfikuj interfejsem.
OpenVPN zatrzymuje się ze skargą errno 2 dotyczącą /dev/net/tun podczas gdy lsmod bez przeszkód wymienia moduł tun. Oba fakty są prawdziwe jednocześnie. Moduł dostarcza sterownik, a ścieżka, którą otwiera klient, jest węzłem urządzenia, który musi utworzyć coś innego. Traktowanie ich jako jednego obiektu jest powodem, dla którego oczywista naprawa polegająca na ponownym wczytaniu modułu nie zmienia absolutnie nic.
Dwa obiekty, dwóch różnych właścicieli
Moduł jądra i węzeł urządzenia to niezależne obiekty o niezależnych cyklach życia. Wczytanie modułu rejestruje sterownik, a w systemie z devtmpfs jądro prosi o utworzenie odpowiedniego węzła. W systemie bez devtmpfs nic niczego nie tworzy, a sterownik siedzi tam bez żadnej ścieżki, która by na niego wskazywała. Moduł może być jednocześnie wczytany, zdrowy i całkowicie nieosiągalny przez system plików.
Dlatego tekst błędu i lista modułów nie przeczą sobie. Klient otwiera ścieżkę, ścieżka nie istnieje, a jądro zwraca ENOENT, zanim sterownik tun w ogóle zostanie zapytany. Ponowne wczytanie modułu nie naprawi brakującej ścieżki, a utworzenie ścieżki nie naprawi brakującego sterownika.
lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts
devtmpfs kontra jawny mknod
Zwykle ten węzeł tworzą dwa mechanizmy, a wiedza, który powinien być odpowiedzialny, mówi, co naprawić. devtmpfs pozwala jądru tworzyć węzły urządzeń w zamontowanej instancji, a udev nakłada na nie własność i uprawnienia. Jawny mknod to ręczna droga dla obrazów i przestrzeni nazw, w których żaden z nich nie działa przy starcie.
Porównuj skutki, a nie intencje. Jeśli devtmpfs jest zamontowany w /dev i węzła nadal nie ma, sterownik nie jest tym, którego zakładasz, albo coś usunęło węzeł po starcie. Jeśli /dev jest zwykłym katalogiem w rozpakowanym rootfs, nie ma żadnego mechanizmu automatycznego i ten, kto buduje obraz, musi utworzyć węzeł.
stat -c "%F major=%t minor=%T" /dev/net/tun
# expect: character special file major=a minor=c8
Tam, gdzie nie działa żaden z mechanizmów, węzeł trzeba zrobić ręcznie, a kolejność ma znaczenie. Najpierw utwórz katalog nadrzędny, bo mknod nie potrafi go wymyślić, potem urządzenie znakowe, potem tryb, który zostawia je zapisywalne tylko dla roota. Wczytaj moduł ponownie, zanim utworzysz węzeł, a istniejącą ścieżkę usuń dopiero po tym, jak ls pokaże, że to katalog, a nie urządzenie.
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
Najszybszym rozróżnieniem jest typ zgłaszany przez stat a katalog w tej ścieżce to najczęstsza niespodzianka w minimalnych obrazach. Dobrze pomyślany mkdir w Dockerfile zostawia dokładnie to, a żadna ilość wczytywania modułów nie zastąpi katalogu urządzeniem znakowym. Major 10 z minor 200 to zarejestrowana para dla tun, wyrażona szesnastkowo jako a i c8.
Cztery ślady, cztery przyczyny
Cztery przyczyny wyjaśniają niemal każdy przypadek, a każda zostawia inny ślad w logach. Zacznij od środowiska startowego. Obrazy bez dysku, płytki wbudowane i etapy initramfs często nie montują ani devtmpfs, ani /devzarządzanego przez udev, więc żaden proces nigdy nie zapisuje węzła. Potem przeczytaj opcje montowania tego, co hostuje /dev, bo nodev pozwala ścieżce istnieć, ale odmawia jej otwarcia, a montowanie bind wzięte z utwardzonego hosta niesie tę flagę, nie ogłaszając się. Montowanie tylko do odczytu zawodzi wcześniej i głośniej: mknod zwraca tam EROFS, podczas gdy EPERM oznacza, że procesowi brakuje zdolności, a nie że system plików chroni sam siebie. Wreszcie środowisko uruchomieniowe kontenerów z własnym /dev tmpfs potrzebuje węzła wstrzykniętego do własnej przestrzeni nazw, a jego cgroup urządzeń musi zezwalać na parę major i minor.
Sprawdź warstwę polityki, zanim znowu zmienisz uprawnienia. SELinux i AppArmor mogą odmówić otwarcia, które dopuszcza każdy atrybut pliku, a ta odmowa pojawia się w logu audytu, a nie w wyjściu klienta. Zmiana uprawnień, która nigdy nie pojawia się w odmowie, to czas spędzony na całkowicie niewłaściwej warstwie.
sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5
Udowodnij to interfejsem, nie listą
Udana lista dowodzi, że ścieżka istnieje i nic więcej. Otwórz zdrowy węzeł tun do odczytu, a wywołanie wraca z błędem, bo urządzenie nie ma semantyki odczytu i nie jest zwykłym plikiem. Ten błąd jest tu sygnałem sukcesu, a rozpoznanie go powstrzymuje cię przed ściganiem go jako usterki.
head -c 1 /dev/net/tun
head: error reading '/dev/net/tun': File descriptor in bad state
Decydujący test tworzy interfejs, bo ćwiczy sterownik, węzeł i twoje uprawnienia w jednym kroku. Jeśli dodanie się powiedzie i link się pojawi, wszystkie trzy działają. Gdy zawodzi, errno rozdziela przyczyny: ENOENT oznacza brak użytecznego węzła, EPERM wskazuje na zdolność, flagi montowania lub politykę, a EBUSY oznacza, że interfejs ma już inny proces.
sudo ip tuntap add dev tun7 mode tun
ip -brief link show tun7
sudo ip tuntap del dev tun7 mode tun
Uruchom ten test w kontekście, który naprawdę zawodzi, bo jednostka usługi, kontener lub zadanie zaplanowane mogą nieść inny zestaw zdolności niż twoja powłoka logowania. Test, który przechodzi w złym kontekście, niczego nie dowodzi o tym, który zawodzi.
Gdy urządzenie nie jest problemem
Jeśli test interfejsu się powiedzie, a klient nadal zawodzi, pozostałym problemem jest profil, kontekst usługi lub trasa, a urządzenie jest w porządku. To moment, by przestać edytować węzły urządzeń, bo dalsze zmiany tylko zwiększają odległość od działającego systemu.
Za każdym razem uruchamiaj te same pięć kontroli, zamiast wymyślać nową: czy moduł jest wczytany bez modułu konkurencyjnego, czy ścieżka jest urządzeniem znakowym z właściwym major i minor, czy opcje montowania są czyste, czy kontekst procesu niesie zdolność, i czy w znaczniku czasu awarii jest odmowa polityki. Usterka, która przetrwa wszystkie pięć, nie jest problemem urządzenia, cokolwiek wspomina komunikat.