Por qué los nombres de host internos se resuelven con dig pero fallan con curl en una VPN
dig responde, pero curl informa de que no puede resolver el host. Compare las dos cadenas de resolución y luego corrija nsswitch, el DNS por enlace o un sufijo de búsqueda erróneo.
Su portátil está en la VPN, dig service.internal.example responde con una dirección 10.x y curl sigue terminando con Could not resolve host. El túnel no es el problema: transportó la consulta de dig sin quejarse. Lo que cambia es quién hace la pregunta. dig envía una consulta a un servidor que usted nombra, mientras que curl pasa por la cadena de resolución del sistema operativo, y esa cadena tiene sus propias reglas sobre a qué servidor se pregunta.
Dos resoluciones para el mismo nombre
dig es un stub resolver propio. Lee /etc/resolv.conf, elige un servidor de nombres, envía una sola consulta A o AAAA e imprime la respuesta. Se salta nsswitch por completo y no sabe nada del estado por enlace que systemd-resolved o NetworkManager mantienen fuera de ese archivo, y por eso una respuesta de dig puede ser correcta y aun así no decirle nada sobre lo que verá su aplicación.
Las aplicaciones llaman a getaddrinfo, y getaddrinfo recorre una cadena más larga: el orden de módulos de nsswitch, luego el módulo que atiende el nombre y después el resolver construido a partir de la configuración de enlace actual. En una máquina con systemd la consulta va a 127.0.0.53 y systemd-resolved elige un servidor ascendente por enlace según el dominio de enrutamiento asociado a la interfaz tun.
Dos comandos separan esas capas sin adivinar:
getent ahosts service.internal.example
resolvectl query service.internal.example
getent usa el mismo camino que curl, así que un fallo de getent junto a un dig que funciona localiza el problema en la política de resolución y no en el enrutamiento de paquetes. resolvectl query también imprime la interfaz y el ascendente que dio la respuesta, lo que muestra si el enlace del túnel o el enlace físico ganó la decisión.
Lea el resolver que la aplicación usa de verdad
/etc/resolv.conf se genera en la mayoría de los escritorios, y un cliente VPN tiene tres formas de interactuar con él: anteponer un servidor de nombres, sobrescribir el archivo o entregar sus servidores a NetworkManager y dejar que el demonio lo reescriba. Solo el tercer patrón conserva el DNS por enlace, porque los servidores siguen ligados a una interfaz en vez de aplanarse en una lista global.
En sistemas NetworkManager el resultado depende del backend en /etc/NetworkManager/NetworkManager.conf:
[main]
dns=systemd-resolved
Con dns=default los servidores del cliente se fusionan en resolv.conf en el orden que gane, y una consulta privada todavía puede enviarse al resolver público. Con un backend que entiende de enlaces, systemd-resolved o dnsmasq, los servidores del túnel quedan acotados al túnel y solo van allí los nombres que coinciden con su dominio de enrutamiento. Ese acotamiento es lo que significa split DNS en la práctica, y es la pieza que más a menudo falta cuando un cliente dice admitirlo.
Lea el estado antes de editar nada:
resolvectl status
resolvectl dns tun0
Usted quiere ver la interfaz tun listada con un servidor DNS y un dominio de enrutamiento para el sufijo privado, mostrado como ~internal.example. Que no haya servidor en el enlace significa que el cliente no envió nada. Un servidor sin dominio significa que las consultas van todas allí o ninguna, según el cliente, y ninguna de las dos cosas es split DNS.
Donde nsswitch corta la resolución antes de tiempo
Una línea estándar de escritorio se ve así:
hosts: files mdns4_minimal [NOTFOUND=return] resolve [!UNAVAIL=return] dns myhostname
mdns4_minimal gestiona el DNS multicast y reclama todo nombre que termine en .local. Un servicio de Kubernetes como api.infra.svc.cluster.local también termina en .local. Cuando el módulo mDNS informa NOTFOUND, la acción [NOTFOUND=return] termina toda la resolución en lugar de continuar al módulo dns, así que el nombre nunca se envía al resolver de la VPN. dig se salta el archivo por completo, y por eso exactamente discrepan las dos herramientas.
Ese es el contraste más nítido de este problema, y se reduce a una palabra en un archivo de configuración anterior a su VPN. Cambiar la acción a [NOTFOUND=continue] conserva mDNS para impresoras y dispositivos locales a la vez que deja que DNS vea el nombre. Sustituir la línea por hosts: files dns también funciona y es más burdo: elimina la resolución .local para la impresora que realmente usa.
Nombres que viven en una sola red
Las zonas privadas solo son autoritativas en un lugar. Un nombre de AWS como ip-10-0-4-31.eu-west-1.compute.internal se responde mediante el resolver de la VPC de esa región, y solo mientras su extremo de VPN esté en la misma región que el recurso. Conéctese a un extremo de Fráncfort, consulte un nombre compute.internal de Irlanda y ningún ajuste local ayudará: la zona que guarda el registro no es alcanzable desde allí.
Los dominios de búsqueda producen la imagen inversa. Un service desnudo se completa con el sufijo que el resolver considere aplicable, y con un enlace VPN el dominio local puede imponerse al corporativo. Consulte con un punto final para quitar la conjetura, getent ahosts service.internal.example., y si eso funciona mientras el nombre corto falla, la corrección es el dominio de búsqueda en el túnel, no la dirección del servidor.
Los clientes gestionados añaden una tercera capa por encima del resolver del sistema. Un perfil de VPN de Windows puede llevar su propia política de resolución de nombres, reglas por aplicación y una tabla NRPT que se aplica incluso con el túnel caído. Las aplicaciones con su propia caché de DNS, habituales en los runtimes .NET y Java, mantienen un fallo obsoleto mucho después de arreglar la cadena. Los clientes de Apple configuran el split DNS mediante dominios de coincidencia en los ajustes de DNS en lugar de mediante resolv.conf, y Chromium o Firefox en modo DNS seguro pueden saltarse el resolver del sistema para nombres públicos. La referencia de Microsoft sobre resolución de nombres de VPN describe el lado Windows de esa capa de políticas.
Decidir qué capa arreglar
Trabaje del síntoma a la capa en vez de probar correcciones en orden:
| 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 |
Dos filas cargan con casi todo el peso. Un tiempo de espera es un problema de alcanzabilidad: el resolver privado no responde a través del túnel, así que compruebe la ruta a su dirección y si el servidor DNS del enlace es el que usted cree. NXDOMAIN es un problema de autoridad: algo respondió y no conoce el nombre, lo que apunta a la zona, a la región o a un resolver que nunca debió recibir la consulta.
La última fila es la que la gente pasa por alto porque ambas mitades parecen un éxito. Un nombre corto que se resuelve de forma distinta al FQDN es un desajuste de sufijo, y reconectar el túnel no cambiará qué sufijo envía el cliente.
Capture el estado antes de editar un archivo de configuración, para poder decir si la edición hizo algo:
resolvectl status > before.txt
getent ahosts service.internal.example >> before.txt
Ejecute las comprobaciones en este orden y deténgase en la primera que falle. getent y resolvectl query deben coincidir; si getent falla mientras dig responde, quédese en la cadena de resolución y no toque el enrutamiento. resolvectl status debe mostrar un servidor DNS y un dominio de enrutamiento en la interfaz tun. nsswitch no debe volver antes de tiempo con NOTFOUND para el sufijo que está probando. El nombre debe ser autoritativo en la red a la que está unido su extremo, probado con un punto final. La aplicación no debe guardar su propia caché ni una anulación de DNS seguro.
Arregle solo la primera capa que falla y vuelva a ejecutar los mismos comandos. Dos cambios a la vez le dejan sin poder decir cuál importó, y la siguiente avería empieza la investigación desde cero.