跳转至

Wireguard

简介

  • WireGuard 是由 Jason Donenfeld 等人用 C 语言编写的一个开源 VPN 协议,被视为下一代 VPN 协议,旨在解决许多困扰 IPSec/IKEv2、OpenVPN 或 L2TP 等其他 VPN 协议的问题。它与 Tinc 和 MeshBird 等现代 VPN 产品有一些相似之处,即加密技术先进、配置简单。
  • 从 2020 年 1 月开始,它已经并入了 Linux 内核的 5.6 版本,这意味着大多数 Linux 发行版的用户将拥有一个开箱即用的 WireGuard。
  • WireGuard 作为一个更先进、更现代的 VPN 协议,比起传统的 IPSec、OpenVPN 等实现,效率更高,配置更简单,并且已经合并入 Linux 内核,使用起来更加方便。

常见VPN方法比较

  • wireguard 精簡、速度極快:
  • 只有 4000 行程式碼,是最精簡的 VPN 協議。对比下 OpenVPN,大约有 10 万行代码。
  • WireGuard 利用内核空间处理来提升性能(更高吞吐和更低延迟),同时避免了不必要的内核和用户空间频繁上下文切换开销。

Wireguard客户端连接Debug

  • 首先,服务端的ip或者域名能ping通
  • 其次端口确定开放> nc -z -v -u 4.shaojiemike.top 51822,wg是udp
  • 修改wg客户端配置文件,限制ip为wg设置的内网段,AllowedIPs = 192.168.31.0/24,10.0.233.1/24.然后ping 192.168.31.1测试
  • 如果还不行,判断为wg的VPN包被中间网关识别并丢弃

配置文件

配置详解参考中文文档

PersistentKeepalive

  • 一端位于 NAT 后面,另一端直接通过公网暴露
  • 这种情况下,最简单的方案是:通过公网暴露的一端作为服务端,另一端指定服务端的公网地址和端口,然后通过 persistent-keepalive 选项维持长连接,让 NAT 记得对应的映射关系。
  • [peer]里设定字段 PersistentKeepalive = 25,表示每隔 25 秒发送一次 ping 来检查连接。

AllowedIPs

虽然AllowedIPs = 0.0.0.0/0AllowedIPs = 0.0.0.0/1, 128.0.0.0/1包含的都是全部的ip。

但是前者在iptable里为default dev wg1,后者为两条0.0.0.0/1 dev wg1128.0.0.0/1 dev wg1

由于路由的ip匹配遵循最长前缀匹配规则,如果路由表里原本有一条efault dev eth0。使用前者会导致混乱。但是使用后者,由于两条的优先级会更高,会屏蔽掉原本的default规则。

前者的iptable修改如下:(macbook上)

> ip route
default via link#18 dev utun3
default via 192.168.233.1 dev en0
10.0.233.5/32 via 10.0.233.5 dev utun3
224.0.0.0/4 dev utun3  scope link
224.0.0.0/4 dev en0  scope link
255.255.255.255/32 dev utun3  scope link
255.255.255.255/32 dev en0  scope link

后者的iptable修改如下

> ip route
0.0.0.0/1 dev utun3  scope link
default via 192.168.233.1 dev en0
default via link#18 dev utun3
10.0.233.5/32 via 10.0.233.5 dev utun3
128.0.0.0/1 dev utun3  scope link
224.0.0.0/4 dev en0  scope link
224.0.0.0/4 dev utun3  scope link
255.255.255.255/32 dev en0  scope link
255.255.255.255/32 dev utun3  scope link

原理

建议看WireGuard 教程:WireGuard 的工作原理WireGuard 基础教程:wg-quick 路由策略解读,详细解释了wg是如何修改路由表规则的。

wireguard 运行原理以及配置文件

默认会产生51840的路由table,ip rule优先级较高。可以通过配置文件中添加PostUp来修改最后一个default的路由规则。

root@snode6:/etc/wireguard# cat wg0.conf
[Interface]
Address = 192.168.253.5/32,fd00::aaaa:5/128
PrivateKey = eGj5skRAGJu8d………………1PVfu0lY=
# PublicKey = VWe0wBVztgX………………xd7/kZ2CVJlEvS51c=

#Table必须有,不然默认的还是会修改ip rule
Table = 51820
#DNS = 1.1.1.1 #指定DNS服务器

#启动时运行: %i 是指wg的路由, 默认修改default, metric 一般不用指定
PostUp   = /sbin/ip -4 route replace default dev %i table default metric 1
PostUp   = /sbin/ip -6 route replace default dev %i table default metric 1
#down后运行
PostDown = /sbin/ip -4 route delete  default dev %i table default metric 1
PostDown = /sbin/ip -6 route delete  default dev %i table default metric 1

PostUp会产生下面的规则

root@snode6:/staff/shaojiemike# ip ro show table default
default dev wg0 scope link metric 1

OpenVPN原理

OpenVPN原理通过在main添加all规则来实现

# shaojiemike @ node5 in ~ [22:29:05]
$ ip route show table main
0.0.0.0/1 via 192.168.255.5 dev tun1

clash TUN模式

Macbook上的应用上的ClashX Pro的增强模式类似, 会添加如下配置,将基本所有流量代理(除开0.0.0.0/8

> ip route
1.0.0.0/8 via 198.18.0.1 dev utun3
2.0.0.0/7 via 198.18.0.1 dev utun3
4.0.0.0/6 via 198.18.0.1 dev utun3
8.0.0.0/5 via 198.18.0.1 dev utun3
16.0.0.0/4 via 198.18.0.1 dev utun3
32.0.0.0/3 via 198.18.0.1 dev utun3
64.0.0.0/2 via 198.18.0.1 dev utun3
128.0.0.0/1 via 198.18.0.1 dev utun3 #前面接受所有的ip,然后转换成198.18.0.1
198.18.0.1/32 via 198.18.0.1 dev utun3 #接受转换后的198.18.0.1,由于最长前缀匹配

明显有代理死循环问题,如何解决???

shaojiemike@shaojiemikedeMacBook-Air ~/github/hugoMinos (main*) [10:59:32]
> ip route get 198.18.0.42
198.18.0.42 via 198.18.0.1 dev utun3  src 198.18.0.1
shaojiemike@shaojiemikedeMacBook-Air ~/github/hugoMinos (main*) [10:59:38]
> ip route get 198.18.0.1
198.18.0.1 dev utun3  src 198.18.0.1

Wireguard 环境配置

wireguard-go: 安装客户端 wg-quick up config wireguard-tools: 安装服务端 wg

Wireguard 常见命令

  • 启动wg-quick up wg1
  • 关闭wg-quick down wg1
  • 查看状态 wg显示全部,或者wg show wg1显示wg1

wireguard开机启动

systemctl enable wg-quick@wg1 --now

使用wireguard 代理ipv6请求

  • WireGuard 也支持 IPv6。OpenWRT 服务端,当然要allowed ip fd00::aaaa:5/128
  • 注意:这是伪需求,为什么ipv6的流量需要走ipv6,不走wg,每个机器可以获得独立的公网ipv6,对于PT做种是很好的。
brainiac1# cat wg-tsj.conf
[Interface]
PrivateKey = xxx
ListenPort = 51828
Address = 10.0.233.7/32, fd00::aaaa:5/128
Table = 51820
#DNS = 1.1.1.1

# 使用iptable修改ipv6的路由规则
PostUp   = /sbin/ip -4 route replace default dev %i table default metric 1
PostUp   = /sbin/ip -6 route replace default dev %i table default metric 1
PostDown = /sbin/ip -4 route delete  default dev %i table default metric 1
PostDown = /sbin/ip -6 route delete  default dev %i table default metric 1

[Peer]
#AllowedIPs = 0.0.0.0/0,::/0
PublicKey = xxx
AllowedIPs = 0.0.0.0/1, 128.0.0.0/1
Endpoint = 4.shaojiemike.top:51822
PersistentKeepalive = 30

两次wireguard上网

修改sysctl.conf文件的net.ipv4.ip_forward参数。其值为0,说明禁止进行IP转发;如果是1,则说明IP转发功能已经打开。

需要执行指令sysctl -p 后新的配置才会生效。

两台机器的wireguard配置

注意中间需要NAT转换, 相当于把kunpeng机器的请求,隐藏成snode6的请求。在后一次wireguard转发时,就不会被过滤掉。

PostUp   = iptables -t nat -A POSTROUTING -s 10.1.0.0/24 ! -o %i -j MASQUERADE
PostDown = iptables -t nat -D POSTROUTING -s 10.1.0.0/24 ! -o %i -j MASQUERADE || true

机器(Nas)使用Wireguard上网

问题场景

由于换了wg服务端,导致nas变成闭环的网络了。最后是通过群晖助手(Synology Assistant / Web Assistant)的设置静态ip才连接上机器,但是iptable被设置乱了。

Synology Assistant can not find nas

静态连接上机器,首先在网页管理页面切换成DHCP(静态ip的DNS解析有误),iptable变成如下

sh-4.4# ip ro
default via 222.195.90.254 dev eth0  src 222.195.90.2
10.0.233.0/24 dev wg1  proto kernel  scope link  src 10.0.233.3
222.195.90.0/24 dev eth0  proto kernel  scope link  src 222.195.90.2

sh-4.4# ip ro s t eth0-table
222.195.90.0/24 via 222.195.90.2 dev eth0

注意iptable的修改是实时生效的。

思路

为了让nas上网我们需要满足两点

  1. 本地ssh eth0的222.195.90.2能访问机器(优先级更高)
  2. 其余网络走wg
# 重要项如下
sh-4.4# ip rule
3:      from 222.195.90.2 lookup eth0-table (ping  ssh ip 222.195.90.2的会使用这个规则)
32766:  from all lookup main (ping  ssh 其余ip 比如wg的10.0.233.3的会使用这个规则)

# 1. 设置本地ssh eth0的222.195.90.2的高优先级,不至于开启wg断开ssh
# 使用命令添加: ip ro add default via 222.195.90.254 dev eth0 table eth0-table
sh-4.4# ip route show table eth0-table
default via 222.195.90.254 dev eth0
222.195.90.0/24 via 222.195.90.2 dev eth0

# 2. 为了使得除开本地ssh网络走wg,需要删除屏蔽default的wg的DHCP(如果提前删,导致机器ssh连接不上了,重新插拔网线,让DHCP重新配置):
# 使用命令添加:ip ro d default via 222.195.90.254 dev eth0  src 222.195.90.2 table main,
# 3. 防止服务端重启,Nas的wg客户端失联
# 使用命令添加:ip ro a 114.214.233.0/24 via 222.195.90.254 dev eth0  src 222.195.90.2 table main 
# 4. 测试: ping域名能正常运行

# 其余方法:为了使得除开本地ssh网络走wg,也可以不删除,在DHCP的前面添加wg的网络通路
# 使用命令添加: ip ro add default dev wg1  proto kernel  scope link  src 10.0.233.3 table main
sh-4.4# ip r s t main
default dev wg1  proto kernel  scope link  src 10.0.233.3

使用wg1配置如下:

sh-4.4# cat /etc/wireguard/wg1.conf
[Interface]
PrivateKey = xxx
ListenPort = xxx
Address = 10.0.xxx.xxx/24

Table = 51820
PostUp   = /sbin/ip -4 route replace default dev %i table default metric 1
PostDown = /sbin/ip -4 route delete  default dev %i table default metric 1

[Peer]
PublicKey = xxx
AllowedIPs = 0.0.0.0/1, 128.0.0.0/1
Endpoint = 114.xxx.xxx.xxx:xxx
PersistentKeepalive = 25

问题:服务端重启,Nas的wg客户端失联

要保留没有wg的时候访问服务端的eth0(114.214.233.xxx)的通路

sh-4.4# ip ro s t main
···
114.214.233.0/24 via 222.195.90.254 dev eth0  src 222.195.90.2
···

来自eth0的ssh与ping请求原路返回

源地址为自身IP的包走学校的路由器

目的:需要ssh和ping ipv4成功

修改netplan的配置文件

# shaojiemike @ node5 in ~ [22:29:11]
$ cat /etc/netplan/acsa.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eno0:
      dhcp4: false
      dhcp6: false
      accept-ra: false
      addresses:
        - 202.38.73.217/24
        - 2001:da8:d800:730::217/64
      gateway4: 202.38.73.254
      gateway6: 2001:da8:d800:730::1
      nameservers:
        addresses:
          - 202.38.64.1
      routing-policy:
        - from: 202.38.73.217
          table: 1
          priority: 2
      routes:
        - to: 0.0.0.0/0
          via: 202.38.73.254
          table: 1

$netplan apply

routing-policy会产生

# shaojiemike @ node5 in ~ [22:30:33]
$ ip rule
0:      from all lookup local
2:      from 202.38.73.217 lookup 1
32766:  from all lookup main
32767:  from all lookup default
# 也可以手动添加
ip rule add from 202.38.73.217 table 1 pref 2
或者
ip rule add from 202.38.73.217 lookup 1 pref 2

由于2优先级高,使得ping和ssh的返回信包(源地址为自身机器IP的包)走table1 规则,而不是走

routes使得所有的table1都会走学校的路由器(202.38.73.254)

$ ip route show table 1
default via 202.38.73.254 dev eno0 proto static
# 也可以通过`ip route add`
$ ip route add default via 202.38.73.254 dev eno0 proto static table 1

衍生问题:网络请求的源地址不是自己吗?怎么确定的

开启wg后,网络请求源地址变成了10.0.33.2。不是202.38.73.217

root@node5:/home/shaojiemike# ip ro
10.0.33.0/24 dev wg2 proto kernel scope link src 10.0.33.2

但是外界ping的是202.38.73.217。返回包交换所以会产生源地址为202.38.73.217的包

wireguard 实现翻墙

  • WireGuard 在国内网络环境下会遇到一个致命的问题:UDP 封锁/限速。虽然通过 WireGuard 可以在隧道内传输任何基于 IP 的协议(TCP、UDP、ICMP、SCTP、IPIP、GRE 等),但 WireGuard 隧道本身是通过 UDP 协议进行通信的,而国内运营商根本没有能力和精力根据 TCP 和 UDP 的不同去深度定制不同的 QoS 策略,几乎全部采取一刀切的手段:对 UDP 进行限速甚至封锁。
  • 虽然对 UDP 不友好,但却无力深度检测 TCP 连接的真实性。
  • 将 UDP 连接伪装成 TCP 连接不就蒙混过关了。目前支持将 UDP 流量伪装成 TCP 流量的主流工具是 udp2raw,但是有一款更强大的新工具: Phantun

需要进一步的研究学习

暂无

遇到的问题

暂无

开题缘由、总结、反思、吐槽~~

参考文献

WireGuard 基础教程:使用 Phantun 将 WireGuard 的 UDP 流量伪装成 TCP

https://nordvpn.com/zh-tw/blog/vpn-xieyi/

https://blog.mozcp.com/wireguard-usage/