之前虽然在软路由上配好了 shadowsocks 的透明代理,本着生命不息折腾不止的心态,一直想尝试一下国内/国际流量的智能分流。
基于目的 IP 地址的智能分流目前有两个流派:
chnroutes 的方案很简单直接,提取所有中国的 IP 地址段,只要不在范围内的一律走国际出口。优点是非常精准,配合 dnsmasq-china-list 解决掉 DNS 污染之后能够非常准确的对国内/国际流量进行分流。缺点也很明显,中国的 IP 地址段数量太庞大,我试着生成了一下,总共产生了8k条以上的路由表项,实在是多得有点可怕。
bestroutetb 项目则提出了一个新的思路,将全球的 IP 地址段分为三类:
- 一定走国内出口的 IP 段(中国 IP 段)
- 一定走国际出口的 IP 段(默认美国/英国/日本/香港 IP 段,可以自定义)
- 可以走国内出口也可以走国际出口的 IP 段
这种方式,通过牺牲一部分分流的精度,实现了对路由表项的压缩,我试着生成了一下,默认配置产生的路由表项只剩下了2k多条,如果可以接受更模糊一点的匹配,可以进一步精简路由表项。
基于这样的对比,很多人都选择使用 bestroutetb 作为智能分流的方案,shadowsocks-libev 的官方文档也推荐了 bestroutetb。然而,这里有一个问题,由于 shadowsocks 透明代理使用防火墙 iptables/nftables 而不是路由表来对目的 IP 地址进行判断实现分流,因此就无法利用防火墙的最长 prefix 匹配规则来对路由表项进行压缩优化。举个例子,以下为 bestroutetb 生成的路由表项:
14.0.0.0/8 net 14.0.0.0/12 vpn 14.0.0.0/21 net
若目的地址为 14.2.0.1
,由于 14.0.0.0/12
的 prefix 长度长于 14.0.0.0/8
因而可以获得更高的匹配优先级,路由结果是国际出口。而对于 shadowsocks 透明代理,由于不能使用路由表,在网上搜了一下,发现大多数人的做法都是只保留其中的国内部分的路由规则,因此路由表项就精简成了:
iptables -t nat -A PREROUTING -p tcp -d 14.0.0.0/8 -j RETURN iptables -t nat -A PREROUTING -p tcp -d 14.0.0.0/21 -j RETURN
即,针对所有国内的 IP 地址段,不走国际出口。拿刚才举例子的 IP 地址 14.2.0.1
,由于命中了 14.0.0.0/8
地址段,因而被识别成了国内 IP,这无疑是不正确的。
bestroutetb 的作者也在 github 上说了,bestroutetb 算法的核心是通过网段二分化来优化路由表,这种用法会导致无法对路由表进行有效优化,因此是不可取的。
因而,得出结论:bestroutetb 只适用于路由表,无法用于防火墙规则。
那么还有什么办法可以让 shadowsocks 也用上 bestroutetb?既然 bestroutetb 只能用于路由表,是不是可以想办法让 shadowsocks 用路由表来分流呢?
这里 shadowsocks-libev 自带的透明代理就不能满足需求了,需要用到另一个工具 tun2socks,tun2socks 可以在系统中创建一个虚拟网卡,然后将虚拟网卡的流量导入到 shadowsocks 客户端所提供的 socks proxy中。既然有了虚拟网卡,我们就能很方便的使用路由表来管理流量,从而实现利用 bestroutetb 进行智能分流的目的。
tun2socks 的安装不再赘述,安装完成后,首先创建一个 tun 虚拟网卡,我给命名为 tun1
:
ip tuntap add dev tun1 mode tun user root
给虚拟网卡分配地址,可以随便分配一个,但是注意不能跟当前局域网的 IP 地址冲突,我给分配了一个 192.168.2.1
:
ip addr add 192.168.2.1 dev tun1
启用虚拟网卡 tun1
:
ip link set dev tun1 up
启动 tun2socks, 根据实际情况填写参数,我的 shadowsocks 客户端监听的是 192.168.1.1:1080
,因而命令行参数是:
badvpn-tun2socks --tundev tun1 --netif-ipaddr 192.168.2.1 --netif-netmask 255.255.255.255 --socks-server-addr 192.168.1.1:1080
至此,tun2socks 已经可以使用,所有路由到虚拟网卡 tun1 的流量将会被转发至 shadowsocks。
安装 bestroutetb:
npm install -g bestroutetb
使用 bestroutetb 生成添加路由规则的脚本:
bestroutetb -p custom -o add-routes --rule-format=$'ip route add %prefix/%length dev %gw table ss\n' --gateway.net=ppp0 --gateway.vpn=tun1 --header=$'#!/bin/sh\n\n'
对应的删除路由规则的脚本:
bestroutetb -p custom -o del-routes --rule-format=$'ip route del %prefix/%length dev %gw table ss\n' --gateway.net=ppp0 --gateway.vpn=tun1 --header=$'#!/bin/sh\n\n'
由于我并不希望让所有设备都使用这张路由表,因此在每一条路由项后面都加了 table ss
,同时需要将特定来源的 IP 加入这张路由表的白名单之中从而实现源地址路由,因此需要在添加路由规则的脚本中加入:
ip rule add from 192.168.1.xx table ss
相应的删除路由规则的脚本中也要加入:
ip rule del from 192.168.1.xx table ss
使用 systemd 以实现自动启动,贴一下我的 tun2socks.service
文件:
[Unit] Description=Tun2Socks Service Requires=network-online.target After=network-online.target [Service] Type=simple ExecStartPre=/usr/sbin/ip tuntap add dev tun1 mode tun user root ExecStartPre=/usr/sbin/ip addr add 192.168.2.1 dev tun1 ExecStartPre=/usr/sbin/ip link set dev tun1 up ExecStart=/usr/local/bin/badvpn-tun2socks --tundev tun1 --netif-ipaddr 192.168.2.1 --netif-netmask 255.255.255.255 --socks-server-addr 192.168.1.1:1080 ExecStartPost=/usr/local/bin/add-routes ExecStopPost=/usr/local/bin/del-routes ExecStopPost=/usr/sbin/ip link del dev tun1 [Install] WantedBy=multi-user.target
启用 tun2socks.service
:
systemd enable tun2socks
systemd start tun2socks
Leave a Comment