Hvorfor iptables-regelen din aldri ser VPN-trafikk over en bro
Rammede over en bro kan omgå IP-kjeden du overvåker. Sammenlign den innebygde bridge-familien med den gamle br_netfilter før du legger til enda en regel.
To virtuelle maskiner på samme vert når LAN-et gjennom en bro, og en regel i ip forward-kjeden viser en teller som aldri flytter seg. Rammene er ekte, trafikken går gjennom, og regelen er rett og slett ikke på veien. Å sammenligne de to måtene Linux eksponerer trafikk over en bro på forklarer denne stillheten, og det forklarer også hvorfor det å laste én gammel modul er et dårligere svar enn det ser ut som.
To veier gjennom én vert
En pakke kan forlate denne verten på to svært ulike måter, og forskjellen avgjør hvilke kroker som ser den. Hvis målet ligger bak en fysisk port og rammen svitsjes mellom to broporter, videresender verten en Ethernet-ramme; rutingskoden blir ikke spurt, og det skjer ingen rutet hopp. Hvis målet er verten selv, eller et nettverk som nås gjennom et tunnelgrensesnitt, rutes pakken, og krokene på IP-laget gjelder faktisk. Ha denne gaffelen i tankene, for hvert senere spørsmål om kjeder og familier følger av hvilken av de to veiene en ramme tar.
Den forskjellen er hele historien bak en regel som ikke teller noe. En ramme over bro fra veth9a1 til enp3s0 krysser broen, ikke IP-stakken, så en ip forward-kjede ser ingenting å matche. Grensesnittnavn i et eldre eksempel avgjør ikke hvilken vei du har, og derfor er første steg å se på topologien i stedet for regelverket.
En tunnel legger til et tredje tilfelle som fortjener et navn. En TUN-enhet leverer IP-pakker til verten, så de rutes og går faktisk gjennom IP-kjeder, mens en TAP-enhet koblet til en bro leverer rammer og oppfører seg som brotilfellet. Det er enhetstypen, ikke produktnavnet, som avgjør.
Sammenlign de to familiene som kan se en ramme over en bro
Linux støtter innebygd brofiltrering gjennom nftables' bridge-familie, og trenger ingen gammel modul for å inspisere og forkaste rammer underveis. Kernels egen brodokumentasjon gir den anbefalingen direkte, noe det er verdt å vite før et søkeresultat forteller deg å laste en modul.
| 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 |
Å bruke nft-kommandoen i stedet for iptables plasserer ikke i seg selv en regel i riktig familie. En kjede som er deklarert i bridge-familien ser rammer; en kjede som er deklarert i ip, ip6 eller inet ser dem ikke, uansett hvilken binærfil som opprettet den. Familien er en egenskap ved kjeden, ikke ved verktøyet som skrev den.
Den gamle veien virker annerledes, og det er grunnen til å sammenligne i stedet for å velge side av vane. Å laste br_netfilter og slå på bridge-nf-call-innstillingene eksponerer igjen IPv4- og IPv6-trafikk over bro gjennom krokene på IP-laget, slik at en vanlig iptables-regel endelig kan matche den. Rammene endres ikke; settet med kroker de passerer, endres, noe som betyr at hver eksisterende vertsregel nå har et nytt publikum.
Les den effektive veien før du legger til en regel
Tre kommandoer fastslår hvor du er: hva broen er koblet til, om den gamle modulen er aktiv, og hvilke kjeder som allerede finnes i bridge-familien. Kjør dem før du skriver noe, fordi svaret avgjør hvilket av de to designene du utvider. Å hoppe over dette steget er måten en korrekt regel ender opp i en kjede som ingenting går gjennom.
bridge link show
lsmod | grep br_netfilter
nft list ruleset | grep -A4 "chain forward"
Utdataene skiller tilfellene rent. Porter som er listet under broen forteller hvilke grensesnitt som svitsjes; et tomt lsmod-resultat betyr ingen synlighet på IP-laget av rammer over bro; en eksisterende forward-kjede i bridge-familien betyr at det allerede finnes en policyeier og at regelen din hører hjemme der i stedet for i en ny kjede for seg selv.
Legg deretter til én regel som er lett å lese tilbake, med en teller og uten å endre avgjørelsen, og send én representativ strøm gjennom broen. En teller som flytter seg beviser at rammen nådde regelen. Det er alt den beviser, så følg opp med den avviste veien også, siden en policy som godtar alt også gir en teller som flytter seg.
nft add rule bridge filter forward iifname "veth9a1" oifname "enp3s0" counter acceptHvor den gamle modulen endrer atferd
Å slå på den gamle veien på en bro som kjører er ikke en nøytral handling med å legge til synlighet. Regler som tidligere var utilgjengelige for trafikk over bro blir tilgjengelige, inkludert vertsregler skrevet for et annet grensesnitt, og en standard drop-policy i ip forward-kjeden kan plutselig gjelde for rammer som før passerte urørt. På en vert som administreres over den broen, er resultatet en utestenging uten konsoll. Dette er ikke en hypotetisk feilmodus; det er den vanlige konsekvensen av å utvide et sett med kroker på en maskin du når gjennom veien du nettopp utvidet.
Den sikrere rekkefølgen er å bestemme hvilken familie som eier policyen, skrive reglene der, og beholde en uavhengig gjenopprettingsvei før du endrer noen sysctl. Hvis to familier begge har regler, dokumenter hvilken som er autoritativ; to overlappende policyer er måten en pakke godtas på ett sted og forkastes på et annet uten en eneste fil å lese.
Isolasjonen selv trenger fortsatt et fullstendig design. Å tillate én kilde til én destinasjon beviser bare at én strøm virker, mens kravet vanligvis er at en VM ikke kan nå naboene sine eller verten. Tellere på avvisningsreglene betyr mer enn telleren på godtakelsesregelen, fordi godtakelsestelleren er den du allerede forventet ville flytte seg.
Til slutt, hold vertsinndata-tilfellet atskilt. Trafikk adressert til broens egen IP kommer inn på input, ikke på forward, og en regel i forward vil aldri se den, uansett hvilken familie du velger. Tre tilfeller, to familier, én lærdom: veien avgjør kroken, og kroken avgjør om regelen din i det hele tatt finnes.