问题很简单,但我认为答案可能并不简单,因为我浏览过无数相关话题却没有得到具体的答复。
我希望将端口1234
从转发x.x.x.x
到y.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
(外部)向主机(转发器)发送数据包F
。F
将具有相同来源的数据包发送到主机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 地址(它仍然来自路由器地址,但您可能能够根据源端口提示路由器后面的哪个系统发送了它)。我还没有看到这种做法在实践中使用。