一个适用于 CN 网络的 VPN 解决方案

部署图

说明

  • VPN Clients 是位于 CN 网络的 VPN 客户端。
  • ns.example.net 和 vpn.example.net 可以是同一台机器,应位于防火墙(即 the Great Firewall,下同)内。
  • radius.example.net 和 pgsql.example.net 位置无所谓,但是最好和 vpn.example.net 很近或者位于同一台机器,以便获得更短的延时。
  • ss-server.example.net 应位于防火墙外。

安装

ss-server.example.net
安装 shadowsocks-libev 服务器端
pgsql.example.net
在 FreeBSD 上安装 PostgreSQL
radius.example.net
在 FreeBSD 上安装 FreeRADIUS
ns.example.net
使用 dnsmasq 和 shadowsocks-libev 构建一个干净的域名服务器
vpn.example.net
strongSwan 的安装和配置

#cisco-ipsec, #dnsmasq, #freebsd, #freeradius, #gfw, #gfwlist, #gfwlist2dnsmasq-awk, #ikev2, #ipsec, #iptables, #letsencrypt, #postgresql, #shadowsocks-libev, #ss-redir, #ss-server, #ss-tunnel, #strongswan, #ubuntu, #vpn

使用 dnsmasq 和 shadowsocks-libev 构建一个干净的域名服务器

需要两台服务器。

一台位于离我们近的机房,这个机房可以是位于有域名服务器缓存污染的防火墙内。(当然如果不是有污染的环境,也没有必要写这篇文章。)

一台位于没有域名服务器缓存污染的防火墙外。

我们把这两台服务器分别取名为 ns.example.net 和 ss-server.example.net。

不能直接使用防火墙外的域名服务器作为客户端的域名服务器,是因为当域名解析数据包经过防火墙时会被投毒。

使用 dnsmasq 来分流不同的域名解析请求,是因为如果全部定向到防火墙外的域名服务器,对某些使用 CDN 的网站,特别是防火墙内的网站将会被解析得到距离我们较远的服务器的 IP。

在 ns.example.net 上安装和运行 dnsmasq 和 ss-tunnel(包含在 shadowsocks-libev),在 ss-server.example.net 上安装和运行 ss-server(包含在 shadowsocks-libev)。

部署图如下:

版本信息

本文测试环境:

  • Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-72-generic x86_64)
  • shadowsocks-libev 2.6.3

ss-server.example.net 的安装

见:安装 shadowsocks-libev 服务器端

ns.example.net 的安装

dnsmasq

轻量级 DNS 转发器、DHCP 和 TFTP 服务器。我们利用它的 DNS 转发功能。

安装

apt install dnsmasq

配置

确保文件 /etc/dnsmasq.conf 包含了如下代码,它通常位于最后一行:

# Include all files in a directory which end in .conf
conf-dir=/etc/dnsmasq.d/,*.conf

gfwlist2dnsmasq.sh

创建一个脚本文件 /usr/local/bin/gfwlist2dnsmasq.sh (chmod +x),内容如下:

#!/bin/sh
curl -s -o /tmp/gfwlist.txt \
	https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt \
	&& base64 -d /tmp/gfwlist.txt \
	| awk -f $(cd "$(dirname "$0")"; pwd)/gfwlist2domainlist.awk \
		- /usr/local/etc/user_rule.txt \
	| grep -F -v -f "/usr/local/etc/skip_domain.txt" \
	| awk -f $(cd "$(dirname "$0")"; pwd)/domainlist2dnsmasq.awk \
		-v "noipset=noipset" \
		- \
	> /etc/dnsmasq.d/gfwlist.conf 2>/dev/null \
	&& service dnsmasq restart

该脚本会生成 dnsmasq 配置文件 /etc/dnsmasq.d/gfwlist.conf 让 dnsmasq 将 gfwlist 中的域名的解析转发到 127.0.0.1:5353 端口。

gfwlist2domainlist.awk 和 domainlist2dnsmasq.awk 可以从 gfwlist2dnsmasq.awk 获得。

/usr/local/etc/user_rule.txt 可以用来存放额外的想交由 127.0.0.1:5353 端口解析的域名列表,
/usr/local/etc/skip_domain.txt 可以用来存放在 gfwlist 列表中,但是不想交由 127.0.0.1:5353 端口解析的域名。

