Por que os nomes de host internos se resolven con dig pero fallan con curl nunha VPN
dig responde, pero curl informa de que non pode resolver o host. Compare as dúas cadeas de resolución e despois corrixa nsswitch, o DNS por ligazón ou un sufixo de busca erróneo.
O teu portátil está na VPN, dig service.internal.example responde cun enderezo 10.x e curl aínda sae con Could not resolve host. O túnel non é o problema: transportou a consulta de dig sen queixarse. O que cambia é quen fai a pregunta. dig envía unha consulta a un servidor que ti nomeas, mentres que curl pasa pola cadea de resolución do sistema operativo, e esa cadea ten as súas propias regras sobre a que servidor se pregunta.
Dúas resolucións para o mesmo nome
dig é un stub resolver propio. Le /etc/resolv.conf, escolle un servidor de nomes, envía unha única consulta A ou AAAA e imprime a resposta. Salta nsswitch por completo e non sabe nada do estado por ligazón que systemd-resolved ou NetworkManager manteñen fóra dese ficheiro, e por iso unha resposta de dig pode ser correcta e non dicirche nada sobre o que verá a túa aplicación.
As aplicacións chaman getaddrinfo, e getaddrinfo percorre unha cadea máis longa: a orde de módulos de nsswitch, despois o módulo que trata o nome e logo o resolver construído a partir da configuración de ligazón actual. Nunha máquina con systemd a consulta vai a 127.0.0.53 e systemd-resolved escolle un servidor upstream por ligazón segundo o dominio de encamiñamento asociado á interface tun.
Dous comandos separan esas capas sen adiviñar:
getent ahosts service.internal.example
resolvectl query service.internal.example
getent usa o mesmo camiño que curl, así que un fallo de getent xunto a un dig que funciona localiza a avaría na política de resolución e non no encamiñamento de paquetes. resolvectl query tamén imprime a interface e o upstream que deu a resposta, o que mostra se a ligazón do túnel ou a ligazón física gañou a decisión.
Le o resolver que a aplicación usa de verdade
/etc/resolv.conf xérase na maioría dos escritorios, e un cliente VPN ten tres xeitos de interactuar con el: antepor un servidor de nomes, sobrescribir o ficheiro ou entregar os seus servidores a NetworkManager e deixar que o daemon o reescriba. Só o terceiro patrón conserva o DNS por ligazón, porque os servidores quedan ligados a unha interface en vez de aplanarse nunha lista global.
En sistemas NetworkManager o resultado depende do backend en /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
Con dns=default os servidores do cliente fusiónanse en resolv.conf na orde que gañe, e unha consulta privada aínda pode ir ao resolver público. Cun backend que entende as ligazóns, systemd-resolved ou dnsmasq, os servidores do túnel quedan limitados ao túnel e só van alí os nomes que coinciden co seu dominio de encamiñamento. Esa limitación é o que significa split DNS na práctica, e é a peza que máis a miúdo falta cando un cliente di que o admite.
Le o estado antes de editar nada:
resolvectl status
resolvectl dns tun0
Queres ver a interface tun listada cun servidor DNS e un dominio de encamiñamento para o sufixo privado, mostrado como ~internal.example. Ningún servidor na ligazón significa que o cliente non enviou nada. Un servidor sen dominio significa que as consultas van todas alí ou ningunha, segundo o cliente, e ningunha das dúas cousas é split DNS.
Onde nsswitch detén a resolución demasiado cedo
Unha liña estándar de escritorio vese así:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
mdns4_minimal xestiona o DNS multicast e reclama calquera nome que remate en .local. Un servizo de Kubernetes como api.infra.svc.cluster.local tamén remata en .local. Cando o módulo mDNS informa NOTFOUND, a acción [NOTFOUND=return] remata toda a resolución en vez de continuar cara ao módulo dns, así que o nome nunca se envía ao resolver da VPN. dig evita o ficheiro por completo, e é exactamente por iso que as dúas ferramentas non coinciden.
Este é o contraste máis nítido deste problema, e redúcese a unha palabra nun ficheiro de configuración máis antigo que a túa VPN. Cambiar a acción a [NOTFOUND=continue] conserva mDNS para impresoras e dispositivos locais mentres deixa que DNS vexa o nome. Substituír a liña por hosts: files dns tamén funciona e é máis groso: elimina a resolución .local para a impresora que realmente usas.
Nomes que viven nunha soa rede
As zonas privadas só son autoritativas nun lugar. Un nome de AWS como ip-10-0-4-31.eu-west-1.compute.internal respóndese a través do resolver da VPC daquela rexión, e só mentres o teu punto final de VPN estea na mesma rexión que o recurso. Conecta cun punto final de Frankfurt, consulta un nome compute.internal de Irlanda, e ningunha configuración local axudará: a zona que garda o rexistro non é alcanzable desde alí.
Os dominios de busca producen a imaxe inversa. Un service espido complétase co sufixo que o resolver considera aplicable, e cunha ligazón VPN o dominio local pode gañar o corporativo. Consulta cun punto final para quitar a adiviñanza, getent ahosts service.internal.example., e se iso funciona mentres o nome curto falla, a corrección é o dominio de busca no túnel, non o enderezo do servidor.
Os clientes xestionados engaden unha terceira capa por riba do resolver do sistema. Un perfil de VPN de Windows pode levar a súa propia política de resolución de nomes, regras por aplicación e unha táboa NRPT que se aplica mesmo co túnel parado. As aplicacións con caché DNS propia, habituais nos runtimes .NET e Java, manteñen un fallo obsoleto moito despois de arranxar a cadea. Os clientes de Apple configuran split DNS mediante dominios de coincidencia nos axustes de DNS en vez de resolv.conf, e Chromium ou Firefox en modo DNS seguro poden saltar o resolver do sistema para nomes públicos. A referencia de Microsoft sobre resolución de nomes de VPN describe o lado Windows desa capa de política.
Decide que capa arranxar
Traballa do síntoma á capa en vez de probar correccións en orde:
| 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 |
Dúas filas levan case todo o peso. Un tempo de espera é un problema de alcanzabilidade: o resolver privado non responde a través do túnel, así que comproba a ruta ata o seu enderezo e se o servidor DNS da ligazón é o que pensas. NXDOMAIN é un problema de autoridade: algo respondeu e non coñece o nome, o que apunta á zona, á rexión ou a un resolver que nunca debería recibir a consulta.
A última fila é a que a xente pasa por alto porque as dúas metades parecen un éxito. Un nome curto que se resolve distinto do FQDN é un desaxuste de sufixo, e reconectar o túnel non cambiará que sufixo envía o cliente.
Captura o estado antes de editar un ficheiro de configuración, para que poidas dicir se a edición fixo algo:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
Executa as comprobacións nesta orde e detente na primeira que falle. getent e resolvectl query deben coincidir; se getent falla mentres dig responde, queda na cadea de resolución e non toques o encamiñamento. resolvectl status debe mostrar un servidor DNS e un dominio de encamiñamento na interface tun. nsswitch non debe volver cedo con NOTFOUND para o sufixo que estás probando. O nome debe ser autoritativo na rede á que está conectado o teu punto final, probado cun punto final. A aplicación non debe gardar a súa propia caché nin unha anulación de DNS seguro.
Arranxa só a primeira capa que falla e despois volve executar os mesmos comandos. Dous cambios á vez déixanche sen poder dicir cal contou, e a seguinte avaría comeza a investigación desde cero.