我在设置 3 个节点之间的路由时遇到了一些困难。情况如下:
- A、B 和 R 是 wireguard(wg0)对等体
- R 是一个公共中心(vpn.example.com),IP 为 172.0.0.1
- A 是与 R 连接的对等体,其 IP 为 172.0.0.10
- B 是与 R 连接的对等体,其 IP 为 172.0.0.20
- B 也连接到 IP 为 192.168.1.20 的 LAN
- C 是同一局域网内的主机,IP 为 192.168.1.30
- R 上的防火墙接受 wg0 和公共网络上通往 wireguard(51820/udp)的流量。
我希望路由流量以便 A 和 C 可以通信,并且从 A 可以访问 192.168.1.30。
我天真地想到以这种方式设置路由:
B# sysctl net.ipv4.ip_forward=1
A# ip route add 192.168.1.30/32 via 172.0.0.20 dev wg0
C# ip route add 172.0.0.10/32 via 192.168.1.20 dev eth0
但这不起作用:如果我tcpdump
在 A 上进行流量,我可以看到从 A 到 C 的包裹:
A# tcpdump -n -l -i wg0 | grep 192
17:27:47.492184 IP 172.0.0.10 > 192.168.1.30: ICMP echo request, id 10, seq 1, length 64
17:52:36.908342 IP 172.0.0.10 > 192.168.1.30: ICMP echo request, id 10, seq 2, length 64
17:52:37.921042 IP 172.0.0.10 > 192.168.1.30: ICMP echo request, id 10, seq 3, length 64
17:52:37.932100 IP 172.0.0.10 > 192.168.1.30: ICMP echo request, id 10, seq 4, length 64
但没有答案,甚至看起来这些数据包永远无法到达 R,即使路由设置显然正确:
A# ip route get 192.168.1.30
192.168.1.30 dev wg0 src 172.0.0.20 uid 1000
cache
所以我认为可能是 wireguard。有一个AllowedIPs
选项可能有用,所以我更改了配置,如下所示:
# wg0.conf on A and B
[Interface]
Address = 172.0.0.10/24
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAA
[Peer]
PublicKey = rrrrrrrrrrrrrrrrrrrrrrrrrr
Endpoint = vpn.example.com:51820
AllowedIPs = 172.0.0.0/24, 192.168.1.30/32 # added second addr
在 RI 上将其更改为如下形式:
# wg0.conf on R, the VPN hub
[Interface]
Address = 172.0.0.1/24
PrivateKey = RRRRRRRRRRRRRRRRRRRRRRRRRR
[Peer]
PublicKey = aaaaaaaaaaaaaaaaaaaaaaaaaa
AllowedIPs = 172.0.0.10/32, 192.168.1.30/32 # added second addr
[Peer]
PublicKey = bbbbbbbbbbbbbbbbbbbbbbbbbb
AllowedIPs = 172.0.0.20/32, 192.168.1.30/32 # added second addr
并在所有主机上重新启动 wireguard。
现在我可以看到一些流量从 A 流向 R,但是似乎没有到达 B:
A# tcpdump -n -l -i wg0 | grep 192.168
...
18:11:15.421908 IP 172.0.0.10 > 192.168.1.30: ICMP echo request, id 25, seq 50, length 64
...
R# tcpdump -n -l -i wg0 | grep 192.168
...
18:11:15.421908 IP 172.0.0.10 > 192.168.1.30: ICMP echo request, id 25, seq 50, length 64
...
B# tcpdump -n -l -i wg0 | grep 192.168
B 上的路线似乎不正确:
B# ip route get 192.168.1.30
192.168.1.30 dev wg0 src 172.0.0.20 uid 30042
cache
...事实上,我无法再从 B ping C...但这是意料之中的,因为我更改了 B 的 wireguard 配置中的路由。所以我将其回滚,B 可以 ping C,但仍然没有收到数据包。
现在我陷入了困境:我不明白发生了什么,为什么数据包没有被路由到 B。另外,我不确定从 wg0 到 B 的数据包应该如何路由到 eth0 到 C:B 是否需要路由表中的其他条目,或者是否sysctl net.ipv4.ip_forward=1
答案1
WireGuard 是一个第 3 层接口(此接口上的最低层是 IPv4(或 IPv6))。这意味着没有网关在该接口的 Linux 路由堆栈中。在这样的接口上使用任何网关参数(有效但被忽略)只会导致其含义混淆。WireGuard 本身使用对等体和AllowedIPs
来扮演相关(但不相同)的角色,而路由堆栈对此一无所知。
因此,一旦创建了接口,除了已经自动添加接口地址的“LAN”路由之外,路由堆栈至少还需要这样做(重写时无需网关wg0
):
R# sysctl net.ipv4.conf.wg0.forwarding=1 # will be a one-armed router
B# sysctl net.ipv4.ip_forward=1 # or else as above with eth0 + wg0
A# ip route add 192.168.1.30/32 dev wg0
C# ip route add 172.0.0.10/32 via 192.168.1.20 dev eth0
可选地,C 也可以从中受益(例如:traceroute
当rp_filter=1
)改为获取 172.0.0.0/24 的完整路由:
C# ip route add 172.0.0.0/24 via 192.168.1.20 dev eth0
现在谈谈AllowedIPs
参数。解释如下:WireGuard 加密密钥路由。
在服务器配置中,每个对等体(客户端)将能够将数据包发送到具有与其相应的允许 IP 列表匹配的源 IP 的网络接口。
在服务器配置中,当网络接口想要将数据包发送到对等方(客户端)时,它会查看该数据包的目标 IP,并将其与每个对等方的允许 IP 列表进行比较,以确定将其发送到哪个对等方。
相同的AllowedIPs
值既充当传入过滤器(第一个引号),又充当传出对等选择器(第二个引号)。最后一个角色是我在上面描述的与网关相关但不完全相同的角色。
不能有重叠,因为 IP 地址映射到一对等体(或 none 会收到网络错误消息,例如ENOKEY
( Required key not available
)),再也不会出现这种情况。尝试在多个对等体上使用相同的 IP 地址是没有意义的。这只会默默地删除前一个对等体的条目,并使整体配置错误。
因此,A、R、B(实际上并不是需要,但对于很有用traceroute
)之间以及 A 和 C 通过 R 之间的通信配置是:
在 A:
[Peer] PublicKey = rrrrrrrrrrrrrrrrrrrrrrrrrr [...] AllowedIPs = 172.0.0.0/24,192.168.1.30/32
A 期望来自 R 的任何源 172.0.0.0/24(当前仅存在 R 和 B 的地址,因此可以写入它们而不是整个 /24)加上来自 R 的 192.168.1.30。
在 B 上:
[Peer] PublicKey = rrrrrrrrrrrrrrrrrrrrrrrrrr [...] AllowedIPs = 172.0.0.0/24
B 期望 R 提供任意 172.0.0.0/24(目前只有 R 和 A 的地址存在,因此可以写入它们而不是整个 /24)。B 不会在任何地方使用 192.168.1.30:它是来自eth0(因此未经 WireGuard 验证)并且也不是通过WG0:它不应该出现在配置中(尽管如果它出现了,除了让读者感到困惑之外,这不会造成任何有害的影响)。
在 R 上:
[Peer] PublicKey = aaaaaaaaaaaaaaaaaaaaaaaaaa AllowedIPs = 172.0.0.10/32 [Peer] PublicKey = bbbbbbbbbbbbbbbbbbbbbbbbbb AllowedIPs = 172.0.0.20/32,192.168.1.30/32
这里不能再使用快捷方式 172.0.0.0/24:每个地址都必须出现在正确的对等点上。R 期望源 192.168.1.30 来自对等点 B,而不是来自对等点 A:它必须位于对等点 B 上,而不能位于对等点 A 上。