我有两台机器 A 和 B。A 是具有全局可路由的 IPv4 和 IPv6 地址的 VPS,B 是位于运营商级 NAT 后面的物理服务器:
A
:- IPv4 地址 A1 和 A2(链路上);
- IPv6 前缀 A3::/56(路由)。
B
在 RFC 6598 100.64.0.0/10 地址块中仅有一个 IPv4 地址 B1。
A 和 B 位于不同的网络、不同的 ISP 上,除了 A1 和 A2 可以从 B 访问之外,没有任何共同之处。
我需要在 A 和 B 之间配置一个隧道,使得 B 表现得好像A2 是它的地址一样。
具体来说,我需要能够:
- 在机器 B 上接收与 A2 的连接,
- 从机器 B 使用 A2 发起新连接,并且
- 对某些传入连接执行 DNAT,并将它们重定向到 B“后面”的其他机器 C1..Cn。
我怎么做?
大多数隧道都可以以相同的方式处理它,但首先要设置一个 WireGuard 隧道,因为它是基于 UDP 的,并且比原始 GRE 更有可能通过 (CG)NAT。(或者,GRE-over-IPsec 也可以工作,因为 IPsec 将自动使用 UDP 封装,为您提供 GRE-ESP-UDP。我相信 L2TP 和 VXLAN 也可以正常工作,因为它们都是基于 UDP 的。)
此外,由于 (CG)NAT 否则会丢失对空闲流的跟踪,因此需要某种类型的保持活动,WireGuard 的内置“PersistentKeepalive”将非常方便。启用从 B(在代表 A 的 [Peer] 上)发送保持活动数据包,因为它是需要“打通”的数据包。
隧道建好后:
对于 IP 地址,路由到 B 很简单;您实际上是通过隧道接口路由该地址。
更重要的是让 B 也通过该隧道路由回复。如果 B 能够做到这一点,最好使用“策略路由”,尽管在紧急情况下可以使用 A 上的 SNAT(如在“NAT 发夹”情况下所见)。(Linux 还实现了第三个更简单的选项,即源特定路由,但仅适用于 IPv6;不适用于 IPv4。)
“On-link” 表示原始服务器仍需要为 A2 应答 ARP 查询,其他方面没有区别。如果 A2 没有直接分配给 A 上的接口,那么 A 无论如何都需要代表其应答(代理 ARP)。
ip neigh add ... proxy
。(或者parpd
如果您愿意,可以使用守护进程;无论哪个更容易配置。)不幸的是,systemd-networkd 的 [Neighbor] 无法替代“ip neigh add”——它仍然缺少与“proxy”标志等效的功能。
注意:我不建议使用“全面启用”proxy_arp 或 IPv4ProxyARP= sysctls——它们有点太宽泛了,您不想意外地将 A 的整个网络代理回自身。
tcpdump -e -n -i eth0 'arp'
ip route list table X
它是否通过 wg0(对应于 AllowedIPs)具有 0.0.0.0/0 路由。如果未使用 wg-quick,请手动添加该路由。ip rule add from A2/32 lookup X
或 systemd-networkd 的 [RoutingPolicyRule]。对于任何隧道类型,步骤都非常相似,例如 GRE,减去“AllowedIPs”业务(GRE 或 IPIP 只有一个对等点,因此它们自动允许任何地址),减去相关的自动路由(而是手动创建它们)。
也可以采用不使用代理 ARP 的替代方法,其中 A2 仍分配给 A,但 A 对 B 的隧道地址进行全面 DNAT。这不会让 B“拥有”A2,但尽管如此,它还是很常见的,例如大型云提供商(GCE、EC2、Oracle)就是这样实现“浮动 IP”的,在家庭网关中也称之为“DMZ”。它仍然允许 B 进一步路由/DNAT 数据包。