使用一台Raspberry Pi作为家庭网关, 无障碍翻墙

Arthor: Archean Zhang

Email: zephyr422@gmail.com

Version: 1.0.1

Date: 2013/8/16

长期被GFW困扰, 我终于忍不住动手了: 把家里的Raspberry Pi和与自由世界的主机建立OpenVPN over Stunnel的链路, 根据大中华3000条路由来匹配, 国外网站自动走OpenVPN出去以实现翻墙.

以下文章是基于一台Linux服务器(CentOS 6.4)撰写的, 将下面Router的换成Raspberry Pi也一样.

1. 准备

硬件:

  • 1台位于自由世界的Linux服务器 (Server)
  • 1台位于本地的Linux服务器 (Router)
  • 客户端 (Client)

软件:

  • Stunnel
  • OpenVPN
  • DNSMasq

拓扑图:
Topology

2. Server端配置

安装好Linux系统后(Red hat或CentOS), 同步服务器时间(非常重要):

1
# ntpdate time.nist.gov

2.1 OpenVPN

下载安装OpenVPN, 生成服务器端证书, OpenVPN依赖lzo, 需要一同安装:

1
2

# yum install lzo openvpn

服务器端配置文件/etc/openvpn/server.conf, 范例及说明如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
local 127.0.0.1 	#监听本地接口
port 4443 #监听端口
proto tcp #协议
dev tap
ca /etc/openvpn/keys/ca.crt #证书
cert /etc/openvpn/keys/server.crt #证书
dh /etc/openvpn/keys/dh1024.pem #证书
server 172.31.189.0 255.255.255.0 #网段
client-to-client
duplicate-cn
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log #状态日志
log-append openvpn.log #执行日志
verb 3

启动openvpn:

1
# openvpn --config /etc/openvpn/server.conf --deamon

观察日志, 如果出现“Initialization Sequence Completed”则代表启动成功.

2.2 Stunnel

Openvpn的Server端只监控本地接口, 就是为了用Stunnel将流量加密, 在Local端安全的链接, 达到加密, 混淆流量的作用, 以绕开GFW的监控.

下载安装stunnel

1
2

# yum install stunnel

安装过程中会生成服务器证书stunnel.pem, 按照提示来即可.

编辑配置文件/usr/bin/etc/stunnel.conf, 如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
cert = /usr/local/etc/stunnel/stunnel.pem
CAfile = /usr/local/etc/stunnel/stunnel.pem
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1

pid = /tmp/stunnel.pid
verify = 3

setuid = stunnel
setgid = stunnel

compression = zlib
delay = no
sslVersion = TLSv1
fips=no

debug = 7
syslog = no
output = /usr/local/etc/stunnel/stunnel.log

[s-openvpn]
accept = 13579 #监听端口
connect = 127.0.0.1:4443 #OpenVPN端口

启动stunnel:

1
# stunnel

查看OpenVPN和Stunnel是否正确执行, 检查相应端口:

1
2
3
4
5
6
7
8
9
10
11

# netstat -ntwla
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:13579 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:4443 127.0.0.1:50223 ESTABLISHED
# lsof -i:4443 -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
openvpn 25290 root 5u IPv4 2982393 0t0 TCP *:pharos (LISTEN)
openvpn 25290 root 8u IPv4 3361561 0t0 TCP 127.0.0.1:pharos->127.0.0.1:50223 (ESTABLISHED)
stunnel 26801 stunnel 10u IPv4 3361560 0t0 TCP 127.0.0.1:50223->127.0.0.1:pharos (ESTABLISHED)

看到端口均已正确监听, 至此Server端配置完成

3. Router配置

安装好Linux系统后(Red hat或CentOS), 同步服务器时间(非常重要):

1
2

# ntpdate time.nist.gov

3.1 安装Stunnel

Router端需要首先安装Stunnel, 在本地开启加密链路, 透传OpenVPN加密端口4443, 然后OpenVPN才能开始接入:

1
# yum install stunnel

将Server端Stunnel证书传过来, 以便验证:

1
# scp root@server:/usr/local/etc/stunnel.pem root@router:/usr/local/etc/stunnel.pem

开始进行stunnel配置, 配置文件/usr/local/etc/stunnel.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
pid = /tmp/stunnel.pid
cert = /usr/local/etc/stunnel/stunnel.pem
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
verify = 3
CAfile = /usr/local/etc/stunnel/stunnel.pem
client=yes
compression = zlib
ciphers = AES256-SHA
delay = no
failover = prio
sslVersion = TLSv1

output = /root/bin/logs/stunnel.log
[s-openvpn]
accept = 127.0.0.1:4443
connect = server.ip.address:13579

