前言
obfsproxy+openvpn 方案说明
通过在一个网络中加入一个 Raspberry Pi 实现全网翻墙
不久前,GFW 升级导致 OpenVPN、SSH Tunnel 等一系列老牌翻墙方式纷纷阵亡,现在的翻墙手段已经开始从单纯的加密向流量混淆发展,这里介绍一种利用 obfsproxy+OpenVPN 进行翻墙的方式,目前情况下相当稳定快速。
obfsproxy 是 Tor Project 的一个附属项目,采用流量混淆的方式专门用于突破互联网封锁。对用户的表现形式是一个 TCP 端口转发隧道,和 ssh -L 的功能完全一致。
除了介绍 obfsproxy+OpenVPN 翻墙以外,本文还介绍了如何使用 Raspberry Pi 搭设翻墙网关实现无缝翻墙的方法。下文中B和C部分属于平行关系,任选其一配置即可。
有任何建议和问题欢迎在 Twitter 上和我讨论: @blankwonder
本文目标读者为有一定 Linux 和网络知识基础的用户,并没有把所有命令全部傻瓜话的列出,如果是小白请先准备技术支持老师一枚(别找我啊……)
A. 服务器端配置
OpenVPN 配置
首先,我们需要先安装配置 OpenVPN,如果你不需要 IPv6 的话,直接用包管理安装就行。否则请到官网下载2.3版本的源码自行编译安装。(目前最新版本是2.3 RC2)
Debian 编译 OpenVPN 所需要的包有 libssl-dev, libpam0g-dev, liblzo2-dev
注:若是自行编译的OpenVPN,会缺少 easy-rsa 和 init.d 脚本,easy-rsa可以从OpenVPN官方的Github获得。init.d 脚本可以从各发行版的源码获得:
- Debian/Ubuntu 用户:下载这个文件包 http://ftp.de.debian.org/debian/pool/main/o/openvpn/openvpn_2.3~rc1-1.debian.tar.gz,解压后找到 openvpn.init.d 文件,将其放到/etc/init.d/openvpn
- Gentoo 用户: sudo wget http://sources.gentoo.org/cgi-bin/viewvc.cgi/gentoo-x86/net-misc/openvpn/files/openvpn-2.1.init -O /etc/init.d/openvpn
如果你没有修改安装 prefix 的话,OpenVPN会被安装到 /usr/local/sbin/openvpn 上,记得修改 init.d 脚本的相应内容。
接下来,按照标准的 OpenVPN 部署流程,生成各种密钥和证书(CA, server, client)。Linode 的官方文档写的非常好,这里不再阐述。
我使用的服务端配置 (/etc/openvpn/openvpn.conf)如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
local 127.0.0.1 port 40059 proto tcp dev tun ca ca.crt cert server.crt key server.key dh dh1024.pem server 172.16.0.0 255.255.255.0 ifconfig-pool-persist ipp.txt duplicate-cn keepalive 10 120 comp-lzo persist-key persist-tun status openvpn-status.log log-append /var/log/openvpn.log verb 3 mute 10 |
由于我们需要使用 obfsproxy 进行二次混淆,所以这里让 OpenVPN 监听在 127.0.0.1 上。市面上的路由器默认的 IPv4 子网一般是 192.168.X.X 或者 10.X.X.X,这里为了避免和原有网络冲突,我选择了 172.16.0.0/24 作为 VPN 的子网。
接下来设置 iptables 进行 NAT 转换,这里省略了 Linode 文档中的安全部分(DROP),需要可自行补上。
1 2 |
sudo iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -o eth0 -j MASQUERADE |
为了保证服务器重启后自动配置 iptables,请需要将这条命令加入启动脚本
- Debian/Ubuntu 用户:启动脚本的路径为 /etc/rc.local
- Gentoo 用户:需要在/etc/local.d目录中创建一个后缀为.start的文件(如openvpn_iptables.start),将命令写在里面,同时记得使用chmod a+x。
接下来启动内核的 IPv4 转发
1 2 |
sudo sysctl -w net.ipv4.ip_forward=1 |
为了保证重启后不需要人工干预,在/etc/sysctl.conf中加入net.ipv4.ip_forward=1,这样重新启动后就不再需要sysctl -w了。
现在可以把 OpenVPN 跑起来了,命令如下
1 2 |
sudo /etc/init.d/openvpn start |
obfsproxy 配置
现在开始编译安装 obfsproxy,官方指导文档在这 https://www.torproject.org/projects/obfsproxy-instructions.html.en
注:Gentoo 用户在 emerge libevent 时请注意添加 USE 标记 ssl。
Debian/Ubuntu 用户可以直接使用包管理安装
1 2 |
sudo apt-get install obfsproxy |
安装配置完毕后,启动 obfsproxy,命令如下:
1 2 |
obfsproxy obfs2 --dest=127.0.0.1:40059 server 0.0.0.0:9132 |
请记得使用 screen,nohup 或 daemon 的方式运行 obfsproxy。daemon当然最好,我比较懒就直接跑在 screen 里面了。
至此,服务端配置完毕。
B. 客户端配置
obfsproxy 配置
首先编译安装 obfsproxy,文档同上。
Mac用户可以用使用 homebrew 安装,请参照这里 https://github.com/mtigas/homebrew-tor/blob/master/README.md
由于我们需要将所有流量重定向到 OpenVPN,而由于使用了 obfsproxy,OpenVPN不知道服务器IP是多少没办法对到 OpenVPN 服务器的流量进行特殊处理,所以我们需要手动将到服务器的路由固定下来,假设你的服务器IP为12.34.56.78,当前网络的网关地址是192.168.1.1:(路由修改的命令请根据自己的操作系统自行调整,此处以Mac OS X为例)
1 2 |
sudo route add 12.34.56.78 192.168.1.1 |
完成了之后,开始运行 obfsproxy
1 2 |
obfsproxy obfs2 --dest=12.34.56.78:9132 client 127.0.0.1:50443 |
如果是 Mac 用户,可以使用我的脚本,稍微简便一些(需要sudo)
1 2 3 4 5 6 7 8 9 10 |
#!/bin/bash SERVER_IP="12.34.56.78" GATEWAY=`netstat -nr | grep '^default' | grep -v 'tun' | sed 's/default *\([0-9\.]*\) .*/\1/'` /sbin/route add $SERVER_IP $GATEWAY /usr/local/bin/obfsproxy obfs2 --dest=${SERVER_IP}:9132 client 127.0.0.1:50443 # Below line won't be excuted until obfsproxy exit /sbin/route delete $SERVER_IP $GATEWAY |
OpenVPN 配置
接下来选择你喜爱的 OpenVPN 客户端软件进行连接就可以了,我的配置式样例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
remote 127.0.0.1 50443 tcp-client pull tls-client ns-cert-type server persist-key ca ca.crt redirect-gateway def1 nobind persist-tun cert cert.crt comp-lzo adaptive dev tun key key.key dhcp-option DNS 8.8.8.8 resolv-retry infinite log-append /var/log/openvpn.log |
好的,现在你又可以尽情享受 OpenVPN 的全局翻墙了,如有需要可以结合 chnroutes 区分国内外流量进行选择性翻墙。
C. Raspberry Pi 翻墙网关配置
整个网络结构图如下
使用 Raspberry Pi 作为翻墙网关有很多好处,一是不用再每次都手动连接VPN,二是一次配置所有设备通用,更奇妙的是结合chnroutes使用,客户端和 RPi 之间会自动使用ICMP Redirect修改客户端路由,下次再访问同一国内IP就不会再经过 RPi 了。
警告:修改网络配置极有可能使得RPi无法联网,请在保证可以直接控制RPi的情况下操作。
Raspberry Pi 使用 Debian wheezy 作为操作系统,其他操作系统也大同小异。
首先,在 RPi 上安装 OpenVPN 和 obfsproxy,同样,如果需要 IPv6 还是得自行编译安装 OpenVPN。编译方法参照之前服务器部署部分,obfsproxy 可以直接使用包管理安装。
同样,我们还是需要启动内核的IPv4转发
1 2 |
sudo sysctl -w net.ipv4.ip_forward=1 |
记得同时修改 /etc/sysctl.conf 保证重启也有效。
接下来我们需要让 RPi 的 IP 固定下来,修改 /etc/network/interfaces 文件,将 eth0 的相关部分改成这样,请参照自己的网络情况修改
1 2 3 4 5 6 7 |
auto eth0 iface eth0 inet static address 192.168.1.2 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 8.8.8.8 |
为了让 interfaces 文件可以设置 DNS 服务器,也就是让 dns-nameservers 8.8.8.8 这句话生效,我们需要再额外安装一个包
1 2 |
sudo apt-get install resolvconf |
使用以下命令使得配置生效,直接重启也行
1 2 |
sudo /etc/init.d/networking restart |
接下来,使用 chnroute 生成路由脚本,(这步可以在电脑上执行,然后将生成好的文件拷贝过来)
1 2 |
python chnroutes.py -p linux |
得到两个文件ip-pre-up和ip-down,其中ip-pre-up开头如下,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
/bin/bash export PATH="/bin:/sbin:/usr/sbin:/usr/bin" OLDGW=`ip route show | grep '^default' | sed -e 's/default via \\([^ ]*\\).*/\\1/'` if [ $OLDGW == '' ]; then exit 0 fi if [ ! -e /tmp/vpn_oldgw ]; then echo $OLDGW > /tmp/vpn_oldgw fi route add -net 1.0.1.0 netmask 255.255.255.0 gw $OLDGW ... |
其中获得网关的命令我自己测试发现有问题不成功,修改为这样
1 2 |
OLDGW=`ip route show | grep eth0 | grep '^default' | sed -e 's/default via \([^ ]\+\) dev eth0/\1/'` |
动态获得网关IP的方法有时会不太可靠,如果网络情况不常变化,可以考虑直接把网关IP写进去
1 2 |
OLDGW="192.168.1.1" |
在RPi上执行 sudo bash ./ip-pre-up,将国内IP的路由固定下来(没有必要等到OpenVPN链接后再固定,也不需要每次断开后就删除,除非网关地址变了,否则一直放着就好)。注意这个脚本可能要运行一段时间才能完成。
和客户端部分一样,连接之前我们也需要先将到服务器的路由固定下来,一体化脚本如下(记得修改服务器IP)
1 2 3 4 5 6 7 8 9 10 11 |
#!/bin/bash SERVER_IP="12.34.56.78" GATEWAY=`ip route show | grep eth0 | grep '^default' | sed -e 's/default via \([^ ]\+\) dev eth0/\1/'` /sbin/route add -host $SERVER_IP gw $GATEWAY /usr/local/bin/obfsproxy obfs2 --dest=${SERVER_IP}:9132 client 0.0.0.0:50443 #/sbin/route delete -host $SERVER_IP gw $GATEWAY |
使用 screen,nohup 或 daemon 的方式将这个脚本运行起来(需要 root 权限),就可以开始进行 OpenVPN 的配置了
将所需要的证书和密钥放到 /etc/openvpn/ 目录下。配置文件和上文B部分一致,命名为 openvpn.conf。启动 openvpn:
1 2 |
sudo /etc/init.d/openvpn start |
可以查看一下 OpenVPN 的日志,看看链接是否成功
1 2 |
sudo tail /var/log/openvpn.log |
当看到 “Initialization Sequence Completed” 后,就表示我们已经基本上大功告成了。接下来测试一下。
1 2 3 4 5 6 7 8 9 10 11 |
[root@blankwonder-rpi]openvpn # ping twitter.com PING twitter.com (199.59.149.230) 56(84) bytes of data. 64 bytes from www4.twitter.com (199.59.149.230): icmp_req=1 ttl=247 time=631 ms 64 bytes from www4.twitter.com (199.59.149.230): icmp_req=2 ttl=247 time=328 ms 64 bytes from www4.twitter.com (199.59.149.230): icmp_req=3 ttl=247 time=477 ms 64 bytes from www4.twitter.com (199.59.149.230): icmp_req=4 ttl=247 time=326 ms ^C --- twitter.com ping statistics --- 5 packets transmitted, 4 received, 20% packet loss, time 4025ms rtt min/avg/max/mdev = 326.018/440.823/631.233/125.840 ms |
OK,RPi 目前已处于翻墙状态了。接下来,让我们的设备也能翻墙。
在 RPi 中启动 iptables 的 NAT 转换
1 2 |
sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE |
将需要翻墙的设备的 IP 地址设为手动,将网关地址设为 RPi 的地址(本文中为192.168.1.2),DNS 服务器地址设为 8.8.8.8,打开浏览器试一下,你是不是已经畅通无阻了?
接下来为了使得以后使用不用再手动修改路由,到路由器上修改 DHCP 设置,将网关地址设置为 RPi 的地址,DNS 改为 8.8.8.8。如果你的路由不支持手动设置 DHCP 路由地址(比如我的 Time Capsule……),那就把他的 DHCP 直接关了,在 RPi 上直接自建一个DHCP服务器(比如 dnsmasq)。
同样的原理我们还可以利用RPi为子网下所有设备提供原生的 IPv6 支持。但配置略微有些繁琐,请待下回分解……
Version 1
0 Comments