DNS van libvirt-gasten repareren die door een op marks gebaseerde VPN-firewall wordt geblokkeerd
Een op marks gebaseerde VPN-firewall laat gast-DNS vallen voordat een filterketen hem ziet. Eén regel met mangle-prioriteit markeert de query en het antwoord, zonder je LAN open te zetten.
Gasten op het standaard libvirt-netwerk lossen namen prima op tot de WireGuard-interface opkomt, en dan blijft elke opzoeking op dezelfde plek hangen. dnsmasq luistert nog steeds op 192.168.122.1:53, de gast heeft dat adres nog steeds als resolver, en de query komt nog steeds aan. Wat veranderd is, is dat de upstream-query van de host zelf, of het antwoord daarop, nu wordt weggegooid door een regel die wordt geëvalueerd vóór elke filterketen die je zou willen bewerken. De uitweg is een mark die vroeg genoeg wordt gezet, op een verbinding die het antwoord erft.
Gasten verliezen DNS op het moment dat de tunnel opkomt
Bevestig de vorm voordat je iets wijzigt. Haal de tunnel neer, voer dig @192.168.122.1 example.com uit vanaf een gast, en kijk hoe hij antwoordt. Haal de tunnel op, herhaal, en kijk hoe hij in een time-out loopt. Dat tweetal resultaten sluit een kapot libvirt-netwerk, een verkeerd resolveradres en een dode dnsmasq in één stap uit.
Kijk dan naar de hostkant. Als dnsmasq de query en de upstream-doorsturing logt, is het pakket aangekomen en zit de fout op egress. Als dnsmasq nooit iets logt, wordt de gastquery op ingress weggegooid en hoort de uitzondering op een andere hook dan degene die dit artikel markeert.
Waarom een accept-regel in een latere keten nooit afgaat
Een op marks gebaseerde VPN-firewall beslist door naar de packet mark of de connection mark te kijken, niet naar je bronadres. Alles wat op de fysieke interface aankomt zonder de verwachte mark wordt geweigerd, en die weigering gebeurt in de regelset die de marktest bezit. ip saddr 192.168.122.0/24 accept regel toegevoegd aan een latere keten wordt voor dat pakket simpelweg nooit geraadpleegd, en daarom lijkt de voor de hand liggende regel correct en verandert niets.
Het verbreden tot iets werkt, is de tweede valkuil. De hele libvirt-subnet accepteren in het inputpad van de host opent elke hostdienst voor gasten, terwijl de werkelijke behoefte één poort is.
Het mechanisme dat een smalle uitzondering mogelijk maakt, is connection tracking. Wanneer je ct mark op een pakket zet, wordt de waarde opgeslagen op de conntrack-entry en niet alleen op het pakket, dus elk pakket in die verbinding draagt hem daarna, inclusief het antwoord van de host terug naar de gast. Dat is de hele truc: markeer het verzoek één keer, en het retourpad is al gemarkeerd.
Markeer de query voordat de VPN-tabel hem ziet
Zet de uitzondering in een eigen tabel, zodat een latere lezer hem kan vinden zonder de VPN-regels te parsen:
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 is negatief, waardoor deze keten vóór de gewone filterketens komt die het VPN-pakket op prioriteit nul installeert. De hookvolgorde is wat de regel effectief maakt; dezelfde regel in een keten die na de VPN-keten sorteert, is decoratie.
Het marknummer zelf is niet overdraagbaar. Neem de waarde die de geïnstalleerde VPN-regels voor hun eigen verkeer accepteren, lees die uit de live regelset, en gebruik die. Een verkeerde mark levert een regel op die schoon laadt, bij elke query past en niets toelaat.
Houd het gat zo breed als poort 53
Zoals geschreven staat dit DNS van de libvirt-subnet naar de host over TCP of UDP poort 53 toe en niets anders. Het laat gasten niet buiten de tunnel bij het internet, en het laat de host geen verbindingen naar gasten openen. Heeft een gast later een andere hostdienst nodig, voeg dan een aparte regel toe die die bestemmingspoort noemt in plaats van deze te verruimen.
Wees eerlijk over wat je ruilt. Een gast die een resolver kan bereiken, kan ook willekeurige data door DNS-queries tunnelen, en deze uitzondering is een bewust gat in de VPN-grens en geen verklaring dat het lokale netwerk vertrouwd is. De bron beperken tot 192.168.122.0/24 houdt het gat weg van elk ander lokaal subnet, en queries op die bron tellen is goedkoop als de dreiging voor jou uitmaakt.
Zorg dat het een herstart overleeft en bewijs beide helften
Een regel die je op een shell-prompt typt, verdwijnt bij de volgende boot, en een regel die wordt geladen nadat de VPN-interface al verkeer doorlaat, verliest de race op de eerste verbinding. Zet de tabel in de persistente nftables-configuratie van de host, of in een unit die vóór de VPN-dienst is geordend, en controleer de volgorde in plaats van hem aan te nemen.
Verificatie vereist drie afzonderlijke antwoorden. Bevestig dat de keten is geladen en als eerste is geordend, bevestig dat de conntrack-entry de mark in beide richtingen toont, en bevestig dat een gastopzoeking een adres teruggeeft. Bevestig dan de andere helft: gewoon webverkeer van de gast naar een publieke host faalt nog steeds terwijl de tunnel neerligt of blokkeert. Als DNS werkt en al het andere lekt, is je regel breder dan die hierboven.
Als opzoekingen nog steeds falen nadat de mark is geplaatst, weersta de neiging de bron te verbreden. Controleer waar dnsmasq naartoe stuurt, of de resolver van de gast naar 192.168.122.1 wijst of naar een publiek adres dat iemand heeft ingetypt, en of de query de host überhaupt bereikt. Markeren laat het pakket toe en niets anders, dus een slechte upstream of een kapot virtueel netwerk blijft kapot, hoe veel regels je ook toevoegt.