Réparer le DNS des invités libvirt bloqué par un pare-feu VPN à base de marques
Un pare-feu VPN à base de marques supprime le DNS des invités avant qu'aucune chaîne de filtrage ne le voie. Une règle à priorité mangle marque la requête et sa réponse, sans ouvrir votre LAN.
Les invités du réseau libvirt par défaut résolvent les noms parfaitement jusqu'à ce que l'interface WireGuard monte, puis chaque requête se bloque au même endroit. dnsmasq écoute toujours sur 192.168.122.1:53, l'invité a toujours cette adresse comme résolveur, et la requête arrive toujours. Ce qui a changé, c'est que la requête amont de l'hôte lui-même, ou la réponse à celle-ci, est désormais supprimée par une règle évaluée avant toute chaîne de filtrage que vous penseriez à modifier. La sortie est une marque appliquée assez tôt, sur une connexion dont la réponse hérite.
Les invités perdent le DNS dès que le tunnel monte
Confirmez la forme avant de changer quoi que ce soit. Coupez le tunnel, exécutez dig @192.168.122.1 example.com depuis un invité et regardez-le répondre. Montez le tunnel, répétez et regardez-le expirer. Cette paire de résultats écarte un réseau libvirt cassé, une adresse de résolveur erronée et un dnsmasq mort en une seule étape.
Regardez ensuite le côté hôte. Si dnsmasq journalise la requête et son transfert amont, le paquet est arrivé et la panne est en sortie. Si dnsmasq ne journalise rien, la requête de l'invité est supprimée en entrée et l'exception relève d'un autre hook que celui que cet article marque.
Pourquoi une règle accept dans une chaîne ultérieure ne se déclenche jamais
Un pare-feu VPN à base de marques décide en regardant la marque du paquet ou la marque de la connexion, pas votre adresse source. Tout ce qui arrive sur l'interface physique sans la marque attendue est refusé, et ce refus se produit dans le jeu de règles qui possède le test de marque. Une ligne ip saddr 192.168.122.0/24 accept ajoutée à une chaîne ultérieure n'est tout simplement jamais consultée pour ce paquet, ce qui explique pourquoi la règle évidente semble correcte et ne change rien.
L'élargir jusqu'à ce que quelque chose fonctionne est le second piège. Accepter tout le sous-réseau libvirt dans le chemin d'entrée de l'hôte ouvre tous les services de l'hôte aux invités, alors que le besoin réel est un seul port.
Le mécanisme qui rend possible une exception étroite est le suivi de connexion. Lorsque vous définissez ct mark sur un paquet, la valeur est stockée dans l'entrée conntrack plutôt que sur le paquet seul, de sorte que chaque paquet de cette connexion la porte ensuite, y compris la réponse de l'hôte vers l'invité. C'est toute l'astuce : marquez la requête une fois, et le chemin de retour est déjà marqué.
Marquez la requête avant que la table VPN ne la voie
Placez l'exception dans sa propre table afin qu'un lecteur ultérieur la trouve sans analyser les règles VPN :
table inet allowedLocal {
chain guest_dns {
type filter hook input priority mangle; policy accept;
ip saddr 192.168.122.0/24 meta l4proto { tcp, udp } \
th dport 53 ct mark set 0x00000f41
}
}
priority mangle est négatif, ce qui place cette chaîne devant les chaînes de filtrage ordinaires que le paquet VPN installe à priorité zéro. C'est l'ordre des hooks qui rend la règle effective ; la même règle dans une chaîne qui se trie après la chaîne VPN n'est que décoration.
Le numéro de marque lui-même n'est pas portable. Prenez la valeur que les règles VPN installées acceptent pour leur propre trafic, lisez-la depuis le jeu de règles actif et utilisez-la. Une mauvaise marque produit une règle qui se charge proprement, correspond à chaque requête et n'admet rien.
Gardez le trou de la largeur du port 53
Tel qu'écrit, cela autorise le DNS du sous-réseau libvirt vers l'hôte via TCP ou UDP port 53 et rien d'autre. Cela ne laisse pas les invités atteindre Internet hors du tunnel, et cela ne laisse pas l'hôte ouvrir des connexions vers les invités. Si un invité a besoin plus tard d'un autre service de l'hôte, ajoutez une règle séparée nommant ce port de destination au lieu d'assouplir celle-ci.
Soyez honnête sur ce que vous échangez. Un invité qui peut atteindre un résolveur peut aussi tunneler des données arbitraires via des requêtes DNS, et cette exception est un trou délibéré dans la frontière VPN, non une affirmation que le réseau local est digne de confiance. Restreindre la source à 192.168.122.0/24 garde le trou à l'écart de tout autre sous-réseau local, et compter les requêtes contre cette source est bon marché si la menace vous importe.
Faites-lui survivre à un redémarrage et prouvez les deux moitiés
Une règle tapée dans une invite de shell disparaît au prochain démarrage, et une règle chargée après que l'interface VPN fait déjà passer du trafic perd la course à la première connexion. Placez la table dans la configuration nftables persistante de l'hôte, ou dans une unité ordonnée avant le service VPN, et vérifiez l'ordre plutôt que de le supposer.
La vérification exige trois réponses distinctes. Confirmez que la chaîne est chargée et ordonnée en premier, confirmez que l'entrée conntrack montre la marque dans les deux sens, et confirmez qu'une recherche d'invité renvoie une adresse. Confirmez ensuite l'autre moitié : le trafic web ordinaire de l'invité vers un hôte public échoue toujours tant que le tunnel est coupé ou bloque. Si le DNS fonctionne et que tout le reste fuit, votre règle est plus large que celle ci-dessus.
Si les recherches échouent encore une fois la marque en place, résistez à l'envie d'élargir la source. Vérifiez vers quoi dnsmasq transfère, si le résolveur de l'invité pointe vers 192.168.122.1 ou vers une adresse publique que quelqu'un a tapée, et si la requête atteint ne serait-ce que l'hôte. Le marquage admet le paquet et rien d'autre, donc un mauvais amont ou un réseau virtuel cassé restent cassés quel que soit le nombre de règles ajoutées.