OpenVPN peatub errno 2 kaebusega /dev/net/tun kohta, samal ajal kui lsmod loetleb tun-moodulit muretult. Mõlemad faktid on korraga tõesed. Moodul annab draiveri, ja tee, mille klient avab, on seadme sõlm, mille peab looma miski muu. Nende käsitlemine ühe objektina on põhjus, miks mooduli uuesti laadimise näiline parandus ei muuda üldse mitte midagi.

Kaks objekti, kaks erinevat omanikku

Tuuma moodul ja seadme sõlm on iseseisvad objektid iseseisvate elutsüklitega. Mooduli laadimine registreerib draiveri, ja devtmpfsiga süsteemis palub tuum vastava sõlme luua. Ilma devtmpfsita süsteemis ei loo miski midagi, ja draiver istub seal ilma ühegi teeta, mis sellele viitaks. Moodul võib samal hetkel olla laaditud, terve ja failisüsteemi kaudu täiesti kättesaamatu.

Seepärast ei ole veatekst ja moodulite loend vastuolus. Klient avab tee, teed ei ole, ja tuum tagastab ENOENT enne, kui tun-draiveri poole üldse pöördutakse. Mooduli uuesti laadimine ei paranda puuduvat teed ja tee loomine ei paranda puuduvat draiverit.

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

devtmpfs versus selgesõnaline mknod

Tavaliselt loovad selle sõlme kaks mehhanismi, ja teadmine, milline peaks vastutama, ütleb sulle, mida parandada. devtmpfs laseb tuumal luua seadmesõlmi mountitud eksemplaris, ja udev rakendab nende peale omandiõigust ja õigusi. Selgesõnaline mknod on käsitsi tee kujutiste ja nimeruumide jaoks, kus kumbki neist alglaadimisel ei tööta.

Võrdle tulemusi, mitte kavatsusi. Kui devtmpfs on mountitud /dev külge ja sõlm on endiselt puudu, ei ole draiver see, mida sa eeldad, või eemaldas miski sõlme pärast alglaadimist. Kui /dev on tavaline kataloog lahtipakitud rootfsis, siis automaatset mehhanismi ei ole ja kujutise ehitaja peab sõlme looma.

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

Seal, kus kumbki mehhanism ei tööta, tuleb sõlm käsitsi teha, ja järjekord on oluline. Loo esmalt ülemkataloog, sest mknod ei suuda seda välja mõelda, seejärel märgiseade, seejärel režiim, mis jätab selle kirjutatavaks ainult rootile. Laadi moodul uuesti enne sõlme loomist ja eemalda olemasolev tee alles pärast seda, kui ls on näidanud, et see on kataloog, mitte seade.

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

Tüüp, mida teatab stat on kiireim eristaja, ja kataloog sellel teel on kõige tavalisem üllatus minimaalsetes kujutistes. Heas usus tehtud mkdir Dockerfile'is jätab täpselt selle, ja ükski moodulilaadimise hulk ei asenda kataloogi märgiseadmega. Major 10 ja minor 200 on tuni registreeritud paar, väljendatuna kuueteistkümnendsüsteemis kui a ja c8.

Neli jälge, neli põhjust

Neli põhjust seletavad peaaegu iga juhtumit, ja igaüks jätab logidesse erineva jälje. Alusta alglaadimiskeskkonnast. Kettata kujutised, manustatud plaadid ja initramfsi etapid ei mounti sageli ei devtmpfsi ega udev-hallatavat /dev, nii et ükski protsess ei kirjuta kunagi sõlme. Seejärel loe mountimisvalikuid sellelt, mis /devmajutab, sest nodev lubab teel olemas olla, kuid keeldub seda avamast, ja karastatud hostist võetud bind-mount kannab seda lippu end teavitamata. Ainult lugemiseks mõeldud mount ebaõnnestub varem ja valjemalt: mknod tagastab seal EROFS, samas kui EPERM tähendab, et protsessil puudub võimekus, mitte et failisüsteem ennast kaitseb. Lõpuks vajab konteineri runtime oma /dev tmpfsiga, et sõlm süstitaks tema enda nimeruumi, ja tema seadme-cgroup peab lubama major ja minor paari.

Kontrolli poliitikakihti enne õiguste uuesti muutmist. SELinux ja AppArmor võivad keelduda avamisest, mille kõik faili atribuudid lubavad, ja see keeldumine ilmub auditilogis, mitte kliendi väljundis. Õiguste muutmine, mis ei ilmu kunagi keeldumises, on aeg, mis on kulutatud täiesti valele kihile.

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

Tõesta seda liidesega, mitte loendiga

Edukas loend tõestab, et tee on olemas ja mitte midagi enamat. Ava terve tun-sõlm lugemiseks ja kutsest tuleb tagasi viga, sest seadmel puudub lugemissemantika ja see ei ole tavaline fail. See viga on siin edusignaal, ja selle äratundmine hoiab sind seda rikkena taga ajamast.

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

Otsustav test loob liidese, sest see rakendab draiverit, sõlme ja sinu privileege ühes sammus. Kui lisamine õnnestub ja link ilmub, töötavad kõik kolm. Kui see ebaõnnestub, eristab errno põhjuseid: ENOENT tähendab, et kasutatavat sõlme ei ole, EPERM osutab võimekusele, mountimislippudele või poliitikale, ja EBUSY tähendab, et liidest omab juba teine protsess.

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

Käivita see test kontekstis, mis tegelikult ebaõnnestub, sest teenuseüksus, konteiner või ajastatud töö võib kanda teistsugust võimekuste komplekti kui sinu sisselogimiskest. Test, mis läbib vales kontekstis, ei tõesta ebaõnnestuva kohta midagi.

Kui seade ei ole probleem

Kui liidese test õnnestub ja klient ikka ebaõnnestub, on ülejäänud probleem profiil, teenusekontekst või marsruut, ja seade on korras. See on hetk lõpetada seadmesõlmede muutmine, sest edasised muudatused lisavad ainult kaugust töötavast süsteemist.

Käivita iga kord samu viit kontrolli, selle asemel et uut välja mõelda: kas moodul on laaditud ilma rivaalmoodulita, kas tee on õige major ja minoriga märgiseade, kas mountimisvalikud on puhtad, kas protsessi kontekst kannab võimekust, ja kas rikke ajatemplil on poliitikakeeldumine. Rike, mis elab üle kõik viis, ei ole seadme probleem, mida iganes teade mainib.

Seotud artiklid