/dev/net/tun nedostaje dok je tun učitan: popravite čvor uređaja
Učitan tun modul ne dokazuje da čvor uređaja postoji. Odvojite drajver od čvora, ponovo ga izgradite po redu i provjerite ga interfejsom.
OpenVPN se zaustavlja uz prijavu errno 2 o /dev/net/tun dok lsmod mirno navodi tun modul. Obje činjenice su istovremeno tačne. Modul pruža drajver, a putanja koju klijent otvara je čvor uređaja koji mora stvoriti nešto drugo. Tretiranje toga kao jednog objekta razlog je zašto očigledna popravka ponovnim učitavanjem modula ne mijenja baš ništa.
Dva objekta, dva različita vlasnika
Kernel modul i čvor uređaja su nezavisni objekti s nezavisnim životnim ciklusima. Učitavanje modula registruje drajver, a na sistemu s devtmpfs kernel traži da se odgovarajući čvor stvori. Na sistemu bez devtmpfs ništa ništa ne stvara, a drajver stoji tamo bez putanje koja pokazuje na njega. Modul može biti učitan, zdrav i potpuno nedostupan kroz datotečni sistem u istom trenutku.
Zato se tekst greške i spisak modula ne protivrječe. Klijent otvara putanju, putanja ne postoji, a kernel vraća ENOENT prije nego što se tun drajver uopšte konsultuje. Ponovno učitavanje modula ne može popraviti putanju koja nedostaje, a stvaranje putanje ne može popraviti drajver koji nedostaje.
lsmod | grep -w tun
stat -c "%F %t:%T" /dev/net/tun
grep " /dev " /proc/mounts
devtmpfs protiv eksplicitnog mknod
Taj čvor obično stvaraju dva mehanizma, a znanje koji bi trebao biti odgovoran kaže vam šta popraviti. devtmpfs pušta kernel da stvara čvorove uređaja u montiranoj instanci, a udev na njih primjenjuje vlasništvo i dozvole. Eksplicitni mknod je ručna putanja za slike i imenske prostore u kojima nijedan od njih ne radi pri podizanju.
Uporedite ishode, a ne namjere. Ako je devtmpfs montiran na /dev i čvor još uvijek nedostaje, drajver nije onaj koji pretpostavljate, ili je nešto uklonilo čvor nakon podizanja. Ako je /dev običan direktorij unutar raspakovane rootfs, nema automatskog mehanizma i onaj ko 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. Ponovo učitajte modul prije nego stvorite čvor 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 razlikovni znak, 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 registrovani 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 okruženjem za podizanje. 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 opcije montiranja onoga što hostuje /dev, jer nodev dopušta da putanja postoji dok odbija da je otvori, a bind montiranje uzeto s očvrslog hosta nosi tu zastavicu a da se ne najavi. Montiranje samo za čitanje pada ranije i glasnije: mknod tamo vraća EROFS, dok EPERM znači da procesu nedostaje sposobnost, a ne da se datotečni sistem štiti. Na kraju, kontejnerski runtime sa sopstvenim /dev tmpfs zahtijeva da čvor bude ubrizgan u njegov vlastiti imenski prostor, a njegova cgroup uređaja mora dopustiti par major i minor.
Provjerite sloj politike prije nego ponovo mijenjate 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 potpuno pogrešan sloj.
sudo journalctl -k -n 20 --no-pager
sudo ausearch -m AVC -ts recent | tail -5
Dokažite to interfejsom, ne spiskom
Uspješan spisak dokazuje da putanja postoji i ništa više. Otvorite zdrav tun čvor za čitanje i poziv se vraća s greškom, jer uređaj nema semantiku čitanja i nije obična datoteka. Ta greška je 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 interfejs, jer vježba drajver, čvor i vaše privilegije u jednom koraku. Ako dodavanje uspije i link 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 interfejs 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 onom koji pada.
Kada uređaj nije problem
Ako test interfejsa uspije, a klijent još uvijek pada, preostali problem je profil, kontekst servisa ili ruta, a uređaj je u redu. To je trenutak da prestanete uređivati čvorove uređaja, jer dalje promjene samo dodaju udaljenost od radnog sistema.
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 opcije 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, šta god poruka spominjala.