WireGuard 系列文章(四):WireGuard 快速上手

2022-04-22 13:47:34 浏览数 (1)

系列文章前情提要:

1.WireGuard系列文章(一):什么是V**[1]

2.WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道[2]

3.WireGuard 系列文章(三):WireGuard 安装[3]

快速入门

您首先要确保对 概念概述[4] 有很好的掌握,然后 安装 WireGuard[5]。之后,请继续阅读此处。

配置实战

单个配置如下所示:(gif 过大,无法上传,点击链接)

wg(8) 演示gif: https://pic-cdn.ewhisper.cn/img/2021/12/04/7246780de4f1b6408a5ff58d6155eba1-walkthrough.gif

命令行界面

可以通过 添加新接口,该接口应自动处理模块加载:ip-link(8)

代码语言:javascript复制
# ip link add dev wg0 type wireguard

IP 地址和 peer 可以通过ifconfig(8)ip-address(8)分配

代码语言:javascript复制
# ip address add dev wg0 192.168.2.1/24

或者,如果总共只有两个 peer ,则可以:

代码语言:javascript复制
# ip address add dev wg0 192.168.2.1 peer 192.168.2.2

该接口可以使用随附的 wg(8)[6] 实用程序配置密钥和对等(peer)端点(endpoint):

代码语言:javascript复制
# wg setconf wg0 myconfig.conf

代码语言:javascript复制
# wg set wg0 listen-port 51820 private-key /path/to/private-key peer ABCDEF... allowed-ips 192.168.88.0/24 endpoint 209.202.254.14:8172

最后,可以使用 ifconfig(8)ip-link(8) 激活接口:

代码语言:javascript复制
# ip link set up dev wg0

还有wg showwg showconf命令,用于查看当前配置。不带参数的 wg 调用 wg show 默认为对所有 WireGuard 接口进行调用。

wg(8) 工具

wg(8)[7] 和 ip(8)的许多例行的启动和拆卸动作都可以通过随附的 wg-quick(8)工具[8] 实现自动化:

wg-quick(8)工具演示: https://pic-cdn.ewhisper.cn/img/2021/12/04/1e7d824a83ad1dde845cab160d5b205c-wg-quick-tool.gif

密钥生成

WireGuard 需要 base64 编码的公钥和私钥。这些可以使用 wg(8)[9] 实用程序生成:

代码语言:javascript复制
umask 077
wg genkey > privatekey

这将在 stdout 上创建包含新私钥 privatekey的内容。

然后,您可以从私钥派生公钥:

代码语言:javascript复制
wg pubkey < privatekey > publickey

这将从 stdin 读取privatekey并将相应的公钥publickey写入 stdout。

当然,您可以一次完成所有操作:

代码语言:javascript复制
wg genkey | tee privatekey | wg pubkey > publickey

NAT 和防火墙遍历持久性

默认情况下,WireGuard 在不使用时会尝试尽可能保持静默;这不是一个健谈的协议。在大多数情况下,它仅在对等方希望发送数据包时传输数据。当系统未要求它发送数据包时,它会停止发送数据包,直到再次被请求。在大多数配置中,这运行良好。但是,当对等方位于 NAT 或防火墙后面时,它可能希望能够接收传入的数据包,即使它不发送任何数据包。由于 NAT 和有状态防火墙会跟踪"连接",因此,如果 NAT 或防火墙后面的对等方希望接收传入的数据包,他必须通过定期发送保持活动数据包来保持 NAT/防火墙映射有效。这称为持久保持活动( persistent keepalives)。启用此选项后,每隔几秒钟就会向服务器终结点(endpoint)发送一次保持活动状态的数据包。适用于各种防火墙的合理间隔为 25 秒。将其设置为 0 会关闭该功能,这是默认设置,因为大多数用户不需要此功能,并且会使 WireGuard 稍微更健谈。可以通过将字段 PersistentKeepalive = 添加到配置文件中的对等项或在命令行中进行设置 persistent-keepalive来指定此功能。如果不需要此功能,请不要启用它。但是,如果您位于 NAT 或防火墙后面,并且希望在网络流量静默很久之后接收传入连接,则此选项将使"连接"在 NAT 眼中保持打开状态。

