OpenVPN stopper med en errno 2-klage over /dev/net/tun mens lsmod lister tun-modulen uten problemer. Begge fakta er sanne samtidig. Modulen leverer en driver, og stien klienten åpner, er en enhetsnode som noe annet må opprette. Å behandle dem som ett objekt er grunnen til at den opplagte reparasjonen med å laste modulen på nytt ikke endrer noe som helst.

To objekter, to forskjellige eiere

En kjernemodul og en enhetsnode er uavhengige objekter med uavhengige livssykluser. Innlasting av modulen registrerer en driver, og på et system med devtmpfs ber kjernen om at den tilsvarende noden opprettes. På et system uten devtmpfs oppretter ingenting noe, og driveren sitter der uten noen sti som peker på den. Modulen kan være lastet, sunn og fullstendig utilgjengelig gjennom filsystemet i samme øyeblikk.

Derfor motsier ikke feilteksten og modullisten hverandre. Klienten åpner en sti, stien finnes ikke, og kjernen returnerer ENOENT før tun-driveren i det hele tatt blir spurt. Å laste modulen på nytt kan ikke reparere en manglende sti, og å opprette 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 eksplisitt mknod

Normalt oppretter to mekanismer den noden, og å vite hvilken som skal være ansvarlig forteller deg hva du skal reparere. devtmpfs lar kjernen opprette enhetsnoder i en montert instans, og udev legger eierskap og rettigheter oppå. En eksplisitt mknod er den manuelle veien for avbildninger og navnerom der ingen av dem kjører ved oppstart.

Sammenlign resultater i stedet for intensjoner. Hvis devtmpfs er montert på /dev og noden fortsatt mangler, er driveren ikke den du antar, eller noe fjernet noden etter oppstart. Hvis /dev er en vanlig katalog i et utpakket rootfs, finnes det ingen automatisk mekanisme, og den som bygger avbildningen må opprette noden.

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

Der ingen av mekanismene kjører, må noden lages for hånd, og rekkefølgen betyr noe. Opprett først overordnet katalog, fordi mknod ikke kan finne den opp, deretter tegntegnenheten, deretter en modus som gjør den skrivbar bare for root. Last modulen på nytt før du oppretter noden, og fjern bare en eksisterende sti etter at ls har vist at det er en katalog og ikke en enhet.

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 raskeste forskjellen er typen som stat rapporterer, og en katalog på den stien er den vanligste overraskelsen i minimale avbildninger. En velment mkdir i en Dockerfile etterlater nettopp det, og ingen mengde modullasting erstatter en katalog med en tegntegnenhet. Major 10 med minor 200 er det registrerte paret for tun, uttrykt heksadesimalt som a og c8.

Fire spor, fire årsaker

Fire årsaker forklarer nesten alle tilfeller, og hver etterlater et ulikt spor i loggene. Start med oppstartsmiljøet. Diskeløse avbildninger, innebygde kort og initramfs-faser monterer ofte verken devtmpfs eller en udev-styrt /dev, så ingen prosess skriver noen gang noden. Les deretter monteringsvalgene på det som er vert for /dev, fordi nodev tillater at stien finnes mens den nekter å åpne den, og en bind-montering hentet fra en herdet vert bærer flagget uten å annonsere det. En skrivebeskyttet montering feiler tidligere og høyere: mknod returnerer EROFS der, mens EPERM betyr at prosessen mangler evnen og ikke at filsystemet beskytter seg selv. Til slutt trenger en containerruntime med sin egen /dev tmpfs at noden injiseres i sitt eget navnerom, og dens enhets-cgroup må tillate major- og minor-paret.

Kontroller policylaget før du endrer rettigheter igjen. SELinux og AppArmor kan avvise en åpning som hver filattributt tillater, og den avvisningen vises i revisjonsloggen i stedet for i klientens utdata. En rettighetsendring som aldri vises i en avvisning, er tid brukt på helt feil lag.

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

Bevis det med et grensesnitt, ikke en liste

En vellykket liste beviser at en sti finnes og ikke noe mer. Åpne en sunn tun-node for lesing, og kallet kommer tilbake med en feil, fordi enheten ikke har lesesemantikk og ikke er en vanlig fil. Den feilen er suksesssignalet her, og å kjenne den igjen hindrer deg i å jage den som en feil.

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

Den avgjørende testen oppretter et grensesnitt, fordi den prøver driveren, noden og privilegiene dine i ett trinn. Hvis tilleggingen lykkes og lenken vises, virker alle tre. Når den feiler, skiller errno årsakene: ENOENT betyr at det ikke finnes noen brukbar node, EPERM peker på evne, monteringsflagg eller policy, og EBUSY betyr at en annen prosess allerede eier grensesnittet.

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

Kjør den testen i den konteksten som faktisk feiler, fordi en tjenesteenhet, en container eller en planlagt jobb kan bære et annet evnesett enn innloggingsskallet ditt. En test som passerer i feil kontekst, beviser ingenting om den som feiler.

Når enheten ikke er problemet

Hvis grensesnitttesten lykkes og klienten fortsatt feiler, er det gjenværende problemet profilen, tjenestekonteksten eller ruten, og enheten er i orden. Det er øyeblikket for å slutte å redigere enhetsnoder, fordi flere endringer bare øker avstanden til et fungerende system.

Kjør de samme fem kontrollene hver gang i stedet for å finne opp en ny: er modulen lastet uten en konkurrerende modul, er stien en tegntegnenhet med riktig major og minor, er monteringsvalgene rene, bærer prosesskonteksten evnen, og finnes det en policyavvisning på tidspunktet for feilen. En feil som overlever alle fem, er ikke et enhetsproblem, uansett hva meldingen nevner.

Relaterte artikler