Waarom je iptables-regel nooit gebridget VPN-verkeer ziet
Gebridget frames kunnen de IP-keten omzeilen die je in de gaten houdt. Vergelijk de native bridge-familie met de oude br_netfilter voordat je nog een regel toevoegt.
Twee virtuele machines op dezelfde host bereiken het LAN via een brug, en een regel in de ip forward-keten toont een teller die nooit beweegt. De frames zijn echt, het verkeer gaat door, en de regel staat simpelweg niet op het pad. De twee manieren waarop Linux gebridget verkeer zichtbaar maakt vergelijken verklaart die stilte, en het verklaart ook waarom één oude module laden een slechter antwoord is dan het lijkt.
Twee paden door één host
Een pakket kan deze host op twee heel verschillende manieren verlaten, en het verschil bepaalt welke hooks het zien. Als de bestemming voorbij een fysieke poort ligt en het frame tussen twee brugpoorten wordt geschakeld, stuurt de host een Ethernet-frame door; de routeringscode wordt niet geraadpleegd, en er vindt geen gerouteerde hop plaats. Als de bestemming de host zelf is, of een netwerk dat via een tunnelinterface bereikbaar is, wordt het pakket gerouteerd en gelden de hooks van de IP-laag wel. Houd die splitsing in gedachten, want elke latere vraag over ketens en families volgt uit welke van de twee paden een frame neemt.
Dat onderscheid is het hele verhaal achter een regel die niets telt. Een gebridget frame van veth9a1 naar enp3s0 steekt de brug over, niet de IP-stack, dus een ip forward-keten ziet niets om te matchen. Interfacenamen in een ouder voorbeeld bepalen niet welk pad je hebt, en daarom is de eerste stap naar de topologie kijken en niet naar de regelset.
Een tunnel voegt een derde geval toe dat een naam verdient. Een TUN-apparaat levert IP-pakketten aan de host, dus die worden gerouteerd en gaan wel door IP-ketens, terwijl een TAP-apparaat dat aan een brug hangt frames levert en zich als het bruggeval gedraagt. Het apparaattype, niet de productnaam, beslist.
Vergelijk de twee families die een gebridget frame kunnen zien
Linux ondersteunt native brugfiltering via de bridge-familie van nftables, en het heeft geen oude module nodig om frames in de vlucht te inspecteren en te laten vallen. De brugdocumentatie van de kernel zelf geeft die aanbeveling rechtstreeks, wat de moeite waard is om te weten voordat een zoekresultaat je vertelt een module te laden.
| Observation point | What it sees | What it costs |
|---|---|---|
nftables bridge family chains | Ethernet frames forwarded between bridge ports, in both directions | Rules must be written in bridge syntax with link-layer matches |
Legacy br_netfilter plus an ip chain | Bridged IPv4 and IPv6 packets, re-exposed through IP-layer hooks | Existing host rules may begin matching traffic they never saw before |
inet chain for routed traffic | Packets the host routes, including traffic arriving from a TUN device | No visibility into purely switched frames |
Het nft-commando in plaats van iptables gebruiken plaatst op zichzelf geen regel in de juiste familie. Een keten die in de bridge-familie is gedeclareerd ziet frames; een keten die in ip, ip6 of inet is gedeclareerd ziet ze niet, ongeacht welk binair bestand hem heeft gemaakt. De familie is een eigenschap van de keten, niet van het gereedschap dat hem typte.
Het oude pad werkt anders, en dat is de reden om te vergelijken in plaats van uit gewoonte een kant te kiezen. Het laden van br_netfilter en het aanzetten van de bridge-nf-call-instellingen stelt gebridget IPv4- en IPv6-verkeer opnieuw bloot via de hooks van de IP-laag, zodat een gewone iptables-regel het eindelijk kan matchen. De frames veranderen niet; de set hooks die ze passeren verandert, wat betekent dat elke bestaande hostregel nu een nieuw publiek heeft.
Lees het effectieve pad voordat je een regel toevoegt
Drie commando's stellen vast waar je staat: waaraan de brug hangt, of de oude module actief is, en welke ketens al in de bridge-familie bestaan. Voer ze uit voordat je iets schrijft, want het antwoord bepaalt welk van de twee ontwerpen je uitbreidt. Deze stap overslaan is hoe een correcte regel in een keten belandt waar niets doorheen gaat.
bridge link show
lsmod | grep br_netfilter
nft list ruleset | grep -A4 "chain forward"
De uitvoer scheidt de gevallen netjes. Poorten die onder de brug staan vermelden welke interfaces worden geschakeld; een leeg lsmod-resultaat betekent helemaal geen zichtbaarheid op de IP-laag van gebridget frames; een bestaande forward-keten van de bridge-familie betekent dat er al een beleidseigenaar is en dat je regel daar thuishoort in plaats van in een nieuwe eigen keten.
Voeg dan één regel toe die makkelijk terug te lezen is, met een teller en zonder het oordeel te veranderen, en stuur één representatieve stroom door de brug. Een teller die beweegt bewijst dat het frame de regel heeft bereikt. Dat is alles wat hij bewijst, dus volg hem ook met het geweigerde pad, want een beleid dat alles accepteert levert ook een bewegende teller op.
nft add rule bridge filter forward iifname "veth9a1" oifname "enp3s0" counter acceptWaar de oude module gedrag verandert
Het oude pad aanzetten op een draaiende brug is geen neutrale daad van zichtbaarheid toevoegen. Regels die eerder onbereikbaar waren voor gebridget verkeer worden bereikbaar, inclusief hostregels die voor een andere interface zijn geschreven, en een standaard drop-beleid in de ip forward-keten kan plotseling gelden voor frames die voorheen onaangeroerd passeerden. Op een host die via die brug wordt beheerd, is het resultaat een uitsluiting zonder console. Dat is geen hypothetische foutmodus; het is de gewone consequentie van het uitbreiden van een set hooks op een machine die je bereikt via het pad dat je zojuist hebt uitgebreid.
De veiligere volgorde is beslissen welke familie het beleid bezit, de regels daar schrijven, en een onafhankelijk herstelpad houden voordat je een sysctl wijzigt. Als twee families beide regels hebben, documenteer dan welke gezaghebbend is; twee overlappende beleidsregels zijn hoe een pakket op de ene plek wordt geaccepteerd en op een andere wordt gedropt zonder één bestand om te lezen.
Isolatie zelf vraagt nog steeds een volledig ontwerp. Eén bron naar één bestemming toestaan bewijst alleen dat één stroom werkt, terwijl de eis meestal is dat een VM zijn buren of de host niet kan bereiken. Tellers op de weigeringsregels zijn belangrijker dan de teller op de acceptatieregel, want de acceptatieteller is degene waarvan je al verwachtte dat hij zou bewegen.
Ten slotte, houd het host-inputgeval apart. Verkeer dat aan de eigen IP van de brug is gericht komt bij input aan, niet bij forward, en een regel in forward zal het nooit zien, welke familie je ook kiest. Drie gevallen, twee families, één les: het pad bepaalt de hook, en de hook bepaalt of je regel überhaupt bestaat.