WireGuard 跨国组网失败后,一个新工具的诞生

236 天前
 lanthora

TL;DR

一个可靠,低延迟,反审查的组网工具

背景

我在国外有一台性能非常弱但是有公网 IP 的 VPS. 国内有一台 7*24 小时开机的 mini 主机.让 mini 主机作为 VPS 的后端,不在 VPS 上存放任何数据,解决了 VPS 性能弱的问题,也解决了替换 VPS 供应商时迁移数据的问题(当然也包括对 VPS 供应商的信任问题).

最初选择的组网方案是 WireGuard, 它平静的陪伴了我几个年头,直到 2023 年某此会议的召开.原因为会议开完我的 WireGuard 就能继续用,一个月后证明我想多了.

于是决定解决这个问题.调研了一系列项目后,没有找到天生隐藏协议特征的组网工具(可能设计者设计之初也没有考虑这种问题把).把 VPN 套到 Proxy 里的这种诡异方案也称试过,虽然能用,但是很不喜欢

整体设计思路

设计的宗旨是简洁.在不牺牲性能和核心功能的情况下,用最少的代码量和最简单的概念完成设计.

降低配置复杂度

WireGuard 在 VPN 里配置已经相对较简单了,但对我来说依旧过于复杂.回忆一下你用多长时间完成的第一次 WireGuard 组网. WireGuard 需要强制指定虚拟地址,不适用于想要灵活接入多个客户端并动态分配地址的场景.

用 WSS(Web Socket Secure) 处理通信,在保证链路数据安全的情况下,免去了配置公私钥的过程. 用口令校验客户端,可以轻松的让新客户端加入网络,这样就能由服务端实现地址动态分配.

高效的断线重连

在某些情况下 WireGuard 会断线,只有重启客户端才能解决.此时对于一个无人值守的设备,就意味着彻底失联. 曾经为了解决这个问题,给设备配置每天重启一次,这显然是一种很丑陋的解决方案.

使用 WSS 通信,就可以用 Ping/Pong 完成 TCP 保活,即使 TCP 连接异常断开,应用也可以及时发现,迅速处理.

支持内网穿透的对等连接

虽然 WireGuard 支持对等连接,但要求设备之间能够直接访问,对于双方都在 NAT 后面的情况无能为力. 增加内网穿透功能,可以节约服务端转发的流量,同时还能降低通信延迟.

内网穿透通过 STUN 服务器获取本地 UDP Socket 被映射后的公网地址和端口,通过服务端与其他客户端交换地址和端口信息,并尝试建立连接.

高速的中继路由

有时候两个客户端之间无法直连,但它们都能与另一个客户端直连.此时可以以这个客户端作为中继相互访问.

这实际上是路由的问题.本项目实现的是距离向量算法.

局域网对等连接

通过 STUN 查到的用于对等连接的地址是公网地址,对于局域网内能够直连的设备来说,绕到最外层的路由器再回来是浪费了时间的,并且还会受到公网带宽的限制.

通过用户配置或主动探测本机的局域网地址,可以优先尝试本地直连.

总结

其实最初的版本只有 WSS 中继功能,后来在用户的反馈中加上了 P2P 和利用网络中的其他客户端做中继的功能.新增的功能我自己也能用得上,体验上也有巨大的提升.

有一些其他的组网工具有着极其丰富的功能,而我的设计初衷是让两台装了客户端的机器能够简单快速稳定的通信,因此舍弃了很多功能,甚至用"口令"这种在现代视角看上去不够零信任的方式鉴权.

13147 次点击
所在节点    宽带症候群
86 条回复
lanthora
236 天前
@KanVivii github 上有邮箱,邮件联系吧
lanthora
236 天前
@blankmiss 有没有一种可能, tailscale 底层用的是 wg, 对我来说这个协议不可用

补充: 换端口或者其他服务是正常的,显然被针对的是 wg
s82kd92l
236 天前
最近一直在找有没有利用 stun/ice 完成 udp duplex 传输的工具,就是只负责包转发,不负责上层的加密/tun/路由。找到好多项目都是基于 webrtc 的 datachannel, 其基于 sctp over udp ,很重且不稳定。

看到楼主的实现也是基于 stun 的,要不考虑加上这个功能?
amrice
236 天前
怎么都在说 wireguard ,没人用 tailscale 吗?我感觉很好用
Archeb
236 天前
同时支持对等连接和 C/S 架构来组网的 SDWAN ,使用常用的互联网协议进行通信,足够简洁的配置和够用的安全系数。

非常棒的思路,这正是我一直在寻找的东西。在此之前 tailscale 的 DERP 勉强可以符合我的需求(毕竟 DERP 协议也是走的 HTTP ,在大部分网络环境下可以正常使用),但 derper 的实现并不是太稳定。

目前有点懒癌发作,等未来这个项目更完善了的时候顺便一波换了。
uncat
236 天前
@wuruxu 路由器重启导致:

1. 导致重新拨号,所以换了 IP
2. 路由器上的 WireGuard 也被重启,导致动态的 Endpoint 信息丢失

