使用ipset进行wireguard国内外分流

起因

我的网络加速方案用了很多年,虽然更换了几轮,整体来说都是围绕全自动国内外透明代理的方案,上一个方案是使用本地客户端透明代理,配合iptables实现自动国内外分流,使用起来并没有什么问题,非常完美。前段时间调整方案all in wg,所有设备都使用WG连接到家里,然后分流出国。

目前设备连接上WG后,由于wg配置文件无法使用复杂路由表,设备只能使用全局代理,确实能实现国内外分流,但是这样国内流量是从我家里绕了一圈出来的,对于不常用的设备这样足够了,但是对于每天使用的笔记本来说全天开wg,国内下载有点慢了。

于是打算研究下,如何让笔记本分流的更加智能一些。

目标

连接wg后,设备可以国外设备走wg,国内设备走本地网络。

看起来目标挺简单的,wg本身就是网络端口,添加国外路由走wg端口即可。但是这样我自己使用起来有几个难受的点。

  1. 添加国外路由后,路由表中会有成千上外的路由规则,这样非常难看,日常查看设备路由的时候不太方便。
  2. 个人一般使用白名单路由,即chnroute中的走国内,其他走国外,国内路由的下一跳在网络切换之后可能会变更,导致需要重新调整路由器。
  3. 管理路由没办法像之前管理ipset那样简单的修改配置文件重新载入。

说起之前iptables+ipset我挺满意的,那么修改一下目标。尝试使用iptables实现不依赖路由表的wireguard国内外分流。

调研

通过简单调研发现实现网络分流,主要通过路由规则(route)和路由策略(rule)实现,route已经不考虑了,看看rule是否有突破口。要结合iptables的规则分流,最好需要对包打上标记,通过文档查看到wireguard配置文件中支持一个选项FwMark用来设置网络包标记。两者结合下,先修改配置,然后查看rule观察。

1
2
3
4
5
6
$ ip rule                                                                                                                                                             [git:master|*?]
0: from all lookup local
31264: from all lookup main suppress_prefixlength 0
31265: not from all fwmark 0xca6c lookup 51820
32766: from all lookup main
32767: from all lookup default

观察以上规则,解读一下,包从上到下匹配规则:

  1. 首先匹配local规则,主要是lo接口的一些路由
  2. 然后查询主路由表中非默认路由的路由规则
  3. 没有标记0xca6c的查询51820表
  4. 剩下的查询主路由表
  5. 最后剩下的包走默认路由表

核心在于第三条,0xca6c就是之前设置的FwMark,查询51820表就是走到wireguard上啦,这里就有一个可以操作的地方,

  1. 打上标记的:不走wireguard
  2. 不打标记的:走wireguard

那么我需要做的就是把国内路由打上标记。

实现

尝试使用iptables配合ipset匹配chnroute后,打上标记,规则如下:

1
2
3
iptables -t mangle -A PREROUTING -m set --match-set chnroute dst -j MARK --set-xmark 0xca6c
iptables -t mangle -A OUTPUT -m set --match-set chnroute dst -j MARK --set-xmark 0xca6c
iptables -t nat -A POSTROUTING -m mark --mark 0xca6c -j MASQUERADE

同理ipv6的规则为:

1
2
3
ip6tables -t mangle -A PREROUTING -m set --match-set chnroute6 dst -j MARK --set-xmark 0xca6c
ip6tables -t mangle -A OUTPUT -m set --match-set chnroute6 dst -j MARK --set-xmark 0xca6c
ip6tables -t nat -A POSTROUTING -m mark --mark 0xca6c -j MASQUERADE

最终效果非常好,可以通过ipset中的chnroute和chnroute6两个表调整动态调整分流策略,并且路由表干净,笔记本更换网络后无须操作自动生效。

需要注意的是,这个方案只能实现ip层面的分流,还需要配合一个无污染的DNS,我是直接使用wireguard服务端的DNS。