iptables 将端口/s 透明地转发到外部 IP(远程端应该看到实际的源 IP)

Sam*_*Sam 5 networking linux routing port-forwarding iptables

问题很简单,但我认为答案可能不是,因为我浏览了无数相关主题而没有具体答复。

我想转发端口1234x.x.x.xy.y.y.y(包括互联网上在不同的位置,即y.y.y.y是不是像一个内部IP10.a.b.c等)的方式,y.y.y.y能够获得原始的源IP连接x.x.x.x

现在,它x.x.x.x使用通常的 SNAT 或 MASQUERADE 规则将源 IP 视为源 IP。如果y.y.y.y是某个内部 IP(例如在其上运行的 lxc 容器x.x.x.x),则相同的规则起作用并且容器能够看到实际的源 IP,但如果y.y.y.y是外部IP,则无法看到。

这可以以任何方式实现吗?

use*_*686 6

只有 NAT - 没有。IP 数据包只有一个“源”字段。

  • 如果您让 iptables 保留原始客户端地址(仅限 DNAT),那么 yyyy 将尝试直接向该原始客户端发送回复(他认为它正在与 xxxx 交谈并且不希望来自 yyyy 的任何数据包)。

  • 如果你让 iptables 把你的地址作为新的源地址(DNAT+SNAT),那么 yyyy 就不会知道原来的源地址了。

(这实际上与尝试从 LAN 端口转发到同一 LAN 的问题相同,第二种方法称为“NAT 发夹”或“NAT 反射”。)


为了使这个工作,你需要一个 xxxx 和 yyyy 之间的隧道/VPN——将你收到的原始数据包包装在另一个发送到 yyyy 的 IP 数据包中,没有任何更改(然后将打开隧道数据包并查看原始来源) .

当然,这意味着您需要在两个系统上都有root 权限才能配置隧道。此外,目的地 (yyyy) 需要支持“策略路由”——Linux 和 FreeBSD pf 能够做到这一点。如果源地址是 VPN 地址,它需要一个规则来通过 VPN 路由所有内容。

您仍然需要 iptables DNAT 规则,但它的“到目的地”将是您的 VPN 地址,而不是公共地址。您可以为此使用任何隧道/VPN 类型,从基本的“IP-in-IP”到 GRE,再到 OpenVPN 到 WireGuard。例如:

(要使用其他隧道/VPN 类型,只需替换“启动隧道”部分。)


dav*_*dgo 2

您可能无法实现此目的,因为源地址用于返回数据包 - 因此,如果源地址位于 NAT 之后,则无法从更广泛的 Internet 访问它。

至少有两种常用的解决方法(需要额外的软件和配置) - 第一种是使用 VPN 绕过路由器,或者在路由器和目的地之间使用,以便目的地知道如何到达源。

对于 HTTP 和 HTTPS,不要使用 IPTABLES 防火墙规则,而是在路由器上使用(透明或常规)代理,并让代理服务器添加外部应用程序可以访问和处理的 X-FORWARDED-FOR 标头。

根据您的具体应用程序和防火墙,还可以通过修改请求来源的源端口来标记“相对”内部 IP 地址(它仍然来自路由器地址,但您可能可以获得根据源端口提示路由器后面的哪个系统发送它)。我还没有看到这个在实践中使用。