![UDP 流量 DNAT 未按预期返回](https://linux22.com/image/794426/UDP%20%E6%B5%81%E9%87%8F%20DNAT%20%E6%9C%AA%E6%8C%89%E9%A2%84%E6%9C%9F%E8%BF%94%E5%9B%9E.png)
我正在寻找以下情况的解决方案。
有一台服务器 1,其公共接口为 eth0,IP 为 33.33.33.33,GRE 接口为 10.10.10.1,GRE 隧道指向第二台服务器 2,其公共接口为 44.44.44.44,GRE 接口为 10.10.10.2。
服务器1配置:
ip_wan:33.33.33.33
ip_gre:10.10.10.1
ip tunnel add gre1 mode gre 本地 33.33.33.33 远程 44.44.44.44 ttl 255
ip addr add 10.10.10.1/30 dev gre1
ip link set gre1 up
iptables -t nat -A POSTROUTING! -s 10.10.10.0/30 -o gre+ -j SNAT --to-source 10.10.10.1
iptables -t nat -A PREROUTING -d 33.33.33.33 -j DNAT --to-destination 10.10.10.2
iptables -A FORWARD -d 10.10.10.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -s 10.10.10.2 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -I INPUT -i gre+ -j ACCEPT
... 所有规则允许流量
server2配置:
ip_wan:44.44.44.44
ip_gre:10.10.10.2
ip tunnel add gre1 mode gre local 44.44.44.44 remote 33.33.33.33 ttl 255
ip addr add 10.10.10.2/30 dev gre1
ip link set gre1 up
ip route add default via 10.10.10.1 dev gre1 table GREP1
.... 所有规则都允许流量
进入服务器 1 的 TCP 流量被转发到服务器 2 并返回,并转换为服务器 1 的公网 IP。进入服务器 1 的 UDP 流量被转发到服务器 2 并通过服务器 2 上的公网 IP 而不是返回。我尝试了很多例子,但没有一个能按需要工作。任何能让我进一步发展的指针。
答案1
如果您在 PREROUTING 链上使用 DNAT,则有一条指导原则是,您通常在 POSTROUTING 链上使用 SNAT,并且它们需要应用于相同的数据包。您的 SNAT 完全错误,因为它们应用于不同的数据包。
我们先来检查一下DNAT:
iptables -t nat -A PREROUTING -d 33.33.33.33 -j DNAT --to-destination 10.10.10.2
这是正确的。来自互联网并发往路由器公共 IP 地址的数据包将经过 NAT,因此将被传送到 10.10.10.2。
但是,SNAT:
iptables -t nat -A POSTROUTING -s 10.10.10.0/30 ! -o gre+ -j SNAT --to-source 33.33.33.33
是错误的。特别是因为这里-o gre
部分被否定了。也许你想否定源地址?
另外,执行 SNAT 时,您需要将源更改为面向“下一跳”的路由器上的地址。
因此修正后的规则如下:
iptables -t nat -A POSTROUTING ! -s 10.10.10.0/30 -o gre+ -j SNAT --to-source 10.10.10.1
具体来说:
- 源(到目前为止尚未更改)不在 10.10.10.0/30 中
- 输出接口是“gre+”(即任何名称以“gre”开头的接口)
- 将数据包的源 IP 更改为 10.10.10.1,这是路由器面向 GRE 的地址
正如您所发现的,使用MASQUERADE
也有效,因为MASQUERADE
基本上是 SNAT,但会自动检测传出的 IP 地址,以防它是动态 IP 地址。但有一个问题:如果 GRE 隧道出现故障,全部NAT 跟踪将被刷新。阅读更多内容
如果传出接口的地址是静态的,尤其是在像您的场景中的隧道中,强烈建议使用 SNAT。