启动stunnel:

1
# stunnel

3.2 安装OpenVPN

下载安装OpenVPN, OpenVPN依赖lzo, 需要一同安装:

1
# yum install lzo openvpn

配置Router端配置文件/etc/openvpn/hk.ovpn:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
dev tap				#设备模式
port 65530 #本地监听端口
proto tcp #协议
client #服务模式:client
tls-client #加密客户端
ns-cert-type server
remote 127.0.0.1 4443 #Server端口, 由于使用Stunnel加密透传, 所以连接本地端口
ca /etc/openvpn/ca/ca.crt #证书
key /etc/openvpn/ca/client1.key #证书
cert /etc/openvpn/ca/client1.crt #证书
persist-key
persist-tun
#route-method exe
#route-delay 2
comp-lzo
status /etc/openvpn/openvpn-status.log #状态日志
log-append /etc/openvpn/ca.log #执行日志
verb 3

启动OpenVPN:

1
# openvpn --daemon --config /etc/openvpn/hk.ovpn

观察日志, 如果出现“Initialization Sequence Completed”则代表启动成功.

检查隧道:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ip addr
11: tap0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 100
link/ether 06:10:50:e5:e5:2c brd ff:ff:ff:ff:ff:ff
inet 172.31.188.2/24 brd 172.31.188.255 scope global tap0
inet6 fe80::410:50ff:fee5:e52c/64 scope link
valid_lft forever preferred_lft forever

# ping 172.31.188.1
PING 172.31.188.1 (172.31.188.1) 56(84) bytes of data.
64 bytes from 172.31.188.1: icmp_seq=1 ttl=64 time=67.3 ms
64 bytes from 172.31.188.1: icmp_seq=2 ttl=64 time=67.1 ms
^C
--- 172.31.188.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1588ms
rtt min/avg/max/mdev = 67.183/67.284/67.386/0.278 ms

链路通畅

3.3 安装DNSmasq

Router若要进行翻墙, 需要使用国外DNS, 而浏览国内网站时, 如果使用国外DNS, 会造成将访问导向国外站点, 造成访问速度变慢, 所以此方案使用DNSmasq解决此问题.

同时DNSmasq也是一个轻量级DHCP服务器, 非常方便好用.

安装DNSmasq:

1
# yum install dnsmasq

编辑DNSmasq配置文件/etc/dnsmasq.conf, 假设Router本地IP是10.2.166.10, 本地分发网段是10.2.166.0/24, 则配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# DHCP config
expand-hosts
domain=archean.me
# DHCP Range
dhcp-range=10.2.166.50,10.2.166.150,12h #DHCP地址池
# DHCP route
dhcp-option=3,10.2.166.10 #路由
# Apple ntp server
dhcp-option=option:ntp-server,10.3.1.233 #ntp时间服务器

# DNS server
no-resolv
no-poll
server=8.8.8.8
server=8.8.4.4
conf-dir=/etc/dnsmasq.d

# AppleTV trailers
address=/trailers.apple.com/180.153.225.136

# Static IPs
# dhcp-host=xx:xx:xx:xx:xx:xx,10.2.166.121

配置分类解析配置文件/etc/dnsmasq.d/china.conf, 以使常用域名走国内DNS解析, 举例如下, 根据自身情况更改:

1
2
3
4
5
6
7
8
9
10
11
# server=/domain.name/dns.server
server=/115.com/114.114.114.114
server=/123u.com/114.114.114.114
server=/126.com/114.114.114.114
server=/126.net/114.114.114.114
server=/163.com/114.114.114.114
server=/17173.com/114.114.114.114
server=/17cdn.com/114.114.114.114
server=/51.la/114.114.114.114
server=/6rooms.com/114.114.114.114
server=/91.com/114.114.114.114

至此准备工作完成, 可以启动路由器了

3.4 启动路由器

思路

默认路由为OpenVPN Server端私网IP, chnroute生成的3000条国内路由走国内链路, 以达到分流/翻墙的目的.

步骤:

  • 启动Stunnel, 启动DNSmasq
  • 开启linux内核转发功能
  • 启动OpenVPN
  • 增加3000条国内路由(点这里下载)
  • 增加默认路由, 增加下一跳为OpenVPN Server端私网IP

将步骤编写成脚本, 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/sh
# Stunnel up
/usr/bin/stunnel
/usr/sbin/dnsmasq

# date ntp time
ntpdate ntp.server.name
/sbin/route add -net 10.0.0.0/8 gw 10.2.166.1
/sbin/route add -host server.ip.address gw 10.2.166.1

