OpenWRT实现OpenVPN按ipset自动分流

接着上面一篇介绍 Windscribe 免费 VPN 的文章,住处的网络通过 OpenVPN 连接 Windscribe 之后虽然速度不快,但好歹广电宽带下没有之前用的几个 VPS 经常超时的问题了。因此想着最好能部署到现在用的 newifi mini 路由器上(毕竟已经刷了 PandoraBox 固件),目标就是能在路由器上用 OpenVPN 连接 Windscribe 并自动分流翻墙访问某些特殊的网站。

OpenWRT 安装使用 OpenVPN

首先在路由器上安装 OpenVPN 客户端:

[root@PandoraBox:/root]# opkg update
[root@PandoraBox:/root]# opkg install openvpn-openssl

把上篇文章中生成的 Windscribe OpenVPN 配置文件上传到 /etc/openvpn 目录,假设配置文件路径为 /etc/openvpn/windscribe.ovpn

这里需要注意 OpenWRT 的 OpenVPN 客户端并不能像 Windows 等客户端那样提示用户输入 Windscribe VPN 连接用户名和密码,只能通过用户密码文件指定。我们需要手工生成用户密码文件 /etc/openvpn/windscribe.txt,文件格式为第一行用户名,第二行密码。

接着修改 OpenVPN 配置文件,增加一行指定用户密码文件:

auth-user-pass windscribe.txt

提示

如果你使用的 OpenVPN 客户端版本比较老(比如我的 PandoraBox 系统里安装的是 2.3.6-2 版本),可能不支持 Windscribe OpenVPN 配置文件里的 block-outside-dns 选项,如果 OpenVPN 运行报错的话可以注释掉这个选项。

然后修改 /etc/config/openvpn 配置文件增加一个新的 OpenVPN instance,新的配置名称不要与现有的重复即可:

config openvpn 'windscribe'
	option config '/etc/openvpn/windscribe.ovpn'
	option enabled '1'

剩下就是激活并启动 OpenVPN 客户端服务了:

[root@PandoraBox:/root]# /etc/init.d/openvpn enable
[root@PandoraBox:/root]# /etc/init.d/openvpn start

稍等一会,如果一切正常的话,用 logread 命令应该能看到 OpenVPN 的连接日志:

[root@PandoraBox:/root]# logread -f
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: TUN/TAP device tun0 opened
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: /sbin/ifconfig tun0 10.110.34.41 netmask 255.255.254.0 mtu 1500 broadcast 10.110.35.255
Fri Jul  7 00:02:13 2017 daemon.notice openvpn(windscribe)[5618]: Initialization Sequence Completed

连接上服务器之后可以看看 OpenVPN tun 设备路由信息:

[root@PandoraBox:/root]# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.110.34.1     128.0.0.0       UG    0      0        0 tun0
0.0.0.0         10.58.71.1      0.0.0.0         UG    0      0        0 eth0.2
10.58.71.0      0.0.0.0         255.255.255.0   U     0      0        0 eth0.2
10.110.34.0     0.0.0.0         255.255.254.0   U     0      0        0 tun0
103.10.197.3    10.58.71.1      255.255.255.255 UGH   0      0        0 eth0.2
128.0.0.0       10.110.34.1     128.0.0.0       UG    0      0        0 tun0
192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 br-lan

dnsmasq 配置修改

与之前使用的 Shadowsocks 通过 ipset 自动分流类似,我们首先需要在 OpenWRT 上安装 dnsmasq-fullipset 包。

基本原理也很简单,OpenWRT 上的 dnsmasq 服务器将 gfwlist 中的域名通过 OpenVPN 解析防止域名污染并将解析结果添加到 ipset,然后设置 ipset 中的所有 IP 地址都走 OpenVPN 翻墙,其它地址仍然走默认的宽带线路。

dnsmasq 使用 gfwlist 和 gfwlist 自动更新的方法可以参考我之前写的 newifi mini路由器OpenWRT初步体验 文章。

我的服务器上基于 gfwlist 自动生成的 dnsmasq 配置文件地址没有变:

https://zohead.com/downloads/dnsmasq.tar.gz

只是自动更新 gfwlist 的 crontab 配置文件要修改一下了,因为上面的 dnsmasq 配置文件是为 Shadowsocks 本地转发解析域名准备的,这里换成 Google 提供的 8.8.8.8 DNS 解析服务器:

[root@PandoraBox:/root]#cat /etc/crontabs/root
10 5 * * * curl -k -o /tmp/dnsmasq.tar.gz https://zohead.com/downloads/dnsmasq.tar.gz && tar -C /tmp -xzf /tmp/dnsmasq.tar.gz && sed -i 's/127\.0\.0\.1#5353$/8.8.8.8/g' /tmp/dnsmasq_list.conf && cat /tmp/dnsmasq_list.conf > /etc/dnsmasq.d/dnsmasq_list.conf && rm -f /tmp/dnsmasq.tar.gz /tmp/dnsmasq_list.conf

