如何将所有流量转发/NAT 到一个接口/IP 到远程 IP?

Dan*_*sta 7 networking linux firewall nat ip-forwarding

我有一个“服务器 A”,它附加了多个 IP,如下所示:

eth0:0 1.1.1.1
eth0:1 1.1.1.2
eth0:2 1.1.1.3
Run Code Online (Sandbox Code Playgroud)

我有另一个“服务器 B”,它也附加了多个 IP,如下所示:

eth0:0 2.2.2.1
eth0:1 2.2.2.2
eth0:2 2.2.2.3
Run Code Online (Sandbox Code Playgroud)

现在,我想在“服务器 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
Run Code Online (Sandbox Code Playgroud)

但是如果我把“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
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

编辑 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
Run Code Online (Sandbox Code Playgroud)

然而,现在出现了另一个问题。服务器 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 发出流量。它被我的提供商锁定在路由器中。

小智 6

对您修改后的问题的简短回答是有两种方法可以做到;两者都要求您删除第二个 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% 的信心。

要理解这一点,您需要了解交通流。

  1. 客户端 X 向 1.1.1.3 发送数据包。
  2. 服务器 A 将该数据包的目的地 NAT 到 2.2.2.3 路由前,然后将流量路由到 2.2.2.3,然后将该数据包的源 NAT 到 1.1.1.3 路由后,然后将数据包发送到服务器 B。
  3. 根据第二个 NAT 步骤,服务器 B 在 2.2.2.3 上接收数据包并看到源地址为 1.1.1.3。它处理数据包并将回复发送回其源 (1.1.1.3)。
  4. 服务器 A 在 1.1.1.3 上收到数据包,反向源 NAT,路由数据包,反向目标 NAT,并将数据包发送回客户端 X。
  5. 客户端 X 收到来自 1.1.1.3 的响应

现在让我们想象一下如果没有第二个 NAT 会发生什么:

  1. 客户端 X 向 1.1.1.3 发送数据包。
  2. 服务器 A 将该数据包的目的地 NAT 到 2.2.2.3 预路由,然后将流量路由到 2.2.2.3,但在将数据包发送到服务器 B 时将源地址保留为 X。
  3. 服务器 B 在 2.2.2.3 上收到数据包并看到 X 的源地址。它处理数据包并将回复发送回其源 X。
  4. 客户端 X 收到来自 2.2.2.3 的响应并丢弃它,因为它不知道来自 Adam 的 2.2.2.3!

为了让客户端 X 理解数据包,它需要使用与原始数据包的目的地相同的源地址到达客户端 X。

发生这种情况的正常方式是服务器 B 有机会反转预路由 NAT。为此,您需要数据包在以后通过它。目前,您通过更改数据包的源地址来做到这一点,但这会破坏您在修改后的问题中要求的信息。

所以你的答案的第一步是,你不能做第二个 NAT 步骤(路由后 SNAT):在服务器 A 上运行iptables -t nat -D POSTROUTING -j SNAT --to 1.1.1.3

现在,您将面临逆转第一个 NAT 步骤的挑战。

如果服务器 B 要这样做,您需要服务器 B 来接收数据包。

  • 如果服务器 A 的地址 C 与服务器 B 位于同一 LAN 上,则这相对容易。在服务器 B 上:ip route replace default via C, OR ip route add default via C table a; ip rule add from 2.2.2.3 table a
  • 否则,您必须对隧道做一些奇特的事情。

但是,如果服务器 B 所在位置的路由器不是特别复杂(有状态地检查数据包并拒绝已知流量流中顺序不正确的数据包),那么您有一个稍微简单的,如果超级丑陋的选项:反转 NAT在服务器 B 基于您对服务器 A 所做操作的了解:在服务器 B 上iptables -t nat -I POSTROUTING -j SNAT -s 2.2.2.3 --to 1.1.1.3应该按照建议的示例进行操作。这将使 A 和 B 的 Linux 连接跟踪系统有些困惑(服务器将无法将返回流量与传入流量相关联,因此它们的连接跟踪将使连接处于 UNREPLIED 状态),但它应该可以正常工作到数百个兆位。

在这种情况下最后一次穿过交通流:

  1. 客户端 X 向 1.1.1.3 发送数据包。
  2. 服务器 A 将该数据包的目的地 NAT 到 2.2.2.3 预路由,然后将流量路由到 2.2.2.3,但在将数据包发送到服务器 B 时将源地址保留为 X。
  3. 服务器 B 在 2.2.2.3 接收数据包并看到 X 的源地址。它处理数据包并将回复路由回其源 X,但在将其发送出去之前,源地址的路由后 NAT 到 1.1.1.3 .
  4. 客户端 X 收到声称来自 1.1.1.3 的响应并且很高兴。


elt*_*rai 0

由于您希望服务器充当路由器,因此您需要检查一些事项:

首先,必须在内核中启用数据包转发(默认情况下不是):

echo "1" > /proc/sys/net/ipv4/ip_forward
Run Code Online (Sandbox Code Playgroud)

您还需要确保 iptables 允许转发流量(查看您的 FORWARD 链)。

这一规则和 DNAT 规则应该足以使数据包沿一个方向流动。但是,如果您需要 TCP 流,您还必须确保您还具有您提到的 SNAT 规则(否则,远程主机会认为存在问题,因为 2.2.2.3 的服务器正在回复他发送的数据包如 1.1.1.3)。

顺便说一句,出于性能原因,如果您有静态 IP,最好使用 SNAT 代替 MASQUERADE。