租用vps搭建翻墙设施

0x00 背景

前两天回国,突然发现不能上很多和谐网站很不方便,于是搜索了一下免费 vpn 想要翻墙,无奈现在免费 vpn 太少而且速度慢,且正好自己刚租了一个海外 vps(ubuntu 的),于是考虑着使用该 vps 搭建一些翻墙设施。翻墙我想到的有两种方法,一个是做 vpn,也是大多数人会选择的,另一个是做 http 代理。本篇将会介绍这两种方法。

0x01 使用 vpn 翻墙

vpn 制作相对来说比较简单,使用 pptpd 即可。具体流程如下:

  1. 安装pptpd:

    apt-get install pptpd

  2. 编辑 /etc/pptpd.conf文件:
    找到以下两行

    #localip 192.168.0.1
    #remoteip 192.168.0.234-238,192.168.0.245

    改为:

    localip 10.0.0.1
    remoteip 10.0.0.100-200

    或者把前面的#注释去掉即可。
    localip 表示作为 vpn 服务器的本机 IP,remoteip表示连上该 vpn 的机器被分配到的 IP(范围),所以这两个都应是私网ip。

  3. 编辑 /etc/ppp/chap-secrets,添加 vpn 用户和密码:

    比如:

    # client server secret IP addresses
    user1 pptpd passwd1 *

    第二列的 pptpd 是固定的,四个域间用 tab 隔开。

  4. 编辑 /etc/ppp/pptpd-options,指定 DNS Servers:

    #ms-dns 10.0.0.1
    #ms-dns 10.0.0.2

    修改为

    ms-dns 8.8.8.8
    ms-dns 8.8.4.4

  5. 重启 pptpd 服务

    service pptpd restart

  6. 编辑 /etc/sysctl.conf,添加:

    net.ipv4.ip_forward = 1

    保存后键入以下命令,使该改动生效:

    sysctl -p

    该步骤是使得 vpn 可以转发包,连接外网。

  7. 设置 iptables 的 NAT 规则

    iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

    表示在 eth0 接口上进行NAT转发。为了使系统重启时能够重新载入该设置,我们可以追加以下操作。

    先保存当前设置:

    iptables-save > /etc/iptables_rules

    然后修改/etc/network/interfaces,在eth0下添加:

    pre-up iptables-restore < /etc/iptables_rules

  8. 现在该 vpn 服务器就已经设置好,可以从客户端建立连接了。比如在 windows下,打开网络共享中心,选择新建工作网络或 vpn 连接,按照向导添加 vpn 服务器的 IP、用户名、密码即可连接。

  9. 有的人会发现链接 vpn 时var/log/syslog里报CTRL: PTY read or GRE write failed (pty,gre)=(6,7)的错误,这是防火墙没有配置好,没有允许 GRE 协议,执行以下命令即可:

    iptables -A INPUT -p 47 -j ACCEPT
    iptables-save

    多说一点,GRE是一个IP协议,并不是一个端口,使用netstat不会看到47号端口打开着。但是出于某种原因我们仍要允许47号端口才能使用GRE(具体原因细节我还不太清楚)。

0x02 使用 http 代理翻墙

使用 http 代理翻墙要稍微麻烦一些,我采用 stunnel+squid 的方法。squid 是 http 代理软件,理论上仅仅使用该软件就可以达到代理效果,由于客户端与代理间的流量是明文的,在实际测试的过程中我发现客户端发往代理的请求如果是谷歌,youtube等网站的话仍然会被 gfw 墙掉。所以需要将客户端与代理间的流量用 stunnel 加密。

分两步说,

一、使用 squid 搭建 http 代理:

squid 的配置非常简单:

  1. 安装

    apt-get install squid3

    这一步结束后其实squid就已经可以用了,但是为了防止别人随意使用我们的代理服务器,我们要对squid的访问规则进行一些设置。

  2. 打开 /etc/squid3/squid.conf,找到

    http_access deny all

    在其上方添加

    acl my_acl src xxx.xxx.xxx.xxx
    http_access allow my_acl

    把 xxx.xxx.xxx.xxx 替换成你允许连接的 IP 即可。但是我在国内时发现联通分配给每家的 IP 并不是固定的,所以使用限定 IP 的方法非常麻烦,于是我采用用户名密码认证的方式。具体操作如下,仍然在 /etc/squid3/squid.conf 中添加以下代码:

    auth_param basic program /usr/lib/squid3/basic_ncsa_auth /etc/squid3/passwd
    auth_param basic children 5
    auth_param basic credentialsttl 2 hours
    acl auth_user proxy_auth REQUIRED
    http_access allow auth_user

    其中/etc/squid3/passwd 文件是自己创建的密码文件,创建方法如下:

    htpasswd -c /etc/squid3/passwd user_name

    之后会提示你设置密码,输入两次密码后生成该文件,然后就可以使用这个用户名和密码来连接squid啦。如果没有 htpasswd 的话apt-get install apache2-utils即可。

  3. 重启服务:

    service squid3 restart

  4. 在客户端,打开比如 chrome 浏览器,安装一个 SwitchySharp 插件,新建一个代理 profile,将 IP 设为你的 vps 的 IP, 端口设为3128,然后设置用户名密码,测试一下,可以顺利连接。3128为 squid 默认端口,如果想改也同样可以在 /etc/squid3/squid.conf 中修改。

