![在 iptables 中,MASQUERADE 是否仅在新连接(SYN 数据包)上匹配?](https://linux22.com/image/142785/%E5%9C%A8%20iptables%20%E4%B8%AD%EF%BC%8CMASQUERADE%20%E6%98%AF%E5%90%A6%E4%BB%85%E5%9C%A8%E6%96%B0%E8%BF%9E%E6%8E%A5%EF%BC%88SYN%20%E6%95%B0%E6%8D%AE%E5%8C%85%EF%BC%89%E4%B8%8A%E5%8C%B9%E9%85%8D%EF%BC%9F.png)
我观察到 MASQUERADE 目标与回复方向的数据包不匹配(就 netfilter conntrack 而言)。
我有一个简单的-t nat -A POSTROUTING -s 10.a.0.0/16 -d 10.b.0.0/16 -j MASQUERADE
规则,除了接受所有链上的策略之外没有其他规则,而且看起来
情况 1) 来自 10.a/16 网络的连接初始化尝试的 SYN 数据包经过 NAT(这是可以的),而
情况 2) 再次来自 10.a/16 网络的 SYN/ACK 数据包(响应来自 10.b/16 的 SYN,即在这种情况下发起者是 10.b/16)不会被转换,但 src 地址是保持原样,简单路由。
我不确定这是预期的行为还是我错过了什么?我的意思是我不希望它以任何其他方式表现,一切似乎都正常。但文档并没有向我证实这是 MASQUERADE 目标的出厂默认行为。
你能确认一下吗?谢谢。
答案1
TCP 连接的身份由四项内容定义:
- 端点A的IP地址
- 端点B的IP地址
- 端点A的端口号
- 端点B的端口号
TCP 协议标准规定,如果任何当这四件事发生变化时,数据包一定不能被视为同一连接的一部分。因此,如果初始 SYN 也未经过 NAT,则开始将 NAT 规则应用于 SYN/ACK 数据包是没有意义的。您必须从头到尾对整个连接应用相同类型的 NAT 映射,或者根本不对其进行 NAT;任何在连接中添加或更改 NAT 映射的尝试都只会导致 TCP 连接失败。这是 TCP 协议的基本事实,Linux iptables/netfilter 代码的设计就考虑到了这一点。
在您的情况 2) 中,SYN/ACK 前面是来自 10.b/16 的 SYN。该 SYN 的源为 10.b/16,因此它与 MASQUERADE 规则不匹配,并使用保持原样的地址进行路由。然后,如果将 SYN/ACK 从 10.a/16 转换回 10.b/16,原始SYN的发送者将不再将其识别为响应到它自己的 SYN,因为源 IP + 目标 IP + 源端口 + 目标端口组合将与有效响应的预期不同。
本质上,在 10.b/16 中发起连接的系统中的 TCP 协议驱动程序会思考:“唉。没有10.a.connection.destination
应答。并且10.b.NAT.system
明显虚假的 SYN/ACK 困扰着我:我正在尝试连接10.a.connection.destination
,如果我有时间,我会发送一两封 RST 给10.b.NAT.system
; 希望他意识到自己的错误并不再打扰我。”
答案2
MASQUERADE 只是带有传出接口源的 SNAT(源 NAT)(请参阅man iptables-extensions
.
连接尝试(初始 SYN)被 NAT 处理,然后在内核中跟踪该连接(“conntrack”),并且该连接中的所有数据包都以适当的方向进行 NAT 处理。
所以是的,对传入 SYN 的传出 SYN/ACK 应答不会被 SNAT 进行 NAT。如果您想要对传入 SYN 进行 NAT,则需要 DNAT,而不是 SNAT。这也会对 SYN/ACK 应答进行 NAT。
答案3
发生这种情况是因为当数据包进入相反方向时,它的源是 10.b/24,目标是 10.a/24,这意味着它不会被您的规则处理。您必须添加两条规则才能使 MASQUERADE 发生:
-t nat -A POSTROUTING -s 10.a.0.0/16 -d 10.b.0.0/16 -j MASQUERADE
-t nat -A POSTROUTING -s 10.b.0.0/16 -d 10.a.0.0/16 -j MASQUERADE