Indirizzare la query DNS di un client WireGuard verso un altro resolver sembra una sola regola e si comporta come tre decisioni. La destinazione va riscritta, il pacchetto va inoltrato, e la risposta deve trovare la via di ritorno attraverso lo stato di traduzione creato dal gateway. Salta la terza e la query esce pulita mentre il client aspetta per sempre.

Prendiamo l’esempio di client autorizzati in 10.77.0.0/24 che arrivano su wg0, interrogano l’indirizzo annunciato 10.77.0.1 e hanno bisogno di un resolver a 203.0.113.53. L’indirizzo a monte è un segnaposto di documentazione, non un servizio funzionante.

Reindirizzare una query cambia solo la sua destinazione

Una regola di NAT di destinazione in PREROUTING riscrive l’indirizzo prima che venga presa la decisione di instradamento, così il pacchetto viene poi instradato verso la nuova destinazione invece della vecchia. L’indirizzo di origine del client non viene toccato da quell’operazione. Per questo una regola che sembra completa può ancora produrre silenzio: la richiesta viaggia ora verso un resolver che non ha mai sentito parlare dell’intervallo privato del client. Il gateway ha tradotto un campo e ha ereditato un secondo problema.

Entrambi i trasporti DNS necessitano di regole corrispondenti, perché un client ripiega su TCP quando una risposta viene troncata.

Le regole seguenti selezionano un’interfaccia in ingresso, un intervallo di client e un indirizzo di destinazione originale. Nient’altro sul gateway è interessato, e una query del gateway stesso non corrisponde affatto.

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p udp --dport 53 -j DNAT --to-destination 203.0.113.53:53
iptables -t nat -A PREROUTING -i wg0 -s 10.77.0.0/24 -d 10.77.0.1 -p tcp --dport 53 -j DNAT --to-destination 203.0.113.53:53

Il percorso di risposta è una decisione separata

Due disposizioni permettono alla risposta di tornare, e sceglierne una presto risparmia una sessione di debug. O il resolver a monte ha una rotta di ritorno verso 10.77.0.0/24 attraverso questo gateway, oppure il gateway traduce l’origine in uscita così che la risposta arrivi a un indirizzo che il monte conosce già. Entrambe funzionano; solo una corrisponde al controllo che hai sul monte.

L’instradamento merita il primo tentativo, perché mantiene l’indirizzo del client visibile al resolver ed evita un secondo strato di traduzione. Quando il monte è fuori dal tuo controllo, la traduzione dell’origine sull’interfaccia di uscita specifica è la scelta pratica.

Circoscrivi quella traduzione con la stessa strettezza del reindirizzamento, altrimenti la regola diventa un NAT generico per tutto ciò che vi corrisponde:

iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p udp --dport 53 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -d 203.0.113.53 -o eth0 -p tcp --dport 53 -j MASQUERADE

Il tracciamento delle connessioni mantiene la mappatura appaiata, così la risposta viene riscritta verso la tupla originale del client al ritorno. Senza la regola di uscita, il resolver invia la sua risposta verso un indirizzo privato che non può raggiungere, e il client vede un timeout anziché un errore.

Scrivi le regole più strette di quanto sembri il compito

Il permesso di inoltro appartiene allo stesso ambito. Consenti il flusso dal client al resolver e il traffico di ritorno che conntrack già riconosce, invece di accettare ogni connessione DNAT sulla macchina. Un’accettazione generalizzata autorizza anche inoltri di porte che non hanno nulla a che fare con DNS.

Il resolver del gateway stesso è un percorso di codice diverso. Una query emessa localmente passa per OUTPUT, quindi provare dalla shell del gateway non esercita né la regola PREROUTING né la politica di inoltro. Per questo un test locale può passare mentre ogni client fallisce, e il contrario è altrettanto frequente.

Niente qui copre DNS su HTTPS sulla porta 443 o DNS su TLS sulla porta 853, e niente copre IPv6. Un client con un resolver IPv6 configurato ignorerà allegramente tutta la disposizione.

Cosa dimostra una query nuova

Il tracciamento delle connessioni ricorda le mappature precedenti, quindi una query inviata prima di un cambio di regola può ricevere risposta dallo stato vecchio e far sembrare rotta la nuova regola. Inizia con una nuova porta di origine e, dove il client memorizza le risposte, con un nuovo nome.

dig @10.77.0.1 example.com A +short
conntrack -L -p udp --dport 53 | head

Il primo comando mostra se il percorso del client si risolve affatto, e il secondo mostra la traduzione che il gateway ha realmente installato, comprese entrambe le direzioni della tupla. Una mappatura che punta al resolver giusto con un contatore di risposte bloccato a zero è un problema di percorso di ritorno, non di filtraggio.

Conferma che il resolver conosca i nomi che ti aspetti prima di reindirizzare qualcosa. Un sostituto che risponde ai nomi pubblici ma non alla tua zona privata trasforma una ricerca funzionante in un NXDOMAIN che sembra un tunnel rotto. Prova il resolver direttamente, dal gateway, prima che il percorso del client sia coinvolto. E il riferimento delle estensioni iptables documenta la semantica di DNAT e masquerade da cui dipendono queste regole.

Articoli correlati