什么是 WireGuard

WireGuard 是一个全新的隧道协议,其 Linux 实现工作在内核态下,即将被整合进 Linux 内核主线,同时也有用户态的不同平台实现。

WireGuard 官方公布的 WhitePaper 中自称为 Next Generation Kernel Network Tunnel,区别于传统 SSL VPN 和 IPSec VPN,配置极为简单,运行高效。

Linus 评价其为“ it’s a work of art.”

因为其要被整合进 Linux 内核主线的新闻,WireGuard 最近着实火了一把,我也慕名使用了一下。就我个人的使用体验来说,WireGuard 非常棒,虽然是抱着科学上网的想法去测试,但是在用过之后被它深深地折服了。WireGuard 把组网这件事做的简单到了极致,配置部署均非常简单,几乎可以和Shadowsocks 相比。再回过头看 OpenVPN、IPSec VPN 等协议的繁琐部署流程,WireGuard 太友好了,无愧于 Next Generation 之名。

同时 WireGuard 的性能也相当不错,就我个人测试在 ER-X 这种 MIPS 路由上也能做到很高的吞吐,同时可以有效利用多核。另有网友测试在 ASUS AC86U 这种路由上能够跑到 400Mbps+

另外 Windows 下还没有官方的开源实现,一直是 coming soon,有一个第三方的闭源客户端 TunSafe,开发者是曾经 uTorrent 的开发者,但 WireGuard 作者在官网和Reddit上均表示极力不推荐使用(后续:TunSafe 现已开源)。

WireGuard 的安装

目前除了 Windows 外的绝大多数平台均有官方实现:https://www.wireguard.com/install/

Ubuntu

1
2
3
$ sudo add-apt-repository ppa:wireguard/wireguard
$ sudo apt-get update
$ sudo apt-get install wireguard

如果你手动进行过更换内核等操作,在启动 WireGuard 时可能会遇到以下问题:

$ [#] ip link add wg0 type wireguard

$ RTNETLINK answers: Operation not supported

这是因为系统中缺失了相应版本内核的 Linux header,可以在这里下载对应内核版本的 linux-headers-alllinux-headers-generic 按顺序进行安装:

$ sudo dpkg -i downloaded_headers.deb

macOS

需要安装包管理器 Homebrew

$ brew install wireguard-tools

EdgeOS

下载路由对应版本的 deb 文件:

https://github.com/Lochnair/vyatta-wireguard/releases

$ sudo dpkg -i ./yourfilename.deb

WireGuard 的配置

WireGuard 官方提供了一个快速配置部署的脚本,安装 WireGuard 完毕后可以直接使用 wg-quick 命令调用。

WireGuard 每个 Peer 都是平等的,可以接受或发起连接。每个 Peer 拥有一对公钥和私钥,私钥自己保管绝不泄露,公钥需要在两个建立连接的 Peer 间交换。

同时为了防止未来可能存在的量子攻击,WireGuard 还额外引入了 PreSharedKey Layer 对所有数据包进行对称加密,尽管短时间内量子攻击可能并不现实,但是可能无意间引入了对抗 GFW 审查的一种方式(类似 Shadowsocks,但 WireGuard 仍是有握手过程的,所以到底有没有效果笔者并不能确定,也未经过仔细思考,仅为臆测。)

首先需要在每个客户端上生成密钥对:

1
2
$ wg genkey > privatekey
$ wg pubkey < privatekey > publickey

仅需要生成一次 PreSharedKey,这个密钥同时部署在两端 Peer 上:

$ wg genpsk > psk

假设存在 Peer A、Peer B,在其之间建立一个 Tunnel:

我们假定连接端口均为 51820。

Peer A Config File:

1
2
3
4
5
6
7
8
9
[Interface] 
Address = 192.168.100.1/24
PrivateKey = Peer A's PrivateKey
ListenPort = 51820
[Peer]
Endpoint = Peer B's Address:51820
PublicKey = Peer B's PrivateKey
AllowedIPs = 192.168.100.2/32
PresharedKey = Your PreSharedKey

Peer B Config File:

1
2
3
4
5
6
7
8
9
[Interface] 
Address = 192.168.100.2/24
PrivateKey = Peer B's PrivateKey
ListenPort = 51820
[Peer]
Endpoint = Peer A's Address:51820
PublicKey = Peer A's PrivateKey
AllowedIPs = 192.168.100.1/32
PresharedKey = Your PreSharedKey

在两端机器上执行:

$ sudo wg-quick up $CONFIGFILE

若 Peer A 在 NAT 之后无法直接访问,可以删去 Peer B 文件中的 Endpoint 参数,仅由 Peer A 主动发起连接,也可以成功建立 Tunnel。

AllowedIPs 参数可以通过逗号分隔符继续添加,wg-quick 会自动帮你添加走该 interface 的路由表。

配置 EdgeOS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ wg genkey > /config/auth/privatekey
$ wg pubkey < /config/auth/privatekey > /config/auth/publickey
$ wg genpsk > /config/auth/psk

$ configure
$ set interfaces wireguard wg0 address 192.168.100.3/24
$ set interfaces wireguard wg0 listen-port 51820
$ set interfaces wireguard wg0 route-allowed-ips true

$ set interfaces wireguard wg0 peer Server's PublicKey allowed-ips 192.168.100.1/32
$ set interfaces wireguard wg0 peer Server's PublicKey allowed-ips 192.168.100.2/32
$ set interfaces wireguard wg0 peer Server's PublicKey endpoint 'Server's Address:51820'
$ set interfaces wireguard wg0 peer Server's PublicKey preshared-key /config/auth/psk
$ set interfaces wireguard wg0 peer Server's PublicKey persistent-keepalive 25

$ set interfaces wireguard wg0 private-key /config/auth/privatekey
$ commit
$ save