Monthly Archive for August, 2012

DD Wrt 路由器级VPN翻墙方案

最近终于抽出时间, 在家里的dd wrt路由器上配置了VPN ,实现区域网内所有设备透明翻墙。这里稍微整理一下。

(注:以下内容适用于使用PPPoE协议连接公网的网路环境;并且要求dd wrt路由器具有jffs空间和USB口)

基本方案还是chnroutes的思路,通过添加国内IP路由表实现国内外IP分流:国内IP直接走ISP,国外IP全部走VPN。之所以没有用autoddvpn方案是因为autoddvpn的graceMode并不完美,它对GFW的关键字封锁(包括url query string关键字封锁和深度包检测)无能为力,仍然会被reset。而且现在大部分国外IP通过VPN访问还能起到加速作用(我用的是Linode东京机房自己架设的OpenVPN)

准备工作:开启路由器jffs空间;挂载USB存储设备到/opt;然后根据这里说明安装Optware组件。

安装配置OpenVPN

请不要使用dd wrt的Web界面,而是手工将配置文件和证书放到路由器上,然后通过命令行启动OpenVPN。配置文件和证书可以放在/jffs或/opt目录里。

创建dd wrt自启动文件 /jffs/etc/config/openvpn.startup,设置许可权为+x

#!/bin/sh
openvpn --config /jffs/openvpn/client.conf

在DD Wrt Web界面 Administration – Commands里添加并保存iptables防火墙规则

# allow OpenVPN
iptables -I FORWARD -i br0 -o tun0 -j ACCEPT
iptables -I FORWARD -i tun0 -o br0 -j ACCEPT
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE

创建国内外IP分流脚本

下载chnroutes项目提供的python脚本,运行

python chnroutes.py -p openvpn

会生成vpn-up.sh和vpn-down.sh两个文件,按照下面的说明将这两个文件做一些修改,然后分别重命令为 script.ipup和script.ipdown,放到/jffs/etc/config/目录下,同样设置许可权+x。

script.ipup:在vpn-up.sh开头添加几行内容,然后删去一些行

#!/bin/sh -

OLDGW=$(nvram get wan_gateway)
if [ $OLDGW == '' ]
then
    exit 1
fi

route add -net 1.0.1.0 netmask 255.255.255.0 gw $OLDGW
route add -net 1.0.2.0 netmask 255.255.254.0 gw $OLDGW
route add -net 1.0.8.0 netmask 255.255.248.0 gw $OLDGW
#.....

script.ipdown:将vpn-down.sh第一行的#!/bin/bash -改为#!/bin/sh -,然后删去下面几行内容

#!/bin/sh -

route del -net 1.0.1.0 netmask 255.255.255.0
route del -net 1.0.2.0 netmask 255.255.254.0
route del -net 1.0.8.0 netmask 255.255.248.0
#......

这里使用的方式是利用dd wrt的脚本自动执行机制,在PPPoE拨号连接和断开时自动添加或删除分流路由表。之所以在PPPoE状态改变而不是在OpenVPN连接和断开时添加 / 删除路由表的原因,是因为OpenVPN在使用中很可能因为网路不稳定等因素断开;而PPPoE连接通常比较稳定,连上后很少中断。目前的国内IP直连路由表共3500多条,每次执行添加或删除操作时都需要较长时间(在我的华硕RT-N16路由器上接近5分钟),将脚本放在PPPoE连接和断开时执行就意味着通常只需要在路由器启动后执行一次,避免了(OpenVPN不稳定中断时)的反复执行。

部署pwx-dns-proxy

这是一个Python写的DNS代理,它的作用是监听LAN内的DNS解析请求,根据域名不同分别转交给不同DNS解析:cn域名和国内常见网站的域名以UDP方式转发给本地ISP解析,快速并且能够享受CDN加速;其它所有域名以TCP方式转发给Google Public DNS解析,避免DNS劫持。

首先请在DD Wrt WEB界面禁用dnsmasq(它会占用53埠,并且现在已经不需要它了。之所以不用dnsmasq是因为它无法将接受的UDP DNS解析请求通过TCP转发给上游DNS伺服器。)