在 /etc/rc.local 的 exit 0 之前添加,使其在开机时运行一次:

/usr/local/bin/gfwlist2dnsmasq.sh

由于 gfwlist 是不断更新的,所以可以在 /etc/crontab 中添加,以便每天早上4点20分更新一次:

20 4	* * *	root	/usr/local/bin/gfwlist2dnsmasq.sh

ss-tunnel

安装

同:安装 shadowsocks-libev 服务器端

启动

在 /etc/rc.local 的 exit 0 之前添加如下代码,以便开机时自动运行一个监听在 127.0.0.1:5353 端口,请求会通过隧道转到 8.8.8.8:53 上。

/usr/local/bin/ss-tunnel -c /usr/local/etc/shadowsocks-libev/config.json -l 5353 -L 8.8.8.8:53 -u -A > /dev/null 2>&1 &

测试

在 ns.example.net 上可以通过如下命令来测试 ss-tunnel 创建的隧道是否正常工作:

root@ns:~# nslookup 
> server 127.0.0.1
Default server: 127.0.0.1
Address: 127.0.0.1#53
> set port=5353
> www.google.com
Server:		127.0.0.1
Address:	127.0.0.1#5353

Non-authoritative answer:
Name:	www.google.com
Address: 172.217.25.4
> exit

#dnsmasq, #gfwlist, #gfwlist2dnsmasq-awk, #shadowsocks-libev, #ss-server, #ss-tunnel, #ubuntu

Mac OS X 到达世界任意角落的一个解决方案概述

Across the Great Wall, we can reach every corner in the world.
network

  1. 操作系统的系统偏好设置(系统偏好设置->网络->高级…->代理)里设置 Web 代理(HTTP)安全 Web 代理(HTTPS)Privoxy 监听的端口 127.0.0.1:8118
  2. SSH tunnel 负责建立 Socks5 代理,监听 127.0.0.1:1080 端口,采用 autosshLaunch Daemon 实现。
  3. tor 负责建立匿名隧道,监听 127.0.0.1:9050 端口,使用 127.0.0.1:1080 端口作为上级代理,用来访问暗网 *.onion,参考Mac OS X 上安装 tor 并配置为自动启动
  4. Privoxy 监听 127.0.0.1:8118 端口,负责分发 HTTP/HTTPS 请求。
    注意,Privoxy 3.0.22 以前的版本不支持 RFC5789 中定义的 HTTP PATCH 方法,不过如果 PATCH 是在 HTTPS 里则没有问题;Privoxy 3.0.22 增加了对 HTTP PATCH 的支持。
    1. gfwlist 或者用户自定义域名列表中的域名,分发到 SSH tunnel 建立的 Socks5 代理(127.0.0.1:1080)。
      使用 gfwlist2privoxygfwlist 和用户自定义域名列表转换成 Privoxy 的 action 配置文件,配置到 crontab 中定时执行。参考:Mac OS X 上 gfwlist2privoxy 的使用
    2. *.onion 域名分发到 tor 建立的 Socks5 代理服务器(127.0.0.1:9050)。
    3. user.action 中配置需要过滤的广告规则,和中国电信 HTTP 劫持所用到的域名。
  5. ZeroNet 连入网络使用(always)工作在 127.0.0.1:9050 端口的 tor
  6. dsocks 用来为不支持设置代理服务器的应用程序单独设置代理,比如 telegram,参考在 Mac OS X 上给 Telegram 单独设置代理服务器

#autossh, #dsocks, #gfwlist, #gfwlist2privoxy, #launch-daemon, #mac-os-x, #onion, #privoxy, #telegram, #tor, #zeronet

Mac OS X 上 gfwlist2privoxy 的使用

Network Diagram

本文中的软件使用 MacPorts(2.3.4) 安装。

安装 Privoxy(3.0.21)、py-pip(8.1.2)、gfwlist2privoxy(1.0.3)

$ sudo port install privoxy py-pip
$ sudo pip install gfwlist2privoxy

查找 gfwlist2privoxy 的安装路径

$ find /opt -iname 'gfwlist2privoxy'
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/gfwlist2privoxy
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/gfwlist2privoxy
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/gfwlist2privoxy-1.0.3-py2.7.egg-info

