简述
这是一种基于域名的 VPN 智能翻越方案。不同于 chnroutes 这类通过维护一个 IP 地址列表来区分国内外网站的方案,基于域名的方式不受 IP 地址变动的影响。仅需维护一个相对很少有变化的域名列表即可。
dnsmasq 在 2.66 版之后加入了对 ipset 的支持,可将指定域名的 IP 解析后自动加入某一 ipset 中。 再配置路由规制,使该 ipset 中的 IP 走 VPN 即可。
感谢 @wzyboy 提供了此方案的思路。
大致流程
- 配置 VPN
- 配置 dnsmasq,指定域名
- 增加一个路由表,默认网关为 VPN
- 使用 iptables 匹配 ipset 并打上 mark
- 使用 ip rule 将打上 mark 的包送入该路由表
所需软件
- iproute2
- dnsmasq (>= 2.66, has ipset)
- iptables (with ipset and mark modules)
opkg update opkg install ip ipset kmod-ipt-ipset dnsmasq-full |
OpenWrt 默认的dnsmasq
包并不包含 ipset 支持,需安装dnsmasq-full
(感谢 @leavic 的提醒)。亦可修改 makefile 自行编译,以节省空间。
配置文件
列举一下涉及的各部分配置文件,供参考。
VPN
各类 VPN 均可,请参考 VPN overview。注意请勿将 VPN 设为默认路由。
rt_tables
添加outwall
路由表。 走 VPN 的流量都将使用此表。
echo "200 outwall" >> /etc/iproute2/rt_tables |
rc.local
使系统启动时创建一个名为outwall
的 ipset。
在 /etc/rc.local 中添加:
# vi /etc/rc.local
ipset create outwall hash:ip |
名字可以随便取,与 dnsmasq.conf 和 firewall.user 中的保持一致即可。
firewall.user
将匹配 ipset outwall
的包全部标上 mark 8。
在 /etc/firewall.user 中添加:
# vi /etc/firewall.user iptables -t mangle -A fwmark -m set --match-set outwall dst -j MARK --set-mark 8 |
打上 mark 以后,就可以指定它们所使用的路由表了。
mark 值可随便选,保持一致即可。若同时装有 qos-scripts,mark 可选一个较大的值,以防与其发生冲突。
VPN Post-connected Script
确保以下脚本在每次 VPN 连接建立后执行。
不同 VPN 的配置方法可能不同。 一个比较通用的方法是使用 Hotplug。
(我这次用的是 vpnc,所以比较偷懒地将脚本放在了/etc/vpnc/post-connect.d/
下)
#!/bin/sh ip route add 8.8.8.8 dev $TUNDEV ip route add default dev $TUNDEV table outwall ip rule add fwmark 8 table outwall |
注意,须将$TUNDEV
替换为 VPN 设备名,比如ppp0
。
这段脚本有三个作用:
- 让 8.8.8.8 走 VPN,防止 DNS 污染;
- 由于 VPN 断线时相关路由会被自动删除,所以在需要每次连接时添加一次;
- ip rule 在 VPN 断线时将手动删除(见下一节),切换至正常路由。
VPN Disconnect Script
见上节说明,须在 VPN 断线时 自动执行的脚本:
#!/bin/sh ip rule del table outwall |
dnsmasq.conf
请参考 dnsmasq man(8)。
修改 /etc/dnsmasq.conf,在其中加入需要翻越的域名。 格式如下:
server=/域名/8.8.8.8 ipset=/域名/outwall
server
将指定域名使用 8.8.8.8 查询(8.8.8.8 已配置为走 VPN,防止 DNS 污染);ipset
将指定域名的所有 IP 加入 ipsetoutwall
中;- 可在一行添加多个域名,如
ipset=/twitter.com/t.co/outwall
; google.com
将同时匹配 google.com 和 plus.google.com。com
将匹配所有 .com 结尾域名。
一个可供参考的配置如下, 该配置:
- 尽可能地让 Google 所有常用服务走 VPN
- 允许访问 Facebook、Twitter 和 YouTube
- 让 GitHub 的 CDN 走 VPN
server=/google.com/8.8.8.8 server=/googleusercontent.com/8.8.8.8 server=/gstatic.com/8.8.8.8 server=/googlehosted.com/8.8.8.8 server=/golang.org/8.8.8.8 server=/googleapis.com/8.8.8.8 ipset=/google.com/outwall ipset=/googleusercontent.com/outwall ipset=/gstatic.com/outwall ipset=/googlehosted.com/outwall ipset=/golang.org/outwall ipset=/googleapis.com/outwall server=/twitter.com/8.8.8.8 server=/twimg.com/8.8.8.8 server=/t.co/8.8.8.8 ipset=/twitter.com/outwall ipset=/twimg.com/outwall ipset=/t.co/outwall server=/facebook.com/8.8.8.8 ipset=/facebook.com/outwall server=/youtube.com/8.8.8.8 server=/ytimg.com/8.8.8.8 server=/ggpht.com/8.8.8.8 server=/youtu.be/8.8.8.8 server=/googlevideo.com/8.8.8.8 server=/youtube-nocookie.com/8.8.8.8 ipset=/youtube.com/outwall ipset=/ytimg.com/outwall ipset=/ggpht.com/outwall ipset=/youtu.be/outwall ipset=/googlevideo.com/outwall ipset=/youtube-nocookie.com/outwall server=/githubusercontent.com/8.8.8.8 server=/github.global.ssl.fastly.net/8.8.8.8 server=/githubapp.com/8.8.8.8 ipset=/githubusercontent.com/outwall ipset=/github.global.ssl.fastly.net/outwall ipset=/githubapp.com/outwall
关于 Shadowsocks
(更新于 2014-11-23)
补充说明一下,此方案亦可与 shadowsocks-libev 配合使用,配置起来会比 VPN 简单很多。自己用了几个月,体验良好。这里简单介绍一下配置方法。
1、在 shdowsocks.org 可以下载到已编译的 ipk 包,在 OpenWrt 上安装即可。
2、配置好 Shadowsocks,并运行,注意服务器那边需要支持 UDP 转发(请使用较新版并配好防火墙)。OpenWrt 中使用ss-redir
代理 TCP 连接,使用ss-tunnel
代理 DNS 查询。具体参数请参考范例:
ss-redir -c /etc/shadowsocks.json -l 1080 ss-tunnel -c /etc/shadowsocks.json -l 5533 -L 8.8.8.8:53 -u
3、在/etc/firewall.user
中加入(参考):
iptables -t nat -N shadowsocks iptables -t nat -A shadowsocks -m set ! --match-set outwall dst -j RETURN iptables -t nat -A shadowsocks -p tcp --syn -m connlimit --connlimit-above 32 -j RETURN iptables -t nat -A shadowsocks -p tcp -j REDIRECT --to-ports 1080 iptables -t nat -A PREROUTING -s 192.168.0.0/16 -j shadowsocks
这将使匹配outwall
(这个 IPSet)的 TCP 连接指向ss-redir。
后者将为这些连接建立隧道并通过 Shadowsocks 协议加密发送。
4、/etc/dnsmasq.conf
中不再使用8.8.8.8
,而是使用127.0.0.1#5533
,范例如下:
server=/google.com/127.0.0.1#5533 ipset=/google.com/outwall
这将使 dnsmasq 将 DNS 查询请求发送至ss-tunnel
,后者在将其通过 SS 转送至 Google Public DNS。
由于不再涉及路由,不需要安装配置iproute2
,不再需要使用-j MARK
打标记。当然,也不用在配置 VPN 及相关脚本。
优点:方便配置,不管是路由器还是服务器。
缺点:只代理 TCP 连接,UDP、ICMP (ping) 等无法使用。
赞!
话说你的博客 InoReader 取 RSS 时经常超时呢喵?
不知道为啥生成一个 feed (有时)需要超过 30s..
我想我找到凶手了..(
WP Github Gist 这个插件在生成全文 RSS 的时候回去 GitHub 转一圈…
原来如此喵……
求一个ar71xx的带ipset的dnsmasq安装包
先试一下我这个 brcm63xx 能否使用?
这个我不太了解,兴许可以通用?
我这里有一个2.71版的ar71xx芯片的带ipset的
http://www.lifetyper.com/?wpdmact=process&did=OS5ob3RsaW5r
非常感谢!
还有顺便求一下pptp链接vpn的配置VPN Post-connected Script和VPN Disconnect Script方式
https://gist.github.com/sorz/b85bae86617ed03505a8
ppp0 换成 PPTP 的名字,ifconfig 里的那个。
保存为 /etc/ppp/ip-up 和 /etc/ppp/ip-down。
(没测试过
Pingback引用通告: 全新的TL-WR720n 4M自动翻墙固件 - LifeTyper
我有一个新的想法:
先设置好策略路由,对打上标记的数据包走vpn。
写一个linux的内核模块,然后监听所有到80端口的syn请求,凡是即将超时没有收到syn-ack数据包的都认为是被防火墙block 的连接,针对这个连接,伪造一个syn-ack给客户端,让浏览器以为连接到服务器成功。再伪造一个syn,给这个syn打上标记,通过vpn连到服务器上。这样双方都会认为连接成功了,就把桥搭上了,以后的数据包都打上标记,全部走vpn出去了。感觉这个办法应该是行,不再需要考虑什么域名,只要是被block的站全部都可以自动连通。但缺点可能会是连接速度较慢,因为需要等那个快超时后再启用这个机制。
动态地检测是否被墙,然后透明无痛地将连接路由到VPN?
要是能实现的话那体验一定不错,检测速度慢倒还好,可以缓存黑名单嘛..
除了 syn-ack 超时,还要考虑被墙 reset 连接的情况,这种情况似乎更多。
不知道 HTTP 持久连接中非首个请求的 URL 是否会触发 reset,如果会,这种情况要透明地处理就更复杂了..
还有 DNS 污染的问题…
iptables -t mangle -A fwmark -m set –match-set outwall dst -j MARK –set-mark 8
这个貌似有点问题 我调整为如下成功翻墙,iptables -t mangle -A PREROUTING -m set –match-set outway dst -j MARK –set-mark 8
本人对iptable不太熟,mangle表应该没有对应fwmark这个状态。
fwmark 是 OpenWrt 自带的一个 chain,没有的话就用 PREROUTING 吧。
怎么修改 支持ipset?
opkg update
opkg install dnsmasq-full
新的build里面没有默认安装iproute2,opkg install也找不到这个包,怎么办?
opkg install ip
多谢。已经成功了.不过如果从openwrt官方的固件安装,还需要装ipset这个包.另外,很奇怪的是,用traceroute google.com,返回的路径是没有走vpn的,但是确实在清单里的网站都能上了.
ipset 是我漏了,谢谢提醒。traceroute 这个有点奇怪..
Pingback引用通告: 路由器自动分流科学上网原理和实现方式研究 | Harvey Hu's Blog