Perché la tua regola iptables non vede mai il traffico VPN in bridging
Le trame in bridging possono aggirare la catena IP che stai osservando. Confronta la famiglia bridge nativa con il vecchio br_netfilter prima di aggiungere un’altra regola.
Due macchine virtuali sullo stesso host raggiungono la LAN attraverso un ponte, e una regola inserita nella catena ip forward mostra un contatore che non si muove mai. Le trame sono reali, il traffico passa, e la regola semplicemente non è sul suo percorso. Confrontare i due modi in cui Linux espone il traffico in bridging spiega questo silenzio, e spiega anche perché caricare un modulo legacy sia una risposta peggiore di quanto sembri.
Due percorsi attraverso un solo host
Un pacchetto può lasciare questo host in due modi molto diversi, e la differenza decide quali hook lo vedono. Se la destinazione è oltre una porta fisica e la trama viene commutata tra due porte del ponte, l’host inoltra una trama Ethernet; il codice di routing non viene consultato e non avviene alcun salto instradato. Se la destinazione è l’host stesso, o una rete raggiunta tramite un’interfaccia tunnel, il pacchetto viene instradato e gli hook del livello IP si applicano davvero. Tieni presente questa biforcazione, perché ogni domanda successiva su catene e famiglie dipende da quale dei due percorsi prende una trama.
Questa distinzione è tutta la storia dietro una regola che non conta nulla. Una trama in bridging da veth9a1 a enp3s0 attraversa il ponte, non lo stack IP, quindi una catena ip forward non vede nulla da confrontare. I nomi delle interfacce in un esempio più vecchio non stabiliscono quale percorso hai, ed è per questo che il primo passo è guardare la topologia e non l’insieme di regole.
Un tunnel aggiunge un terzo caso che merita un nome. Un dispositivo TUN consegna pacchetti IP all’host, quindi vengono instradati e attraversano davvero le catene IP, mentre un dispositivo TAP collegato a un ponte consegna trame e si comporta come il caso in bridging. È il tipo di dispositivo, non il nome del prodotto, a decidere.
Confronta le due famiglie che possono vedere una trama in bridging
Linux supporta il filtro del ponte nativo tramite la famiglia bridge di nftables, e non ha bisogno di alcun modulo legacy per ispezionare e scartare trame in volo. La documentazione del ponte del kernel stesso fa direttamente questa raccomandazione, cosa che vale la pena sapere prima che un risultato di ricerca ti dica di caricare un modulo.
| 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 |
Usare il comando nft invece di iptables non colloca, di per sé, una regola nella famiglia giusta. Una catena dichiarata nella famiglia bridge vede le trame; una catena dichiarata in ip, ip6 o inet non le vede, qualunque binario l’abbia creata. La famiglia è una proprietà della catena, non dello strumento che l’ha digitata.
Il percorso legacy funziona diversamente, ed è per questo che conviene confrontare invece di scegliere un lato per abitudine. Caricare br_netfilter e abilitare le impostazioni bridge-nf-call riespone il traffico IPv4 e IPv6 in bridging attraverso gli hook del livello IP, così una normale regola iptables può finalmente corrispondervi. Le trame non cambiano; cambia l’insieme degli hook che attraversano, il che significa che ogni regola host esistente ha ora un nuovo pubblico.
Leggi il percorso effettivo prima di aggiungere una regola
Tre comandi stabiliscono dove ti trovi: a cosa è collegato il ponte, se il modulo legacy è attivo e quali catene esistono già nella famiglia bridge. Eseguili prima di scrivere qualsiasi cosa, perché la risposta decide quale dei due progetti stai estendendo. Saltare questo passo è il modo in cui una regola corretta finisce in una catena che nulla attraversa.
bridge link show
lsmod | grep br_netfilter
nft list ruleset | grep -A4 "chain forward"
L’output separa i casi in modo pulito. Le porte elencate sotto il ponte ti dicono quali interfacce sono commutate; un risultato lsmod vuoto significa nessuna visibilità a livello IP delle trame in bridging; una catena forward esistente della famiglia bridge significa che esiste già un proprietario della politica e che la tua regola appartiene lì invece che a una nuova catena propria.
Poi aggiungi una regola facile da rileggere, con un contatore e senza cambiare il verdetto, e fai passare un solo flusso rappresentativo attraverso il ponte. Un contatore che si muove dimostra che la trama ha raggiunto la regola. È tutto ciò che dimostra, quindi prosegui anche con il percorso negato, dato che una politica che accetta tutto produce anch’essa un contatore in movimento.
nft add rule bridge filter forward iifname "veth9a1" oifname "enp3s0" counter acceptDove il modulo legacy cambia il comportamento
Abilitare il percorso legacy su un ponte in funzione non è un atto neutro di aggiunta di visibilità. Le regole prima irraggiungibili per il traffico in bridging diventano raggiungibili, comprese le regole host scritte per un’altra interfaccia, e una politica drop predefinita nella catena ip forward può improvvisamente applicarsi a trame che prima passavano intatte. Su un host gestito attraverso quel ponte, il risultato è un blocco senza console. Non è un modo di guasto ipotetico; è la conseguenza ordinaria dell’ampliare un insieme di hook su una macchina che raggiungi attraverso il percorso che hai appena ampliato.
La sequenza più sicura è decidere quale famiglia possiede la politica, scrivere lì le regole e mantenere un percorso di ripristino indipendente prima di modificare qualsiasi sysctl. Se due famiglie detengono regole, documenta quale sia l’autorità; due politiche sovrapposte sono il modo in cui un pacchetto viene accettato in un punto e scartato in un altro senza un solo file da leggere.
L’isolamento in sé richiede ancora un progetto completo. Consentire a una sorgente di raggiungere una destinazione dimostra solo che un flusso funziona, mentre il requisito di solito è che una VM non possa raggiungere i vicini o l’host. I contatori sulle regole di negazione contano più del contatore sulla regola di accettazione, perché il contatore di accettazione è quello che già ti aspettavi si muovesse.
Infine, tieni separato il caso dell’input dell’host. Il traffico indirizzato all’IP del ponte stesso arriva a input, non a forward, e una regola in forward non lo vedrà mai, qualunque famiglia scegli. Tre casi, due famiglie, una lezione: il percorso decide l’hook, e l’hook decide se la tua regola esiste affatto.