# iptables NAT
/sbin/iptables -t nat -A POSTROUTING -o tap0 -j MASQUERADE
sysctl -w net.ipv4.ip_forward=1

# start Openvpn
killall openvpn
/usr/local/sbin/openvpn --daemon --config /etc/openvpn/hk.ovpn
sleep 5
# Chnrouters
for i in `cat /root/bin/CN` ; do /sbin/route add -net $i gw 10.2.166.1 ; done
/sbin/route del default
/sbin/route add default gw 10.2.166.1
/sbin/route add default gw 172.31.188.1

启动脚本, Router环境搭建完成, 国外网络访问测试:

1
2
3
4
5
6
7
8
9
10
11
# tracert 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 172.31.188.1 (172.31.188.1) 68.963 ms 68.913 ms 68.914 ms
2 103.30.4.1 (103.30.4.1) 109.650 ms 109.651 ms 109.645 ms
3 172.16.0.2 (172.16.0.2) 109.410 ms 109.454 ms 109.448 ms
4 gi1-26.br02.hkg04.pccwbtn.net (63.218.241.1) 109.384 ms 109.384 ms 109.465 ms
5 72.14.196.197 (72.14.196.197) 109.415 ms 109.381 ms 109.344 ms
6 209.85.241.56 (209.85.241.56) 109.368 ms 209.85.241.58 (209.85.241.58) 105.488 ms 149.385 ms
7 216.239.43.17 (216.239.43.17) 108.792 ms 68.841 ms 209.85.253.69 (209.85.253.69) 69.430 ms
8 * * *
9 google-public-dns-a.google.com (8.8.8.8) 108.102 ms 107.936 ms 107.819 ms

可以看到直接走OpenVPN私网IP出去, 国内网络访问测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# traceroute www.baidu.com
traceroute to www.baidu.com (115.239.210.26), 30 hops max, 60 byte packets
1 10.2.166.1 (10.2.166.1) 2.267 ms 2.470 ms 2.623 ms
2 10.2.255.254 (10.2.255.254) 2.180 ms 2.492 ms 2.648 ms
3 * * *
4 * * *
5 * * *
6 123.125.40.254 (123.125.40.254) 2.714 ms 2.634 ms 2.883 ms
7 61.49.44.65 (61.49.44.65) 1.459 ms 1.448 ms 1.521 ms
8 61.148.160.5 (61.148.160.5) 1.443 ms 1.466 ms 1.459 ms
9 124.65.60.77 (124.65.60.77) 3.258 ms 5.805 ms 5.790 ms
10 123.126.0.85 (123.126.0.85) 3.392 ms 3.202 ms 3.245 ms
11 123.126.0.85 (123.126.0.85) 3.214 ms 5.487 ms 3.913 ms
12 219.158.35.90 (219.158.35.90) 71.347 ms 71.338 ms 71.337 ms

国内链路则直接走原本的网络环境出去.

3.5 配置监控脚本

由于国际出口不一定稳定, OpenVPN有可能会间歇性断掉, 如果发生此情况, 则会造成默认路由不可达, 从而导致国内网站浏览也会出现问题, 所以配置监控脚本, 一旦国际链路抽风, 则立刻将路由切换至国内.

脚本内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
ip="172.31.188.1"
i=-1
j=-1
while : ; do
ping $ip -c 5 -w 30
if [ $? -ge "1" ]; then
route del default gw $ip
j=-1
i=$((i+1))
txt=`date +%F" "%X`" Ping $ip timed out."
(($i%30==0)) && echo $txt >> /root/bin/logs/checkip.log
(($i%30==0)) && echo $txt | mailx -s "VPN disconnected" admin@domain.com
else
route add default gw $ip
i=-1
j=$((j+1))
txt=`date +%F" "%X`" Ping $ip OK."
(($j%30==0)) && echo $txt >> /root/bin/logs/checkip.log
(($j%100000==0)) && echo $txt | mailx -s "VPN OK." admin@domain.com
fi
sleep 10
done

后台启动此脚本, 则会每10秒监控一次出国链路, 如果断掉, 将会把路由切至国内, 不影响正常上网; 如果出国链路长期无法恢复, 则每5分钟给管理员发送一封告警邮件.

4. Client

客户端接入路由器所在交换机后, 配置为自动获取IP地址, 即可进行翻墙.

使用一台Raspberry Pi作为家庭网关, 无障碍翻墙

https://archeanz.com/2013/10/16/breaking-gfw-with-raspberry-pi/

Author

Archean Zhang

Posted on

2013-10-16

Updated on

2022-07-11

Licensed under

Comments