我有两台机器 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 是它的地址一样。

具体来说,我需要能够:

  1. 在机器 B 上接收与 A2 的连接,
  2. 从机器 B 使用 A2 发起新连接,并且
  3. 对某些传入连接执行 DNAT,并将它们重定向到 B“后面”的其他机器 C1..Cn。

我怎么做?


最佳答案
1

大多数隧道都可以以相同的方式处理它,但首先要设置一个 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)。

  1. 从 A 的任何接口上取消分配 A2。
  2. 使用 为 A2 启用代理 ARP ip neigh add ... proxy。(或者parpd如果您愿意,可以使用守护进程;无论哪个更容易配置。)
    不幸的是,systemd-networkd 的 [Neighbor] 无法替代“ip neigh add”——它仍然缺少与“proxy”标志等效的功能。
    注意:我建议使用“全面启用”proxy_arp 或 IPv4ProxyARP= sysctls——它们有点太宽泛了,您不想意外地将 A 的整个网络代理回自身。
  3. 使用 tcpdump 验证 A 是否仍然响应 A2 的 ARP 查询,例如当从外部 ping A2 并且 A 的上游网关尝试进行 ARP 查询时。tcpdump -e -n -i eth0 'arp'
  4. 通过 wg0 路由 A2/32。如果使用 wg-quick,它将在下一步根据 AllowedIPs 自动执行此操作。
  5. 更新 A 上的 wg0“AllowedIPs”,以内部将 A2/32 路由到代表 B 的 [Peer](这也导致 A 接受来自该对等方“来自 A2”的数据包)。
  6. 使用 tcpdump 验证发往 A2 的数据包是否通过 A 的 wg0 离开。
  7. 将 B 上的 wg0“AllowedIPs”更新为代表 A 的对等端上的 0.0.0.0/0,以便接受来自任何来源的数据包并在内部路由任何目的地的数据包。不要重新加载配置(如果您没有物理控制台访问权限)。
  8. 假设正在使用 wg-quick,请更新 B 的 wg0 配置,将“表”设置为当前未使用的路由表 ID。验证ip route list table X它是否通过 wg0(对应于 AllowedIPs)具有 0.0.0.0/0 路由。如果未使用 wg-quick,请手动添加该路由。
  9. 使用 tcpdump 验证发往 A2 的数据包是否到达 B 的 wg0。这必须在 AllowedIPs 之后完成。
  10. 将 A2/32 分配给 B 的 wg0 接口(或 B 的任何其他接口)。
  11. 在 B 上添加策略路由规则,以便为任何以 A2 为源的数据包选择表 X。例如,ip rule add from A2/32 lookup X或 systemd-networkd 的 [RoutingPolicyRule]。
  12. 使用 tcpdump 验证 B 现在正在回复 ping 并且这些回复正在通过其 wg0 发出。
  13. 使用 tcpdump 验证 A 是否通过其 wg0 接收这些回复并通过 WAN 接口将其转发至 pinger。
  14. B 现在就可以对数据包进行任何操作了。

对于任何隧道类型,步骤都非常相似,例如 GRE,减去“AllowedIPs”业务(GRE 或 IPIP 只有一个对等点,因此它们自动允许任何地址),减去相关的自动路由(而是手动创建它们)。

也可以采用不使用代理 ARP 的替代方法,其中 A2 仍分配给 A,但 A 对 B 的隧道地址进行全面 DNAT。这不会让 B“拥有”A2,但尽管如此,它还是很常见的,例如大型云提供商(GCE、EC2、Oracle)就是这样实现“浮动 IP”的,在家庭网关中也称之为“DMZ”。它仍然允许 B 进一步路由/DNAT 数据包。

2

  • 谢谢!这几乎回答了我关于此设置的所有问题。只有一件事:在 B 上作为“移植主机”使用哪个接口“最好”?我理解“任何”意味着“任何”,但我可以想象其他接口的生命周期的各种问题会干扰此地址分配,例如,如果我将其分配给 WAN 接口并且它暂时关闭,地址将消失等。是否可以创建一个不连接到任何东西的虚拟接口?或者我可以将 A2 直接添加到 wg0?


    – 


  • 由于此地址的数据包仅通过 wg0 到达(不涉及动态路由),因此将地址分配给 wg0 是最合适的——它几乎可以反映标准设置,其中 eth0 地址位于 eth0 接口上,等等(“lo”是我的第二选择)。如果您的目标只是将这些数据包路由或 DNAT 到更远的地方,而 B 从未直接使用它们,则根本不需要将地址分配给任何地方。


    –