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

Γιατί ο πίνακας δρομολόγησης δεν μπορεί να δει το πρόγραμμά σας

Όταν μια διεργασία στέλνει ένα πακέτο, η στοίβα αναζητά τη διεύθυνση προορισμού στον πίνακα δρομολόγησης. Ούτε το όνομα του εκτελέσιμου ούτε η θύρα μπαίνουν σε αυτή την αναζήτηση. Τα ονόματα τομέα αποτυγχάνουν για τον ίδιο λόγο: μια δίοδος μεταφέρει κίνηση σε μια διεύθυνση, και όταν ένα όνομα λυθεί σε μία, η δρομολόγηση είναι ο μόνος μοχλός που έχει ακόμη ο πυρήνας. Γι’ αυτό το «VPN μόνο για αυτόν τον ιστότοπο» καταλήγει να σημαίνει διαμεσολαβητή, και το «VPN μόνο για αυτό το πρόγραμμα» σημαίνει έναν από μια μικρή ομάδα μηχανισμών.

MechanismWhat selectsCoversOn tunnel drop
Socket bindsource addressa client you controlconnections fail
UID rule (Linux)owning userevery process of one accountconnections fail
Firewall profile (Windows)adapter profileone programfails closed
Network namespacenamespace membershipeverything started insideconnections fail
SOCKS hopapp proxy settingone app or one browser profileconnections fail

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

Ένας μόνος προορισμός είναι ακόμη διαδρομή, όχι κανόνας προγράμματος. Στο macOS η συνήθης συνταγή είναι να αποεπιλέξετε το «Αποστολή όλης της κίνησης μέσω VPN» και να προσθέσετε διαδρομή κεντρικού υπολογιστή: sudo route add -host internal-tuner.example -interface ppp0, που αφαιρείται ξανά με sudo route delete -host internal-tuner.example -interface ppp0. Διαβάστε πρώτα το όνομα της διεπαφής από ifconfig, καθώς το ppp0 είναι μόνο παράδειγμα. Οι χαρακτήρες μπαλαντέρ δεν λειτουργούν σε διαδρομή κεντρικού υπολογιστή, οπότε μια υπηρεσία που μιλά με πολλά ονόματα χρειάζεται μία καταχώριση ανά όνομα, και ο κανόνας καλύπτει κάθε διεργασία στο μηχάνημα, όχι αυτή που είχατε στο μυαλό σας.

Δεσμεύστε την υποδοχή στη διεύθυνση της διόδου

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

import socket
s = socket.socket()
s.bind(("10.8.0.2", 0))
s.connect(("build.internal.example", 443))

Εργαλεία υψηλότερου επιπέδου εκθέτουν την ίδια ιδέα: curl --interface 10.8.0.2, CURLOPT_INTERFACE στην PHP και το όρισμα source_address στους πελάτες HTTP της Python. Η διεύθυνση πρέπει να ανήκει στη δίοδο, και ένα τυπογραφικό εδώ αποτυγχάνει ως συνηθισμένο σφάλμα σύνδεσης, όχι ως παράπονο δρομολόγησης. Η δέσμευση σε όνομα συσκευής αντί για διεύθυνση είναι προνόμιο του Linux και δεν μεταφέρεται σε Windows ή macOS, γι’ αυτό τα φορητά σενάρια περνούν τη διεύθυνση.

Linux: αντιστοιχίστε τον κάτοχο, όχι το όνομα του προγράμματος

Ο πυρήνας μπορεί να αντιστοιχίσει τον κάτοχο μιας υποδοχής, οπότε ένας αποκλειστικός λογαριασμός γίνεται ο επιλογέας. Βάλτε τη δίοδο στον δικό της πίνακα δρομολόγησης και στείλτε εκεί μόνο την κίνηση αυτού του λογαριασμού:

ip rule add uidrange 1001-1001 lookup 100
ip route add default dev tun0 table 100

Αυτό λειτουργεί μόνο αν η δίοδος δεν είναι ήδη η προεπιλεγμένη διαδρομή. Ξεκινήστε τον πελάτη με --route-nopull, ή φιλτράρετε την ανακατεύθυνση που ωθείται με --pull-filter ignore "redirect-gateway" στο OpenVPN 2.4 και νεότερο, και μετά προσθέστε την καταχώριση του πίνακα μόνοι σας. Αλλιώς υπάρχουν και οι δύο προεπιλογές και κερδίζει αυτή με τη χαμηλότερη προτεραιότητα. Η σκόπιμη εκδοχή αυτού είναι να δείξετε την προεπιλεγμένη διαδρομή στην πύλη της διόδου, ή να το κάνετε από σενάριο αποσύνδεσης: κρατά την κίνηση έξω από το διαδίκτυο όταν πέσει η δίοδος, αλλά αυτό είναι διακόπτης ασφαλείας, όχι επιλογέας, και μένει μέχρι να τον αφαιρέσει κάποιος.

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

