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

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

问题很简单,但我认为答案可能并不简单,因为我浏览过无数相关话题却没有得到具体的答复。

我希望将端口1234从转发x.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。如果y.y.y.y是某个内部 IP(例如在 上运行的 lxc 容器x.x.x.x),则相同的规则适用,并且容器能够看到实际的源 IP,但如果y.y.y.y是外部的,则看不到。

有什么方法可以实现这个目标吗?

答案1

仅使用 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 规则,但其“目的地”将是 y 的 VPN 地址,而不是公共地址。您可以为此使用任何隧道/VPN 类型,从基本的“IP-in-IP”到 GRE 到 OpenVPN 到 WireGuard。例如:

  • xxxxx

    启动隧道:

    ip link add gre-y type gre local x.x.x.x remote y.y.y.y ttl 64
    ip link set gre-y up
    ip addr add 192.168.47.1/24 dev gre-y
    

    添加端口转发规则,就像在 LAN 上一样:

    iptables -t nat -I PREROUTING -p tcp --dport 1234 -j DNAT --to-destination 192.168.47.2
    
  • 启动隧道:

    ip link add gre-x type gre local y.y.y.y remote x.x.x.x ttl 64
    ip link set gre-x up
    ip addr add 192.168.47.2/24 dev gre-x
    

    确保其有效:

    ping 192.168.47.1
    

    设置策略路由,以便回复(且只有回复)能够通过隧道:

    ip route add default via 192.168.47.1 dev gre-x table 1111
    ip rule add pref 1000 from 192.168.47.2 lookup 1111
    

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

答案2

不,你无法做到这一点。问题是路由不起作用。

主机E(外部)向主机(转发器)发送数据包FF将具有相同来源的数据包发送到主机D(目的地)。此部分有效,无论D是内部还是外部。

现在D必须返回一个答案,并将其发送到数据包中的源地址,即E

  • 如果D是内部主机,并且F是 的默认网关D,则数据包将通过F,其中应答数据包中的源D将更改为F。主机E看到来自 的数据包F,一切正常。
  • 如果D是外部主机,则F不会是 的默认网关D,因此D会将答案直接发送到E。主机E将从 获得答案D,但期望从 获得答案F,因此会丢弃来自 的数据包D。主机E将重试几次,将再次丢弃来自错误源地址的答案,并最终超时。

答案3

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

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

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

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

相关内容