OpenVPN σταματά με παράπονο errno 2 για το /dev/net/tun ενώ το lsmod απαριθμεί άνετα το άρθρωμα tun. Και τα δύο γεγονότα ισχύουν ταυτόχρονα. Το άρθρωμα παρέχει οδηγό, και η διαδρομή που ανοίγει ο πελάτης είναι κόμβος συσκευής που πρέπει να δημιουργήσει κάτι άλλο. Το να τα αντιμετωπίζουμε ως ένα αντικείμενο είναι ο λόγος που η προφανής επιδιόρθωση της επαναφόρτωσης του αρθρώματος δεν αλλάζει απολύτως τίποτα.

Δύο αντικείμενα, δύο διαφορετικοί ιδιοκτήτες

Ένα άρθρωμα πυρήνα και ένας κόμβος συσκευής είναι ανεξάρτητα αντικείμενα με ανεξάρτητους κύκλους ζωής. Η φόρτωση του αρθρώματος καταχωρεί οδηγό, και σε σύστημα με devtmpfs ο πυρήνας ζητά να δημιουργηθεί ο αντίστοιχος κόμβος. Σε σύστημα χωρίς devtmpfs τίποτα δεν δημιουργεί τίποτα, και ο οδηγός κάθεται εκεί χωρίς καμία διαδρομή να δείχνει προς αυτόν. Το άρθρωμα μπορεί να είναι φορτωμένο, υγιές και εντελώς απρόσιτο μέσω του συστήματος αρχείων την ίδια στιγμή.

Γι' αυτό το κείμενο σφάλματος και η λίστα αρθρωμάτων δεν αντιφάσκουν. Ο πελάτης ανοίγει μια διαδρομή, η διαδρομή δεν υπάρχει, και ο πυρήνας επιστρέφει ENOENT πριν καν ερωτηθεί ο οδηγός tun. Η επαναφόρτωση του αρθρώματος δεν μπορεί να επιδιορθώσει μια διαδρομή που λείπει, και η δημιουργία της διαδρομής δεν μπορεί να επιδιορθώσει έναν οδηγό που λείπει.

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

devtmpfs έναντι ρητού mknod

Δύο μηχανισμοί συνήθως δημιουργούν αυτόν τον κόμβο, και το να ξέρετε ποιος υποτίθεται ότι είναι υπεύθυνος σας λέει τι να επιδιορθώσετε. Το devtmpfs αφήνει τον πυρήνα να δημιουργεί κόμβους συσκευών σε ένα προσαρτημένο στιγμιότυπο, και το udev εφαρμόζει ιδιοκτησία και δικαιώματα από πάνω τους. Ένα ρητό mknod είναι η χειροκίνητη διαδρομή για είδωλα και χώρους ονομάτων όπου κανένα από τα δύο δεν εκτελείται στην εκκίνηση.

Συγκρίνετε αποτελέσματα αντί για προθέσεις. Αν το devtmpfs είναι προσαρτημένο στο /dev και ο κόμβος εξακολουθεί να λείπει, ο οδηγός δεν είναι αυτός που υποθέτετε, ή κάτι αφαίρεσε τον κόμβο μετά την εκκίνηση. Αν το /dev είναι ένας συνηθισμένος κατάλογος μέσα σε αποσυμπιεσμένο rootfs, δεν υπάρχει αυτόματος μηχανισμός και όποιος χτίζει το είδωλο πρέπει να δημιουργήσει τον κόμβο.

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

Όπου δεν εκτελείται κανένας από τους δύο μηχανισμούς, ο κόμβος πρέπει να φτιαχτεί με το χέρι, και η σειρά μετράει. Δημιουργήστε πρώτα τον γονικό κατάλογο, γιατί το mknod δεν μπορεί να τον εφεύρει, μετά τη συσκευή χαρακτήρων, μετά έναν τρόπο που την αφήνει εγγράψιμη μόνο για το root. Επαναφορτώστε το άρθρωμα πριν δημιουργήσετε τον κόμβο, και αφαιρέστε μια υπάρχουσα διαδρομή μόνο αφού το ls δείξει ότι είναι κατάλογος και όχι συσκευή.

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

Ο τύπος που αναφέρει το stat είναι ο ταχύτερος διαχωριστής, και ένας κατάλογος σε αυτή τη διαδρομή είναι η πιο συνηθισμένη έκπληξη στα ελάχιστα είδωλα. Ένα καλοπροαίρετο mkdir σε ένα Dockerfile αφήνει ακριβώς αυτό, και καμία ποσότητα φόρτωσης αρθρωμάτων δεν αντικαθιστά έναν κατάλογο με συσκευή χαρακτήρων. Το Major 10 με minor 200 είναι το καταχωρημένο ζεύγος για το tun, εκφρασμένο σε δεκαεξαδικό ως a και c8.

Τέσσερα ίχνη, τέσσερις αιτίες