Δύο τρόποι αποτυχίας εξηγούν τις περισσότερες διαρροές. Η επίλυση ονομάτων εξακολουθεί να γίνεται στον επιλυτή του κεντρικού υπολογιστή, οπότε το ερώτημα βγαίνει έξω από τη δίοδο ακόμη και όταν η σύνδεση TCP μπαίνει μέσα. Και το IPv6 χρειάζεται δικό του ip -6 rule, επειδή ένας κανόνας v4 δεν το καλύπτει.

Windows και macOS: περιορίστε το τείχος προστασίας ή δώστε διαμεσολαβητή

Ούτε τα Windows έχουν επιλογέα διαδρομής ανά εφαρμογή, αλλά οι κανόνες του τείχους προστασίας τους μπορούν να περιοριστούν σε προφίλ, και ένας προσαρμογέας VPN μπορεί να χαρακτηριστεί «δημόσιος» ενώ το οικιακό LAN μένει «ιδιωτικό». Δημιουργήστε κανόνες αποκλεισμού εξερχόμενης κίνησης για το πρόγραμμα στα προφίλ «ιδιωτικό» και «τομέας», αφήστε το «δημόσιο» ανοιχτό, και η εφαρμογή μπορεί να φτάσει στο δίκτυο μόνο μέσω της διόδου. Ορίστε πρώτα την κατηγορία δικτύου της σύνδεσης και μετά επιβεβαιώστε ότι ο κανόνας αντιστοιχίστηκε στο πλαίσιο παρακολούθησης του τείχους προστασίας. Είναι αποκλεισμός, όχι διαδρομή: αποτυγχάνει κλειστά όταν πέσει η δίοδος, και δεν μπορεί να σταματήσει μια εφαρμογή που αγνοεί το τείχος προστασίας.

Το macOS ακολουθεί την ίδια λογική με άλλα εργαλεία. Ένας ακροατής SOCKS που φτάνει μέσω SSH είναι η λιγότερο παρεμβατική επιλογή, επειδή το ssh -D 1080 user@host δημιουργεί μία τοπική θύρα και μόνο εφαρμογές ρυθμισμένες να τη χρησιμοποιούν παίρνουν αυτή τη διαδρομή. Ένας κανόνας pf μπορεί να αποκλείσει ένα πρόγραμμα κατά χρήστη ή ομάδα, αλλά ακόμη δεν μπορεί να επιλέξει τη δίοδο μόνο για αυτό το πρόγραμμα. Το Tunnelblick δεν μπορεί να φιλτράρει κατά τομέα καθόλου, επειδή οι διαδρομές εργάζονται με διευθύνσεις· οι χρήστες του OpenConnect καταφεύγουν στο vpn-slice όταν ο διακομιστής ωθεί πολύ ευρύ κατάλογο προθεμάτων.

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

Άλμα SOCKS για εργαλεία χωρίς επιλογή δέσμευσης

Οι περισσότερες εφαρμογές μπορούν να στραφούν σε διαμεσολαβητή HTTP ή SOCKS ακόμη και όταν δεν γνωρίζουν τίποτα για διεπαφές. Ένας πελάτης SSH παρέχει έναν χωρίς καμία αλλαγή στην πλευρά του διακομιστή:

ssh -N -D 127.0.0.1:9999 [email protected]

Ό,τι έχει ρυθμιστεί να χρησιμοποιεί αυτή τη θύρα βγαίνει στο οχυρό ενώ η υπόλοιπη επιφάνεια εργασίας κρατά την κανονική της σύνδεση. Ένα τοπικό στιγμιότυπο 3proxy δεσμευμένο στη διεύθυνση της διόδου κάνει το ίδιο για μία θύρα χωρίς SSH, και το stunnel καλύπτει μία μόνο θύρα τυλιγμένη σε TLS. Τα όρια είναι πρακτικά: ένας διαμεσολαβητής μεταφέρει μόνο πρωτόκολλα που ξέρουν να τον χρησιμοποιούν, το UDP χρειάζεται συσχέτιση UDP του SOCKS5 που η ρύθμιση «SOCKS5» πολλών πελατών δεν ενεργοποιεί, και το DNS πρέπει να λύνεται από τον διαμεσολαβητή (socks5h στο curl), αλλιώς το όνομα διαρρέει στον τοπικό επιλυτή.

Κρατήστε τον ακροατή στην τοπική διεπαφή εκτός αν τον χρειάζεται άλλο μηχάνημα.

Επαληθεύστε τη διαδρομή με σύλληψη, όχι με μήνυμα κατάστασης

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

tcpdump -i any -n port 443
ss -tnp | grep 443

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

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

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