我有一个 Wireguard VPN 设置,基本上如下所示:
P1 ---- S ---- P2 --- Internet
IP 地址:
P1 = 10.200.1.5
S = 10.200.1.1
P2 = 10.200.1.3
allowedIps = 0.0.0.0/0
我通过在 P1 的客户端配置中指定将 P1 的所有流量重定向到 S。
现在我希望 S 将流量路由到 P2。我在 S 上尝试了以下操作:
ip rule add from 10.200.1.5 lookup 200
ip route add default via 10.200.1.3 dev wg0 table 200
sysctl -w net.ipv4.ip_forward=1
但是,当我在 P2 上运行 tcpdump 时,我看不到任何流入的流量。此外,P1 也没有任何互联网连接。
编辑:通过以下方式测试 S 上的自定义路由表
ip route get 8.8.8.8 from 10.200.1.5 iif wg0
给出以下响应
8.8.8.8 from 10.200.1.5 via 10.200.1.3 dev wg0 table 200
cache iif wg0
这看起来不错,但是
tcpdump -nn -i wg0
显示S
无法访问,如下所示
09:58:22.207251 IP 10.200.1.5.9134 > 8.8.8.8.53: 36555+ A? play.googleapis.com. (37)
09:58:22.207270 IP 10.200.1.1 > 10.200.1.5: ICMP host 8.8.8.8 unreachable, length 73
答案1
WireGuard 是第 3 层接口,因此声明via 10.200.1.3
没有效果,因为它将用于链路层协议(通常是 ARP)来解析此处不存在的第 2 层地址。
所以
ip route add default via 10.200.1.3 dev wg0 table 200
可以重写为:
ip route add default dev wg0 table 200
这有助于记住,这部分不是选择数据包前往 P1 或 P2 的部分:WireGuard 也有自己的内部路由:密钥路由,这可以通过在每个对等点的配置中正确设置来完成AllowedIPs
。有一个重要的限制:与标准路由相反,AllowedIPs
不支持任何重叠地址。如果尝试这样做(例如在服务器 S 上AllowedIPs = 0.0.0.0/0
为对等点 P2 设置),这将自动删除其他对等点上的冲突地址(例如AllowedIPs = 10.200.1.5
从对等点 P1 中删除,因为与0.0.0.0/0
其他任何地址重叠)并且连接将受到影响(S 不会将任何东西加密路由到 P1:不再有连接)。
有两种方法可以解决这个问题:
使用两个不同的 WireGuard 接口
先前的限制是针对每个 WireGuard 接口的。使用第二个接口可以避免此类冲突,但会使路由更加复杂。现在可能需要在路由表 200 和/或主表中添加多个条目:一个用于左侧接口,一个(默认)用于右侧接口。
对冲突的范围进行集合减法
可能确实有一些工具能够计算集合 0.0.0.0/0 和集合 10.200.1.5 之间的差异,但我不知道。还有一个方便的工具叫做
netmask
(主页:https://github.com/tlby/netmask) 通过将范围转换为最小的网络掩码集来提供帮助:$ netmask 0.0.0.0:9.255.255.255 10.200.1.3 11.0.0.0:255.255.255.255 0.0.0.0/5 8.0.0.0/7 10.200.1.3/32 11.0.0.0/8 12.0.0.0/6 16.0.0.0/4 32.0.0.0/3 64.0.0.0/2 128.0.0.0/1
这些是服务器 S 上应该为 Peer P2 使用的值(以逗号分隔),
AllowedIPs
因此加密密钥路由将在那里路由除 10.0.0.0/8 之外的任何内容,其中只有 10.200.1.3 将在 P2 端定义,而 P1 端已定义的 10.200.1.5 保持不变:不再重叠。P1 发送到 Internet 的数据包现在应该继续发送到 P2 进行进一步路由。
答案2
如果你想
P1 <--> S <--> P2 <--> Internet
其中 S 是“Wireguard 服务器”,P1 和 P2 是 Wireguard 对等体(假设位于 NAT 后面且未配置端口转发),“连接”到 S,P2 充当 P1 的互联网网关,首先需要进行以下基本设置:
P1 Wireguard 配置
[Interface]
PrivateKey = ...
Address = 10.200.1.5/32
[Peer] # S
PublicKey = ...
Endpoint = ...:51820
AllowedIPs = 0.0.0.0/0
S Wireguard 配置
[Interface]
ListenPort = 51820
PrivateKey = ...
Address = 10.200.1.1/32
[Peer] # P1
PublicKey = ...
AllowedIPs = 10.200.1.5
[Peer] # P2
PublicKey = ...
AllowedIPs = 0.0.0.0/0
P2 Wireguard 配置
[Interface]
PrivateKey = ...
Address = 10.200.1.3/32
[Peer] # S
PublicKey = ...
Endpoint = ...:51820
PersistentKeepalive = 25 # allows S to reach P2
AllowedIPs = 10.200.1.0/24
此外,确保在 S 和 P2 上启用了 IP 转发,并且当从 S1 转发的数据包在其面向互联网的网络接口上离开 P2 时,P2 执行必要的 NAT/伪装。
这应该已经奏效了,因为 P1 的互联网流量被转发到 P2。但是,现在 S 的互联网访问还通过 P2。这可能是不理想的。例如,您将无法通过互联网通过 SSH 进入 S,因为 S 会尝试通过 P2 进行响应(沿途使用 NAT 的非对称路由)。如果您不希望 S 本身使用 P2 作为网关,您可以像这样在 S 上手动配置基于策略的路由:
具有自定义基于策略的路由的配置
[Interface]
ListenPort = 51820
PrivateKey = ...
Address = 10.200.1.1/32
Table = 123 # <-- AllowedIPs-based routes end up here
PostUp = ip rule add from 10.200.1.0/24 table 123
PreDown = ip rule del from 10.200.1.0/24 table 123
[Peer] # P1
PublicKey = ...
AllowedIPs = 10.200.1.5
[Peer] # P2
PublicKey = ...
AllowedIPs = 0.0.0.0/0
这使得将基于的路由wg-quick
添加AllowedIPs
到自定义路由表(table 123
)并有条件地根据使用源 IP 地址“启用”此路由表ip rule
。
您可能还想在 S 上添加一些防火墙规则,例如,确保通过 Wireguard 传入的流量不会逃逸到任何地方,而只是转发到同一设备。您可以通过添加
PostUp = iptables -I FORWARD -i %i ! -o %i -j REJECT
PreDown = iptables -D FORWARD -i %i ! -o %i -j REJECT
到 S' 配置。