OpenVPN haltas kun errno 2-plendo pri /dev/net/tun dum lsmod trankvile listigas la tun-modulon. Ambaŭ faktoj veras samtempe. La modulo provizas pelilon, kaj la vojo, kiun la kliento malfermas, estas aparata nodo, kiun io alia devas krei. Trakti ilin kiel unu objekton estas la kialo, ke la evidenta riparo per reŝargo de la modulo tute nenion ŝanĝas.

Du objektoj, du malsamaj posedantoj

Kernela modulo kaj aparata nodo estas sendependaj objektoj kun sendependaj vivcikloj. Ŝargado de la modulo registras pelilon, kaj en sistemo kun devtmpfs la kerno petas, ke la konforma nodo estu kreita. En sistemo sen devtmpfs nenio kreas ion, kaj la pelilo sidas tie sen ia vojo montranta al ĝi. La modulo povas esti ŝargita, sana kaj tute neatingebla tra la dosiersistemo en la sama momento.

Tial la erarteksto kaj la modullisto ne kontraŭdiras unu la alian. La kliento malfermas vojon, la vojo ne ekzistas, kaj la kerno redonas ENOENT antaŭ ol la tun-pelilo entute estas konsultita. Reŝargi la modulon ne povas ripari mankan vojon, kaj krei la vojon ne povas ripari mankan pelilon.

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

devtmpfs kontraŭ eksplicita mknod

Kutime du mekanismoj kreas tiun nodon, kaj scii, kiu devus respondeci, diras al vi, kion ripari. devtmpfs lasas la kernon krei aparatajn nodojn en muntita instanco, kaj udev surmetas posedrajton kaj permesojn. Eksplicita mknod estas la permana vojo por bildoj kaj nomspacoj, kie neniu el ili funkcias dum la ŝargado.

Komparu rezultojn anstataŭ intencojn. Se devtmpfs estas muntita ĉe /dev kaj la nodo ankoraŭ mankas, la pelilo ne estas tiu, kiun vi supozas, aŭ io forigis la nodon post la ŝargado. Se /dev estas ordinara dosierujo en malpakita rootfs, neniu aŭtomata mekanismo ekzistas kaj tiu, kiu konstruas la bildon, devas krei la nodon.

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

Kie neniu mekanismo funkcias, la nodo devas esti farita permane, kaj la ordo gravas. Unue kreu la patran dosierujon, ĉar mknod ne povas elpensi ĝin, poste la signan aparaton, poste reĝimon, kiu lasas ĝin skribebla nur por root. Reŝargu la modulon antaŭ ol krei la nodon, kaj forigu ekzistantan vojon nur post kiam ls montris, ke ĝi estas dosierujo kaj ne aparato.

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

La tipo, kiun raportas stat estas la plej rapida distingilo, kaj dosierujo ĉe tiu vojo estas la plej ofta surprizo en minimumaj bildoj. Bonintenca mkdir en Dockerfile lasas ĝuste tion, kaj neniu kvanto da modulŝargado anstataŭigas dosierujon per signa aparato. Major 10 kun minor 200 estas la registrita paro por tun, esprimita en deksesuma kiel a kaj c8.

Kvar spuroj, kvar kaŭzoj

Kvar kaŭzoj klarigas preskaŭ ĉiun kazon, kaj ĉiu lasas malsaman spuron en la protokoloj. Komencu per la ŝarga medio. Sendiskaj bildoj, enkorpigitaj tabuloj kaj initramfs-etapoj ofte muntas nek devtmpfs nek /devregata de udev, do neniu procezo iam skribas la nodon. Poste legu la muntajn opciojn de tio, kio gastigas /dev, ĉar nodev permesas al la vojo ekzisti dum rifuzas malfermi ĝin, kaj bind-munto prenita de hardita gastiganto portas la flagon sen anonci sin. Nurlega munto fiaskas pli frue kaj pli laŭte: mknod redonas tie EROFS, dum EPERM signifas, ke la procezo mankas kapablon kaj ne ke la dosiersistemo protektas sin. Fine, kontenera runtime kun propra /dev tmpfs bezonas la nodon enĵetita en sian propran nomspacon, kaj ĝia aparata cgroup devas permesi la paron major kaj minor.

Kontrolu la politikan tavolon antaŭ ol denove ŝanĝi permesojn. SELinux kaj AppArmor povas rifuzi malfermon, kiun ĉiu dosiera atributo permesas, kaj tiu rifuzo aperas en la revizia protokolo anstataŭ en la klienta eligo. Permesŝanĝo, kiu neniam aperas en rifuzo, estas tempo elspezita sur tute malĝusta tavolo.

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

Pruvu ĝin per interfaco, ne per listo

Sukcesa listo pruvas, ke vojo ekzistas kaj nenion pli. Malfermu sanan tun-nodon por legado kaj la voko revenas kun eraro, ĉar la aparato ne havas legan semantikon kaj ne estas ordinara dosiero. Tiu eraro estas ĉi tie la sukcesa signalo, kaj rekoni ĝin gardas vin kontraŭ ĉasi ĝin kiel difekton.

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

La decida testo kreas interfacon, ĉar ĝi ekzercas la pelilon, la nodon kaj viajn privilegiojn en unu paŝo. Se la aldono sukcesas kaj la ligilo aperas, ĉiuj tri funkcias. Kiam ĝi fiaskas, errno apartigas la kaŭzojn: ENOENT signifas, ke mankas uzebla nodo, EPERM montras al kapablo, muntaj flagoj aŭ politiko, kaj EBUSY signifas, ke alia procezo jam posedas la interfacon.

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

Rulu tiun teston en la kunteksto, kiu efektive fiaskas, ĉar serva unuo, kontenero aŭ planita tasko povas porti alian kapablaron ol via saluta ŝelo. Testo, kiu pasas en malĝusta kunteksto, pruvas nenion pri la fiaskanta.

Kiam la aparato ne estas la problemo

Se la interfaca testo sukcesas kaj la kliento ankoraŭ fiaskas, la restanta problemo estas la profilo, la serva kunteksto aŭ la vojo, kaj la aparato estas en ordo. Tio estas la momento ĉesi redakti aparatajn nodojn, ĉar pliaj ŝanĝoj nur aldonas distancon de funkcianta sistemo.

Rulu la samajn kvin kontrolojn ĉiufoje anstataŭ elpensi novan: ĉu la modulo estas ŝargita sen rivala modulo, ĉu la vojo estas signa aparato kun la ĝusta major kaj minor, ĉu la muntaj opcioj estas puraj, ĉu la proceza kunteksto portas la kapablon, kaj ĉu ekzistas politika rifuzo ĉe la tempomarko de la fiasko. Difekto, kiu postvivas ĉiujn kvin, ne estas aparata problemo, kion ajn la mesaĝo mencias.

Rilataj artikoloj