OpenVPN se ustavi s pritožbo errno 2 glede /dev/net/tun medtem ko lsmod brez težav navaja modul tun. Obe dejstvi veljata hkrati. Modul zagotavlja gonilnik, pot, ki jo odpre odjemalec, pa je vozlišče naprave, ki ga mora ustvariti nekaj drugega. Obravnavanje obeh kot en objekt je razlog, da očitna popravava s ponovnim nalaganjem modula ne spremeni prav ničesar.

Dva objekta, dva različna lastnika

Modul jedra in vozlišče naprave sta neodvisna objekta z neodvisnimi življenjskimi cikli. Nalaganje modula registrira gonilnik, v sistemu z devtmpfs pa jedro zahteva, da se ustvari ustrezno vozlišče. V sistemu brez devtmpfs nič ničesar ne ustvari in gonilnik tam sedi brez kakršne koli poti, ki bi kazala nanj. Modul je lahko hkrati naložen, zdrav in popolnoma nedosegljiv prek datotečnega sistema.

Zato si besedilo napake in seznam modulov ne nasprotujeta. Odjemalec odpre pot, poti ni in jedro vrne ENOENT, preden je gonilnik tun sploh vprašan. Ponovno nalaganje modula ne more popraviti manjkajoče poti, ustvarjanje poti pa ne more popraviti manjkajočega gonilnika.

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

devtmpfs proti izrecnemu mknod

To vozlišče običajno ustvarita dva mehanizma in vedenje, kateri bi moral biti odgovoren, vam pove, kaj popraviti. devtmpfs pusti jedru, da ustvari vozlišča naprav v priklopljeni instanci, udev pa nanje položi lastništvo in dovoljenja. Izrecni mknod je ročna pot za slike in imenske prostore, kjer ob zagonu ne teče nobeden od njiju.

Primerjajte izide, ne namenov. Če je devtmpfs priklopljen na /dev in vozlišča še vedno ni, gonilnik ni tisti, ki ga predpostavljate, ali je nekaj vozlišče po zagonu odstranilo. Če je /dev navaden imenik v razpakiranem rootfs, avtomatskega mehanizma ni in tisti, ki gradi sliko, mora ustvariti vozlišče.

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

Kjer ne teče nobeden od mehanizmov, je treba vozlišče narediti ročno, vrstni red pa je pomemben. Najprej ustvarite nadrejeni imenik, ker mknod si ga ne more izmisliti, nato znakovno napravo, nato način, ki jo pusti zapisljivo samo za root. Znova naložite modul, preden ustvarite vozlišče, in odstranite obstoječo pot šele potem, ko je ls pokazal, da gre za imenik in ne za napravo.

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

Najhitrejši razlikovalnik je tip, ki ga sporoča stat in imenik na tej poti je najpogostejše presenečenje v minimalnih slikah. Dobro mišljen mkdir v Dockerfile pusti natanko to in nobena količina nalaganja modulov ne nadomesti imenika z znakovno napravo. Major 10 z minor 200 je registriran par za tun, izražen šestnajstiško kot a in c8.

Štiri sledi, štirje vzroki

Štirje vzroki pojasnijo skoraj vsak primer in vsak pusti drugačno sled v dnevnikih. Začnite z zagonskim okoljem. Slike brez diska, vgrajene plošče in faze initramfs pogosto ne priklopijo niti devtmpfs niti /devki ga upravlja udev, zato noben proces nikoli ne zapiše vozlišča. Nato preberite možnosti priklopa tistega, kar gosti /dev, ker nodev dovoli, da pot obstaja, a zavrne njeno odpiranje, in bind priklop, vzet s utrjenega gostitelja, nosi to zastavico, ne da bi se najavil. Priklop samo za branje spodleti prej in glasneje: mknod tam vrne EROFS, medtem ko EPERM pomeni, da procesu manjka zmožnost in ne, da se datotečni sistem ščiti. Nazadnje, container runtime z lastnim /dev tmpfs potrebuje, da se vozlišče vbrizga v njegov lastni imenski prostor, in njegova device cgroup mora dovoliti par major in minor.

Preverite plast politike, preden znova spremenite dovoljenja. SELinux in AppArmor lahko zavrneta odpiranje, ki ga dovoljuje vsak atribut datoteke, in ta zavrnitev se pojavi v revizijskem dnevniku, ne v izhodu odjemalca. Sprememba dovoljenj, ki se nikoli ne pojavi v zavrnitvi, je čas, porabljen na popolnoma napačni plasti.

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

Dokažite to z vmesnikom, ne s seznamom

Uspešen seznam dokazuje, da pot obstaja in nič več. Odprite zdravo vozlišče tun za branje in klic se vrne z napako, ker naprava nima semantike branja in ni navadna datoteka. Ta napaka je tu signal uspeha in prepoznavanje vas obvaruje, da bi ji sledili kot okvari.

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

Odločilni test ustvari vmesnik, ker v enem koraku preizkusi gonilnik, vozlišče in vaše pravice. Če dodajanje uspe in se povezava pojavi, delujejo vsi trije. Ko spodleti, errno loči vzroke: ENOENT pomeni, da ni uporabnega vozlišča, EPERM kaže na zmožnost, zastavice priklopa ali politiko, EBUSY pa pomeni, da vmesnik že ima drug proces.

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

Zaženite ta test v kontekstu, ki resnično spodleti, ker lahko service unit, container ali načrtovana naloga nosi drugačen nabor zmožnosti kot vaša prijavna lupina. Test, ki uspe v napačnem kontekstu, ne dokaže ničesar o tistem, ki spodleti.

Ko naprava ni težava

Če test vmesnika uspe in odjemalec še vedno spodleti, je preostala težava profil, kontekst storitve ali pot, naprava pa je v redu. To je trenutek, ko prenehate urejati vozlišča naprav, ker nadaljnje spremembe samo povečujejo razdaljo od delujočega sistema.

Vsakič zaženite istih pet preverjanj, namesto da bi izmislili novo: je modul naložen brez konkurenčnega modula, je pot znakovna naprava s pravim major in minor, so možnosti priklopa čiste, nosi kontekst procesa zmožnost in obstaja zavrnitev politike ob času okvare. Okvara, ki preživi vseh pet, ni težava naprave, kar koli navaja sporočilo.

Sorodni članki