Hvorfor interne værtsnavne slår op i dig, men fejler i curl på en VPN
dig svarer, men curl rapporterer, at den ikke kan slå værten op. Sammenlign de to opslagningskæder, og ret derefter nsswitch, DNS pr. link eller et forkert søgesuffiks.
Din bærbare er på VPN’en, dig service.internal.example svarer med en 10.x-adresse, og curl afslutter stadig med Could not resolve host. Tunnelen er ikke problemet: den transporterede dig-forespørgslen uden klager. Det, der er forskelligt, er, hvem der stiller spørgsmålet. dig sender én forespørgsel til én server, du angiver, mens curl går gennem operativsystemets opslagningskæde, og den kæde har sine egne regler for, hvilken server der bliver spurgt.
To opslag for det samme navn
dig er sin egen stub-resolver. Den læser /etc/resolv.conf, vælger en navneserver, sender én enkelt A- eller AAAA-forespørgsel og udskriver svaret. Den springer nsswitch helt over og ved intet om den per-link-tilstand, som systemd-resolved eller NetworkManager holder uden for den fil, og derfor kan et dig-svar være korrekt og alligevel ikke sige dig noget om, hvad din applikation vil se.
Applikationer kalder getaddrinfo, og getaddrinfo går gennem en længere kæde: modulrækkefølgen i nsswitch, derefter modulet der håndterer navnet, og så resolveren, der er bygget ud fra den aktuelle linkkonfiguration. På en systemd-maskine går forespørgslen til 127.0.0.53, og systemd-resolved vælger en upstream-server per link ud fra det routingdomæne, der er knyttet til tun-interfacet.
To kommandoer adskiller de lag uden at gætte:
getent ahosts service.internal.example
resolvectl query service.internal.example
getent bruger samme vej som curl, så en getent-fejl ved siden af en fungerende dig lokaliserer fejlen til opslagningspolitikken og ikke til pakkerutingen. resolvectl query udskriver også det interface og den upstream, der gav svaret, hvilket viser, om tunnellinket eller det fysiske link vandt beslutningen.
Læs den resolver, applikationen faktisk bruger
/etc/resolv.conf genereres på de fleste skriveborde, og en VPN-klient har tre måder at forholde sig til den på: sætte en navneserver foran, overskrive filen eller overlade sine servere til NetworkManager og lade daemonen skrive den igen. Kun det tredje mønster bevarer DNS per link, fordi serverne forbliver knyttet til et interface i stedet for at blive gjort flade til én global liste.
På NetworkManager-systemer afhænger resultatet af backenden i /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
Med dns=default bliver klientens servere flettet ind i resolv.conf i den rækkefølge, der vinder, og et privat opslag kan stadig blive sendt til den offentlige resolver. Med en backend, der forstår links, systemd-resolved eller dnsmasq, forbliver tunnelens servere afgrænset til tunnelen, og kun navne, der matcher dens routingdomæne, går derhen. Den afgrænsning er, hvad split DNS betyder i praksis, og det er den del, der oftest mangler, når en klient hævder at understøtte det.
Læs tilstanden, før du ændrer noget:
resolvectl status
resolvectl dns tun0
Du vil se tun-interfacet opført med en DNS-server og et routingdomæne til det private suffix, vist som ~internal.example. Ingen server på linket betyder, at klienten ikke har sendt noget. En server uden domæne betyder, at opslag enten alle sendes derhen eller slet ikke, afhængigt af klienten, og ingen af delene er split DNS.
Hvor nsswitch afslutter opslaget for tidligt
En standardlinje på et skrivebord ser sådan ud:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
mdns4_minimal håndterer multicast-DNS og gør krav på ethvert navn, der ender på .local. En Kubernetes-tjeneste som api.infra.svc.cluster.local ender også på .local. Når mDNS-modulet rapporterer NOTFOUND, afslutter handlingen [NOTFOUND=return] hele opslaget i stedet for at fortsætte til dns-modulet, så navnet bliver aldrig sendt til VPN-resolveren. dig omgår filen fuldstændigt, og det er netop derfor, de to værktøjer er uenige.
Det er den skarpeste kontrast i dette problem, og den kommer ned til ét ord i en konfigurationsfil, der er ældre end din VPN. Ændrer du handlingen til [NOTFOUND=continue], bevares mDNS til printere og lokale enheder, mens DNS kan se navnet. At erstatte linjen med hosts: files dns virker også og er grovere: det dropper .local-opslaget til den printer, du faktisk bruger.
Navne, der kun findes i ét netværk
Private zoner er autoritative på præcis ét sted. Et AWS-navn som ip-10-0-4-31.eu-west-1.compute.internal besvares via den regions VPC-resolver, og kun så længe dit VPN-endpoint er i samme region som ressourcen. Forbind til et endpoint i Frankfurt, slå et compute.internal-navn fra Irland op, og ingen lokal indstilling hjælper: zonen, der holder posten, er ikke tilgængelig derfra.
Søgedomæner giver spejlbilledet. Et bart service udfyldes med det suffix, resolveren mener gælder, og med et VPN-link kan det lokale domæne vinde over virksomhedens. Slå op med et punktum til sidst for at fjerne gætteriet, getent ahosts service.internal.example., og hvis det virker, mens det korte navn fejler, er rettelsen søgedomænet på tunnelen, ikke serveradressen.
Administrerede klienter tilføjer et tredje lag over operativsystemets resolver. En Windows-VPN-profil kan bære sin egen navneopløsningspolitik, regler per app og en NRPT-tabel, der gælder, selv når tunnelen er nede. Applikationer med egen DNS-cache, almindeligt i .NET- og Java-runtimes, holder en forældet fejl længe efter, at kæden er rettet. Apple-klienter konfigurerer split DNS via match-domæner i DNS-indstillingerne i stedet for via resolv.conf, og Chromium eller Firefox i secure-DNS-tilstand kan omgå systemets resolver for offentlige navne. Microsofts reference om VPN-navneopløsning beskriver Windows-siden af det politiktlag.
Beslut, hvilket lag der skal rettes
Arbejd fra symptomet til laget i stedet for at prøve rettelser i rækkefølge:
| 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 |
To rækker bærer det meste. En timeout er et tilgængelighedsproblem: den private resolver svarer ikke gennem tunnelen, så kontrollér ruten til dens adresse og om DNS-serveren på linket er den, du tror. NXDOMAIN er et autoritetsproblem: noget svarede, og det kender ikke navnet, hvilket peger på zonen, regionen eller en resolver, der aldrig skulle have modtaget forespørgslen.
Den sidste række er den, folk overser, fordi begge halvdele ligner succes. Et kort navn, der opløses anderledes end FQDN’en, er en suffix-ufase, og at genoprette tunnelen ændrer ikke, hvilket suffix klienten sender.
Registrér tilstanden, før du redigerer en konfigurationsfil, så du kan se, om ændringen gjorde noget:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
Kør kontrollerne i denne rækkefølge, og stop ved den første, der fejler. getent og resolvectl query skal stemme overens; hvis getent fejler, mens dig svarer, så bliv i opslægningskæden og lad routing være. resolvectl status skal vise en DNS-server og et routingdomæne på tun-interfacet. nsswitch må ikke vende tidligt tilbage ved NOTFOUND for det suffix, du tester. Navnet skal være autoritativt i det netværk, dit endpoint er knyttet til, testet med et punktum til sidst. Applikationen må ikke holde sin egen cache eller en secure-DNS-tilsidesættelse.
Ret kun det første lag, der fejler, og kør derefter de samme kommandoer igen. To ændringer på én gang gør det umuligt at sige, hvilken der betød noget, og den næste nedbrud starter undersøgelsen fra nul.