OpenVPN errno 2 şikayəti ilə dayanır — söhbət /dev/net/tun halbuki lsmod tun modulunu rahatlıqla siyahıya alır. Hər iki fakt eyni anda doğrudur. Modul sürücü təmin edir, müştərinin açdığı yol isə başqa bir şeyin yaratmalı olduğu cihaz qovşağıdır. Onları bir obyekt kimi qəbul etmək, modulu yenidən yükləmək kimi aşkar təmirin niyə heç nəyi dəyişmədiyinin səbəbidir.

İki obyekt, iki fərqli sahib

Nüvə modulu və cihaz qovşağı müstəqil həyat dövrlərinə malik müstəqil obyektlərdir. Modulun yüklənməsi sürücünü qeydiyyata alır və devtmpfs olan sistemdə nüvə uyğun qovşağın yaradılmasını tələb edir. devtmpfs olmayan sistemdə heç nə yaratmır və sürücü ona işarə edən yol olmadan orada qalır. Modul eyni anda həm yüklü, həm sağlam, həm də fayl sistemi vasitəsilə tamamilə əlçatmaz ola bilər.

Buna görə xəta mətni ilə modul siyahısı bir-birinə zidd deyil. Müştəri bir yol açır, yol mövcud deyil və nüvə tun sürücüsünə müraciət etməmişdən əvvəl ENOENT qaytarır. Modulu yenidən yükləmək itkin yolu bərpa edə bilməz, yolu yaratmaq isə itkin sürücünü bərpa edə bilməz.

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

devtmpfs və açıq mknod

Adətən həmin qovşağı iki mexanizm yaradır və hansının məsuliyyət daşımalı olduğunu bilmək nəyi təmir etməli olduğunuzu deyir. devtmpfs nüvənin quraşdırılmış nüsxədə cihaz qovşaqları yaratmasını təmin edir, udev isə onların üzərinə sahiblik və icazələri tətbiq edir. Açıq mknod isə hər ikisinin yükləmə zamanı işləmədiyi obrazlar və ad məkanları üçün əl yolu ilə həlldir.

Niyyətləri deyil, nəticələri müqayisə edin. devtmpfs /dev üzərində quraşdırılıbsa və qovşaq hələ də yoxdursa, sürücü sizin güman etdiyiniz deyil, ya da kimsə qovşağı yükləmədən sonra silib. Əgər /dev açılmış rootfs daxilində adi qovluqdursa, heç bir avtomatik mexanizm yoxdur və obrazı kim qurursa qovşağı o yaratmalıdır.

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

Heç bir mexanizm işləmədiyi yerdə qovşaq əl ilə hazırlanmalıdır və ardıcıllıq vacibdir. Əvvəlcə valideyn qovluğu yaradın, çünki mknod onu icad edə bilmir, sonra simvol cihazı, sonra isə yalnız root üçün yazıla bilən rejim. Qovşağı yaratmazdan əvvəl modulu yenidən yükləyin və mövcud yolu yalnız ls onun cihaz deyil, qovluq olduğunu göstərdikdən sonra silin.

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

Hansı tip olduğunu stat ən sürətli şəkildə göstərir və həmin yolda qovluq olması minimal obrazlarda ən çox rast gəlinən sürprizdir. Yaxşı niyyətlə yazılmış mkdir Dockerfile daxilində məhz bunu qoyub gedir və heç bir modul yükləməsi qovluğu simvol cihazı ilə əvəz etmir. Major 10 və minor 200 tun üçün qeydiyyata alınmış cütdür və onaltılıq sistemdə a və c8 kimi ifadə olunur.

Dörd iz, dörd səbəb

Dörd səbəb demək olar ki, hər halı izah edir və hər biri jurnallarda fərqli iz qoyur. Yükləmə mühitindən başlayın. Disksiz obrazlar, daxili lövhələr və initramfs mərhələləri çox vaxt nə devtmpfs, nə də udev tərəfindən idarə olunan /devquraşdırmır, ona görə heç bir proses qovşağı yazmır. Sonra /devhansı sahibdirsə, onun quraşdırma seçimlərini oxuyun, çünki nodev yolun mövcud olmasına icazə verir, amma onu açmaqdan imtina edir və sərtləşdirilmiş hostdan götürülmüş bind mount bu bayrağı özü bildirmədən daşıyır. Yalnız oxuma üçün quraşdırma daha erkən və daha uca səslə uğursuz olur: mknod orada EROFS qaytarır, EPERM isə fayl sisteminin özünü qoruması deyil, prosesin imkanının olmaması deməkdir. Nəhayət, öz /dev tmpfs-i olan konteyner runtime-ı qovşağın öz ad məkanına yeridilməsini tələb edir və onun cihaz cgroup-u major və minor cütünə icazə verməlidir.

İcazələri yenidən dəyişməzdən əvvəl siyasət qatını yoxlayın. SELinux və AppArmor hər fayl atributunun icazə verdiyi açılışı rədd edə bilər və bu rədd müştəri çıxışında deyil, audit jurnalında görünür. Heç bir rəddə görünməyən icazə dəyişikliyi tamamilə yanlış qata sərf olunmuş vaxtdır.

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

Bunu siyahı ilə deyil, interfeyslə sübut edin

Uğurlu siyahı yalnız yolun mövcud olduğunu sübut edir və başqa heç nəyi. Sağlam tun qovşağını oxumaq üçün açın və çağırış xəta ilə qayıdır, çünki cihazın oxuma semantikası yoxdur və adi fayl deyil. Bu xəta burada uğur siqnalıdır və onu tanımaq sizi onu nasazlıq kimi təqib etməkdən saxlayır.

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

Həlledici test interfeys yaradır, çünki bu, sürücünü, qovşağı və sizin imtiyazlarınızı bir addımda yoxlayır. Əlavə uğurlu olarsa və link görünərsə, üçü də işləyir. Uğursuz olduqda errno səbəbləri ayırır: ENOENT yararlı qovşaq olmadığını, EPERM imkan, quraşdırma bayraqları və ya siyasətə işarə etdiyini, EBUSY isə interfeysin artıq başqa prosesə aid olduğunu bildirir.

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

Bu testi həqiqətən uğursuz olan kontekstdə işlədin, çünki xidmət vahidi, konteyner və ya planlaşdırılmış iş giriş shellinizdən fərqli imkan dəsti daşıya bilər. Yanlış kontekstdə keçən test uğursuz kontekst haqqında heç nə sübut etmir.

Cihaz problem olmadıqda

İnterfeys testi keçərsə və müştəri hələ də uğursuz olarsa, qalan problem profil, xidmət konteksti və ya marşrutdur və cihaz qaydasındadır. Bu, cihaz qovşaqlarını redaktə etməyi dayandırmaq lazım olan məqamdır, çünki sonrakı dəyişikliklər yalnız işləyən sistemdən uzaqlaşdırır.

Hər dəfə yeni bir yoxlama icad etmək əvəzinə eyni beş yoxlamanı işlədin: modul rəqib modul olmadan yüklənibmi, yol düzgün major və minor ilə simvol cihazdırmı, quraşdırma seçimləri təmizdirmi, proses konteksti imkanı daşıyırmı və nasazlığın vaxt damğasında siyasət rəddi varmı. Beşinin hamısından keçən nasazlıq cihaz problemi deyil, mesaj nəyi qeyd edirsə etsin.

Əlaqəli məqalələr