Δημοσίευση οικιακού διακομιστή μέσω VPS όταν το CGNAT μπλοκάρει θύρες
Η διαδρομή από το πρόγραμμα περιήγησης στον υπολογιστή του σπιτιού: απόδειξε ότι η γραμμή είναι πίσω από CGNAT, στρέψε το DNS στο VPS, κάνε DNAT σε μία θύρα, διόρθωσε τη διαδρομή επιστροφής και επαλήθευσε από έξω.
Ξεκίνησα από έξω, όπως θα έκανε ένας χρήστης: πληκτρολόγησα το όνομα στο πρόγραμμα περιήγησης ενός τηλεφώνου με δεδομένα κινητής και είδα τη σύνδεση να κρέμεται μέχρι να λήξει ο χρόνος. Το όνομα επιλυόταν, άρα το DNS ήταν εντάξει. Ούτε η σελίδα προώθησης θυρών του οικιακού δρομολογητή ήταν λύση, γιατί η διεύθυνση WAN έδειχνε 100.64.31.42, και αυτή δεν είναι διεύθυνση προς την οποία ένας πάροχος με δρομολογεί από το διαδίκτυο. Αυτός ο αριθμός εξηγεί όλη τη βλάβη: η γραμμή βρίσκεται πίσω από carrier-grade NAT, άρα η δημόσια διεύθυνση από τη δική μου πλευρά της σήραγγας ανήκει στον πάροχο. Ακολουθεί η διαδρομή που διένυσα από εκείνη την κολλημένη καρτέλα σε μια υπηρεσία που απαντά.
Ξεκίνα από τον πελάτη και προχώρα προς τα μέσα
Πριν αλλάξεις οποιονδήποτε κανόνα, απόδειξε πού σταματά η αλυσίδα. Στο φορητό υπολογιστή εκτέλεσα το dig +short files.example.net και πήρα πίσω τη διεύθυνση του VPS, κάτι που απέκλεισε παλιό DNS στο μηχάνημά μου. Έπειτα το curl -v --connect-timeout 5 files.example.net:5022 έληξε λόγω χρόνου αντί να απορριφθεί. Αυτή η διαφορά έχει σημασία: η λήξη χρόνου συνήθως σημαίνει ότι τα πακέτα ρίχνονται στη διαδρομή, ενώ η απόρριψη σημαίνει ότι κάτι απάντησε και είπε όχι.
Το επόμενο βήμα προς τα μέσα ήταν το ίδιο το VPS. Το ss -ltnp δεν έδειξε τίποτα να ακούει στη θύρα 5022, κάτι που αναμενόταν πριν υπάρξει ο κανόνας DNAT. Στο ίδιο μηχάνημα το wg show (ή το ip -br a show tun0 για OpenVPN) επιβεβαίωσε ότι ο οικιακός peer είναι ενεργός με πρόσφατο handshake. Αν ο peer είναι κάτω, κανένας κανόνας NAT δεν βοηθά, και το πράσινο φως στη σελίδα VPN του οικιακού δρομολογητή δεν σημαίνει τίποτα.
Επιβεβαίωσε ότι η οικιακή γραμμή είναι πραγματικά πίσω από CGNAT
Σύγκρινε τη διεύθυνση που αναφέρει ο δρομολογητής στη διεπαφή WAN με αυτό που βλέπει μια εξωτερική υπηρεσία. Ό,τι βρίσκεται στο 100.64.0.0/10, δηλαδή από 100.64.x.x έως 100.127.x.x, είναι το εύρος κοινόχρηστων διευθύνσεων του RFC 6598 και δεν είναι προσβάσιμο από το διαδίκτυο. Στο ίδιο συμπέρασμα καταλήγεις όταν ο δρομολογητής ισχυρίζεται ότι έχει μια συνηθισμένη ιδιωτική διεύθυνση και μια δημόσια αναζήτηση επιστρέφει κάτι άσχετο. Μια γραμμή CGNAT μπορεί επίσης να έχει δημόσια διεύθυνση που ισχύει μόνο μέχρι την επόμενη lease, οπότε η προώθηση θύρας φαίνεται να δουλεύει μία ώρα και μετά πεθαίνει ήσυχα.
Ορισμένοι πάροχοι δίνουν πράγματι αληθινή δημόσια διεύθυνση αλλά μπλοκάρουν τις εισερχόμενες θύρες 80 και 443 σε οικιακές συνδέσεις. Αν η υπηρεσία σου είναι μόνο web και η διεύθυνση WAN είναι πραγματικά δημόσια, ρώτησε την υποστήριξη πριν στήσεις relay. Αν δεν είναι, ο σχεδιασμός παρακάτω ισχύει εξίσου για κάθε θύρα, και αξίζει να σταματήσεις το πείραμα στην πλευρά του δρομολογητή: ο μεταφραστής στο δίκτυο του παρόχου τερματίζει τη σύνδεση πριν αυτή φτάσει ποτέ στη διεπαφή WAN σου.
Στρέψε το όνομα στη διεύθυνση του VPS
Το DNS δεν προωθεί κίνηση, άρα η εγγραφή A της υπηρεσίας πρέπει να περιέχει τη δημόσια διεύθυνση του VPS. Μια εγγραφή A προς το 192.168.1.20 επιλύεται χρήσιμα μόνο για πελάτες που βρίσκονται ήδη στο VPN· από το διαδίκτυο επιλύεται σε μια διεύθυνση που κανείς δεν μπορεί να δρομολογήσει. Για τη διαχειριστική πρόσβαση του ίδιου του VPS κρατώ ξεχωριστό όνομα, για να μην μπερδεύω ποτέ σε ποιον κεντρικό υπολογιστή αναφέρεται μια εγγραφή.
Αν και το VPS και το οικιακό μηχάνημα σερβίρουν HTTP, δώσε σε καθένα το δικό του όνομα και άφησε το VPS να αποφασίσει ποιος απαντά. Το να τα ενώσεις σε ένα όνομα και να ελπίζεις ότι ο μεσολαβητής θα διαλέξει το σωστό backend είναι ακριβώς το πώς περνάς ένα απόγευμα κάνοντας αποσφαλμάτωση στον λάθος κεντρικό υπολογιστή.
Μία θύρα με DNAT, το SSH μένει στο 22
Η άμεση επιλογή είναι NAT προορισμού στο VPS. Ενεργοποίησε το forwarding για τον πυρήνα που εκτελείται και κράτα στη ρήτρα τη διεύθυνση σήραγγας του οικιακού διακομιστή, όχι τη διεύθυνση LAN του:
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp -d 198.51.100.10 --dport 5022 -j DNAT --to-destination 10.8.0.2
Άφησε το SSH προς το ίδιο το VPS στο 22 και προώθησε άλλη θύρα, για παράδειγμα τη 5022, στο οικιακό μηχάνημα. Αν προωθήσεις τη 22 σε μηχάνημα που είναι σβηστό, χάνεις τη μόνη διαδρομή που θα μπορούσε να το διορθώσει. Η ίδια λογική ισχύει για τον μεσολαβητή: κράτα τη θύρα διαχείρισης του VPS έξω από τους κανόνες relay.
Κάνε τους κανόνες μόνιμους μόλις δουλέψουν. Σε Debian ή Ubuntu, το apt install iptables-persistent και μετά το netfilter-persistent save τους γράφουν στο /etc/iptables/rules.v4. Σε κεντρικό υπολογιστή με firewalld το αντίστοιχο είναι μόνιμη προώθηση θύρας στη ζώνη, που χρειάζεται το firewall-cmd --reload πριν εφαρμοστεί. Οι κανόνες που ζουν μόνο στη μνήμη εξαφανίζονται στην πρώτη επανεκκίνηση συντήρησης του παρόχου, συνήθως σε κακή ώρα.
Διόρθωσε τη διαδρομή επιστροφής ή απόφυγε την ανάγκη της
Το DNAT ξαναγράφει μόνο τον προορισμό. Ο οικιακός διακομιστής βλέπει σύνδεση από την αρχική διεύθυνση του πελάτη, και αν η προεπιλεγμένη διαδρομή του δείχνει στον οικιακό δρομολογητή, η απάντηση φεύγει από το WAN του σπιτιού όπου ο μεταφραστής του παρόχου τη ρίχνει. Αυτή η ασυμμετρία ήταν η δεύτερη βλάβη που συνάντησα, αφού ο κανόνας DNAT φαινόταν απόλυτα σωστός.
Δύο διορθώσεις δουλεύουν. Δώσε στο οικιακό μηχάνημα διαδρομή πολιτικής ώστε η κίνηση από τη σήραγγα να επιστρέφει μέσα από τη σήραγγα:
ip rule add from 10.8.0.2 table 100
ip route add default dev wg0 table 100
Ή άφησε το VPS να ξαναγράψει την πηγή ώστε η απάντηση να έχει διεύθυνση που μπορεί να φτάσει, και άφησε το conntrack να την αντιστρέψει στην έξοδο:
iptables -t nat -A POSTROUTING -d 10.8.0.2 -p tcp --dport 5022 -j SNAT --to-source 10.8.0.1
Η έκδοση SNAT κρύβει την πραγματική διεύθυνση του πελάτη από τον οικιακό διακομιστή, οπότε τα αρχεία καταγραφής της εφαρμογής δείχνουν 10.8.0.1 ως peer. Πέρασε την αρχική διεύθυνση στο επίπεδο εφαρμογής ή δέξου την απώλεια καταγραφής ανά πελάτη, αλλά αποφάσισέ το συνειδητά αντί να το ανακαλύψεις κατά τη διάρκεια ενός περιστατικού.
Έλεγξε ολόκληρη τη διαδρομή από έξω
Επαλήθευσε από δίκτυο που δεν είναι ούτε το VPS ούτε το σπίτι: τηλέφωνο με δεδομένα κινητής ή ένα φθηνό shell αλλού. Το nc -vz files.example.net 5022 θα πρέπει να αναφέρει επιτυχή σύνδεση, και το openssl s_client -connect files.example.net:443 -servername files.example.net θα πρέπει να δείχνει το πιστοποιητικό για το δημόσιο όνομα. Έπειτα έλεγξε την ομάδα ασφαλείας ή το τείχος προστασίας cloud του παρόχου. Ένας κανόνας DNAT που δεν βλέπει ποτέ πακέτο συνήθως μπλοκάρεται ένα επίπεδο πάνω από τον κεντρικό υπολογιστή.
Τέλος, απόφασισε τι γίνεται όταν πέσει η σήραγγα. Ένας κανόνας DNAT συνεχίζει να δέχεται συνδέσεις και τις τροφοδοτεί ήσυχα σε μια νεκρή σήραγγα, κάτι που μοιάζει ακριβώς με χαλασμένη υπηρεσία. Ένας έλεγχος υγείας στο VPS που απορρίπτει τη θύρα όσο ο peer είναι κάτω κοστίζει λίγες γραμμές και γλιτώνει μία ώρα εικασιών. Μετά από αυτό, σταμάτα να επεξεργάζεσαι κανόνες και παρακολούθησέ το για μια μέρα πριν το εμπιστευτείς.