二、搭建 stunnel

正如之前所说,光有 squid 仍然是无法翻墙的,因为 squid 并不会把客户端与服务器间的流量加密,这之间的流量很轻易就被 gfw 偷窥到,然后被墙。

即使是 https 连接也是会被墙的,我们可以通过 wireshark 抓包来分析一下原因。在通过代理与谷歌建立 https 连接最初都是用明文的 http 包,进行密钥的交换。如下图,虽然中间打码的 IP 是代理服务器 IP 而非真实请求目的地的 IP,但CONNECT 请求和 Client Hello 请求都为明文,)。
connect
client hello
,所以在这一步就会被墙。

而之后即使在 TLS 信道建立完毕后,由于通过了一层代理,给代理发送的 http 头仍然是明文的,虽然在这层 http 中包裹了真实的加密的传向谷歌的数据,但是从下图我们可以看出,http 头的 [Proxy-Connect-Hostname]这个域出卖了真实的链接地址,所以也会很容易被墙。
app data

body data

综上,光使用 squid 代理是没法隐蔽我们的流量的,所以我们要使用 stunnel 对客户端和代理服务器间的流量进行加密。下面简述步骤。

  1. 首先在服务器上安装 stunnel:

    apt-get install stunnel4

  2. 创建证书:

    openssl req -new -x509 -days 365 -nodes -out /etc/stunnel4/stunnel.pem -keyout /etc/stunnel4/stunnel.pem

    然后会出现让你填Country Name,邮箱地址之类的交互界面,这里因为是我们自己用,随便填即可。

  3. 修改配置文件:

    打开 /etc/default/stunnel4,把 ENABLED 设为1,使得 stunnel 可以开机启动。
    在 /etc/stunnel4/ 目录下新建 stunnel.conf 文件,写入如下语句:

    socket = l:TCP_NODELAY=1
    socket = r:TCP_NODELAY=1

    pid = /var/lib/stunnel4/stunnel.pid
    verify = 3

    setuid = root
    setgid = root

    client=no
    delay = no
    sslVersion = TLSv1
    debug = 7
    syslog = yes
    output = stunnel.log

    [sproxy]
    accept = 34567
    connect = XXX.XXX.XXX.XXX:3128

    其中最后两行最重要,这是我们设置的 stunnel 服务器的 LISTEN 端口(可以自己指定,比如设为34567)和 要转发到的地址(这里也就是squid 服务器的 IP 和端口),这里由于我们的 stunnel 服务器与 squid 服务器是同一台机器,填写服务器本机地址即可。

  4. 重启服务:

     service stunnel4 restart

  5. 客户端设置:

    https://www.stunnel.org/downloads.html 下载windows版的客户端并安装(虽然服务器端 stunnel 的版本是4,但是客户端下载最新的版本5也是没有问题的)。安装完成后打开 stunnel 后点击Configuration->Edit Configuration,在弹出的 txt 文件最后添加如下代码: 

    cert = ./stunnel.pem
    client = yes

    [sproxy-client] 
    accept = 0.0.0.0:7071  
    connect = XXX.XXX.XXX.XXX:34567 

    XXX.XXX.XXX.XXX 替换为 stunnel 服务器的地址即可。然后还需要将刚刚在服务器上建立的 stunnel.pem 远程拷贝到客户端安装路径里,其实与 cert = ./stunnel.pem 这句话里的路径一致即可。最后保存 txt 文件,Reload Configuration 或者重启 stunnel 客户端即可。

  6. 好的,最后来设置浏览器的代理,打开 SwitchySharp,新建一个代理 profile,IP 设为本地 IP 127.0.0.1,端口为7071,也就是上一步中倒数第二行的端口,用户名和密码设置为 squid 的用户名密码。连接一下试试,可以翻墙啦!注意,我们现在有两个代理profile,一个是 直接使用 squid 的代理profile,如果开启这个代理的话虽然我们的流量都会走 squid 转发,但是还是只能上你原来能上的那些网站,并不能上和谐网站,所以我们每次要上和谐网站时应打开 stunnel 客户端,并使用 stunnel 的代理profile。

0x03 vpn 与 http 代理对比

搭建vpn的优点是简单有效,而缺点是你所有流量都经过 vpn,不能自如切换,如果连着vpn上国内网站速度其实挺慢的(如果想指定某些网站不走 vpn 还要手动改客户端路由网关,还比较麻烦。如果有什么自动工具还望告诉我)。另外 pptp 因为用户名和密码是明文传输的,所以有安全隐患。建议尝试 L2TP/IPSec。

http 代理的优点是切换自如,使用 SwitchySharp 更是可以自动切换代理,上国内网站和国外网站两不误。当然缺点也很多啦,一是比如走 tcp 的流量就无法转发了(典型场景是你想下载谷歌日文输入法,而它是在线安装,由于是 C/S 结构,走的不是 http 流量,所以根本无法安装),二是搭建起来确实麻烦。