Η στοίβαξη δεύτερου client OpenVPN σε έναν υπολογιστή Linux αποτυγχάνει σε ένα από δύο σημεία. Ή ο εσωτερικός client δεν φτάνει στον δικό του διακομιστή επειδή η εξωτερική σήραγγα έχει καταλάβει αυτή τη μεταφορά, ή ο δεύτερος client ξαναγράφει τον πίνακα διαδρομών και η πρώτη σήραγγα παύει να λειτουργεί. Και τα δύο προβλήματα βρίσκονται στη δρομολόγηση, όχι στην κρυπτογράφηση, και και τα δύο λύνονται πριν η νέα σήραγγα μεταφέρει οποιαδήποτε κίνηση εφαρμογών. Οι διευθύνσεις εδώ είναι ενδεικτικές: το tun0 είναι η εξωτερική σήραγγα, το 203.0.113.9 είναι ο εσωτερικός διακομιστής και το TCP 9999 είναι η ροή που πρέπει να χρησιμοποιεί την εσωτερική διαδρομή.

Δύο τρόποι αποτυχίας, ένας πίνακας δρομολόγησης

Ένας εσωτερικός client ανοίγει υποδοχή UDP προς τον διακομιστή του, και αυτή η υποδοχή ακολουθεί τον τρέχοντα πίνακα διαδρομών όπως κάθε άλλη. Αν η εξωτερική σήραγγα κατέχει ήδη την προεπιλεγμένη διαδρομή, τα πακέτα χειραψίας μπαίνουν στην εξωτερική σήραγγα. Αυτό λειτουργεί μόνο όταν ο εξωτερικός διακομιστής μπορεί να φτάσει τον εσωτερικό και η άλλη πλευρά δέχεται να μεταφέρει τη ροή· αλλιώς η χειραψία κολλάει και ο client ξαναπροσπαθεί.

Η δεύτερη αποτυχία προέρχεται από το push του διακομιστή. Το συνηθισμένο push είναι redirect-gateway def1, το οποίο εγκαθιστά 0.0.0.0/1 και 128.0.0.0/1 αντί να αντικαταστήσει την προεπιλεγμένη διαδρομή. Έτσι δύο clients που εγκαθιστούν ο καθένας το δικό του ζεύγος /1 συγκρούονται, και το νεότερο ζεύγος επικρατεί σχεδόν για κάθε προορισμό. Αναζητήστε αυτά τα δύο προθέματα στον πίνακα όταν μια σήραγγα πεθαίνει αφού συνδεθεί η δεύτερη, γιατί η ίδια η προεπιλεγμένη διαδρομή μπορεί να μην άλλαξε ποτέ.

Σημάνετε τη ροή και δώστε της πίνακα

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

iptables -t mangle -A PREROUTING -p tcp -m multiport --dport 9999 -j MARK --set-mark 0x9999
ip rule add fwmark 0x9999 table 200 pref 1000
ip route add default dev tun1 table 200

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

Αφαιρέστε την κυριότητα των διαδρομών από τον δεύτερο client

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

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

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

Καρφώστε και τις δύο διευθύνσεις διακομιστή

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

ip route add 203.0.113.9/32 dev tun0
ip route get 203.0.113.9

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

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

Δοκιμάστε την αλυσίδα και κάντε την αποτυχία ορατή

Καταγράψτε στην εξωτερική διεπαφή όσο συνδέεται ο εσωτερικός client. Η εσωτερική χειραψία θα πρέπει να εμφανίζεται ως κρυπτογραφημένο φορτίο μέσα στην εξωτερική σήραγγα· αν εμφανίζεται ως απλό UDP προς το 203.0.113.9, λείπει η διαδρομή υπολογιστή και η αλυσίδα δεν χτίστηκε ποτέ.

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

Τελειώστε με δύο ροές και μία εκτύπωση κανόνων: μια σημασμένη και μια ασημάδευτη σύνδεση θα πρέπει να ακολουθούν διαφορετικές διαδρομές, και το ip rule show θα πρέπει να εμφανίζει την προτεραιότητα που σκοπεύατε. Αν και οι δύο ροές ακολουθούν την ίδια διαδρομή, η σήμανση δεν εφαρμόζεται εκεί που νομίζετε.

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