配置详解

WireGuard 使用 INI 语法作为其配置文件格式。配置文件可以放在任何路径下,但必须通过绝对路径引用。默认路径是 /etc/wireguard/wg0.conf

配置文件的命名形式必须为 {WireGuard 接口的名称}.conf。通常情况下 WireGuard 接口名称以 wg 为前缀,并从 0 开始编号,但你也可以使用其他名称,只要符合正则表达式 ^[a-zA-Z0-9_= .-]{1,15}就行。

你可以选择使用 wg 命令来手动配置 V**,但一般建议使用 wg-quick,它提供了更强大和用户友好的配置体验,可以通过配置文件来管理配置。

下面是一个配置文件示例:

代码语言:javascript复制
[Interface]
# Name = peer1.private
Address = 10.4.1.3/32
ListenPort = 51820
PrivateKey = thisPeerPrivateKeyXXXXXXXX=
DNS = 223.5.5.5
MTU = 1500
PreUp = echo WireGuard PreUp
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PreDown = echo WireGuard PreDown
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]
# Name = peer2.private
AllowedIPs = 10.4.1.1/24
Endpoint = peer1.private:51820
PublicKey = remotePeerPublicKeyXXXX=
PersistentKeepalive = 25

✔️ 实用配置: PostUp 和 PostDown 可以按照上文进行配置: PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE 当然,目前的体验最好的实践是傻瓜式地通过 Netmaker 完成所有配置。

[Interface]

这一节定义本地 V** 配置。例如:

•如果本地节点是客户端,只需路由自身的流量,那就只暴露一个 IP(作为客户端嘛,就不需指定端口)。

代码语言:javascript复制
[Interface]
# Name = phone.private
Address = 10.4.1.5/32
PrivateKey = <private key for phone.private>

•如果本地节点是中继服务器,它需要将流量转发到其他对等节点(peer),并公开整个 V** 子网的路由。

代码语言:javascript复制
[Interface]
# Name = public-server1.example-vpn.tld
Address = 10.4.1.1/24
ListenPort = 51820
PrivateKey = <private key for public-server1.example-vpn.tld>
DNS = 223.5.5.5
Address

定义本地节点应该对哪个地址范围进行路由。

1.如果是常规的客户端,则将其设置为节点本身的单个 IP(使用 CIDR 指定,例如 10.4.1.3/32);

2.如果是中继服务器,则将其设置为可路由的子网范围。

例如:

•常规客户端,只路由自身的流量:Address = 10.4.1.3/32

•中继服务器,可以将流量转发到其他对等节点(peer):Address = 10.4.1.1/24 (注意是 /24, 即整个子网)

•也可以指定多个子网或 IPv6 子网:Address = 10.4.1.1/24,2001:DB8::/64

ListenPort

当本地节点是中继服务器时,需要通过该参数指定端口来监听传入 V**连接,默认端口号是 51820。常规客户端(只作为客户端,不作为服务器端)则不需要此选项。

PrivateKey

本地节点的私钥,所有节点(包括中继服务器)都必须设置。不可与其他服务器共用。

DNS

通过 DHCP 向客户端宣告 DNS 服务器。客户端将会使用这里指定的 DNS 服务器来处理 V**子网中的 DNS 请求,但也可以在系统中覆盖此选项。例如:

•如果不配置则使用系统默认 DNS

•可以指定单个 DNS:DNS = 223.5.5.5

•也可以指定多个 DNS:DNS = 223.5.5.5,223.6.6.6

MTU

定义连接到对等节点(peer)的 MTU(Maximum Transmission Unit,最大传输单元),默认不需要设置,一般由系统自动确定。

PreUp

启动 V** 接口之前运行的命令。这个选项可以指定多次,按顺序执行。

例如:

•添加路由:PreUp = ip rule add ipproto tcp dport 22 table 1234

PostUp

启动 V** 接口之后运行的命令。这个选项可以指定多次,按顺序执行。

例如:

•从文件或某个命令的输出中读取配置值:

