Γιατί τα εσωτερικά ονόματα κεντρικών υπολογιστών επιλύονται στο dig αλλά αποτυγχάνουν στο curl σε VPN
Το dig απαντά, αλλά το curl αναφέρει ότι δεν μπορεί να επιλύσει τον κεντρικό υπολογιστή. Συγκρίνετε τις δύο αλυσίδες αναζήτησης και μετά διορθώστε το nsswitch, το DNS ανά σύνδεσμο ή ένα λανθασμένο επίθημα αναζήτησης.
Ο φορητός σας υπολογιστής είναι στο VPN, το dig service.internal.example απαντά με διεύθυνση 10.x και το curl εξακολουθεί να τερματίζει με Could not resolve host. Η σήραγγα δεν είναι το πρόβλημα: μετέφερε το ερώτημα του dig χωρίς παράπονο. Η διαφορά είναι ποιος κάνει την ερώτηση. Το dig στέλνει ένα ερώτημα σε έναν διακομιστή που ονομάζετε εσείς, ενώ το curl περνά από την αλυσίδα αναζήτησης του λειτουργικού συστήματος, και αυτή η αλυσίδα έχει τους δικούς της κανόνες για το ποιος διακομιστής ερωτάται.
Δύο αναζητήσεις για το ίδιο όνομα
Το dig είναι δικός του stub resolver. Διαβάζει το /etc/resolv.conf, επιλέγει έναν διακομιστή ονομάτων, στέλνει ένα μόνο ερώτημα A ή AAAA και εκτυπώνει την απάντηση. Παρακάμπτει εντελώς το nsswitch και δεν γνωρίζει τίποτα για την κατάσταση ανά σύνδεσμο που κρατούν το systemd-resolved ή το NetworkManager έξω από αυτό το αρχείο, γι’ αυτό μια απάντηση του dig μπορεί να είναι σωστή και παρ’ όλα αυτά να μη σας λέει τίποτα για το τι θα δει η εφαρμογή σας.
Οι εφαρμογές καλούν το getaddrinfo, και το getaddrinfo διασχίζει μια μεγαλύτερη αλυσίδα: τη σειρά των μονάδων του nsswitch, έπειτα τη μονάδα που χειρίζεται το όνομα και τέλος τον resolver που χτίζεται από την τρέχουσα διαμόρφωση της σύνδεσης. Σε μηχάνημα systemd το ερώτημα πηγαίνει στη 127.0.0.53 και το systemd-resolved επιλέγει ανάντη διακομιστή ανά σύνδεσμο με βάση τον τομέα δρομολόγησης που είναι συνδεδεμένος στη διεπαφή tun.
Δύο εντολές χωρίζουν αυτά τα στρώματα χωρίς εικασίες:
getent ahosts service.internal.example
resolvectl query service.internal.example
Το getent χρησιμοποιεί την ίδια διαδρομή με το curl, οπότε μια αποτυχία του getent δίπλα σε ένα dig που δουλεύει εντοπίζει το σφάλμα στην πολιτική αναζήτησης και όχι στη δρομολόγηση πακέτων. Το resolvectl query εκτυπώνει επίσης τη διεπαφή και τον ανάντη διακομιστή που έδωσαν την απάντηση, κάτι που δείχνει αν κέρδισε η σύνδεση της σήραγγας ή η φυσική σύνδεση.
Διαβάστε τον resolver που χρησιμοποιεί πραγματικά η εφαρμογή
Το /etc/resolv.conf παράγεται στους περισσότερους υπολογιστές επιφάνειας εργασίας, και ένας πελάτης VPN έχει τρεις τρόπους να αλληλεπιδράσει μαζί του: να προσθέσει έναν διακομιστή ονομάτων μπροστά, να αντικαταστήσει το αρχείο ή να δώσει τους διακομιστές του στο NetworkManager και να αφήσει τον δαίμονα να το ξαναγράψει. Μόνο το τρίτο μοτίβο διατηρεί το DNS ανά σύνδεσμο, γιατί οι διακομιστές μένουν συνδεδεμένοι σε μια διεπαφή αντί να ισοπεδώνονται σε έναν παγκόσμιο κατάλογο.
Σε συστήματα NetworkManager το αποτέλεσμα εξαρτάται από το backend στο /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
Με dns=default οι διακομιστές του πελάτη συνενώνονται στο resolv.conf με τη σειρά που κερδίζει, και μια ιδιωτική αναζήτηση μπορεί ακόμη να σταλεί στον δημόσιο resolver. Με backend που καταλαβαίνει συνδέσεις, systemd-resolved ή dnsmasq, οι διακομιστές της σήραγγας μένουν περιορισμένοι στη σήραγγα και εκεί πηγαίνουν μόνο ονόματα που ταιριάζουν με τον τομέα δρομολόγησής της. Αυτός ο περιορισμός είναι ό,τι σημαίνει στην πράξη το split DNS, και είναι το κομμάτι που λείπει συχνότερα όταν ένας πελάτης ισχυρίζεται ότι το υποστηρίζει.
Διαβάστε την κατάσταση πριν αλλάξετε οτιδήποτε:
resolvectl status
resolvectl dns tun0
Θέλετε να δείτε τη διεπαφή tun καταγεγραμμένη με διακομιστή DNS και τομέα δρομολόγησης για το ιδιωτικό επίθημα, εμφανιζόμενη ως ~internal.example. Κανένας διακομιστής στη σύνδεση σημαίνει ότι ο πελάτης δεν έσπρωξε τίποτα. Διακομιστής χωρίς τομέα σημαίνει ότι οι αναζητήσεις είτε πηγαίνουν όλες εκεί είτε καμία, ανάλογα με τον πελάτη, και κανένα από τα δύο δεν είναι split DNS.
Πού το nsswitch τελειώνει την αναζήτηση νωρίς
Μια τυπική γραμμή επιφάνειας εργασίας μοιάζει έτσι:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
Το mdns4_minimal χειρίζεται το multicast DNS και διεκδικεί κάθε όνομα που τελειώνει σε .local. Μια υπηρεσία Kubernetes όπως το api.infra.svc.cluster.local τελειώνει επίσης σε .local. Όταν η μονάδα mDNS αναφέρει NOTFOUND, η ενέργεια [NOTFOUND=return] τερματίζει ολόκληρη την αναζήτηση αντί να συνεχίσει στη μονάδα dns, οπότε το όνομα δεν αποστέλλεται ποτέ στον resolver του VPN. Το dig παρακάμπτει εντελώς το αρχείο, και γι’ αυτό ακριβώς διαφωνούν τα δύο εργαλεία.
Αυτή είναι η πιο έντονη αντίθεση σε αυτό το πρόβλημα, και ανάγεται σε μία λέξη σε ένα αρχείο διαμόρφωσης παλαιότερο από το VPN σας. Η αλλαγή της ενέργειας σε [NOTFOUND=continue] διατηρεί το mDNS για εκτυπωτές και τοπικές συσκευές επιτρέποντας στο DNS να δει το όνομα. Η αντικατάσταση της γραμμής με hosts: files dns λειτουργεί επίσης και είναι πιο χονδροειδής: αφαιρεί την επίλυση .local για τον εκτυπωτή που χρησιμοποιείτε πραγματικά.
Ονόματα που ζουν σε ένα μόνο δίκτυο
Οι ιδιωτικές ζώνες είναι αυθεντικές σε ένα μόνο σημείο. Ένα όνομα AWS όπως το ip-10-0-4-31.eu-west-1.compute.internal απαντάται μέσω του resolver VPC εκείνης της περιοχής, και μόνο όσο το τελικό σημείο του VPN σας βρίσκεται στην ίδια περιοχή με τον πόρο. Συνδεθείτε σε τελικό σημείο στη Φρανκφούρτη, ρωτήστε ένα όνομα compute.internal από την Ιρλανδία, και καμία τοπική ρύθμιση δεν θα βοηθήσει: η ζώνη που κρατά την εγγραφή δεν είναι προσβάσιμη από εκεί.
Οι τομείς αναζήτησης παράγουν το κατοπτρικό είδωλο. Ένα γυμνό service συμπληρώνεται με το επίθημα που ο resolver θεωρεί εφαρμόσιμο, και με σύνδεση VPN ο τοπικός τομέας μπορεί να νικήσει τον εταιρικό. Ρωτήστε με τελεία στο τέλος για να αφαιρέσετε την εικασία, getent ahosts service.internal.example., και αν αυτό λειτουργεί ενώ το σύντομο όνομα αποτυγχάνει, η διόρθωση είναι ο τομέας αναζήτησης στη σήραγγα, όχι η διεύθυνση του διακομιστή.
Οι διαχειριζόμενοι πελάτες προσθέτουν ένα τρίτο στρώμα πάνω από τον resolver του συστήματος. Ένα προφίλ VPN των Windows μπορεί να φέρει δική του πολιτική επίλυσης ονομάτων, κανόνες ανά εφαρμογή και έναν πίνακα NRPT που ισχύει ακόμη και όταν η σήραγγα είναι κάτω. Οι εφαρμογές με δική τους κρυφή μνήμη DNS, συνηθισμένες σε περιβάλλοντα .NET και Java, κρατούν μια παλιά αποτυχία πολύ μετά τη διόρθωση της αλυσίδας. Οι πελάτες Apple ρυθμίζουν το split DNS μέσω τομέων αντιστοίχισης στις ρυθμίσεις DNS και όχι μέσω του resolv.conf, ενώ το Chromium ή το Firefox σε λειτουργία ασφαλούς DNS μπορούν να παρακάμψουν τον resolver του συστήματος για δημόσια ονόματα. Η αναφορά της Microsoft για την επίλυση ονομάτων VPN περιγράφει την πλευρά των Windows αυτού του στρώματος πολιτικής.
Αποφασίστε ποιο στρώμα θα διορθώσετε
Προχωρήστε από το σύμπτωμα προς το στρώμα αντί να δοκιμάζετε διορθώσεις με σειρά:
| Symptom | What it means | Check first |
|---|---|---|
| dig answers, getent fails | lookup chain, not the packet path | nsswitch line and resolvectl status |
| Timeout rather than NXDOMAIN | private resolver unreachable through the tunnel | resolvectl dns tun0, route to that address |
| NXDOMAIN | an authority answered and does not know the name | zone owner, endpoint region |
| FQDN works, short name fails | search suffix mismatch | resolvectl domain on the tun link |
| getent works, app fails | app cache or its own resolver | restart the app, check secure DNS |
Δύο γραμμές σηκώνουν το μεγαλύτερο βάρος. Το χρονικό όριο είναι πρόβλημα προσβασιμότητας: ο ιδιωτικός resolver δεν απαντά μέσω της σήραγγας, οπότε ελέγξτε τη διαδρομή προς τη διεύθυνσή του και αν ο διακομιστής DNS στη σύνδεση είναι αυτός που νομίζετε. Το NXDOMAIN είναι πρόβλημα αυθεντίας: κάτι απάντησε και δεν γνωρίζει το όνομα, κάτι που δείχνει στη ζώνη, στην περιοχή ή σε έναν resolver που δεν έπρεπε ποτέ να λάβει το ερώτημα.
Η τελευταία γραμμή είναι αυτή που χάνουν οι άνθρωποι επειδή και τα δύο μισά μοιάζουν με επιτυχία. Ένα σύντομο όνομα που επιλύεται διαφορετικά από το FQDN είναι αναντιστοιχία επιθήματος, και η επανασύνδεση της σήραγγας δεν θα αλλάξει ποιο επίθημα στέλνει ο πελάτης.
Καταγράψτε την κατάσταση πριν επεξεργαστείτε ένα αρχείο διαμόρφωσης, ώστε να μπορείτε να πείτε αν η αλλαγή έκανε κάτι:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
Εκτελέστε τους ελέγχους με αυτή τη σειρά και σταματήστε στον πρώτο που αποτυγχάνει. Το getent και το resolvectl query πρέπει να συμφωνούν: αν το getent αποτυγχάνει ενώ το dig απαντά, μείνετε στην αλυσίδα αναζήτησης και μην αγγίξετε τη δρομολόγηση. Το resolvectl status πρέπει να δείχνει διακομιστή DNS και τομέα δρομολόγησης στη διεπαφή tun. Το nsswitch δεν πρέπει να επιστρέφει νωρίς με NOTFOUND για το επίθημα που δοκιμάζετε. Το όνομα πρέπει να είναι αυθεντικό στο δίκτυο όπου είναι συνδεδεμένο το τελικό σας σημείο, ελεγμένο με τελεία στο τέλος. Η εφαρμογή δεν πρέπει να κρατά δική της κρυφή μνήμη ή παράκαμψη ασφαλούς DNS.
Διορθώστε μόνο το πρώτο στρώμα που αποτυγχάνει και μετά εκτελέστε ξανά τις ίδιες εντολές. Δύο αλλαγές ταυτόχρονα σας αφήνουν ανίκανους να πείτε ποια είχε σημασία, και η επόμενη βλάβη αρχίζει την έρευνα από το μηδέν.