什么是虚拟专用网络
互联网上存在大量命名为 VPN (虚拟专用网络)的代理工具,严格意义上来说这些工具应该被称为 Proxy (代理). 这里需要澄清一下它们的区别: VPN 可以让虚拟网络中的设备相互访问; Proxy 则是把一台设备作为跳板访问另一台设备.
典型的 VPN 有 OpenVPN 和 IPSec, 以及最近几年出现的 WireGuard. 典型的 Proxy 有 Socks5, ShadowSocks, V2Ray. 而 VPN 添加路由和转发配置后,可以实现 Proxy 的效果.这大概就是两个概念混淆的原因吧.
显然这篇文章介绍的是一款组网工具,而非翻墙工具.
为什么再实现一款虚拟专用网络工具
上面已经提到许多经典的 VPN, 它们能满足用户的绝大多数场景. 我曾是 WireGuard 用户,但在国内众所周知的网络环境下,它们的设计存在明显的“缺陷”,即明显的协议特征. 这原本不是 VPN 需要考虑的问题,但当流量通过防火墙时,存在被丢包的风险. 我就是在 WireGuard 被丢包后才决定实现一款不容易被防火墙探测的 VPN.
在此之前,还尝试过我认为很复杂扭曲的方案: 使用可靠的代理转发流量,并在代理之上组网.
整体设计思路
设计的宗旨是简洁.在不牺牲性能和核心功能的情况下,用最少的代码量和最简单的概念完成设计.
降低配置复杂度
WireGuard 在 VPN 里配置已经相对较简单了,但对我来说依旧过于复杂.回忆一下你用多长时间完成的第一次 WireGuard 组网. WireGuard 需要强制指定虚拟地址,不适用于想要灵活接入多个客户端并动态分配地址的场景.
用 WSS(Web Socket Secure) 处理通信,在保证链路数据安全的情况下,免去了配置公私钥的过程. 用口令校验客户端,可以轻松的让新客户端加入网络,这样就能由服务端实现地址动态分配.
高效的断线重连
在某些情况下 WireGuard 会断线,只有重启客户端才能解决.此时对于一个无人值守的设备,就意味着彻底失联. 曾经为了解决这个问题,给设备配置每天重启一次,这显然是一种很丑陋的解决方案.
使用 WSS 通信,就可以用 Ping/Pong 完成 TCP 保活,即使 TCP 连接异常断开,应用也可以及时发现,迅速处理.
支持内网穿透的对等连接
虽然 WireGuard 支持对等连接,但要求设备之间能够直接访问,对于双方都在 NAT 后面的情况无能为力. 增加内网穿透功能,可以节约服务端转发的流量,同时还能降低通信延迟.
内网穿透通过 STUN 服务器获取本地 UDP Socket 被映射后的公网地址和端口,通过服务端与其他客户端交换地址和端口信息,并尝试建立连接.
高速的中继路由
有时候两个客户端之间无法直连,但它们都能与另一个客户端直连.此时可以以这个客户端作为中继相互访问.
这实际上是路由的问题.本项目实现的是距离向量算法.
局域网对等连接
通过 STUN 查到的用于对等连接的地址是公网地址,对于局域网内能够直连的设备来说,绕到最外层的路由器再回来是浪费了时间的,并且还会受到公网带宽的限制.
通过用户配置或主动探测本机的局域网地址,可以优先尝试本地直连.
这个软件给我带来了什么
预期之内的,替代 WireGuard 完成组网,让我国内外的设备又可以在同一个虚拟网络下工作.
更多的还是意料之外的惊喜.首先是认识到 VPN 实际上是用用户态软件模拟网络设备.
其次,为了方便容器化部署,我终于学会了用 Github Actions, 代码提交后自动检查并生成镜像上传.
对于软件本身,由于部署过于简单,就让我可能需要的设备都参与了组网.进而轻易解决了公司的 VPN 没有 Linux 版的问题.我把 Shadowsocks 部署在 VPN 里,也解决了 Splatoon 3 掉线问题.这次回家买了个 Mac mini, 接入由树莓派制作的 AP, 由于在树莓派上也接入的虚拟网络,因此可以直接在 Mac mini 上访问所有接入了网络的设备.同时由于对等连接的功劳,这些设备之间访问的延迟非常低.这篇文章就是在 Mac mini 上远程连接到距离我 500 公里远的服务器上完成的,整个写作过程非常丝滑.
总而言之,它在解决原始需求的情况下,带给我更大的想象空间.
未来的发展方向
只增加能提升性能和稳定性的功能,不添加任何与其他工具组合就能实现的功能.
实际体验一下效果
目前支持 Linux, Mac 和 Windows. 选择你使用的系统安装客户端,这些客户端的默认配置会连到测试网络,并被随机分配一个地址.
如果你已经看到了这里,大概率对这个软件还算感兴趣,源代码托管在了 Github,暗示点星星.你可以调整启动参数部署自己的服务端,然后组建自己的的虚拟专用网络.