代码语言:javascript复制
PostUp = wg set %i private-key /etc/wireguard/wg0.key <(some command here)

•添加一行日志到文件中:

代码语言:javascript复制
PostUp = echo "$(date  %s) WireGuard Started" >> /var/log/wireguard.log

•调用 WebHook:

代码语言:javascript复制
PostUp = curl https://events.example.dev/wireguard/started/?key=abcdefg

•添加路由:

代码语言:javascript复制
PostUp = ip rule add ipproto tcp dport 22 table 1234

•添加 iptables 规则,启用数据包转发:

代码语言:javascript复制
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

•强制 WireGuard 重新解析对端域名的 IP 地址:

代码语言:javascript复制
PostUp = resolvectl domain %i "~."; resolvectl dns %i 10.4.1.1; resolvectl dnssec %i yes
PreDown

停止 V** 接口之前运行的命令。这个选项可以指定多次,按顺序执行。

例如:

•添加一行日志到文件中:

代码语言:javascript复制
PreDown = echo "$(date  %s) WireGuard Going Down" >> /var/log/wireguard.log

•调用 WebHook:

代码语言:javascript复制
PreDown = curl https://events.example.dev/wireguard/stopping/?key=abcdefg
PostDown

停止 V** 接口之后运行的命令。这个选项可以指定多次,按顺序执行。

例如:

•添加一行日志到文件中:

代码语言:javascript复制
PostDown = echo "$(date  %s) WireGuard Going Down" >> /var/log/wireguard.log

•调用 WebHook:

代码语言:javascript复制
PostDown = curl https://events.example.dev/wireguard/stopping/?key=abcdefg

•删除 iptables 规则,关闭数据包转发:

代码语言:javascript复制
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

[Peer]

定义能够为一个或多个地址路由流量的对等节点(peer)的 V** 设置。对等节点(peer)可以是将流量转发到其他对等节点(peer)的中继服务器,也可以是通过公网或内网直连的客户端。

中继服务器必须将所有的客户端定义为对等节点(peer),除了中继服务器之外,其他客户端都不能将位于 NAT 后面的节点定义为对等节点(peer),因为路由不可达。对于那些只为自己路由流量的客户端,只需将中继服务器作为对等节点(peer),以及其他需要直接访问的节点。

举个例子,在下面的配置中,public-server1 作为中继服务器,其他的客户端有的是直连,有的位于 NAT 后面:

public-server1(中继服务器)[peer] : public-server2, home-server, laptop, phone

public-server2(直连客户端)[peer] : public-server1

home-server(客户端位于 NAT 后面)[peer] : public-server1, public-server2

laptop(客户端位于 NAT 后面)[peer] : public-server1, public-server2

phone(客户端位于 NAT 后面)[peer] : public-server1, public-server2

配置示例:

•对等节点(peer)是路由可达的客户端,只为自己路由流量

代码语言:javascript复制
[Peer]
# Name = public-server2.private
Endpoint = public-server2.private:51820
PublicKey = <public key for public-server2.private>
AllowedIPs = 10.4.1.2/32

•对等节点(peer)是位于 NAT 后面的客户端,只为自己路由流量

代码语言:javascript复制
[Peer]
# Name = home-server.private
Endpoint = home-server.private:51820
PublicKey = <public key for home-server.private>
AllowedIPs = 10.4.1.3/32

•对等节点(peer)是中继服务器,用来将流量转发到其他对等节点(peer)

代码语言:javascript复制
[Peer]
# Name = public-server1.example-vpn.tld
Endpoint = public-server1.example-vpn.tld:51820
PublicKey = <public key for public-server1.example-vpn.tld>
# 路由整个 VPN 子网的流量
AllowedIPs = 10.4.1.1/24
PersistentKeepalive = 25
Endpoint

指定远端对等节点(peer)的公网地址。如果对等节点(peer)位于 NAT 后面或者没有稳定的公网访问地址,就忽略这个字段。通常只需要指定中继服务器Endpoint,当然有稳定公网 IP 的节点也可以指定。例如:

•通过 IP 指定:

