使用ipset进行wireguard国内外分流
起因
我的网络加速方案用了很多年,虽然更换了几轮,整体来说都是围绕全自动国内外透明代理的方案,上一个方案是使用本地客户端透明代理,配合iptables实现自动国内外分流,使用起来并没有什么问题,非常完美。前段时间调整方案all in wg,所有设备都使用WG连接到家里,然后分流出国。
目前设备连接上WG后,由于wg配置文件无法使用复杂路由表,设备只能使用全局代理,确实能实现国内外分流,但是这样国内流量是从我家里绕了一圈出来的,对于不常用的设备这样足够了,但是对于每天使用的笔记本来说全天开wg,国内下载有点慢了。
于是打算研究下,如何让笔记本分流的更加智能一些。
目标
连接wg后,设备可以国外设备走wg,国内设备走本地网络。
看起来目标挺简单的,wg本身就是网络端口,添加国外路由走wg端口即可。但是这样我自己使用起来有几个难受的点。
- 添加国外路由后,路由表中会有成千上外的路由规则,这样非常难看,日常查看设备路由的时候不太方便。
- 个人一般使用白名单路由,即chnroute中的走国内,其他走国外,国内路由的下一跳在网络切换之后可能会变更,导致需要重新调整路由器。
- 管理路由没办法像之前管理ipset那样简单的修改配置文件重新载入。
说起之前iptables+ipset我挺满意的,那么修改一下目标。尝试使用iptables实现不依赖路由表的wireguard国内外分流。
调研
通过简单调研发现实现网络分流,主要通过路由规则(route)和路由策略(rule)实现,route已经不考虑了,看看rule是否有突破口。要结合iptables的规则分流,最好需要对包打上标记,通过文档查看到wireguard配置文件中支持一个选项FwMark
用来设置网络包标记。两者结合下,先修改配置,然后查看rule观察。
1 | $ ip rule [git:master|*?] |
观察以上规则,解读一下,包从上到下匹配规则:
- 首先匹配local规则,主要是lo接口的一些路由
- 然后查询主路由表中非默认路由的路由规则
- 没有标记0xca6c的查询51820表
- 剩下的查询主路由表
- 最后剩下的包走默认路由表
核心在于第三条,0xca6c就是之前设置的FwMark
,查询51820表就是走到wireguard上啦,这里就有一个可以操作的地方,
- 打上标记的:不走wireguard
- 不打标记的:走wireguard
那么我需要做的就是把国内路由打上标记。
实现
尝试使用iptables配合ipset匹配chnroute后,打上标记,规则如下:
1 | iptables -t mangle -A PREROUTING -m set --match-set chnroute dst -j MARK --set-xmark 0xca6c |
同理ipv6的规则为:
1 | ip6tables -t mangle -A PREROUTING -m set --match-set chnroute6 dst -j MARK --set-xmark 0xca6c |
最终效果非常好,可以通过ipset中的chnroute和chnroute6两个表调整动态调整分流策略,并且路由表干净,笔记本更换网络后无须操作自动生效。
需要注意的是,这个方案只能实现ip层面的分流,还需要配合一个无污染的DNS,我是直接使用wireguard服务端的DNS。