AdGuard Home répond aux clients WireGuard depuis votre adresse LAN
Un attachement sur 0.0.0.0 laisse le noyau choisir la source de la réponse. Sur un hôte multi-réseaux, cette réponse peut partir d'une adresse que le tunnel n'atteint pas.
Le tunnel est monté, le pare-feu autorise le port 53, AdGuard Home tourne, et pourtant les noms ne se résolvent toujours pas pour le client WireGuard. La requête arrive normalement et une réponse repart normalement, si bien que les compteurs de paquets du résolveur paraissent sains et que le service semble innocent. Ce qui cloche, c'est l'adresse source de cette réponse : elle part d'une adresse locale que le client n'a jamais demandée, et le résolveur stub du client la rejette. Une seule liste dans la configuration d'AdGuard Home décide de cela, et sa valeur par défaut habituelle confie la décision au noyau.
La requête arrive, la réponse part d'ailleurs
Un client configuré avec 10.6.0.1 comme résolveur envoie une requête UDP vers 10.6.0.1 port 53. Ce paquet traverse le tunnel et atteint l'hôte, et AdGuard Home y répond. Sur le réseau, en revanche, la réponse est un nouveau paquet dont l'adresse source est choisie par la pile de l'hôte, et non selon ce que le client attend.
Quand le résolveur du client est une socket connectée, ce qui est le cas de systemd-resolved, de dnsmasq et de la plupart des résolveurs stub, il n'accepte que les réponses venant exactement de l'adresse à laquelle il a envoyé la requête. Une réponse dont la source est 192.168.1.10 pour une requête envoyée à 10.6.0.1 est jetée avant même toute analyse. Le résolveur journalise une réponse réussie, le client journalise un délai d'attente dépassé, et les deux disent la vérité.
Les compteurs ne mentent donc pas, et le client non plus. Les preuves utiles se trouvent à trois endroits, dans cet ordre : l'adresse sur laquelle l'écoute est attachée, la route que le noyau utiliserait pour revenir vers le client, et l'adresse source du paquet de réponse réel.
Comment le noyau choisit la source de la réponse
Une socket UDP attachée à 0.0.0.0 n'a pas d'adresse source propre, si bien que chaque réponse sortante déclenche une recherche de route vers la destination. Le noyau prend alors la source de cette route : l'adresse épinglée par la route, ou l'adresse principale de l'interface de sortie. Rien de l'adresse de destination de la requête n'est mémorisé.
Sur un hôte rattaché à un seul réseau, cela reste invisible, car une seule réponse est plausible. Sur une machine qui porte une adresse LAN, une adresse WireGuard et une adresse d'administration, plusieurs réponses sont plausibles, et la gagnante dépend de la table de routage à cet instant. Ajoutez une route supplémentaire, une seconde adresse sur la même interface, une redirection NAT devant le résolveur, ou faites tourner AdGuard dans un conteneur avec son propre namespace : la source choisie peut différer de celle que le client a interrogée.
ss -lunp | grep :53 indique à quel jeu vous jouez. Une écoute sur 0.0.0.0:53 relève du cas générique ; une écoute sur 10.6.0.1:53 a déjà épinglé la réponse. Lire la socket est plus rapide que lire le YAML, et cela reflète ce qui tourne réellement plutôt que ce qui a été enregistré en dernier.
Ce que bind_hosts contrôle vraiment
Le dns.bind_hosts d'AdGuard Home est la liste des adresses locales qu'utilise l'écoute DNS. La valeur par défaut livrée est le joker, c'est-à-dire accepter sur toutes les adresses locales et laisser le noyau choisir la source à chaque réponse. Remplacer le joker par l'adresse que les clients interrogent change la socket, et avec elle l'adresse source de chaque réponse.
La liste accepte plus d'une entrée, ce qui compte sur un résolveur servant deux réseaux. Indiquer 10.6.0.1 et 192.168.1.10 donne deux sockets attachées, et une requête arrivant sur l'une ou l'autre reçoit sa réponse depuis l'adresse par laquelle elle est arrivée. C'est le comportement que la plupart des gens prêtent déjà au joker.
Le YAML est simple, et l'adresse qu'il contient est celle que l'on a indiquée à vos clients du tunnel, pas l'adresse principale de l'hôte :
dns:
bind_hosts:
- 10.6.0.1
port: 53
Pourquoi deux installations du même résolveur ne sont pas d'accord
Géré par un plugin signifie ici que le résolveur a été installé et qu'il est supervisé par un autre paquet : un paquet de firmware de routeur, un paquet de NAS ou un module complémentaire de domotique. Ce paquet embarque généralement sa propre copie du YAML d'AdGuard Home et redémarre le processus selon son propre calendrier, tandis qu'une instance autonome est le binaire ou le conteneur de l'éditeur que vous configurez vous-même. Dans les deux cas, vous avez affaire à deux processus indépendants, avec des fichiers de configuration séparés et des choix d'attachement séparés, même si les deux lisent la même liste d'amont et les mêmes listes de filtres. L'un peut attacher l'adresse précise du tunnel pendant que l'autre hérite du joker, et l'interface web est identique des deux côtés.
C'est pourquoi « le même résolveur fonctionnait avant la migration » ne prouve rien sur l'attachement actuel. Vérifiez la socket, puis vérifiez le fichier de configuration que le processus en cours a réellement chargé. Une copie obsolète dans un autre répertoire explique souvent pourquoi la modification semble sans effet.
Épinglez l'attachement, puis testez depuis le tunnel
Passez bind_hosts à l'adresse du tunnel, redémarrez le service et confirmez que la socket a bougé : ss -lunp | grep :53 doit maintenant afficher 10.6.0.1:53 et aucune entrée générique. Si la sortie montre encore 0.0.0.0, le processus en cours ne lit pas le fichier que vous avez modifié.
Testez ensuite depuis le client, car c'est le seul côté qui compte. Une requête avec dig @10.6.0.1 example.com emprunte le chemin que l'utilisateur emprunte, et une capture sur l'hôte avec tcpdump -ni wg0 udp port 53 montre l'adresse source de la réponse sur le réseau. Comparez-la avec l'adresse réglée dans le résolveur du client ; quand elles sont égales, le délai d'attente cesse d'être un mystère.
ip route get 10.6.0.2 explique toute anomalie restante, car la commande affiche l'interface et la source que l'hôte utiliserait pour revenir vers le client. Si cette sortie nomme l'interface LAN, changer l'attachement n'est pas toute la correction et la table de routage est la prochaine chose à lire.
Ce que le réglage d'attachement ne peut pas corriger
Épingler l'écoute ne répare pas une liste d'accès qui omet le sous-réseau du tunnel, une règle de pare-feu qui autorise la requête mais pas la réponse, ou une route manquante vers le pool WireGuard. Ces problèmes échouent avant ou après le stade de l'adresse source, et chacun a un responsable différent.
Cela ne change pas non plus l'amont vers lequel le résolveur transfère, ni si la protection contre le rebinding rejette une réponse privée pour un nom privé, ni la façon dont le client applique ses propres domaines de recherche. Ce sont des contrôles distincts. Changez l'adresse d'attachement quand la source de la réponse est fausse, et changez autre chose quand elle ne l'est pas.