代码语言:javascript复制
Endpoint = 123.123.123.123:51820

•通过域名指定:

代码语言:javascript复制
Endpoint = public-server1.private:51820
AllowedIPs

允许该对等节点(peer)发送过来的 V** 流量中的源地址范围。同时这个字段也会作为本机路由表中 wg0 绑定的 IP 地址范围。如果对等节点(peer)是常规的客户端,则将其设置为节点本身的单个 IP;如果对等节点(peer)是中继服务器,则将其设置为可路由的子网范围。可以使用 , 来指定多个 IP 或子网范围。该字段也可以指定多次。

当决定如何对一个数据包进行路由时,系统首先会选择最具体的路由,如果不匹配再选择更宽泛的路由。例如,对于一个发往 10.4.1.3 的数据包,系统首先会寻找地址为 10.4.1.3/32 的对等节点(peer),如果没有再寻找地址为 10.4.1.1/24 的对等节点(peer),以此类推。

例如:

•对等节点(peer)是常规客户端,只路由自身的流量:

代码语言:javascript复制
AllowedIPs = 10.4.1.3/32

•对等节点(peer)是中继服务器,可以将流量转发到其他对等节点(peer):

代码语言:javascript复制
AllowedIPs = 10.4.1.1/24

•对等节点(peer)是中继服务器,可以转发所有的流量,包括外网流量和 V** 流量:

代码语言:javascript复制
AllowedIPs = 0.0.0.0/0,::/0

•对等节点(peer)是中继服务器,可以路由其自身和其他对等节点(peer)的流量:

代码语言:javascript复制
AllowedIPs = 10.4.1.3/32,10.4.1.4/32

•对等节点(peer)是中继服务器,可以路由其自身的流量和它所在的内网的流量:

代码语言:javascript复制
AllowedIPs = 10.4.1.3/32,192.168.1.1/24
PublicKey

对等节点(peer)的公钥,所有节点(包括中继服务器)都必须设置。可与其他对等节点(peer)共用同一个公钥。

公钥可通过命令 wg pubkey < example.key > example.key.pub 来生成,其中 example.key 是上面生成的私钥。

例如:PublicKey = somePublicKeyAbcdAbcdAbcdAbcd=

PersistentKeepalive

如果连接是从一个位于 NAT 后面的对等节点(peer)到一个公网可达的对等节点(peer),那么 NAT 后面的对等节点(peer)必须定期发送一个出站 ping 包来检查连通性,如果 IP 有变化,就会自动更新Endpoint

例如:

•本地节点与对等节点(peer)可直连:该字段不需要指定,因为不需要连接检查。

•对等节点(peer)位于 NAT 后面:该字段不需要指定,因为维持连接是客户端(连接的发起方)的责任。

•本地节点位于 NAT 后面,对等节点(peer)公网可达:需要指定该字段 PersistentKeepalive = 25,表示每隔 25 秒发送一次 ping 来检查连接。

参考资料

•Quick Start - WireGuard[10]•WireGuard 教程:WireGuard 的搭建使用与配置详解 by 米开朗基杨[11]

References

[1] WireGuard系列文章(一):什么是V**: http://ewhisper.cn/posts/32152/ [2] WireGuard 系列文章(二):WireGuard 简介 - 快速、现代、安全的 V** 隧道: http://ewhisper.cn/posts/23685/ [3] WireGuard 系列文章(三):WireGuard 安装: http://ewhisper.cn/posts/59274/ [4] 概念概述: https://ewhisper.cn/posts/23685 [5] 安装 WireGuard: https://ewhisper.cn/posts/59274 [6] wg(8): https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 [7] wg(8): https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 [8] wg-quick(8)工具: https://git.zx2c4.com/wireguard-tools/about/src/man/wg-quick.8 [9] wg(8): https://git.zx2c4.com/wireguard-tools/about/src/man/wg.8 [10] Quick Start - WireGuard: https://www.wireguard.com/quickstart/ [11] WireGuard 教程:WireGuard 的搭建使用与配置详解 by 米开朗基杨: https://fuckcloudnative.io/posts/wireguard-docs-practice/

0 人点赞