AdGuard Home risponde ai client WireGuard dal tuo indirizzo LAN
Un bind a 0.0.0.0 permette al kernel di scegliere la sorgente della risposta. Su un host multi-homed quella risposta può provenire da un indirizzo che il tunnel non può raggiungere.
Il tunnel è attivo, il firewall permette la porta 53, AdGuard Home è in esecuzione, e i nomi non vengono ancora risolti per il client WireGuard. La query normalmente arriva e una risposta normalmente parte, quindi i contatori dei pacchetti sul resolver sembrano sani e il servizio appare innocente. Quello che va storto è l'indirizzo sorgente di quella risposta: parte da un indirizzo locale che il client non ha mai richiesto, e lo stub resolver del client lo scarta. Una lista nella configurazione di AdGuard Home decide questo, e il suo default abituale lascia la decisione al kernel.
La query arriva, la risposta parte da un'altra origine
Un client configurato con 10.6.0.1 come suo resolver invia una query UDP a 10.6.0.1 porta 53. Quel pacchetto attraversa il tunnel e arriva sull'host, e AdGuard Home lo risponde. Sulla linea, però, la risposta è un nuovo pacchetto la cui indirizzo sorgente è scelto dallo stack dell'host, non dalle aspettative del client.
Quando il resolver del client è un socket connesso, che è ciò che systemd-resolved, dnsmasq e la maggior parte dei resolver stub usano, accetta solo risposte dall'indirizzo esatto a cui ha inviato. Una risposta proveniente da 192.168.1.10 a una query inviata a 10.6.0.1 viene scartata prima che qualsiasi parsing accada. Il resolver registra una risposta avvenuta con successo, il client registra un timeout, e entrambi stanno dicendo la verità.
Quindi i contatori non mentono e nemmeno il cliente. Le prove di cui hai bisogno si trovano in tre posti, in questo ordine: l'indirizzo a cui il listener è vincolato, il percorso che il kernel utilizzerebbe per tornare al cliente, e l'indirizzo sorgente nel pacchetto di risposta effettivo.
Come il kernel sceglie la sorgente della risposta
Un socket UDP vincolato a0.0.0.0non ha un indirizzo sorgente proprio, quindi ogni risposta in uscita innesca una ricerca del percorso per la destinazione. Il kernel poi prende la sorgente da quel percorso: l'indirizzo fissato dal percorso, o l'indirizzo principale dell'interfaccia di uscita. Nulla dell'indirizzo di destinazione della query viene ricordato.
Su un host con una sola interfaccia questo è invisibile, perché c'è solo una risposta plausibile. Su una macchina che possiede un indirizzo LAN, un indirizzo WireGuard e un indirizzo di gestione, diverse risposte sono plausibili e il vincitore dipende dalla tabella di routing in quel momento. Aggiungi una rotta extra, un secondo indirizzo sulla stessa interfaccia, un reindirizzamento NAT davanti al resolver, o esegui AdGuard in un container con il suo namespace, e la sorgente scelta può differire da quella consultata dal client.
ss -lunp | grep :53mostra a quale gioco stai giocando. Un listener su0.0.0.0:53è il caso jolly; un listener su10.6.0.1:53ha già fissato la risposta. Leggere il socket è più veloce che leggere lo YAML e riflette ciò che è effettivamente in esecuzione piuttosto che ciò che è stato salvato l'ultima volta.
Ciò che bind_hosts controlla effettivamente
AdGuard Home'sdns.bind_hostsè l'elenco degli indirizzi locali utilizzati dal listener DNS. Il valore predefinito fornito è il carattere jolly, che significa accettare su ogni indirizzo locale e lasciare al kernel la scelta della sorgente per ogni risposta. Sostituire il carattere jolly con l'indirizzo interrogato dai client cambia il socket e con esso l'indirizzo sorgente su ogni risposta.
L'elenco può contenere più di una voce, il che è rilevante su un resolver che serve due reti. Inserire10.6.0.1e192.168.1.10dà due socket legati, e una query che arriva su uno dei due viene risposta dall'indirizzo su cui è arrivata. Questo è il comportamento che la maggior parte delle persone presume già fornito dal carattere jolly.
Lo YAML è semplice, e l'indirizzo in esso è quello che i client del tunnel sono stati istruiti a usare, non l'indirizzo principale dell'host:
dns:
bind_hosts:
- 10.6.0.1
port: 53Perché due installazioni di uno stesso resolver non sono d'accordo
Gestito tramite plugin, in questo contesto, significa che il resolver è stato installato ed è supervisionato da un altro pacchetto: un pacchetto del firmware del router, un pacchetto NAS o un componente aggiuntivo per l'automazione domestica. Quel pacchetto di solito fornisce la propria copia del YAML di AdGuard Home e riavvia il processo secondo il proprio programma, mentre un'istanza autonoma è il binario o il contenitore del fornitore che configuri personalmente. In ogni caso, si tratta di due processi indipendenti con file di configurazione separati e scelte di binding separate, anche quando entrambi leggono la stessa lista principale e le stesse liste di filtri. Uno può legarsi all'indirizzo specifico del tunnel mentre l'altro eredita il wildcard, e l'interfaccia web appare identica da entrambe le parti.
Ecco perché "lo stesso risolutore funzionava prima della migrazione" non prova nulla riguardo al binding attuale. Controlla il socket, poi il file di configurazione effettivamente caricato dal processo in esecuzione. Una copia obsoleta in un'altra directory è una causa comune per cui la modifica sembra non avere effetto.
Fissalo, quindi testa dal lato del tunnel
Cambiabind_hostscon l'indirizzo del tunnel, riavvia il servizio e conferma che il socket si sia spostato:ss -lunp | grep :53dovrebbe ora mostrare10.6.0.1:53e nessuna voce generica. Se mostra ancora0.0.0.0,il processo in esecuzione non sta leggendo il file che hai modificato.
Poi testa dal client, perché quello è l'unico lato che conta. Una query condig @10.6.0.1 example.comesercita il percorso che l'utente utilizza, e una cattura sull'host contcpdump -ni wg0 udp port 53mostra l'indirizzo sorgente della risposta sulla rete. Confrontalo con l'indirizzo nelle impostazioni del resolver del client; quando sono uguali, il timeout smette di essere un mistero.
ip route get 10.6.0.2spiega qualsiasi stranezza residua, perché stampa l'interfaccia e la sorgente che l'host utilizzerebbe per rispondere al client. Se quell'output indica l'interfaccia LAN, il cambiamento del bind non è la soluzione completa e la tabella di routing è la prossima cosa da leggere.
Cosa il settaggio del bind non può risolvere
Fissare il listener non ripara una lista di accesso che ometta la subnet del tunnel, una regola del firewall che permette la query ma non la risposta, o una rotta mancante di ritorno verso il pool WireGuard. Questi falliscono prima o dopo l'indirizzo sorgente, e ognuno ha un proprietario diverso.
Non cambia neanchea quale upstream il resolver inoltra le richieste, che la protezione dal ricollegamento rifiuti una risposta privata per un nome privato, o come il client applica i propri domini di ricerca. Questi sono controlli separati. Cambia l'indirizzo di bind quando la fonte della risposta è sbagliata, e cambia qualcos'altro quando non lo è.