OpenVPN bleibt mit einer errno-2-Meldung über /dev/net/tun stehen, während lsmod das tun-Modul munter auflistet. Beide Fakten stimmen gleichzeitig. Das Modul stellt einen Treiber bereit, und der Pfad, den der Client öffnet, ist ein Geräteknoten, den etwas anderes anlegen muss. Beides als ein Objekt zu behandeln ist der Grund, warum die naheliegende Reparatur des erneuten Ladens des Moduls überhaupt nichts ändert.

Zwei Objekte, zwei verschiedene Eigentümer

Ein Kernelmodul und ein Geräteknoten sind unabhängige Objekte mit unabhängigen Lebenszyklen. Das Laden des Moduls registriert einen Treiber, und auf einem System mit devtmpfs bittet der Kernel darum, den passenden Knoten anzulegen. Auf einem System ohne devtmpfs legt nichts etwas an, und der Treiber sitzt dort ohne einen Pfad, der auf ihn zeigt. Das Modul kann im selben Moment geladen, gesund und über das Dateisystem völlig unerreichbar sein.

Deshalb widersprechen sich Fehlertext und Modulliste nicht. Der Client öffnet einen Pfad, der Pfad existiert nicht, und der Kernel gibt ENOENT zurück, bevor der tun-Treiber überhaupt befragt wird. Das erneute Laden des Moduls kann einen fehlenden Pfad nicht reparieren, und das Anlegen des Pfades kann einen fehlenden Treiber nicht reparieren.

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

devtmpfs gegenüber einem ausdrücklichen mknod

Normalerweise legen zwei Mechanismen diesen Knoten an, und zu wissen, welcher zuständig sein sollte, sagt Ihnen, was zu reparieren ist. devtmpfs lässt den Kernel Geräteknoten in einer eingebundenen Instanz anlegen, und udev setzt Eigentümer und Rechte darüber. Ein ausdrückliches mknod ist der manuelle Weg für Images und Namespaces, in denen keiner von beiden beim Start läuft.

Vergleichen Sie Ergebnisse statt Absichten. Wenn devtmpfs unter /dev eingebunden ist und der Knoten trotzdem fehlt, ist der Treiber nicht der, den Sie annehmen, oder etwas hat den Knoten nach dem Start entfernt. Wenn /dev ein gewöhnliches Verzeichnis in einem entpackten rootfs ist, gibt es keinen automatischen Mechanismus, und wer das Image baut, muss den Knoten anlegen.

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

Wo keiner der Mechanismen läuft, muss der Knoten von Hand angelegt werden, und die Reihenfolge zählt. Legen Sie zuerst das übergeordnete Verzeichnis an, weil mknod es nicht erfinden kann, dann das Zeichengerät, dann einen Modus, der es allein für root beschreibbar lässt. Laden Sie das Modul neu, bevor Sie den Knoten anlegen, und entfernen Sie einen vorhandenen Pfad erst, nachdem ls gezeigt hat, dass es ein Verzeichnis und kein Gerät ist.

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

Der Typ, den stat meldet, ist der schnellste Unterschied, und ein Verzeichnis an diesem Pfad ist die häufigste Überraschung in minimalen Images. Ein gut gemeintes mkdir in einem Dockerfile hinterlässt genau das, und keine Menge Modulladen ersetzt ein Verzeichnis durch ein Zeichengerät. Major 10 mit minor 200 ist das registrierte Paar für tun, hexadezimal als a und c8 ausgedrückt.

Vier Spuren, vier Ursachen

Vier Ursachen erklären fast jeden Fall, und jede hinterlässt eine andere Spur in den Protokollen. Beginnen Sie mit der Startumgebung. Disklose Images, eingebettete Boards und initramfs-Phasen binden oft weder devtmpfs noch ein udev-verwaltetes /devein, sodass kein Prozess jemals den Knoten schreibt. Lesen Sie dann die Einhängeoptionen von dem, was /devbeherbergt, denn nodev erlaubt, dass der Pfad existiert, verweigert aber das Öffnen, und ein Bind-Mount von einem gehärteten Host trägt das Flag, ohne sich anzukündigen. Ein Nur-Lese-Mount scheitert früher und lauter: mknod gibt dort EROFS zurück, während EPERM bedeutet, dass dem Prozess die Fähigkeit fehlt und nicht, dass das Dateisystem sich selbst schützt. Schließlich braucht eine Container-Laufzeit mit eigenem /dev tmpfs den Knoten in ihrem eigenen Namespace injiziert, und ihre Device-cgroup muss das Major-Minor-Paar zulassen.

Prüfen Sie die Richtlinienebene, bevor Sie erneut Berechtigungen ändern. SELinux und AppArmor können ein Öffnen verweigern, das jedes Dateiattribut erlaubt, und diese Verweigerung erscheint im Audit-Protokoll statt in der Client-Ausgabe. Eine Berechtigungsänderung, die nie in einer Verweigerung auftaucht, ist Zeit, die auf der völlig falschen Ebene verbracht wird.

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

Beweisen Sie es mit einer Schnittstelle, nicht mit einer Liste

Eine erfolgreiche Liste beweist, dass ein Pfad existiert und nichts weiter. Öffnen Sie einen gesunden tun-Knoten zum Lesen, und der Aufruf kommt mit einem Fehler zurück, weil das Gerät keine Lesesemantik hat und keine reguläre Datei ist. Dieser Fehler ist hier das Erfolgssignal, und ihn zu erkennen bewahrt Sie davor, ihn als Störung zu verfolgen.

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

Der entscheidende Test legt eine Schnittstelle an, weil er Treiber, Knoten und Ihre Rechte in einem Schritt beansprucht. Wenn das Hinzufügen gelingt und die Verbindung erscheint, arbeiten alle drei. Wenn er scheitert, trennt errno die Ursachen: ENOENT bedeutet, dass es keinen brauchbaren Knoten gibt, EPERM deutet auf Fähigkeit, Einhängeflags oder Richtlinie, und EBUSY bedeutet, dass ein anderer Prozess die Schnittstelle bereits besitzt.

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

Führen Sie diesen Test in dem Kontext aus, der tatsächlich scheitert, weil eine Service-Unit, ein Container oder ein geplanter Job einen anderen Fähigkeitssatz tragen kann als Ihre Login-Shell. Ein Test, der im falschen Kontext besteht, beweist nichts über den scheiternden.

Wenn das Gerät nicht das Problem ist

Wenn der Schnittstellentest gelingt und der Client trotzdem scheitert, ist das verbleibende Problem das Profil, der Dienstkontext oder die Route, und das Gerät ist in Ordnung. Das ist der Moment, mit dem Bearbeiten von Geräteknoten aufzuhören, weil weitere Änderungen nur den Abstand zu einem funktionierenden System vergrößern.

Führen Sie jedes Mal dieselben fünf Prüfungen aus, statt eine neue zu erfinden: Ist das Modul ohne ein konkurrierendes Modul geladen, ist der Pfad ein Zeichengerät mit dem richtigen Major und Minor, sind die Einhängeoptionen sauber, trägt der Prozesskontext die Fähigkeit, und gibt es eine Richtlinienverweigerung zum Zeitstempel des Fehlers. Eine Störung, die alle fünf übersteht, ist kein Geräteproblem, was auch immer die Meldung erwähnt.

Ähnliche Artikel