桥接流量走bridge→br_nf_pre_routing→forward路径,不进入input链,故-i eth0无法匹配;必须用physdev模块配合--physdev-in指定虚拟端口(如vnet0)并在forward链中控制。

在桥接模式下,虚拟机网卡(如 vnet0、tap0 或绑定到 br0 的接口)的流量默认不经过常规的 -i eth0 这类物理接口匹配逻辑——因为数据包在二层桥接路径中,内核 netfilter 的 INPUT 链根本收不到它;此时必须借助 physdev 模块,才能精准识别并控制“从哪个物理端口进来的桥接流量”。
为什么普通 -i 无法匹配桥接入站流量
桥接流量在内核中走的是 bridge → br_nf_pre_routing → FORWARD 路径,而非传统路由路径。即使目标是本机(比如访问宿主机上监听在 0.0.0.0:22 的 sshd),只要该 IP 属于桥接网段(如 192.168.100.1/24),且流量经由 br0 进入,它就不会进入 INPUT 链,而是被归为 FORWARD 流量处理。此时用 -i br0 匹配无效,因为 br0 是逻辑桥设备,不是物理入口;真正承载数据包的底层物理口(如 enp0s3)才需要被识别。
启用 physdev 模块并确认支持
physdev 是内核模块,需确保已加载:
检查是否可用:
iptables -m physdev --help 2>/dev/null && echo "physdev module ready" || echo "not loaded"
若报错,加载模块:
modprobe br_netfilter echo 'br_netfilter' >> /etc/modules
注意:启用 br_netfilter 后,还需开启转发开关(否则桥接流量不会进入 netfilter):
sysctl -w net.bridge.bridge-nf-call-iptables=1 sysctl -w net.ipv4.ip_forward=1 # 永久生效写入 /etc/sysctl.conf
针对虚拟网卡入站流量的典型控制方式
假设环境如下:
- 物理网卡:
enp0s3 - 桥接设备:
br0(绑定enp0s3) - 某虚拟机 vNIC 对应的 tap 设备:
vnet0(实际挂载在br0上) - 你想限制从
vnet0进来的所有 TCP 80 流量
关键点:vnet0 是桥的“物理端口”,但它是虚拟设备,在桥接上下文中被视为 physdev-in 的源端口。
正确规则示例(写入 FORWARD 链):
iptables -I FORWARD -m physdev --physdev-in vnet0 -p tcp --dport 80 -j DROP
说明:
-
--physdev-in vnet0:匹配从vnet0这个桥接端口进入的数据包(即虚拟机发出、经桥转发给宿主机或其他设备的包) - 必须放在
FORWARD链(桥接流量不走 INPUT) - 若要限制“发往宿主机自身”的流量(例如虚拟机访问宿主机的 Web 服务),需额外配合
--physdev-is-bridged和INPUT链(仅当br_netfilter开启且目标地址属于本机时才可能触发)
更安全的做法是统一在 FORWARD 中控制,并明确允许或拒绝特定方向:
# 允许 vnet0 访问外部网络(出向) iptables -A FORWARD -m physdev --physdev-in vnet0 -o enp0s3 -j ACCEPT <h1>禁止 vnet0 访问宿主机的敏感端口(入向,即目标为本机)</h1><p>iptables -A FORWARD -m physdev --physdev-in vnet0 -d 192.168.100.1 -p tcp --dport 22 -j DROP</p><h1>允许 DNS 和 DHCP(必要基础通信)</h1><p>iptables -A FORWARD -m physdev --physdev-in vnet0 -p udp --dport 53 -j ACCEPT iptables -A FORWARD -m physdev --physdev-in vnet0 -p udp --dport 67:68 -j ACCEPT</p>
注意事项与常见陷阱
physdev-in 不等于 ifconfig 中看到的 vnet0 接口名:某些 KVM/QEMU 场景中,vnet0 可能未直接暴露为 physdev 名称,而显示为 tapX 或由 libvirt 自动生成的名称(如 macvtap0)。可通过以下方式确认真实 physdev 名:
bridge fdb show | grep -v self # 查看桥学习到的 MAC 和端口映射
cat /sys/class/net/br0/br/fdb | awk '{print $2}' | xargs -I{} ip link show {} 2>/dev/null | grep "link/ether\|mtu"
规则顺序至关重要:因 FORWARD 链按序匹配,务必把具体 physdev 规则放在通用放行规则之前,否则会被提前放过。
不要混用 -i 和 --physdev-in:在桥接场景下,-i br0 匹配成功率极低,且语义模糊;--physdev-in 才是定位真实入口端口的可靠方式。











