Nomi dei client OpenVPN in dnsmasq: script o voci statiche?
Gli indirizzi dei client cambiano, i nomi dei servizi no. Genera i nomi dei client dalla sessione VPN, fissa i nomi dei servizi in un file drop-in, poi fai usare ai client quel file.
Due problemi di nomi compaiono su quasi ogni piccolo gateway OpenVPN. Non riesci a raggiungere un portatile connesso con il nome del suo certificato, e i servizi dietro il tunnel non hanno alcun nome. Sembrano un solo problema e richiedono trattamenti opposti, perché un indirizzo si sposta a ogni sessione e l’altro no. Decidi che tipo di nome stai aggiungendo prima di modificare qualcosa.
Decidi per nome, non per gateway
Il test è semplice: questo indirizzo cambia quando un client si riconnette? Se sì, il nome deve essere generato dalla sessione VPN. Se no, appartiene a una voce statica che puoi leggere e riesaminare.
| 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 |
Mescolarli è il fallimento abituale. Un servizio fissato nel file generato scompare la prima volta che lo script lo riscrive, e un client scritto in una voce statica punta a chi deteneva quell’indirizzo per ultimo. Entrambi gli errori restano invisibili finché un nome non si risolve sulla macchina sbagliata. A quel punto chi fa debug presume che sia rotto il DNS e non il file.
Il percorso dinamico: learn-address e il pool
OpenVPN conosce l’assegnazione, quindi lascia che te la dica. Queste opzioni del server rendono l’assegnazione duratura e scriptabile:
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 esegue il tuo script ogni volta che un indirizzo viene aggiunto, aggiornato o eliminato, e passa l’operazione, l’indirizzo e il nome comune. Uno script minimo aggiunge una riga per client e la rimuove all’eliminazione:
#!/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)
Su un dispositivo tun il secondo argomento è l’indirizzo di tunnel del client, quindi la riga è direttamente utilizzabile. Su un dispositivo tap OpenVPN passa invece l’indirizzo MAC del client, perché un segmento tap può trasportare protocolli diversi da IPv4, e allora devi cercare l’indirizzo nel file del pool per nome comune prima di scrivere qualsiasi cosa.
Sii chiaro su che cos’è il file generato: un’istantanea di chi è connesso adesso. I nomi svaniscono alla disconnessione, che è esattamente ciò che vuoi per portatili che passano da una rete all’altra e esattamente ciò che non vuoi per un server acceso tutta la notte.
Il percorso statico: address= ed espansione del dominio
Punta dnsmasq al file generato invece che al file hosts di sistema, e dagli un dominio perché i nomi brevi si espandano in nomi pienamente qualificati:
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 impostato, una riga come 10.8.0.6 alice risponde sia per alice sia per alice.corp.example. Mantieni listen-address sul gateway del tunnel e su loopback, perché un resolver pubblicato per errore sull’interfaccia LAN è un servizio che non intendevi offrire.
I servizi che non arrivano mai dal pool hanno le proprie voci. Mettili in un file drop-in separato nella directory di configurazione della distribuzione così un aggiornamento dei pacchetti non può sovrascriverli:
address=/files.corp.example/10.8.0.20
address=/db.corp.example/10.9.0.5
Consegna il resolver o non succede nulla
Un resolver che nessuno interroga non cambia nulla. Il server deve annunciarlo:
push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"
I client Windows applicano entrambe le opzioni da soli. La maggior parte dei client Linux no: hanno bisogno di un’integrazione del resolver supportata, come l’hook update-resolv-conf della distribuzione o la gestione DNS di NetworkManager, oppure di un dominio di ricerca e di un server dei nomi manuali. Controlla il resolver reale del client invece di dare per scontato che il push sia stato rispettato, perché un push ignorato sembra esattamente un server che non risponde.
Verifica su tre livelli
Chiedi prima direttamente al server, poi a un client, poi all’applicazione:
dig +short @10.8.0.1 alice.corp.example
getent hosts files.corp.example
Se le query dirette rispondono e l’applicazione no, la colpa è della consegna al client e non della zona. Se il nome si risolve e la connessione fallisce ancora, il nome va bene e la cosa successiva da guardare è la rotta o il firewall.
Annota le due categorie accanto alla configurazione: quali nomi sono generati, quali sono fissati e a quale certificato deve corrispondere ciascuno. La prossima persona che aggiunge un server copierà il primo schema che trova.