因此我们在课堂上使用 iptables,并且我一直在测试 NAT 表中的某些规则。据我所知,SNAT 会将数据包的 IP 源更改为规则所规定的 IP 源,但我测试的方法似乎并非每次都有效。
我添加了这条规则:iptables -t nat -A POSTROUTING -j SNAT --to 1.2.3.4
当我 ping 网络中的其他机器时,它们会收到来自 1.2.3.4 的数据包,这是正确的,因为我添加了上述规则。但是当这些机器 ping 时(知道防火墙机器 IP不是 1.2.3.4) 它的真实 IP 不会转换为新 IP,并且它们会回答其真实 IP,而不是 1.2.3.4。
我检查了 iptables 流程图,以防规则没有被执行,但我看到的似乎没问题。我想可能是因为它是一个传入数据包或类似的东西,但 POSTROUTING 不应该被执行每个包而不只是机器输出的那些?
我怎样才能让它认为是 1.2.3.4 机器回答了?通过翻译源代码可以实现吗?
答案1
表中的任何规则nat
都会针对每个第一的数据包联系。
当一个新的数据包到达时,系统会搜索连接跟踪表如果它属于已知连接。如果是这种情况,则将其分配给该连接并应用表中为该连接记录的转换。该表存储了足够的信息来识别连接的转发和回复数据包并对其进行转换。连接是双向的,两个流。nat
对于由连接跟踪器 ( ) 识别的数据包,不会遍历该表conntrack
。
但是,如果没有找到,则会在 conntrack 表中创建新记录,然后根据该nat
表处理数据包。如果请求转换,则会转换数据包并将信息记录到 conntrack 表中,以便后续转发和回复数据包以相同的方式进行转换。
如果发生超时,或者 TCP 连接已完成或已重置,则删除连接。对于无连接协议,什么被视为“连接”因情况而异。例如,对于 UDP,仅考虑地址、端口和超时。
您可以通过伪文件查看此表的当前内容/proc/net/nf_conntrack
。请注意,您可以看到具体翻译成了什么。您还可以使用辅助实用程序,例如conntrack-tools
或iptstate
。
请考虑此图。
所有数据包都将被转换。它们被转换,因为规则指示这样做。传出的数据包将按预期进行转换,其源地址将更改为 1.2.3.4,然后它们将被发送到原始目的地。
传入的数据包得到来源地址转换为 1.2.3.4,然后它们被路由到原始目的地。您已在路由之前设置了源转换(链SNAT
中的规则PREROUTING
),还记得吗?该规则适用于全部郵件。
我认为,本例中的目的地是 localhost。经过转换后,系统看到一个数据包从 1.2.3.4 进入到其自己的地址。
如果你在那里安装一个 HTTP 服务器并阅读它的访问日志,你会发现所有请求都是从 1.2.3.4 发出的。这是因为它只看到源地址转换后的数据包。真正的源被源 nat 隐藏了。
然后,如果它愿意回复,它会从自己的地址向 1.2.3.4 形成一个数据包。连接跟踪器(参见图中的“输出路径”)将其识别为对已知连接的回复,并根据它找到的表条目将其转换回来(但请注意,现在它将目标地址从 1.2.3.4 更改为它在表中找到的地址,因为它是一个回复)。然后回复数据包被重新路由并发送给原始发送者。
不能转换答复数据包的源地址 — — 没有指令要求这样做。
为了避免这种令人困惑的效果,您总是将传出接口匹配添加到 SNAT 规则中。例如,iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 1.2.3.4
。
如果您转换传入的数据包,则可以实现有趣的效果,例如,您可以使来自远程主机的数据包看起来是从 LAN 发送的,但这种规则的匹配度会非常严格,至少要有一个您希望显示为本地的源 IP 和一个用作其别名的 LAN 中的地址。该地址可能与您在一般 SNAT 规则中使用的地址不同。