配置 ipset 自动分流

首先修改 /etc/iproute2/rt_tables 配置文件,为 OpenVPN 专门增加一个名字为 gfwtable 的路由表(数字不和现有的表重复即可):

99	gfwtable

需要注意的是我们可以从上面的 OpenVPN tun 设备路由信息中看到 OpenVPN 客户端连接上服务器之后自动添加了默认路由,而为了使默认流量都走宽带线路,需要修改 OpenVPN 配置文件禁用默认路由:

route-nopull

编辑 /etc/firewall.user 文件增加自定义的防火墙规则:

[root@PandoraBox:/root]# cat /etc/firewall.user
ipset -N gfwlist iphash
iptables -t mangle -N fwmark
iptables -t mangle -C OUTPUT -j fwmark || iptables -t mangle -A OUTPUT -j fwmark
iptables -t mangle -C PREROUTING -j fwmark || iptables -t mangle -A PREROUTING -j fwmark

分别简单解释一下:

  • 第一行增加新的 iphash 类型的名为 gfwlist 的 ipset;
  • 第二行在 iptables 的 mangle 表中新增 fwmark 链;
  • 第三和第四行分别在 iptables 的 mangle 表的 OUTPUTPREROUTING 链中增加 fwmark target,为了避免重复,增加之前都用了 iptables 命令判断原有规则是否已经存在;
  • 后面三条规则有些 OpenWRT 系统里已经自带了,这里为了保险还是加上了。

接着还要再修改 Windscribe OpenVPN 配置文件,增加 VPN 的启动和停止脚本设置,因为我们要在脚本中 添加 / 删除 路由和 iptables 规则:

script-security 2
up /etc/openvpn/openvpn-up.sh
down /etc/openvpn/openvpn-down.sh

当然别忘了给 OpenVPN 启动和停止脚本增加执行权限:

[root@PandoraBox:/root]#chmod +x /etc/openvpn/openvpn-up.sh /etc/openvpn/openvpn-down.sh

OpenVPN 调用启动和停止脚本的参数格式会区分 tun 和 tap 设备,对于 tun 设备脚本调用参数是这样的:

cmd tun_dev tun_mtu link_mtu ifconfig_local_ip ifconfig_remote_ip [ init | restart ]

tap 设备则是:

cmd tap_dev tap_mtu link_mtu ifconfig_local_ip ifconfig_netmask [ init | restart ]

这里我们只需要关心第一个 tun /tap 设备名参数,我的 OpenVPN 启动脚本如下:

[root@PandoraBox:/root]#cat /etc/openvpn/openvpn-up.sh
#!/bin/sh
ip route add 8.8.8.8 dev $1
iptables -t mangle -A fwmark -m set --match-set gfwlist dst -j MARK --set-mark 0xffff
ip rule add fwmark 0xffff table gfwtable
ip route add default dev $1 table gfwtable
iptables -I FORWARD -o $1 -j ACCEPT
iptables -t nat -I POSTROUTING -o $1 -j MASQUERADE

同样简单说明一下:

  • 首先将 8.8.8.8 DNS 解析服务器设置为从 OpenVPN 走防止域名污染;
  • 使用 iptables mangle 表中的 fwmark 链为所有目标为 gfwlist ipset 中 IP 地址的数据包打标记,这里标记号用的是 0xffff;
  • 所有标记号为 0xffff 的数据包都使用上面新增的 gfwtable 路由表;
  • gfwtable 路由表固定使用 OpenVPN 线路;
  • 最后两条 iptables 规则也非常重要,允许路由器下的其它设备访问被封锁域名时走 OpenVPN 线路。

类似的 OpenVPN 停止脚本就比较简单了:

[root@PandoraBox:/root]#cat /etc/openvpn/openvpn-down.sh
#!/bin/sh
ip rule del table gfwtable
iptables -t mangle -D fwmark -m set --match-set gfwlist dst -j MARK --set-mark 0xffff
iptables -D FORWARD -o $1 -j ACCEPT
iptables -t nat -D POSTROUTING -o $1 -j MASQUERADE

都是清理启动脚本中增加的规则,ip route 项会在 tun 设备停止时自动删除,不需要手工进行清理了。

总结

经过这番对 OpenWRT 的配置折腾,现在住处的手机和电脑就都能通过 Windscribe OpenVPN 自动翻墙了。

最后贴上我的 newifi mini 路由器上的 Windscribe 完整 OpenVPN 配置文件给大家参考,由于文件比较长我放到 Pastebin 上了,最后祝大家炎炎夏日也能玩的开心:

http://pastebin.com/raw.php?i=TWbaMXdg