我正在跟进这个视频关于Linux中的网络命名空间,并尝试自己实践,但由于某种原因它不起作用。我所做的是:
创建 2 个名为“blue”和“red”的网络命名空间后:
sudo ip link add bridge type bridge
sudo ip link set dev bridge up
sudo ip link add veth-red type veth peer name veth-red-br
sudo ip link add veth-blue type veth peer name veth-blue-br
sudo ip link set veth-red netns red
sudo ip link set veth-red-br master bridge
sudo ip link set veth-blue netns blue
sudo ip link set veth-blue-br master bridge
sudo ip netns exec red ip addr add 192.168.15.1/24 dev veth-red
sudo ip netns exec blue ip addr add 192.168.15.2/24 dev veth-blue
sudo ip netns exec red ip link set veth-red up
sudo ip link set veth-red-br up
sudo ip netns exec blue ip link set veth-blue up
sudo ip link set veth-blue-br up
现在,如果我尝试从红色 ping 到蓝色,反之亦然,则不起作用。奇怪的是,ARP 确实有效,因此接口之间存在连接。我知道这一点是因为当我arp
在命名空间中运行时我可以看到正确的值:
$ sudo ip netns exec red arp
Address HWtype HWaddress Flags Mask Iface
192.168.15.2 ether ca:4f:b6:65:a0:f8 C veth-red
$ sudo ip netns exec blue ifconfig
veth-blue: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.15.2 netmask 255.255.255.0 broadcast 0.0.0.0
inet6 fe80::c84f:b6ff:fe65:a0f8 prefixlen 64 scopeid 0x20<link>
ether ca:4f:b6:65:a0:f8 txqueuelen 1000 (Ethernet)
RX packets 85 bytes 8946 (8.9 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 27 bytes 1986 (1.9 KB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
所以你可以看到红色命名空间在其 ARP 表中具有蓝色命名空间 veth 的 MAC 地址,那么为什么 ping 不起作用呢?
答案1
那是因为 IPv4 被过滤了iptables或者nftables。你可能会想:不可能,以太网桥工作在第 2 层,所以与iptables在第 3 层使用 IPv4。
但有一个办法:br_netfilter
(显示通过回溯机因为他们让证书过期):
bridge-netfilter 代码启用以下功能:
{Ip,Ip6,Arp}表可以过滤桥接的 IPv4/IPv6/ARP 数据包,即使封装在 802.1Q VLAN 或 PPPoE 标头中也是如此。这启用了状态透明防火墙的功能。
因此,这 3 个工具的所有过滤、日志记录和 NAT 功能都可以在桥接帧上使用。
也可以看看基于 Linux 的桥上的 ebtables/iptables 交互了解详情。
所以如果有人这样做:
iptables -I FORWARD -j DROP
modprobe br_netfilter
(或者将 FORWARD 策略设置为 DROP,而没有规则接受数据包)则默认情况下,网桥将丢弃在第 2 层接收到的所有 IPv4 流量iptables:对于 IPv4 帧,br_netfilter
将临时将第 2 层以太网帧“升级”为 IPv4 数据包,并将其馈送到iptables,仍然在桥路上。丢弃的数据包iptables不会出桥。那些未丢弃的(在上面的示例中没有)将作为以太网帧反馈到网桥中以继续网桥处理。
可能的罪魁祸首:Docker。 Docker 确实启用了br_netfilter
(可能是为了容器间隔离)。没有明确记录,但这是Docker 部分的来源:
if config.EnableIPTables || config.EnableIP6Tables { if _, err := os.Stat("/proc/sys/net/bridge"); err != nil { if out, err := exec.Command("modprobe", "-va", "bridge", "br_netfilter").CombinedOutput(); err != nil { logrus.Warnf("Running modprobe bridge br_netfilter failed with message: %s, error: %v", out, err) } } }
当它加载bridge
内核模块时,它也会加载br_netfilter
.
Docker确实设置了iptables' 将策略转发为 DROP:
Docker 还将链的策略设置
FORWARD
为DROP
.
[...]
即使这不是因为 Docker,您也肯定已经br_netfilter
加载了(很可能是通过physdev
然后)和防火墙规则丢弃数据包iptables' (或者nftables') 转发规则。否则你真的有桥牌规则,要么使用ebtables或者nftables与桥家庭阻止转发帧。
在内核 5.3 之前,这可能是在桥接级别执行状态防火墙的唯一方法。
在这个示意图蓝色字段(以太网)中的绿色(IPv4)框代表iptables(或者nftablesbr_netfilter
)在启用它时在以太网桥接路径中运行:
有多种方法可以使用桥粒度而不是系统范围的粒度来执行此操作(最好在启动早期执行此操作,以便它也在新的命名空间中继承):
加载
br_netfilter
但禁用其效果:modprobe br_netfilter sysctl -w net.bridge.bridge-nf-call-arptables=0 sysctl -w net.bridge.bridge-nf-call-ip6tables=0 sysctl -w net.bridge.bridge-nf-call-iptables=0
在此刻红色的和蓝色的能够通信,但 Docker(可能是损坏的最初原因)会随机损坏自身。
在选择的网桥上重新启用它:
ip link set bridge type bridge nf_call_iptables 1
之间的通信将再次停止红色的和蓝色的。
从内核 5.3 开始,系统范围内设置获取每个网络命名空间,如果需要在非初始网络命名空间中禁用(或重新启用)此功能,从而影响其中的所有网桥:
ip netns FOO sysctl -w net.bridge.bridge-nf-call-iptables=X
Docker 不支持这些模式:它需要在它创建的所有桥上启用 sysctl(如果有创建桥的设置,则可能在它创建的网络命名空间上启用 sysctl),但目前不知道这一点。
当然,删除内核模块也会阻止交互并允许流量返回:
rmmod br_netfilter
仍然从内核 5.3 开始,nftables直接在网桥系列中获得状态防火墙支持,因此br_netfilter
不再需要使用此功能。br_netfilter
今天对于使用 sysctl 与 PPPoE 相关的防火墙net.bridge.bridge-nf-filter-pppoe-tagged
(默认情况下未启用)可能仍然有用,据我所知,目前还没有简单的替代品。
另请参阅我在此处和 SF 上这些 Q/A 中的相关答案: