Åtgärda gäst-DNS i libvirt som blockeras av en markbaserad VPN-brandvägg
En markbaserad VPN-brandvägg släpper gästernas DNS innan en filterkedja ser den. En regel med mangle-prioritet markerar frågan och svaret, utan att öppna ditt LAN.
Gäster på standardnätverket libvirt löser namn perfekt tills WireGuard-gränssnittet kommer upp, och då fastnar varje uppslag på samma ställe. dnsmasq lyssnar fortfarande på 192.168.122.1:53, gästen har fortfarande den adressen som resolver, och frågan kommer fortfarande fram. Det som ändrats är att värdens egen uppströmsfråga, eller svaret på den, nu släpps av en regel som utvärderas före varje filterkedja du skulle tro att du måste redigera. Vägen ut är en mark som sätts tillräckligt tidigt, på en anslutning som svaret ärver.
Gästerna tappar DNS i samma stund som tunneln kommer upp
Bekräfta formen innan du ändrar något. Ta ner tunneln, kör dig @192.168.122.1 example.com från en gäst och se att den svarar. Ta upp tunneln, upprepa och se att den får timeout. Det paret resultat utesluter ett trasigt libvirt-nätverk, en felaktig resolveradress och en död dnsmasq i ett enda steg.
Titta sedan på värdsidan. Om dnsmasq loggar frågan och dess uppströmsvidarebefordran kom paketet fram och felet ligger på egress. Om dnsmasq aldrig loggar något släpps gästfrågan på ingress, och undantaget hör hemma på en annan hook än den den här artikeln markerar.
Varför en accept-regel i en senare kedja aldrig utlöses
En markbaserad VPN-brandvägg avgör genom att titta på paketmarken eller anslutningsmarken, inte på din källadress. Allt som kommer in på det fysiska gränssnittet utan den förväntade marken avvisas, och den avvisningen sker i regeluppsättningen som äger marktestet. ip saddr 192.168.122.0/24 accept rad tillagd i någon senare kedja konsulteras helt enkelt aldrig för det paketet, och därför ser den uppenbara regeln korrekt ut och ändrar ingenting.
Att bredda den tills något fungerar är den andra fällan. Att acceptera hela libvirt-subnätet i värdens input-väg öppnar varje värdtjänst för gästerna, när det faktiska behovet är en enda port.
Mekanismen som gör ett smalt undantag möjligt är anslutningsspårning. När du sätter ct mark på ett paket lagras värdet på conntrack-posten och inte bara på paketet, så varje paket i den anslutningen bär det därefter, inklusive svaret från värden tillbaka till gästen. Det är hela tricket: markera begäran en gång, och returvägen är redan markerad.
Markera frågan innan VPN-tabellen ser den
Lägg undantaget i en egen tabell så att en senare läsare hittar det utan att tolka VPN-reglerna:
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 är negativ, vilket placerar den här kedjan före de vanliga filterkedjorna som VPN-paketet installerar vid prioritet noll. Det är hookordningen som gör regeln effektiv; samma regel i en kedja som sorterar efter VPN-kedjan är bara dekoration.
Själva marknumret är inte portabelt. Ta det värde som de installerade VPN-reglerna accepterar för sin egen trafik, läs ut det ur den levande regeluppsättningen och använd det. En fel mark ger en regel som laddas rent, matchar varje fråga och släpper in ingenting.
Håll hålet lika brett som port 53
Som skrivet tillåter detta DNS från libvirt-subnätet till värden över TCP eller UDP port 53 och ingenting annat. Det släpper inte ut gästerna på internet utanför tunneln, och det låter inte värden öppna anslutningar mot gästerna. Behöver en gäst en annan värdtjänst senare, lägg till en separat regel som namnger den destinationsporten i stället för att luckra upp den här.
Var ärlig om vad du byter bort. En gäst som kan nå en resolver kan också tunnla godtyckliga data genom DNS-frågor, och det här undantaget är ett medvetet hål i VPN-gränsen och inte ett påstående att det lokala nätverket är betrott. Att begränsa källan till 192.168.122.0/24 håller hålet borta från varje annat lokalt subnät, och att räkna frågor mot den källan är billigt om hotet spelar roll för dig.
Se till att det överlever omstart och bevisa båda halvorna
En regel som skrivs i en shell-prompt försvinner vid nästa uppstart, och en regel som laddas efter att VPN-gränssnittet redan passerar trafik förlorar kapplöpningen vid den första anslutningen. Lägg tabellen i värdens beständiga nftables-konfiguration, eller i en enhet ordnad före VPN-tjänsten, och kontrollera ordningen i stället för att anta den.
Verifieringen behöver tre separata svar. Bekräfta att kedjan är laddad och ordnad först, bekräfta att conntrack-posten visar marken i båda riktningarna, och bekräfta att ett gästuppslag returnerar en adress. Bekräfta sedan den andra halvan: vanlig gästwebbtrafik till en offentlig värd misslyckas fortfarande medan tunneln är nere eller blockerar. Om DNS fungerar och allt annat läcker är din regel bredare än den ovan.
Om uppslag fortfarande misslyckas efter att marken är på plats, stå emot lusten att bredda källan. Kontrollera vad dnsmasq vidarebefordrar till, om gästens resolver pekar på 192.168.122.1 eller på en offentlig adress som någon skrivit in, och om frågan över huvud taget når värden. Markering släpper in paketet och ingenting annat, så en dålig uppström eller ett trasigt virtuellt nätverk förblir trasigt hur många regler du än lägger till.