我有一个“服务器 A”,它连接了多个 IP,如下所示:
eth0:0 1.1.1.1
eth0:1 1.1.1.2
eth0:2 1.1.1.3
我还有另一个“服务器 B”,它也连接了多个 IP,如下所示:
eth0:0 2.2.2.1
eth0:1 2.2.2.2
eth0:2 2.2.2.3
现在,我想在“服务器 A”上设置 iptables,以将“eth0:2”上的所有传入流量转发/NAT 到“服务器 B”上的 IP 2.2.2.3。
我已经验证“服务器 A”能够通过 IP 2.2.2.3 与“服务器 B”进行“通信”。Ping 和 telnet 打开端口工作正常,并且我已打开转发标志 (net.ipv4.ip_forward=1)
我尝试了多种不同的方法,DNAT、SNAT、MASQUERADE 等,但都无法奏效。
如果我尝试在同一台服务器上的 IP 之间转发流量,此行可以正常工作:
iptables -t nat -A PREROUTING -d 1.1.1.3 -j DNAT --to-destination 1.1.1.2
但是如果我将“1.1.1.2”换成“2.2.2.3”,它就不起作用。
我认为我需要第二个 iptable 规则来解决这个问题。我尝试过以下 POSTROUTING 规则,但没有成功(不是同时尝试):
iptables -t nat -A POSTROUTING -d 2.2.2.3 -j MASQUERADE
iptables -t nat -A POSTROUTING -d 2.2.2.3 -j SNAT --to 1.1.1.3
iptables -t nat -A POSTROUTING -j MASQUERADE
我错过了什么?
编辑1:
我最终通过使用以下命令使其工作:
net.bridge.bridge-nf-call-iptables=0
iptables -t nat -A PREROUTING -d 1.1.1.3 -j DNAT --to-destination 2.2.2.3
iptables -t nat -A POSTROUTING -d 2.2.2.3 -j SNAT --to 1.1.1.3
但是现在又出现了另一个问题。服务器 2.2.2.3 上的所有日志等都显示所有流量现在都来自 1.1.1.3,如 apache 日志、邮件日志等。我认为这是 NAT 的本质。
但是,当我在家用路由器上对运行 Apache 的笔记本电脑进行标准端口转发时,我在日志中看到了原始的“请求者 IP”。那么,路由器是如何做到这一点的?我如何在服务器设置上做同样的事情?
底线是,我想将所有流量从服务器 A(1.1.1.3)转发到服务器 B(2.2.2.3),但我还希望能够看到流量来自服务器 B(2.2.2.3)的哪个位置,即 apache 日志应该显示请求者的原始 IP。
我认为我应该使用 NAT 以外的其他方式来实现这一点,而且这应该是可能的,因为即使是我的简单家用路由器也可以做到这一点。
另外,服务器 A 和服务器 B 所连接的 IP 被锁定到各自的服务器。因此,服务器 A 无法从 IP 2.2.2.3 发送流量。它被我的提供商在路由器中锁定。
答案1
对你修改后的问题的简短回答是,有两种方法可以做到这一点;两者都需要你删除第二个 NAT 步骤(这会破坏你正在寻找的信息)。完成此操作后,你的选择是:
1) 将服务器 A 设置为所讨论流量的服务器 B 的下一跳,这就是它适用于您的路由器的原因。这可以通过将服务器 A 设置为服务器 B 的默认路由来实现,或者使用策略路由或使用一些花哨的 iptables或者使用某种隧道。
2) “手动”在服务器 B 上反转服务器 A 的 NAT,导致流量不对称(一般不建议这样做)。例如iptables -t nat -I POSTROUTING -j SNAT -s 2.2.2.3 --to 1.1.1.3
我对选项 (1) 有 100% 的信心。我对选项 (2) 有 90% 的信心。
要理解这一点,您需要了解流量流。
- 客户端 X 向 1.1.1.3 发送数据包。
- 服务器 A 在路由前将该数据包的目标 NAT 为 2.2.2.3,然后将流量路由到 2.2.2.3,在路由后将该数据包的源 NAT 为 1.1.1.3,然后将数据包发送到服务器 B。
- 服务器 B 在 2.2.2.3 上接收数据包,并根据第二个 NAT 步骤看到源地址为 1.1.1.3。它处理数据包并将回复发送回其源(1.1.1.3)。
- 服务器 A 在 1.1.1.3 上接收数据包,反转源 NAT,路由数据包,反转目标 NAT,并将数据包发送回客户端 X。
- 客户端 X 收到来自 1.1.1.3 的响应
现在让我们想象一下如果没有第二个 NAT 会发生什么:
- 客户端 X 向 1.1.1.3 发送数据包。
- 服务器 A 将该数据包的目标 NAT 为 2.2.2.3 预路由,然后将流量路由到 2.2.2.3,但在将数据包发送到服务器 B 时将源地址保留为 X。
- 服务器 B 在 2.2.2.3 上接收数据包并看到源地址 X。它处理该数据包并将答复发送回其源 X。
- 客户端 X 收到来自 2.2.2.3 的响应并将其丢弃,因为它不知道来自 Adam 的 2.2.2.3!
为了让客户端 X 能够理解该数据包,它需要使用与原始数据包的目的地相同的源地址到达客户端 X。
正常情况下,服务器 B 有机会逆转预路由 NAT。要做到这一点,您需要让数据包稍后再通过它。目前,您可以通过更改数据包的源地址来实现这一点,但这会破坏您在修改后的问题中要求的信息。
所以你答案的第一步是,你不能在服务器 A 上运行第二个 NAT 步骤(后路由 SNAT)iptables -t nat -D POSTROUTING -j SNAT --to 1.1.1.3
:。
现在您面临的挑战是逆转第一步 NAT。
如果服务器 B 要执行此操作,则需要服务器 B 接收数据包。
- 如果服务器 A 在与服务器 B 相同的 LAN 上具有地址 C,则这相对容易。在服务器 B 上:
ip route replace default via C
,或ip route add default via C table a; ip rule add from 2.2.2.3 table a
。 - 否则你就得用隧道做一些奇特的事情。
但是,如果服务器 B 处的路由器不是特别复杂(状态检查数据包并拒绝不符合已知流量顺序的数据包),则您有一个稍微简单(但非常丑陋)的选择:根据您对服务器 A 上所做工作的了解,在服务器 B 上反转 NAT:在服务器 B 上iptables -t nat -I POSTROUTING -j SNAT -s 2.2.2.3 --to 1.1.1.3
应该执行建议的示例。这将使 A 和 B 上的 Linux 连接跟踪系统有些困惑(服务器将无法将返回流量与传入流量关联,因此它们的连接跟踪将使连接处于未回复状态),但它应该可以很好地处理数百兆位的大多数流量。
在这种情况下,最后一次穿过交通流:
- 客户端 X 向 1.1.1.3 发送数据包。
- 服务器 A 将该数据包的目标 NAT 为 2.2.2.3 预路由,然后将流量路由到 2.2.2.3,但在将数据包发送到服务器 B 时将源地址保留为 X。
- 服务器 B 在 2.2.2.3 上接收数据包并看到源地址 X。它处理该数据包并将答复路由回其源 X,但在发送之前,会将源地址的后路由 NAT 执行为 1.1.1.3。
- 客户端 X 收到声称来自 1.1.1.3 的响应并且很高兴。
答案2
由于您希望服务器充当路由器,因此您需要检查以下几件事:
首先,必须在内核中启用数据包转发(默认情况下不启用):
echo "1" > /proc/sys/net/ipv4/ip_forward
您还需要确保 iptables 允许转发流量(查看您的 FORWARD 链)。
此规则和 DNAT 规则应该足以使数据包单向流动。但是,如果您需要 TCP 流,您还必须确保您还具有您提到的 SNAT 规则(否则,远程主机会认为存在问题,因为位于 2.2.2.3 的服务器正在以 1.1.1.3 的身份回复他发送的数据包)。
顺便说一句,出于性能原因,如果您有静态 IP,最好使用 SNAT 代替 MASQUERADE。