Τέσσερις αιτίες εξηγούν σχεδόν κάθε περίπτωση, και κάθε μία αφήνει διαφορετικό ίχνος στα αρχεία καταγραφής. Ξεκινήστε από το περιβάλλον εκκίνησης. Τα είδωλα χωρίς δίσκο, οι ενσωματωμένες πλακέτες και τα στάδια initramfs συχνά δεν προσαρτούν ούτε devtmpfs ούτε /devυπό τη διαχείριση του udev, οπότε καμία διεργασία δεν γράφει ποτέ τον κόμβο. Μετά διαβάστε τις επιλογές προσάρτησης σε ό,τι φιλοξενεί το /dev, γιατί το nodev επιτρέπει στη διαδρομή να υπάρχει ενώ αρνείται να την ανοίξει, και μια bind προσάρτηση παρμένη από σκληρυμένο host φέρει τη σημαία χωρίς να ανακοινωθεί. Μια προσάρτηση μόνο για ανάγνωση αποτυγχάνει νωρίτερα και πιο δυνατά: το mknod επιστρέφει εκεί EROFS, ενώ το EPERM σημαίνει ότι η διεργασία δεν έχει την ικανότητα και όχι ότι το σύστημα αρχείων προστατεύεται. Τέλος, ένα runtime κοντέινερ με δικό του /dev tmpfs χρειάζεται τον κόμβο να εγχέεται στον δικό του χώρο ονομάτων, και το cgroup συσκευών του πρέπει να επιτρέπει το ζεύγος major και minor.

Ελέγξτε το επίπεδο πολιτικής πριν αλλάξετε ξανά δικαιώματα. Τα SELinux και AppArmor μπορούν να αρνηθούν ένα άνοιγμα που κάθε χαρακτηριστικό αρχείου επιτρέπει, και αυτή η άρνηση εμφανίζεται στο αρχείο ελέγχου και όχι στην έξοδο του πελάτη. Μια αλλαγή δικαιωμάτων που δεν εμφανίζεται ποτέ σε άρνηση είναι χρόνος σπαταλημένος σε εντελώς λάθος επίπεδο.

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

Αποδείξτε το με διεπαφή, όχι με λίστα

Μια επιτυχημένη λίστα αποδεικνύει ότι υπάρχει μια διαδρομή και τίποτα παραπάνω. Ανοίξτε έναν υγιή κόμβο tun για ανάγνωση και η κλήση επιστρέφει με σφάλμα, γιατί η συσκευή δεν έχει σημασιολογία ανάγνωσης και δεν είναι κανονικό αρχείο. Αυτό το σφάλμα είναι το σήμα επιτυχίας εδώ, και η αναγνώρισή του σας κρατά από το να το κυνηγάτε ως βλάβη.

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

Η αποφασιστική δοκιμή δημιουργεί μια διεπαφή, γιατί ασκεί τον οδηγό, τον κόμβο και τα προνόμιά σας σε ένα βήμα. Αν η προσθήκη πετύχει και εμφανιστεί ο σύνδεσμος, και τα τρία λειτουργούν. Όταν αποτυγχάνει, το errno διαχωρίζει τις αιτίες: το ENOENT σημαίνει ότι δεν υπάρχει χρησιμοποιήσιμος κόμβος, το EPERM δείχνει ικανότητα, σημαίες προσάρτησης ή πολιτική, και το EBUSY σημαίνει ότι μια άλλη διεργασία κατέχει ήδη τη διεπαφή.

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

Εκτελέστε αυτή τη δοκιμή στο περιβάλλον που πραγματικά αποτυγχάνει, γιατί μια μονάδα υπηρεσίας, ένα κοντέινερ ή μια προγραμματισμένη εργασία μπορεί να φέρει διαφορετικό σύνολο ικανοτήτων από το κέλυφος σύνδεσής σας. Μια δοκιμή που περνά στο λάθος περιβάλλον δεν αποδεικνύει τίποτα για εκείνο που αποτυγχάνει.

Όταν η συσκευή δεν είναι το πρόβλημα

Αν η δοκιμή διεπαφής πετύχει και ο πελάτης εξακολουθεί να αποτυγχάνει, το εναπομείναν πρόβλημα είναι το προφίλ, το περιβάλλον υπηρεσίας ή η διαδρομή, και η συσκευή είναι εντάξει. Αυτή είναι η στιγμή να σταματήσετε να επεξεργάζεστε κόμβους συσκευών, γιατί περαιτέρω αλλαγές προσθέτουν μόνο απόσταση από ένα λειτουργικό σύστημα.

Εκτελείτε τους ίδιους πέντε ελέγχους κάθε φορά αντί να εφευρίσκετε νέο: είναι το άρθρωμα φορτωμένο χωρίς ανταγωνιστικό άρθρωμα, είναι η διαδρομή συσκευή χαρακτήρων με το σωστό major και minor, είναι καθαρές οι επιλογές προσάρτησης, φέρει το περιβάλλον της διεργασίας την ικανότητα, και υπάρχει άρνηση πολιτικής στη χρονική σήμανση της αποτυχίας. Μια βλάβη που επιβιώνει και από τους πέντε δεν είναι πρόβλημα συσκευής, ό,τι κι αν αναφέρει το μήνυμα.

Σχετικά άρθρα