Το hook λειτουργεί την πρώτη φορά, και μετά από τρεις επανασυνδέσεις η αλυσίδα κρατά τρία αντίγραφα του ίδιου κανόνα. Τίποτα δεν απέτυχε ηχηρά· το script απλώς έκανε ό,τι του έλεγαν κάθε φορά που έτρεχε. Ένα hook VPN είναι μια λειτουργία διαμόρφωσης που μπορεί να εκτελεστεί περισσότερες από μία φορές, γι’ αυτό χρειάζεται ιδιοκτήτη, επιθυμητή κατάσταση και σειριοποιημένη αλλαγή. Ακολουθήστε αυτή τη σειρά και τα διπλότυπα σταματούν.

Δώστε στους κανόνες ιδιοκτήτη πριν γράψετε έστω έναν

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

iptables -N VPN_HOOK 2>/dev/null || true
iptables -C INPUT -j VPN_HOOK 2>/dev/null || iptables -I INPUT -j VPN_HOOK
iptables -S VPN_HOOK

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

Ελέγξτε την επιθυμητή κατάσταση αντί να προσθέσετε ξανά

Γράψτε τι πρέπει να υπάρχει όσο το tunnel είναι ενεργό: ποιες διεπαφές, ποια πηγή και προορισμός, ποιο πρωτόκολλο και ποια θύρα. Έπειτα εκφράστε κάθε κανόνα ως έλεγχο που ακολουθείται από εισαγωγή, ώστε μια δεύτερη εκτέλεση να βρει τον κανόνα και να μην κάνει τίποτα. Η εντολή ελέγχου επιστρέφει μηδέν όταν ο κανόνας υπάρχει, και αυτό είναι ακριβώς το σήμα που χρειάζεται το script. Η αναφορά του iptables τεκμηριώνει τις μορφές ελέγχου, προσάρτησης και εισαγωγής που χρησιμοποιούνται εδώ.

iptables -C VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT ||
  iptables -A VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT

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

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

Σειριοποιήστε την αλλαγή αντί να ελπίζετε ότι θα κρατήσει

Δύο κλήσεις του hook μπορούν να αλληλοκαλυφθούν, και και οι δύο μπορούν να δουν έναν απόντα κανόνα πριν τον προσθέσει κάποια. Η επιλογή αναμονής του xtables κάνει μια εντολή να περιμένει το κλείδωμα, αλλά δεν κάνει την ακολουθία ελέγχου-και-προσθήκης ατομική σε δύο εντολές. Σειριοποιήστε ολόκληρη τη λειτουργία με δικό σας κλείδωμα, ή χρησιμοποιήστε έναν διαχειριστή που εφαρμόζει μια δηλωμένη παρτίδα ως μία συναλλαγή. Το nftables μπορεί το δεύτερο, και αυτός είναι ένας λόγος να το προτιμάτε σε hosts όπου είναι διαθέσιμο.

flock /run/vpn-hook.lock /usr/local/sbin/vpn-firewall-apply
nft -f /etc/nftables/vpn-hook.nft

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

Κατεβάστε μόνο ό,τι σας ανήκει

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

iptables -D VPN_HOOK -i tun0 -p tcp --dport 443 -j ACCEPT
iptables -F VPN_HOOK
ip -brief link show type tun

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

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

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