Por qué resolv.conf muestra el DNS de tu VPN pero las consultas lo ignoran
En un host con resolved el archivo es una vista, no el estado. Sigue el stub, los servidores de cada enlace y la línea nsswitch para ver cuál usa realmente una consulta.
En los registros nada parece estar mal: la interfaz está activa, el resolutor informa del servidor DNS de la VPN y el archivo del disco lo enumera. Aun así, un nombre de host interno sigue resolviéndose a través del router local. Las tres afirmaciones no se contradicen, porque el archivo, el estado de cada enlace y la ruta de la consulta son objetos distintos que casualmente comparten nombre. Lo que sigue es la ruta que una consulta recorre realmente en un host con systemd-resolved.
Tres objetos llamados resolv.conf
En un host con resolved, /etc/resolv.conf suele ser un enlace simbólico a /run/systemd/resolve/stub-resolv.conf. Ese destino contiene la dirección de un escucha stub local, 127.0.0.53, además de los dominios de búsqueda que resolved calculó. Es una vista del estado, no el estado mismo.
El estado vive en la configuración por enlace de resolved, y por eso resolvectl status puede discrepar del archivo y aun así tener razón. Cada enlace lleva sus propios servidores y sus propios dominios de enrutamiento, y el stub consulta esos datos cuando llega una consulta. El manual de systemd-resolved describe los archivos generados y el modelo por enlace; la separación entre vista y estado es la parte que merece recordarse. Editar el destino del enlace simbólico cambia lo que leen los clientes tradicionales, no lo que sabe el resolutor.
Un tercer objeto, /run/systemd/resolve/resolv.conf, aplana cada enlace en una sola lista de servidores. Un programa apuntado a ese archivo envía las consultas directamente a los servidores listados y omite el stub, así que la política por enlace ya no se le aplica. Por eso dos programas en la misma máquina pueden responder el mismo nombre de forma distinta, y ninguno está roto.
Sigue una consulta a través de NSS
glibc lee /etc/nsswitch.conf para decidir quién responde a un nombre. Una línea hosts que contenga resolve encamina la pregunta a nss-resolve, que pregunta a resolved por D-Bus y recibe la respuesta por enlace. Una línea con solo files dns envía la consulta a la dirección que tenga /etc/resolv.conf.
Esa sola línea explica la mayoría de desacuerdos entre un navegador y dig. dig lee resolv.conf directamente y nunca toca NSS, así que prueba el stub o un servidor superior en lugar de la ruta que usa la aplicación. getent hosts internal.example pasa por NSS, y comparar su respuesta con la de dig es la primera medición útil.
Las aplicaciones que incorporan su propio resolutor, o que hablan DNS sobre HTTPS con un extremo fijo, evitan ambas rutas. Nada en resolv.conf ni en el estado de resolved las limita.
Comprueba quién es dueño del archivo y hacia dónde apunta
Lee la cadena de enlaces antes de cambiar nada, porque la propiedad decide qué archivo es autoritativo. Cada comando de abajo solo lee estado.
stat -c '%N' /etc/resolv.conf
resolvectl status --no-pager
grep '^hosts' /etc/nsswitch.conf
ls -l /run/systemd/resolve/
La primera línea imprime el enlace y su destino juntos, y un archivo normal propiedad de un script de VPN significa que el resolutor nunca trata esa escritura como entrada. La salida de estado enumera los servidores por enlace más los dominios de enrutamiento que deciden adónde va cada consulta. La línea nsswitch dice si el stub se consulta siquiera, así que una dirección stub en el archivo sin resolve allí significa que las consultas llegan al escucha local mientras nada gestiona la división. Esa última lista también importa, porque un host sin stub-resolv.conf no ejecuta el arreglo aquí descrito.
Si la cadena termina en un archivo que gestiona otro paquete, el cliente VPN y ese paquete son los dos propietarios que hay que conciliar. Sustituir el enlace descarta el trabajo de un propietario y deja el del otro en su sitio.
Repara en el propietario del enlace
Una conexión VPN debería registrar sus servidores y sus dominios en su propio enlace y luego retirarlos al desconectar. La integración de resolved de NetworkManager y el ayudante propio de un cliente funcionan así; un script que solo reescribe resolv.conf no lo hace.
En un enlace que ya existe, la configuración en tiempo de ejecución muestra el mecanismo. resolvectl dns tun0 10.40.0.53 adjunta un servidor, y resolvectl domain tun0 '~corp.example' adjunta un dominio de enrutamiento. La tilde es el carácter que sostiene todo: confina las consultas de ese sufijo a este enlace y deja lo demás en paz, mientras que el mismo valor sin ella se convierte en un dominio de búsqueda y la división se evapora. Esas direcciones son ejemplos de laboratorio, no una configuración persistente. Confírmalo con resolvectl query host.corp.example y lee qué enlace respondió.
Un servidor registrado sigue necesitando una ruta. Cuando la consulta llega al enlace correcto y expira, el fallo está en la accesibilidad a través del túnel y no en la propiedad del resolutor.
Cómo se ve un estado que funciona
Un resultado sano es coherente en las tres vistas: los servidores por enlace coinciden con lo que repartió la VPN, los dominios de enrutamiento cubren solo sufijos internos, y la aplicación que importa resuelve un nombre interno mientras un nombre público sigue la ruta local. Una consulta exitosa demuestra menos que esa concordancia.
Luego desconecta y repite ambas consultas. Un cliente que deja sus dominios registrados tras el desmontaje produce una máquina que falla las consultas internas horas después, sin túnel abierto y sin causa evidente.