iptables
works at the routing layer. It doesn't work at the bridging layer. Once eth1
was set as bridge port it's not involved in routing anymore. That means there won't be a packet seen routed through eth1
, and normally it won't traverse iptables at all.
br_netfilter
, bridging and iptables
There's a catch: when the br_netfilter
module is loaded (typically by Docker), iptables
will also filter bridged IPv4 frames. OP's question hints the module is loaded. This case is shown in the schematic below with the green boxes (iptables handling IPv4) in the blue field (Ethernet bridging):

In this case, any bridged frame will appear to iptables through the bridge that handled this frame (br0
) instead. eth1
still cannot be referenced like a routed interface. Instead this requires the special physdev
module (which also triggers the loading of br_netfilter
) to specify a bridge port. One must take care to distinguish bridged traffic from routed traffic, because iptables will see both. This documentation can help with more complex rulesets: ebtables/iptables interaction on a Linux-based bridge section 7.
So in the end, when the module br_netfilter
is loaded, or anyway gets loaded by the following rules, to achieve the goal, the very simple example below will do. As I don't have context from OP about Docker or anything else present, I must force FORWARD's policy to ACCEPT and insert rules first because if the default policy was DROP and Docker loaded its own rules, this simple example would be far from enough:
iptables -P FORWARD ACCEPT
iptables -F FORWARD
iptables -I FORWARD 1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -I FORWARD 2 -m physdev --physdev-in eth1 -j DROP
nftables
This requires kernel >= 5.3.
Note that if there's no reason to load br_netfilter
(such as running Docker), instead of using iptables for this, one could use nftables directly in the proper place: the bridge family, because nftables can use the conntrack facility for a stateful firewall directly in the bridge family, without this kludge (initially because ebtables cannot use conntrack).
So instead one could remove the br_netfilter
module altogether:
rmmod br_netfilter
Doing this will disrupt Docker.
Or just disable br_netfilter
's feature if loaded (a failed test is supposed to mean the module is not loaded) in the current network namespace and on the current bridge (where it was not enabled by default anyway but just to be thorough):
if sysctl -n net.bridge.bridge-nf-call-iptables 2>/dev/null; then
sysctl -qw net.bridge.bridge-nf-call-iptables=0
ip link set dev br0 type bridge nf_call_iptables 0
fi
The per-namespace toggle or the bridge toggle is enough for the feature to be activated: both must be disabled to disable it.
Else it will still affect iptables and also nftables in the ip family (nftables has no tool to cope with this properly). Doing this will also disrupt Docker if it's running and in the same network namespace (the host), unless it's actually a Docker-in-Docker running in an other network namespace.
The equivalent nftables ruleset directly in the bridge family is (load with nft -f ...
):
table bridge t {
chain forward { type filter hook forward priority filter; policy accept;
ct state established,related accept
iif eth1 drop
}
}