OpenVPN zaustavlja se s prijavom errno 2 o /dev/net/tun dok lsmod mirno navodi tun modul. Obje su činjenice istodobno točne. Modul pruža upravljački program, a putanja koju klijent otvara čvor je uređaja koji mora stvoriti nešto drugo. Tretiranje toga kao jednog objekta razlog je zašto očito popravljanje ponovnim učitavanjem modula ne mijenja baš ništa.

Dva objekta, dva različita vlasnika

Modul jezgre i čvor uređaja neovisni su objekti s neovisnim životnim ciklusima. Učitavanje modula registrira upravljački program, a na sustavu s devtmpfs jezgra traži da se odgovarajući čvor stvori. Na sustavu bez devtmpfs ništa ništa ne stvara, a upravljački program stoji ondje bez putanje koja pokazuje na njega. Modul može biti učitan, zdrav i potpuno nedostupan kroz datotečni sustav u istom trenutku.

Zato se tekst pogreške i popis modula ne proturječe. Klijent otvara putanju, putanja ne postoji, a jezgra vraća ENOENT prije nego što se tun upravljački program uopće konzultira. Ponovno učitavanje modula ne može popraviti putanju koja nedostaje, a stvaranje putanje ne može popraviti upravljački program koji nedostaje.

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

devtmpfs protiv izričitog mknod

Taj čvor obično stvaraju dva mehanizma, a znanje koji bi trebao biti odgovoran govori vam što popraviti. devtmpfs pušta jezgru da stvara čvorove uređaja u montiranoj instanci, a udev na njih primjenjuje vlasništvo i dozvole. Izričiti mknod ručna je putanja za slike i imenske prostore u kojima nijedan od njih ne radi pri podizanju.

Usporedite ishode, a ne namjere. Ako je devtmpfs montiran na /dev i čvor još uvijek nedostaje, upravljački program nije onaj koji pretpostavljate, ili je nešto uklonilo čvor nakon podizanja. Ako je /dev običan direktorij unutar raspakirane rootfs, nema automatskog mehanizma i onaj koji gradi sliku mora stvoriti čvor.

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

Gdje nijedan mehanizam ne radi, čvor se mora napraviti ručno, a redoslijed je važan. Prvo stvorite roditeljski direktorij, jer mknod ga ne može izmisliti, zatim znakovni uređaj, zatim način rada koji ga ostavlja zapisivim samo za root. Ponovno učitajte modul prije stvaranja čvora i uklonite postojeću putanju tek nakon što je ls pokazao da je to direktorij, a ne uređaj.

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

Tip koji prijavljuje stat najbrži je razlučivač, a direktorij na toj putanji najčešće je iznenađenje u minimalnim slikama. Dobronamjerni mkdir u Dockerfileu ostavlja upravo to, i nikakvo učitavanje modula ne zamjenjuje direktorij znakovnim uređajem. Major 10 s minor 200 registrirani je par za tun, izražen heksadecimalno kao a i c8.

Četiri traga, četiri uzroka

Četiri uzroka objašnjavaju gotovo svaki slučaj, a svaki ostavlja drugačiji trag u zapisima. Počnite s okolinom podizanja. Slike bez diska, ugrađene ploče i faze initramfs često ne montiraju ni devtmpfs ni /devkojim upravlja udev, pa nijedan proces nikada ne zapisuje čvor. Zatim pročitajte mogućnosti montiranja onoga što hosta /dev, jer nodev dopušta da putanja postoji dok odbija otvoriti je, a bind montiranje uzeto s očvrslog hosta nosi tu zastavicu bez najave. Montiranje samo za čitanje pada ranije i glasnije: mknod ondje vraća EROFS, dok EPERM znači da procesu nedostaje sposobnost, a ne da se datotečni sustav štiti. Naposljetku, kontejnerski runtime sa svojim /dev tmpfs zahtijeva da se čvor ubaci u njegov vlastiti imenski prostor, a njegova cgroup uređaja mora dopustiti par major i minor.

Provjerite sloj politike prije nego ponovno promijenite dozvole. SELinux i AppArmor mogu odbiti otvaranje koje svaki atribut datoteke dopušta, a to odbijanje pojavljuje se u revizijskom zapisu, a ne u izlazu klijenta. Promjena dozvole koja se nikada ne pojavi u odbijanju vrijeme je potrošeno na posve pogrešan sloj.

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

Dokažite to sučeljem, ne popisom

Uspješan popis dokazuje da putanja postoji i ništa više. Otvorite zdrav tun čvor za čitanje i poziv se vraća s pogreškom, jer uređaj nema semantiku čitanja i nije obična datoteka. Ta je pogreška ovdje signal uspjeha, a prepoznavanje vas sprječava da je lovite kao kvar.

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

Odlučujući test stvara sučelje, jer uvježbava upravljački program, čvor i vaše privilegije u jednom koraku. Ako dodavanje uspije i veza se pojavi, sva tri rade. Kada ne uspije, errno razdvaja uzroke: ENOENT znači da nema upotrebljivog čvora, EPERM upućuje na sposobnost, zastavice montiranja ili politiku, a EBUSY znači da sučelje već posjeduje drugi proces.

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

Pokrenite taj test u kontekstu koji zaista pada, jer servisna jedinica, kontejner ili zakazani posao mogu nositi drugačiji skup sposobnosti od vaše prijavne ljuske. Test koji prođe u pogrešnom kontekstu ne dokazuje ništa o onome koji pada.

Kada uređaj nije problem

Ako test sučelja uspije, a klijent još uvijek pada, preostali je problem profil, kontekst usluge ili ruta, a uređaj je u redu. To je trenutak da prestanete uređivati čvorove uređaja, jer daljnje promjene samo dodaju udaljenost od radnog sustava.

Pokrenite istih pet provjera svaki put umjesto da izmišljate novu: je li modul učitan bez suparničkog modula, je li putanja znakovni uređaj s pravim major i minor, jesu li mogućnosti montiranja čiste, nosi li kontekst procesa sposobnost i postoji li odbijanje politike na vremenskoj oznaci kvara. Kvar koji preživi svih pet nije problem uređaja, što god poruka spominjala.

Povezani članci