配置 Privoxy

生成空文件:

$ sudo touch /opt/local/etc/privoxy/gfwlist.action

修改文件所有者:

$ sudo chown privoxy:privoxy /opt/local/etc/privoxy/gfwlist.action

修改文件权限:

$ sudo chmod 660 /opt/local/etc/privoxy/gfwlist.action

允许当前用户修改该文件,便于后续使用当前用户的 crontab 定时生成该文件:

$ sudo chmod +a "${USER} allow read,write" /opt/local/etc/privoxy/gfwlist.action

查看文件权限:

$ ls -le /opt/local/etc/privoxy/gfwlist.action
-rw-rw----+ 1 privoxy  privoxy  62526 Sep  6 00:00 /opt/local/etc/privoxy/gfwlist.action
 0: user:YOURNAME allow read,write

在文件 /opt/local/etc/privoxy/config 的行 actionsfile user.action 下一行追加 actionsfile gfwlist.action,原文件会备份为 /opt/local/etc/privoxy/config.bak。注意这个命令就是写作三行的:

$ sudo sed -i '.bak' '/actionsfile user.action/a\ \
actionsfile gfwlist.action\
' /opt/local/etc/privoxy/config

对比原文件和修改后的文件,确保上述命令被正确执行:

$ sudo diff -ruN /opt/local/etc/privoxy/config.bak /opt/local/etc/privoxy/config
--- /opt/local/etc/privoxy/config.bak
+++ /opt/local/etc/privoxy/config
@@ -370,6 +370,7 @@
actionsfile match-all.action # Actions that are applied to all sites and maybe overruled later on.
actionsfile default.action # Main actions file
actionsfile user.action # User customizations
+actionsfile gfwlist.action
#
#
# 2.5. filterfile

删除备份文件

$ sudo rm /opt/local/etc/privoxy/config.bak

启动 Privoxy

$ sudo launchctl load -w /Library/LaunchDaemons/org.macports.Privoxy.plist

生成 gfwlist.action 文件

下载 gfwlist 并生成 gfwlist.action 文件。其中 127.0.0.1:1080 是监听在本地 1080 端口的 socks5 代理服务器,至于如何建立一个 socks5 代理服务器并不在本文讨论的范畴。
/opt/local/etc/privoxy/gfwlist.action修改后不需要重启 PrivoxyPrivoxy 会自动应用修改。

$ mkdir -p ~/bin/
$ echo "\!this is a user defined rule" >> ~/bin/user_rule.txt
$ echo "ip.cn" >> ~/bin/user_rule.txt
$ /opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/gfwlist2privoxy -f /opt/local/etc/privoxy/gfwlist.action -p '127.0.0.1:1080' -t socks5 --user-rule ~/bin/user_rule.txt

可以将这个命令加入 crontab 中定时执行,使用命令crontab -e编辑当前用户的 crontab
添加一条记录,这里的例子是每天0点执行一次:

#minute	hour	mday	month	wday	command
0	0	*	*	*	/opt/local/Library/Frameworks/Python.framework/Versions/2.7/bin/gfwlist2privoxy -f /opt/local/etc/privoxy/gfwlist.action -p '127.0.0.1:1080' -t socks5 --user-rule ~/bin/user_rule.txt > /dev/null 2>&1

测试

测试 socks5 代理服务器正在监听 1080 端口:

$ telnet 127.0.0.1 1080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

测试通过 socks5 代理服务器访问 ip.cn

curl -x 'socks5://127.0.0.1:1080' ip.cn
当前 IP:x.x.x.x 来自:xxxxxx xxx

测试通过 Privoxy 访问 ip.cn 分流到了 socks5 代理服务器。我们已经把 ip.cn 添加到了 user_rule.txt,因此下述命令输出结果应该和上述命令一致:

$ curl -x 'http://127.0.0.1:8118' ip.cn
当前 IP:x.x.x.x 来自:xxxxxx xxx

使用

在操作系统的系统偏好设置(系统偏好设置->网络->高级…->代理)里设置 Web 代理(HTTP)安全 Web 代理(HTTPS)为 Privoxy 监听的地址 127.0.0.1:8118

#gfwlist, #gfwlist2privoxy, #privoxy

#mac-os-x, #macports

#curl

#minute