/dev/net/tun mangler, selvom tun er indlæst: reparer enhedsknuden
Et indlæst tun-modul beviser ikke, at enhedsknuden findes. Adskil driveren fra knuden, genopbyg den i rækkefølge, og verificer den med et interface.
OpenVPN stopper med en errno 2-klage over /dev/net/tun mens lsmod roligt viser tun-modulet. Begge fakta er sande samtidig. Modulet leverer en driver, og den sti klienten åbner, er en enhedsknude, som noget andet skal oprette. At behandle dem som ét objekt er grunden til, at den oplagte reparation med genindlæsning af modulet slet ikke ændrer noget.
To objekter, to forskellige ejere
Et kernelmodul og en enhedsknude er uafhængige objekter med uafhængige livscyklusser. Indlæsning af modulet registrerer en driver, og på et system med devtmpfs beder kernen om, at den matchende knude oprettes. På et system uden devtmpfs opretter intet noget, og driveren sidder der uden nogen sti, der peger på den. Modulet kan være indlæst, sundt og fuldstændig utilgængeligt gennem filsystemet i samme øjeblik.
Derfor modsiger fejlteksten og modullisten ikke hinanden. Klienten åbner en sti, stien findes ikke, og kernen returnerer ENOENT, før tun-driveren overhovedet bliver spurgt. Genindlæsning af modulet kan ikke reparere en manglende sti, og oprettelse af stien kan ikke reparere en manglende driver.
lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts
devtmpfs kontra en eksplicit mknod
Normalt opretter to mekanismer den knude, og viden om, hvilken der burde være ansvarlig, fortæller dig, hvad du skal reparere. devtmpfs lader kernen oprette enhedsknuder i en monteret instans, og udev lægger ejerskab og rettigheder ovenpå. En eksplicit mknod er den manuelle vej til images og namespaces, hvor ingen af dem kører ved boot.
Sammenlign resultater i stedet for hensigter. Hvis devtmpfs er monteret på /dev og knuden stadig mangler, er driveren ikke den, du antager, eller også har noget fjernet knuden efter boot. Hvis /dev er en almindelig mappe i et udpakket rootfs, findes der ingen automatisk mekanisme, og den, der bygger imaget, må oprette knuden.
stat -c "%F major=%t minor=%T" /dev/net/tun
# expect: character special file major=a minor=c8
Hvor ingen af mekanismerne kører, skal knuden laves i hånden, og rækkefølgen er vigtig. Opret først den overordnede mappe, fordi mknod ikke kan opfinde den, derefter tegngenheden, derefter en tilstand, der kun gør den skrivbar for root. Genindlæs modulet, før du opretter knuden, og fjern kun en eksisterende sti, efter at ls har vist, at det er en mappe og ikke en enhed.
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
Den type, som stat rapporterer, er den hurtigste skelner, og en mappe på den sti er den mest almindelige overraskelse i minimale images. En velment mkdir i en Dockerfile efterlader præcis det, og ingen mængde modulindlæsning erstatter en mappe med en tegngenhed. Major 10 med minor 200 er det registrerede par for tun, udtrykt i hex som a og c8.
Fire spor, fire årsager
Fire årsager forklarer næsten alle tilfælde, og hver efterlader et forskelligt spor i loggene. Start med bootmiljøet. Diskløse images, indlejrede boards og initramfs-faser monterer ofte hverken devtmpfs eller en udev-styret /dev, så ingen proces skriver nogensinde knuden. Læs derefter monteringsmulighederne på det, der hoster /dev, fordi nodev tillader, at stien findes, men nægter at åbne den, og et bind-mount taget fra en hærdet host bærer flaget uden at annoncere det. Et skrivebeskyttet mount fejler tidligere og højere: mknod returnerer EROFS der, mens EPERM betyder, at processen mangler kapaciteten, og ikke at filsystemet beskytter sig selv. Endelig kræver en container-runtime med sin egen /dev tmpfs, at knuden injiceres i dens eget namespace, og dens device-cgroup skal tillade major- og minor-parret.
Kontroller politiklaget, før du ændrer rettigheder igen. SELinux og AppArmor kan afvise en åbning, som alle filattributter tillader, og den afvisning vises i audit-loggen i stedet for i klientens output. En rettighedsændring, der aldrig vises i en afvisning, er tid brugt på det helt forkerte lag.
sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5
Bevis det med et interface, ikke en liste
En vellykket liste beviser, at en sti findes og intet mere. Åbn en sund tun-knude til læsning, og kaldet kommer tilbage med en fejl, fordi enheden ikke har læsesemantik og ikke er en almindelig fil. Den fejl er succesignalet her, og at genkende den forhindrer dig i at jage den som en fejl.
head -c 1 /dev/net/tun
head: error reading '/dev/net/tun': File descriptor in bad state
Den afgørende test opretter et interface, fordi den øver driveren, knuden og dine privilegier i ét trin. Hvis tilføjelsen lykkes, og linket vises, virker alle tre. Når den fejler, skiller errno årsagerne: ENOENT betyder, at der ikke er nogen brugbar knude, EPERM peger på kapacitet, monteringsflag eller politik, og EBUSY betyder, at en anden proces allerede ejer interfacet.
sudo ip tuntap add dev tun7 mode tun
ip -brief link show tun7
sudo ip tuntap del dev tun7 mode tun
Kør den test i den kontekst, der faktisk fejler, fordi en service-unit, en container eller et planlagt job kan bære et andet kapacitetssæt end dit login-shell. En test, der består i den forkerte kontekst, beviser intet om den fejlende.
Når enheden ikke er problemet
Hvis interfacetesten lykkes, og klienten stadig fejler, er det resterende problem profilen, servicekonteksten eller ruten, og enheden er fin. Det er øjeblikket, hvor du skal stoppe med at redigere enhedsknuder, fordi yderligere ændringer kun øger afstanden til et fungerende system.
Kør de samme fem kontroller hver gang i stedet for at opfinde en ny: er modulet indlæst uden et konkurrerende modul, er stien en tegngenhed med det rigtige major og minor, er monteringsmulighederne rene, bærer proceskonteksten kapaciteten, og er der en politikafvisning på tidspunktet for fejlen. En fejl, der overlever alle fem, er ikke et enhedsproblem, uanset hvad beskeden nævner.