在路由器上安装python环境。

ipkg-opt update
ipkg-opt install python26
ipkg-opt install py26-twisted

修改pwx-dns-proxy配置文件dnsproxy.conf

#这里修改为你路由器的LAN IP
listen_tcp(53, "192.168.0.1")
listen_udp(53, "192.168.0.1")

#将ISP DNS修改为你的本地ISP DNS
# add_server(name, address, port, is_tcp, [timeout])
add_server("google", "8.8.8.8", 53, True)
add_server("isp", "218.2.135.1", 53, False) #218.2.135.1 江苏电信主DNS伺服器

#设置使用ISP解析的域名, 以下是我的设置,包含了国内常见主要网站。
# 在 domain_list 中的域,将使用指定 server 查询。
# example.tld 仅精确匹配这个二级域。若要匹配其子域,
# 请使用 .example.tld。
add_lookups("isp", [
	".cn",
	
	#baidu
	".baidu.com",
	".bdimg.com",
	
	#sohu
	".sohu.com",
	".sogou.com",
	
	#163
	".163.com",
	".126.net",
	".126.com",
	".netease.com",
	".youdao.com",
	
	#cctv
	".cctv.com",
	".cctvpic.com",
	
	#tencent
	".qq.com",
	".gtimg.com",
	".paipai.com",
	".soso.com",
	
	#sina
	".sina.com",
	".weibo.com",
	".iask.com",
	
	#taobao
	".taobao.com",
	".taobaocdn.com",
	".tmall.com",
	".etao.com",
	
	#cdn
	".lxdns.com",
	
	#360buy
	".360buy.com",
	".360buyimg.com",
	".minitiao.com",
	
	#51buy
	".51buy.com",
	".icson.com",
	
	#general
	".qidian.com",
	".renren.com",
	".115.com",
	".hao123.com",
	".youku.com",
	".tudou.com",
	".56.com",
	".pptv.com",
	".ku6.com",
	".iqiyi.com",
	".xunlei.com",
	".vancl.com",
	".mop.com",
	".cn.yahoo.com",
	".china.com",
	".gougou.com",
])

修改pwx-dns-proxy启动脚本run.sh里的Python路径:

python2.6 src/dnsproxy.py

将pwx-dns-proxy上传到路由器上,创建开机自运行文件/jffs/etc/config/dns.startup

#!/bin/sh

ps | grep dnsproxy.py | grep -v grep | head -n1 | awk '{print $1}' | xargs kill -9
cd /jffs/pwx-dns-proxy
./run.sh &

在dd wrt Web管理界面 Setup页DHCP设置里将Static DNS 1,Static DNS 2,Static DNS 3分别设为你的路由器LAN IP (在我这里就是192.168.0.1)、8.8.8.8和8.8.4.4。

最后

回过头编辑你的OpenVPN配置文件,加入一行

route 8.8.8.8 255.255.255.255 net_gateway 5

强迫8.8.8.8直连而不走VPN,因为我们已经通过pwx-dns-proxy的本地DNS代理使用TCP方式查询Google DNS伺服器,所以直连它并不会被DNS劫持,反而有助于增加网路稳定性,提高速度并减轻OpenVPN连接不稳定时对网路的影响。

以上就是主要步骤。一些细节我省略了。如设置OpenVPN配置文件里”max-routes 3535″最大路由条数,这个我是通过脚本在每次生成ip-pre-up和ip-down时自动修改的:

#!/bin/sh

ROUTES_FILE=/jffs/openvpn/ip-pre-up
ROUTE_COUNT=$(wc -l $ROUTES_FILE | awk '{print $1}' )
ROUTE_COUNT=$(awk -v a=$ROUTE_COUNT -v b=20 'BEGIN{printf "%d",a+b}')

sed -i "s/max-routes[ \t]*[0-9]*/max-routes $ROUTE_COUNT/" /jffs/openvpn/client.conf

按照上面步骤全部设置好后,路由器开机后就自动连接VPN并且国内外IP分流,所有设备连上路由器直接翻墙,无需设置。