NAT 和复杂的网桥配置

NAT 和复杂的网桥配置

我有一个复杂的桥接配置,如下所示:

在此输入图像描述

有一条默认路由via 172.31.0.1 dev eth0_bridge

lan_bridge现在我尝试在和之间设置伪装,eth0_bridge以便其他设备可以连接到eth1,从 DHCP 服务器获取地址,然后通过 的默认路由访问互联网eth0

为此,我添加了一条 iptables 规则,如下所示:

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0_bridge -j MASQUERADE

一旦我完成了这一点(并添加了其他常用的 NAT 规则 - 但正是这个规则导致了麻烦),我尝试ping 172.31.0.1从连接到eth1. tcpdump on172.31.0.1显示数据包到达时带有其原始源地址。看来这个规则从来没有被打破过。所以我添加了这样的规则:

iptables -t nat -I POSTROUTING 1 -s 192.168.100.0/24 -j LOG --log-prefix NAT:

这是 dmesg 中显示的唯一匹配项:

[10555.271048] NAT:IN= OUT=eth1_bridge PHYSIN=eth1 PHYSOUT=ve_eth1_lan SRC=192.168.100.210 DST=172.31.0.1 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=55162 DF PROTO=ICMP TYPE=8 CODE=0 ID=13662 SEQ=1

因此,这些数据包唯一一次到达 POSTROUTING 表是当它们离开eth1_bridge进入 veth 对,前往 时lan_bridge。此时将数据包发送到 MASQUERADE:

iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth1_bridge -j MASQUERADE

导致 100% 丢包。

这种情况下192.168.100.0/24网络与网络之间如何设置NAT呢?172.31.0.0/24

编辑更多细节:

我发现这个的系统是运行 4.9 内核的 Alpine 3.9。我还在运行 4.15 的 Ubuntu 18.04 中重现了它,仅使用两个桥。

答案1

br_netfilter仅当加载模块并在相关网桥上启用 iptables时才会观察到此行为(请参阅/sys/class/net/*/bridge/nf_call_iptables/proc/sys/net/bridge/bridge-nf-call-iptables- 这些应用为逻辑 OR,因此您可以为系统上的每个网桥启用它,也可以为特定网桥启用它,您无法为特定网桥禁用它)。

通过此配置,当数据包到达第一个网桥时,NAT POSTROUTING 链将应用于数据包。此时,OUT设备为eth1_bridge,如问题中的日志消息所示,因此作为eth0_bridge输出接口的规则不起作用。设置太宽的 MASQUERADE 规则,使数据包在仍处于打开状态时被 MASQUERADE eth1_bridge,会导致 MASQUERADE,但源地址错误。

理论上的解决方案是在系统范围内的网桥上禁用 iptables,只在实际需要的地方启用它。遗憾的是,Docker 将其手指插入此处并强制(a)加载模块br-netfilter并(b)将 /proc/sys/net/bridge/bridge-nf-call-iptables 设置为 1。因为我们使用的是 docker在这个系统上,修复起来有点困难。我已经为此在 libnetwork 上提出了错误报告,并打算在第二天左右提交补丁来修复它。

答案2

我设置了一个测试环境来尝试重现您的问题。以下脚本设置三个网络命名空间来代表三个系统:

  • 您在问题中描绘的节点称为n0
  • gw附有eth0地址的系统173.31.0.1
  • n1附加到eth1地址 的系统192.168.100.100

它在主机上创建两个网桥来代表 192.168.100.0/24 网络和 173.31.0.0/24 网络。

里面的配置n0就如你所描述的那样。

#!/bin/sh

set -x

ip netns add gw
ip netns add n0
ip netns add n1

ip link add gw-eth0-out type veth peer name gw-eth0-in
ip link add n0-eth0-out type veth peer name n0-eth0-in
ip link add n0-eth1-out type veth peer name n0-eth1-in
ip link add n1-eth0-out type veth peer name n1-eth0-in

brctl addbr 192_168_100
brctl addbr 172_31_0

brctl addif 172_31_0 gw-eth0-out
brctl addif 172_31_0 n0-eth0-out
brctl addif 192_168_100 n0-eth1-out
brctl addif 192_168_100 n1-eth0-out

for iface in 172_31_0 192_168_100 gw-eth0-out n0-eth0-out n0-eth1-out n1-eth0-out; do
    ip link set $iface up
done

ip link set netns gw name eth0 gw-eth0-in
ip link set netns n0 name eth0 n0-eth0-in
ip link set netns n0 name eth1 n0-eth1-in
ip link set netns n1 name eth0 n1-eth0-in

ip netns exec gw ip addr add 172.31.0.1/24 dev eth0
ip netns exec gw ip link set eth0 up

ip netns exec n1 ip addr add 192.168.100.100/24 dev eth0
ip netns exec n1 ip link set eth0 up
ip netns exec n1 ip route add default via 192.168.100.1

ip netns exec n0 brctl addbr eth0_bridge
ip netns exec n0 brctl addbr eth1_bridge
ip netns exec n0 brctl addbr lan_bridge
ip netns exec n0 ip link add patch-eth1 type veth peer name patch-lan

ip netns exec n0 brctl addif eth0_bridge eth0
ip netns exec n0 brctl addif eth1_bridge eth1
ip netns exec n0 brctl addif eth1_bridge patch-lan
ip netns exec n0 brctl addif lan_bridge patch-eth1
ip netns exec n0 ip addr add 172.31.0.10/24 dev eth0_bridge
ip netns exec n0 ip addr add 192.168.100.1/24 dev lan_bridge
for iface in eth0 eth1 eth0_bridge eth1_bridge lan_bridge patch-lan patch-eth1; do
    ip netns exec n0 ip link set $iface up
done

当脚本运行完成后,我们将获得一个没有MASQUERADE规则的环境模型。正如预期的172.31.0.1那样,尝试 ping192.168.100.100将会失败。

如果我们将伪装规则添加到n0

ip netns exec n0 iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o eth0_bridge -j MASQUERADE

仍然ping失败。

如果我启用 ip 转发n0...

ip netns exec n0 sysctl -w net.ipv4.ip_forward=1

一切开始按预期进行。

相关内容