Nombres de clientes OpenVPN en dnsmasq: ¿script o entradas estáticas?
Las direcciones de los clientes cambian, los nombres de los servicios no. Genere los nombres de los clientes a partir de la sesión VPN, fije los nombres de los servicios en un archivo drop-in y luego haga que los clientes lo usen.
Dos problemas de nombres aparecen en casi cualquier puerta de enlace OpenVPN pequeña. No puede llegar a un portátil conectado por el nombre de su certificado, y los servicios detrás del túnel no tienen ningún nombre. Parecen un solo problema y necesitan tratamientos opuestos, porque una dirección se mueve con cada sesión y la otra no. Decida qué tipo de nombre está añadiendo antes de editar nada.
Decida por nombre, no por puerta de enlace
La prueba es sencilla: ¿cambia esta dirección cuando un cliente se reconecta? Si es así, el nombre debe generarse a partir de la sesión VPN. Si no, pertenece a una entrada estática que puede leer y revisar.
| Name kind | Source of truth | Where it lives |
|---|---|---|
| Connected client | The address OpenVPN just assigned | Generated hosts file, rewritten per session |
| Service behind the tunnel | A fixed address you chose | Static address= drop-in |
| Anything with a certificate name | The certificate, not the pool | Either, but the name must match the certificate |
Mezclarlos es el fallo habitual. Un servicio fijado en el archivo generado desaparece la primera vez que el script lo reescribe, y un cliente escrito en una entrada estática apunta a quien tuvo esa dirección por última vez. Ambos errores permanecen invisibles hasta que un nombre se resuelve a la máquina equivocada. Para entonces, quien depura supone que el DNS está roto y no el archivo.
La ruta dinámica: learn-address y el pool
OpenVPN conoce la asignación, así que deje que se la diga. Estas opciones del servidor hacen que la asignación sea duradera y programable:
client-config-dir /etc/openvpn/ccd
ifconfig-pool-persist /etc/openvpn/ip-pool 60
script-security 2
learn-address /etc/openvpn/learn-address.sh
learn-address ejecuta su script cada vez que se añade, actualiza o elimina una dirección, y pasa la operación, la dirección y el nombre común. Un script mínimo añade una línea por cliente y la elimina al borrar:
#!/bin/sh
HOSTS=/etc/openvpn/hosts.lan
case "$1" in
add|update) echo "$2 $3" >> "$HOSTS" ;;
delete) sed -i "/^$2 /d" "$HOSTS" ;;
esac
kill -HUP $(cat /var/run/dnsmasq.pid)
En un dispositivo tun el segundo argumento es la dirección de túnel del cliente, así que la línea es directamente utilizable. En un dispositivo tap OpenVPN pasa en cambio la dirección MAC del cliente, porque un segmento tap puede transportar protocolos distintos de IPv4, y entonces debe buscar la dirección en el archivo del pool por el nombre común antes de escribir nada.
Tenga claro qué es el archivo generado: una instantánea de quién está conectado ahora mismo. Los nombres desaparecen al desconectar, que es justo lo que quiere para portátiles que se mueven entre redes y justo lo que no quiere para un servidor encendido toda la noche.
La ruta estática: address= y expansión de dominio
Apunte dnsmasq al archivo generado en lugar del archivo hosts del sistema, y dele un dominio para que los nombres cortos se expandan a nombres plenamente cualificados:
domain=corp.example
no-hosts
addn-hosts=/etc/openvpn/hosts.lan
listen-address=127.0.0.1,10.8.0.1
bind-interfaces
Con domain definido, una línea como 10.8.0.6 alice responde tanto para alice como para alice.corp.example. Mantenga listen-address en la puerta de enlace del túnel y loopback, porque un resolutor publicado por accidente en la interfaz LAN es un servicio que no pretendía ofrecer.
Los servicios que nunca vienen del pool tienen sus propias entradas. Póngalos en un archivo drop-in separado dentro del directorio de configuración de la distribución para que una actualización de paquete no pueda sobrescribirlos:
address=/files.corp.example/10.8.0.20
address=/db.corp.example/10.9.0.5
Entregue el resolutor o no pasará nada
Un resolutor que nadie consulta no cambia nada. El servidor tiene que anunciarlo:
push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"
Los clientes de Windows aplican ambas opciones por sí mismos. La mayoría de los clientes de Linux no: necesitan una integración de resolutor compatible, como el gancho update-resolv-conf de la distribución o la gestión de DNS de NetworkManager, o bien un dominio de búsqueda y un servidor de nombres manuales. Compruebe el resolutor real del cliente en lugar de suponer que se respetó el push, porque un push ignorado se ve exactamente como un servidor que no responde.
Verifique en tres capas
Pregunte primero al servidor directamente, luego a un cliente y luego a la aplicación:
dig +short @10.8.0.1 alice.corp.example
getent hosts files.corp.example
Si las consultas directas responden y la aplicación no, la culpa es de la entrega al cliente y no de la zona. Si el nombre se resuelve y la conexión sigue fallando, el nombre está bien y lo siguiente que hay que mirar es la ruta o el cortafuegos.
Anote las dos categorías junto a la configuración: qué nombres se generan, cuáles están fijados y con qué certificado debe coincidir cada uno. La próxima persona que añada un servidor copiará el primer patrón que encuentre.