我想在家里使用 RPi 作为 WireGuard VPN。不幸的是,我的 ISP 要求使用 CGNAT。我的计划是让 RPi 作为 WireGuard 对等体连接到我的服务器(使用静态 IP)。然后,我将我的客户端(我的手机)连接到服务器,并将其所有流量通过 RPi 通过服务器路由到互联网。
这张图表展示了我想要实现的目标:
我让 RPi 和客户端连接到服务器。但是,我不知道如何设置路由。我尝试在服务器上配置路由,以便当流量来自 上的10.6.0.0/24
(VPN 子网)时wg1
,将其重新路由回 上10.6.0.1
的(RPi)wg1
。这似乎不起作用。使用 tcpdump 查看,我发现来自客户端的数据包到达了服务器,但没有到达 RPi。
以下是我的配置的重要部分(全部以 PostUp 规则的形式显示在服务器上wg1.conf
):
ufw route allow in on wg1 out on wg1
ip rule add from 10.6.0.0/24 lookup 200
ip route add default via 10.6.0.1 dev wg1 table 200
iptables -t nat -I POSTROUTING -o wg1 -j MASQUERADE
RPi 也配置为应用 NAT(iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
)。
客户端配置为通过 WireGuard 路由所有内容(AllowedIPs = 0.0.0.0/0
)。
服务器和 RPi 都启用了 ip_forward。
答案1
您的路由部分via <gw>
在这里无法执行任何操作,因为 WireGuard 是 L3 隧道,内部不包含任何 L2(MAC)寻址。相反,WireGuard 接口本身会通过将目标 IP 地址与所有对等点的“AllowedIPs=”参数进行匹配来选择将数据包转发到哪个对等点。
因此,您只能通过 进行路由dev wg1
,并且AllowedIPs = 0.0.0.0/0, ::/0
所有内容都将转发到具有 的对等点。(如果指定了 'via' 参数,则将被忽略。)没有其他方法可以做到这一点。
(这种设计缺陷实际上将 WireGuard 隧道限制为每个接口只有一个“网关”。在某些情况下,您可能需要创建多个专用的 WireGuard 接口,每个接口都有一个将 AllowedIPs 设置为 /0 的对等体,以便能够从外部控制路由。)
我知道在 RPi AllowedIPs 上放置 0.0.0.0/0 应该会让客户端流量通过 RPi 路由,但服务器的全部流量也会被路由,这是不受欢迎的。
这不是由 AllowedIPs= 本身完成的,而是由您用来启动 WireGuard 隧道的辅助程序完成的。具体来说,它wg-quick
默认根据所有对等点的 AllowedIPs= 通过隧道创建系统级路由。
为了避免这种情况,请Table=
在 wg-quick 配置中指定将路线放在备用表中(或根本不放在任何地方)。
或者,通过 systemd-networkd 配置隧道(它也有类似的选项,但默认不创建任何路由)。
答案2
互联网网关作为辐条
我们有一个运行着 WireGuard 的端点,即端点 A,我们希望从该端点访问互联网。但是,在这种情况下,要从端点 A 访问互联网,WireGuard 流量需要经过两个跳跃:一个通过 VPN 集线器主机 C;第二个通过集线器的辐条主机 β。但是,虽然我们希望将主机 β 用作端点 A 的互联网网关,但我们不希望主机 C 也这样做 — 主机 C 本身可以根据需要使用站点 C 的默认路由访问互联网。带有互联网网关辐条的集线器
在我们的 WireGuard 网络中,端点 A 的 IPv4 地址为 10.0.0.1,IPv6 地址为 fd10:0:0:1::1;主机 C 的 IPv4 地址为 10.0.0.3,IPv6 地址为 fd10:0:0:3::1;主机 β 的 IPv4 地址为 10.0.0.2,IPv6 地址为 fd10:0:0:2::1。主机 C 的公共 IP 地址为 192.0.2.3,允许端点 A 和主机 β 各自建立到它的 WireGuard 隧道。
终点 A
在端点 A 上,当 WireGuard 网络启动时,我们希望通过主机 C 发送所有 Internet 流量,因此我们在端点 A 的 WireGuard 配置中为主机 C 配置 AllowedIPs = 0.0.0.0/0, ::/0:
# /etc/wireguard/wg0.conf
# local settings for Endpoint A
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.0.0.1/32, fd10:0:0:1::1/64
ListenPort = 51821
# remote settings for Host C
[Peer]
PublicKey = jUd41n3XYa3yXBzyBvWqlLhYgRef5RiBD7jwo70U+Rw=
Endpoint = 192.0.2.3:51823
AllowedIPs = 0.0.0.0/0, ::/0
0.0.0.0/0 是整个 IPv4 空间,而 ::/0 是整个 IPv6 空间。(如果您不关心 IPv6 流量,则可以从此配置和其他 WireGuard 配置中省略 IPv6 地址和地址块。)
主机C
在主机 C 上,我们希望将发往 10.0.0.1 或 fd10:0:0:1::/64 的所有流量发送到端点 A,并将通过我们的 WireGuard 网络的所有其他流量发送到主机 β。因此,我们在主机 C 上配置 WireGuard,其端点 A [Peer] 部分为 AllowedIPs = 10.0.0.1/32、fd10:0:0:1::/64,其主机 β [Peer] 部分为 AllowedIPs = 0.0.0.0/0、::/0。
但是,由于我们不希望主机 C 的所有流量都流向主机 β(仅希望流量通过 WireGuard 网络转发),因此我们通过接口的 Table = 123 设置将此 WireGuard 接口的路由配置为使用自定义路由表。然后,我们使用 PreUp 命令添加策略路由规则,指示主机仅将此表用于来自此 WireGuard 接口的流量(ip rule add iif wg0 table 123 priority 456):
# /etc/wireguard/wg0.conf
# local settings for Host C
[Interface]
PrivateKey = CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCGA=
Address = 10.0.0.3/32, fd10:0:0:3::1/64
ListenPort = 51823
Table = 123
# IPv4 forwarding & routing
PreUp = sysctl -w net.ipv4.ip_forward=1
PreUp = ip rule add iif wg0 table 123 priority 456
PostDown = ip rule del iif wg0 table 123 priority 456
# IPv6 forwarding & routing
PreUp = sysctl -w net.ipv6.conf.all.forwarding=1
PreUp = ip -6 rule add iif wg0 table 123 priority 456
PostDown = ip -6 rule del iif wg0 table 123 priority 456
# remote settings for Endpoint A
[Peer]
PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU=
AllowedIPs = 10.0.0.1/32, fd10:0:0:1::/64
# remote settings for Host β
[Peer]
PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds=
AllowedIPs = 0.0.0.0/0, ::/0
主机B
与之前的站点网关作为 Spoke 场景类似,在主机 β 上,我们希望将发往 10.0.0.0/24 和 fd10::/56 网络的所有流量通过主机 C 发送回去 — — 因此,我们在主机 β 的 WireGuard 配置中将其用作主机 C 的 AllowedIPs 设置:
# /etc/wireguard/wg0.conf
# local settings for Host β
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.0.0.2/32, fd10:0:0:2::1/64
ListenPort = 51822
# IPv4 forwarding
PreUp = sysctl -w net.ipv4.ip_forward=1
# IPv4 masquerading
PreUp = iptables -t mangle -A PREROUTING -i wg0 -j MARK --set-mark 0x30
PreUp = iptables -t nat -A POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE
PostDown = iptables -t mangle -D PREROUTING -i wg0 -j MARK --set-mark 0x30
PostDown = iptables -t nat -D POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE
# IPv6 forwarding
PreUp = sysctl -w net.ipv6.conf.all.forwarding=1
# IPv6 masquerading
PreUp = ip6tables -t mangle -A PREROUTING -i wg0 -j MARK --set-mark 0x30
PreUp = ip6tables -t nat -A POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE
PostDown = ip6tables -t mangle -D PREROUTING -i wg0 -j MARK --set-mark 0x30
PostDown = ip6tables -t nat -D POSTROUTING ! -o wg0 -m mark --mark 0x30 -j MASQUERADE
# remote settings for Host C
[Peer]
PublicKey = jUd41n3XYa3yXBzyBvWqlLhYgRef5RiBD7jwo70U+Rw=
Endpoint = 192.0.2.3:51823
AllowedIPs = 10.0.0.0/24, fd10::/56
PersistentKeepalive = 25
请注意,在主机 β 的主机 C 配置中,我们还添加了 PersistentKeepalive = 25 设置。这可确保主机 β 在主机 C 和主机 β 之间的任何 NAT(或仅出口)防火墙上打开一个漏洞,从而允许端点 A 通过 WireGuard 网络发起与主机 β 的连接。如果主机 C 和主机 β 之间没有 NAT 或仅出口防火墙,则可以省略此设置(但如果这样做,请确保将主机 C 的 WireGuard 配置设置为在其主机 β 的端点设置中包含主机 β 的公共 IP 地址)。
另请注意,我们在主机 β 的 WireGuard 配置中包含了一些 iptables 规则。当主机 β 将数据包转发到站点 B 时,这些 iptables 规则会伪装来自 WireGuard 网络的数据包。如果站点 B 的 LAN 路由器(或每个单独的端点)已配置为将发往 WireGuard 网络 (10.0.0.0/24) 的流量路由回主机 β,则可以省略这些规则。
测试一下
在每个主机(端点 A、主机 C 和主机 β)上启动我们配置的 WireGuard 接口后,我们可以从端点 A 运行 cURL(或常规网络浏览器)通过我们的 WireGuard 网络访问 Google(或任何其他互联网网站):`` $ curl google.com
301 已移动... ```参考 :
复制粘贴自https://www.procustodibus.com/blog/2022/06/multi-hop-wireguard/#internet-gateway-as-a-spoke(让我免于两周徒劳的搜寻……)