解决思路:

将 WireGuard 运行到非路由器的设备上,然后开启 WireGuard 所有 Peer 的 Keepalive ,路由器重启但 WireGuard 不重启即可。WireGuard 会根据最后一次成功收包时 Peer 的来源信息,作为发包的目的地址( Endpoint 地址,首次连接可以指定,后续会被动态更新),这个信息就是 NAT 后设备对应的 NAT 记录(即 NAT 的公网 IP 和端口),本地的 WireGuard 将通过动态 Endpoint 地址,主动连接 NAT 后的设备,NAT 后的设备收到数据包,也会主动更新 Endpoint 地址的。
uncat
236 天前
WireGuard 会动态更新 Endpoint 的地址为该 Peer 最后一次收到的有效的数据包的来源地址。

假设你有公网 IP 且通过 DDNS 将公网 IP 通过域名进行实时更新,域名更新有延迟,所以这里面就可以利用 WireGuard 的这个特性了。

当有公网 IP 的 WireGuard 节点地址变化时,由于这个公网节点会主动的发送保活的空数据包( Keepalive )给所有对端节点,对端节点收到包后会根据数据包的来源 IP 更新 Endpoint 地址(这个地址将作为回包的目的地址),所以即使 IP 变化,通信也不会中断。
lanthora
236 天前
@s82kd92l 不考虑,除非真的有利于组网(更低的延迟或者更好的稳定性),否则就不加功能,代码越少越不容易出 BUG 。那些能配合其他工具实现的功能都不考虑
wuruxu
236 天前
@uncat 你这个想法,也挺好,就相当加一个 firewall rule 和一个单独的 wg 设备
wuruxu
236 天前
@Damn 我的 wg 在 openwrt 上,有 ipv6 和 ipv4 公网地址的
wuruxu
236 天前
@uncat 其实只要把上一次的 wireguard peer 信息 cache 起来,下次重启 restore 回来,也没有问题的
maybeonly
236 天前
@lanthora @Damn
> 在某些情况下 WireGuard 会断线,只有重启客户端才能解决
这是因为防火墙或者 nat 造成的。因为 wireguard 不会改变 udp 的源端口。
同时目的 ip 和端口也不会变,这就会导致,对应的失效 nat 表项一直不会超时。
对于自家路由器 ip 变化的情况,可以在路由器更换 ip 的时候清理出口的 conntrack 表得到解决。

但是这也是权衡利弊的结果。只有依赖这样的固定端口 udp ,才能组成“网状网络”而非“一个一个的连接”

其实跨国的话试试看 wireguard over ipv6 吧,感觉根本没人管啊。
作为后备方案,可以考虑 openvpn tcp over xray/hysteria ,不要嫌弃 openvpn 重,人家原生支持 tcp ,而且组网功能完善。
wuruxu
236 天前
@maybeonly 是的,测试下来,wireguard over ipv6 还是很稳的
wuruxu
236 天前
@maybeonly 清理出口的 conntrack 表 这个怎么清理,有什么命令吗?
maybeonly
236 天前
@wuruxu
conntrack -F conntrack
小心网络波动/中断
lanthora
236 天前
@maybeonly

> 其实跨国的话试试看 wireguard over ipv6 吧,感觉根本没人管啊

并非所有 VPS 都有 IPv6 地址.不太清楚有没有人管,不过现在确实有一些人即使用 IPv4 也能正常用.

> VPN over Proxy 的方案是能用的,但是不喜欢那么复杂,单单因为重这一条就被我抛弃了.还得是自己用的爽才行
uncat
236 天前
@lanthora

> 并非所有 VPS 都有 IPv6 地址.不太清楚有没有人管,不过现在确实有一些人即使用 IPv4 也能正常用.

我就是长期 IPv4 WireGuard 用户。跟你场景很像,一台公网服务器作为中转,实际的所有流量和负载都在个人局域网的物理服务器上。

> 局域网对等连接

如果两个端都在 Symmetric NAT 后呢?也可以对等连接么?
lanthora
236 天前
@uncat

> 如果两个端都在 Symmetric NAT 后呢?也可以对等连接么?

如果两个机器能通过某个局域网 IP 通的话就可以(至少能单向访问).这个功能跟 NAT 类型没有关系,也不会用到公网的任何信息.如果是两个不同 NAT 下的就不可以了
uncat
236 天前
@lanthora

> 如果两个机器能通过某个局域网 IP 通的话就可以(至少能单向访问).这个功能跟 NAT 类型没有关系,也不会用到公网的任何信息.如果是两个不同 NAT 下的就不可以了

明白了你的意思了,如果两个端都在同一个局域网内,基于局域网而不是绕行公网进行通信的意思。
wacke
236 天前
个人目前使用混淆版 wireguard ,也从 compat 版 port 到了 mainline ,3 年了吧,除了链路本身的波动外,基本没有不稳定的情况。。。。用户态的程序,效能还是弱了些。。。
https://github.com/el3xyz/wireguard-linux-compat

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1035681

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX