Navigate back to the homepage

iOS8 不越狱翻墙方案

宋辰文
October 12th, 2014 · 2 min read

iOS8 为我们带来了第三方输入法和 App Extentions,越狱的需求越来越少。而且自从在 Bither 里存了一些比特币之后,我就越来越关注手机系统的安全性。现在真的是能不越狱就尽量不越了。那么不越狱的话怎么满足我自由的访问互联网的需求呢?

OS X,PC 或者 Android 翻墙,请移步 Shadowsocks

我目前在 iPhone 上所用的翻墙方案包含如下两部分 :

  • 自动连接并区分墙内外流量的 IPsec VPN
  • 避开 GFW 污染,并尽量就近解析域名的 DNS

以下步骤需要你有自己的 VPS。

以下操作基于 Ubuntu,以非 root 用户 ssh 登录。其它发行版应该只有包管理和防火墙部分稍有不同。

IPsec VPN

我是在 Twitter 上看到 Justin 说 Anyconnect 在 iOS8 上变的特别慢之后,才开始考虑停掉 ocserv 换用 IPsec VPN 的,IPsec 的配置方法参考了 Justin文章。由于 IKEv2 在 iOS8 上有 Bug,所以这里还是用的 IKEv1 协议。不过如果 Apple 在哪个版本修复了 IKEv2 的话,现在这个配置方式也是很容易迁移到 IKEv2 的。

编译 Strongswan

apt-get 里的 Strongswan 版本低,所以这里需要自行编译最新版的 Strongswan。

检查依赖

如果是基于 OpenVZ 的 VPS 的话,先要检查一下有没有 TUN Device。输入下面的命令。非 OpenVZ 可以跳过这一步。

1cat /dev/net/tun

如果执行结果如下,那么就可以安装 Strongswan 了。否则的话,去给 VPS 提供商发 Ticket 看能不能解决吧。

1cat: /dev/net/tun: File descriptor in bad state

下载源码

1wget http://download.strongswan.org/strongswan.tar.gz && tar zxvf strongswan*
2cd strongswan*

安装编译所需的包

1sudo apt-get build-dep strongswan
2sudo apt-get install libgmp3-dev openssl libssl-dev

编译

Strongswan 在 configure 时要对 OpenVZ 特殊处理。

非 OpenVZ 执行如下命令。

1./configure --sysconfdir=/etc --disable-sql --disable-mysql --disable-ldap --enable-dhcp --enable-eap-identity --enable-eap-mschapv2 --enable-md4 --enable-xauth-eap --enable-eap-peap --enable-eap-md5 --enable-openssl --enable-shared --enable-unity --enable-eap-tls --enable-eap-ttls --enable-eap-tnc --enable-eap-dynamic --enable-addrblock --enable-radattr --enable-nat-transport --enable-kernel-netlink

OpenVZ 要加上 --enable-kernel-libipsec 参数,完整命令如下。

1./configure --sysconfdir=/etc --disable-sql --disable-mysql --disable-ldap --enable-dhcp --enable-eap-identity --enable-eap-mschapv2 --enable-md4 --enable-xauth-eap --enable-eap-peap --enable-eap-md5 --enable-openssl --enable-shared --enable-unity --enable-eap-tls --enable-eap-ttls --enable-eap-tnc --enable-eap-dynamic --enable-addrblock --enable-radattr --enable-nat-transport --enable-kernel-netlink --enable-kernel-libipsec

configure 完之后就可以 makeinstall

1make && sudo make install

生成证书

这里是使用的自签名证书,需要你把 CA 证书用邮件发到 iOS 设备上安装才行。如果要用 ssl 证书,可以参考 wzxjohn文章

Strongswan 的证书都是要放在 /etc/ipsec.d/ 里的,不过我们是非 root 登录的,不方便直接操作这个目录,可以现在 home 目录下新建个目录来生成证书,等都生成好了再复制到 /etc/ipsec.d/ 就行了。

1mkdir ~/ipsec_cert && cd ~/ipsec_cert

生成证书用到的命令比较多,我写好了 script 来做这件事

生成服务器证书

记得把我这里写的 emptyzone.github.io 换成你自己的 Server IP 或者是域名。你打算用域名访问 VPN 就写 域名,打算用 IP 访问就写 IP,别写错了。

1wget https://gist.githubusercontent.com/songchenwen/14c1c663ea65d5d4a28b/raw/cef8d8bafe6168388b105f780c442412e6f8ede7/server_key.sh
2sh server_key.sh emptyzone.github.io

生成客户端证书

gary[email protected] 换成你自己的用户名和email。这个脚本执行完会生成好导入 iOS 时需要的 p12 证书文件,最后提示你输入的密码就是用来加密它的,在往 iOS 导入时输入相同的即可。

1wget https://gist.githubusercontent.com/songchenwen/14c1c663ea65d5d4a28b/raw/54843ae2e5e6d1159134cd9a90a08c31ff5a253d/client_key.sh
2sh client_key.sh gary [email protected]

执行完成后可以把以用户名开头的 .p12 文件 和 cacerts/strongswanCert.pem 下载到本地来备用。

复制证书到 /etc/ipsec.d/

Strongswan 需要的是 cacerts/strongswanCert.pem certs/vpnHostCert.pem private/vpnHostKey.pem 这三个文件。

1sudo cp cacerts/strongswanCert.pem /etc/ipsec.d/cacerts/strongswanCert.pem
2sudo cp certs/vpnHostCert.pem /etc/ipsec.d/certs/vpnHostCert.pem
3sudo cp private/vpnHostKey.pem /etc/ipsec.d/private/vpnHostKey.pem

配置 Strongswan

编辑 /etc/ipsec.conf

1sudo vi /etc/ipsec.conf
1config setup
2 # strictcrlpolicy=yes
3 # uniqueids = replace
4 # charondebug="cfg 2, dmn 2, ike 2, net 0" #要看Log时,取消注释本行
5
6conn %default
7 keyexchange=ikev1
8 dpdaction=hold
9 dpddelay=600s
10 dpdtimeout=5s
11 lifetime=24h
12 ikelifetime=240h
13 rekey=no
14 left=emptyzone.github.io #这里换成你登录 VPN 用的域名或 IP,与生成证书时相同
15 leftsubnet=0.0.0.0/0
16 leftcert=vpnHostCert.pem
17 leftsendcert=always
18 right=%any
19 rightdns=8.8.8.8
20 rightsourceip=10.0.0.0/8
21
22conn CiscoIPSec
23 rightauth=pubkey
24 rightauth2=xauth
25 auto=add

编辑 /etc/ipsec.secrets

1sudo vi /etc/ipsec.secrets
1#验证用户所需的信息
2#用户名 : EAP "密码"
3: RSA vpnHostKey.pem
4gary : EAP "strongpassword"

配置防火墙 iptables

参考我的配置文件,重要的是开启 NAT 转发 开放 4500 500 端口和 esp 协议

/etc/iptables.firewall.rules

注意别把自己的 ssh 端口关闭了

1*filter
2
3# Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
4-A INPUT -i lo -j ACCEPT
5-A INPUT -d 127.0.0.0/8 -j LOG --log-prefix "looback denied: " --log-level 7
6-A INPUT -d 127.0.0.0/8 -j REJECT
7
8# Accept all established inbound connections
9-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
10
11# Allow all outbound traffic - you can modify this to only allow certain traffic
12-A OUTPUT -j ACCEPT
13
14# Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
15-A INPUT -p tcp --dport 80 -j ACCEPT
16
17# Allow ipsec
18-A INPUT -p udp --dport 4500 --j ACCEPT
19-A INPUT -p udp --dport 500 --j ACCEPT
20-A INPUT -p esp -j ACCEPT
21
22# Allow SSH connections
23#
24# The -dport number should be the same port number you set in sshd_config
25#
26-A INPUT -p tcp -m state --state NEW --dport 1010 -j ACCEPT
27
28# Allow ping
29-A INPUT -p icmp -j ACCEPT
30
31# Log iptables denied calls
32-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7
33
34-A INPUT -j DROP
35
36COMMIT

/etc/sysctl.conf 中开启 net.ipv4.ip_forward=1

编辑 /etc/network/if-pre-up.d/firewall

1#!/bin/sh
2/sbin/iptables-restore < /etc/iptables.firewall.rules

执行

1sudo chmod +x /etc/network/if-pre-up.d/firewall

编辑 /etc/rc.localexit 0 前加上,20.16.3.18 换成你的服务器 IP。

1iptables -t nat -A POSTROUTING -j MASQUERADE
2iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
3iptables -A POSTROUTING -t nat -s 10.0.0.0/8 -j SNAT --to-source 20.16.3.18

现在可以重启一下服务器,然后执行 sudo iptables -L,看看防火墙有没有添加对。

区分流量自动路由

是的,你没看错,IPsec IKEv1 也是支持自动路由的。IPsec 支持 SplitTunneling。iOS 上的 IPsec 客户端用的是 Racoon,这货支持 Unity Plugin。也就是说我们可以用 IP 列表来区分国内外流量了。

但是当启用了 SplitTunneling 之后,iOS 端就不会使用我们在服务器端配置的 DNS 了,所以我们还需要利用 Unity Plugin 的 Split DNS 来把抗干扰的 DNS 推给客户端。

IP 列表可能会经常维护,所以我希望把它和主配置文件分开放置。放在我的 home 目录里就好了。

修改 /etc/strongswan.conf

在文件最后加上一句 include /home/gary/ipsec_config/*.confgary 换成你的 ssh 用户名,这样strongswan 就会导入我的 ~/ipsec_config 目录下的所有 .conf 文件。

添加 IP 列表配置

这是我现在用的 IP 列表,目前除了 Instagram 经常有图片下载不下来以外,没有别的问题。这个 IP 列表 iOS 端估计是有数量上限的。我测试的结果是当数量大于160时,iOS 端会返回 IKE DELETE

28675Split DNS 的 Key,我这里用上了 GFWList 中的所有顶级域名。

创建并编辑 ~/ipsec_config/attr.conf

1charon {
2 plugins {
3 attr {
4
5 split-include = 63.140.32.0/19, 66.117.16.0/20, 66.235.0.0/16, 130.248.0.0/16, 153.32.0.0/16, 185.34.188.0/22, 192.147.117.0/24, 192.150.0.0/16, 192.243.224.0/20, 192.243.248.0/21, 193.104.215.0/24, 195.35.86.0/24, 208.77.136.0/22, 216.104.0.0/16, 8.18.144.0/23, 23.20.0.0/14, 27.0.0.0/22, 46.51.128.0/18, 46.51.192.0/20, 46.51.216.0/21, 46.51.224.0/19, 46.137.0.0/17, 46.137.128.0/18, 46.137.224.0/19, 50.16.0.0/14, 50.112.0.0/16, 54.0.0.0/8, 67.202.0.0/18, 72.21.192.0/19, 72.44.32.0/19, 75.101.128.0/17, 79.125.0.0/17, 87.238.80.0/21, 96.127.0.0/17, 103.246.148.0/22, 107.20.0.0/14, 122.248.192.0/18, 174.129.0.0/16, 176.32.64.0/19, 176.34.0.0/16, 178.236.0.0/20, 184.72.0.0/15, 184.169.128.0/17, 184.154.0.0/16, 185.48.120.0/22, 199.0.0.0/8, 203.83.220.0/22, 204.236.128.0/17, 204.246.160.0/20, 204.246.176.0/22, 204.246.180.0/23, 204.246.182.0/24, 204.246.184.0/21, 205.251.192.0/19, 205.251.224.0/20, 205.251.240.0/21, 205.251.248.0/22, 205.251.252.0/23, 205.251.254.0/24, 207.171.160.0/19, 216.137.32.0/21, 216.137.40.0/22, 216.137.44.0/23, 216.137.48.0/20, 216.182.224.0/20, 17.0.0.0/8, 63.92.224.0/19, 192.12.74.0/24, 192.42.249.0/24, 204.79.190.0/24, 104.16.0.0/12, 108.162.192.0/19, 108.162.224.0/20, 108.162.240.0/21, 108.162.248.0/22, 108.162.252.0/23, 108.162.254.0/24, 162.158.0.0/15, 173.245.48.0/20, 198.41.128.0/17, 204.93.177.0/24, 108.160.160.0/20, 205.189.0.0/24, 37.48.64.0/18, 85.17.0.0/16, 95.211.0.0/16, 31.13.24.0/21, 31.13.64.0/18, 66.220.144.0/20, 69.63.176.0/20, 69.171.224.0/19, 74.119.76.0/22, 173.252.64.0/18, 204.15.20.0/22, 23.235.32.0/20, 104.156.80.0/20, 208.71.104.0/22, 192.30.252.0/22, 8.6.48.0/21, 8.8.4.0/24, 8.8.8.0/24, 8.15.202.0/24, 8.34.208.0/20, 8.35.192.0/20, 23.236.48.0/20, 23.251.128.0/19, 64.9.224.0/19, 64.233.160.0/19, 66.102.0.0/20, 66.249.64.0/19, 70.32.128.0/19, 72.14.192.0/18, 74.125.0.0/16, 104.132.0.0/14, 104.154.0.0/15, 104.196.0.0/14, 107.167.160.0/19, 107.178.192.0/18, 108.59.80.0/20, 108.170.192.0/18, 108.177.0.0/17, 130.211.0.0/16, 142.250.0.0/15, 146.148.0.0/17, 162.216.148.0/22, 162.222.176.0/21, 172.217.0.0/16, 172.253.0.0/16, 172.16.16.1/32, 173.255.112.0/20, 192.158.28.0/22, 192.178.0.0/15, 207.223.160.0/20, 209.85.128.0/17, 216.58.192.0/19, 216.239.32.0/19, 205.196.120.0/22, 8.25.0.0/16, 192.133.76.0/22, 93.184.216.0/24, 59.24.3.0/24, 91.198.174.0/24, 185.15.56.0/22, 198.35.26.0/23, 198.73.209.0/24, 208.80.152.0/22, 66.155.8.0/21, 76.74.248.0/21, 192.0.64.0/18, 198.181.116.0/22
6
7 28675 = mil com tv fm za tw org info biz ca net ru au us de hk jp me uk io is it in li gov ly fr nu st asia im my xxx tk eu cc mobi se edu il kr ie ar nl cm ua es ph bz br be mp cz name lu ch su to no co nz sg ma vc am at la sh tl gd sk id pl mo tc hu
8
9 }
10 }
11}

现在可以执行 sudo ipsec start --nofork,试一下了。--nofork 参数会让 strongswan 在前台运行,调试时加上就可以了,平时就让它在后台运行吧。

开机自启

编辑 /etc/rc.localexit 0 前加上 ipsec start

iOS 端自动配置文件

这里完全参考 Justin文章就可以了,他那有截图,我就只说一下步骤吧。

用 Apple Configurator 创建配置描述文件。

通用里的名称和标识符自己填好。

凭证里导入刚才下载好的客户端 .p12 证书。

VPN里连接类型选 IPsec(Cisco),机器鉴定选证书,在下面选中刚才导入的证书。

导出这个配置描述文件,别签名。

用文本编辑器编辑。

找到这一段

1<key>OnDemandEnabled</key>
2<integer>1</integer>

改成下面这样

1<key>OnDemandEnabled</key>
2<integer>1</integer>
3<key>OnDemandRules</key>
4<array>
5 <dict>
6 <key>Action</key>
7 <string>Connect</string>
8 </dict>
9</array>

另外,如果配置描述文件里只有 XAuthName,没有 XAuthPassword的话,可以自己加上这个 Key,然后把密码填上。

把这个配置描述文件,连同刚才下载好的服务器CA证书 strongswanCert.pem 一起,用邮件发到自己的 iOS 设备上,然后安装好,试一下吧。

DNS

使用刚才配置的 IPsec VPN 翻墙的话,就总会使用谷歌的 DNS 服务器做域名查询。这样很多明明国内有 CDN 的域名,却会解析到国外的 IP 上,造成访问缓慢。所以我要利用 pdnsd 来创建一个带缓存的域名解析服务。这里主要参考了这篇文章

安装 pdsnd

1sudo apt-get install pdnsd

配置 pdnsd

编辑 /etc/pdnsd.conf

1global {
2 perm_cache = 8192;
3 cache_dir = "/var/cache/pdnsd";
4 run_as = "pdnsd";
5 server_ip = 0.0.0.0;
6 status_ctl = on;
7 paranoid = on;
8 query_method = udp_tcp;
9 tcp_server = on;
10 min_ttl = 1d;
11 max_ttl = 52w;
12 timeout = 10;
13
14 randomize_recs = on;
15 debug = off;
16 daemon = on;
17 verbosity = 1;
18 neg_rrs_pol = on;
19 neg_domain_pol = on;
20 par_queries = 4;
21}
22
23server {
24 label = "Unicom Beijing";
25 ip = 202.106.196.115, 202.106.46.151, 202.106.0.20, 202.106.195.68;
26 timeout = 10;
27 proxy_only = on;
28 caching = on;
29 randomize_servers = off;
30 reject_policy = fail;
31 reject_recursively = on;
32 include =
33// Place Domains Below. Remember add a dot(".") at the start of domain, if you also want to redirect all subdomains!
34 ".cn",
35// Place Domains Above.
36 "DOMAIN.PADDING";
37
38
39 exclude =
40// Place Domains Below. Remember add a dot(".") at the start of domain, if you also want to redirect all subdomains!
41
42".darpa.mil", ".fxnetworks.com", ".hulu.com", ".huluim.com", ".muzu.tv", ".netflix.com"
43
44// Place Domains Above.
45 "DOMAIN.PADDING";
46
47reject = 118.5.49.6, 128.121.126.139, 159.106.121.75, 169.132.13.103, 188.5.4.96, 189.163.17.5, 192.67.198.6, 197.4.4.12, 202.106.1.2, 202.181.7.85, 203.161.230.171, 203.98.7.65, 207.12.88.98, 208.56.31.43, 209.145.54.50, 209.220.30.174, 209.36.73.33, 209.85.229.138, 211.94.66.147, 213.169.251.35, 216.221.188.182, 216.234.179.13, 23.89.5.60, 243.185.187.39, 249.129.46.48, 253.157.14.165, 37.61.54.158, 4.36.66.178, 46.82.174.68, 49.2.123.56, 54.76.135.1, 59.24.3.173, 64.33.88.161, 64.33.99.47, 64.66.163.251, 65.104.202.252, 65.160.219.113, 66.45.252.237, 72.14.205.104, 72.14.205.99, 74.125.127.102, 74.125.155.102, 74.125.39.102, 74.125.39.113, 77.4.7.92, 78.16.49.15, 8.7.198.45, 93.46.8.89;
48
49}
50
51server {
52 label = "Google"; // Primary
53 timeout = 3;
54 ip = 8.8.8.8, 8.8.4.4, 208.67.222.222, 208.67.220.220;
55 proxy_only = on;
56 caching = on;
57 randomize_servers = on;
58}
59
60rr {
61 name=localhost;
62 reverse=on;
63 a=127.0.0.1;
64 owner=localhost;
65 soa=localhost,root.localhost,42,86400,900,86400,86400;
66}
67
68/* vim:set ft=c: */

这里默认使用北京联通的域名解析服务器,你也可以换成更适合自己的。当遇到被墙域名或者收到了被污染的 IP 时,再使用谷歌和 OpenDNS 的服务器。

执行 sudo service pdnsd start 来启动 pdnsd。

为使用 pdnsd 配置 Strongswan

我们刚才配置的 iptables 中并没有开启 DNS 服务需要的53端口。这个端口如果完全开放的话,VPS 提供商可能会给我们发安全警告。所以我们要利用 Strongswan 的 updown script 来完成对 iptables 的设置。

创建 leftupdown 脚本

我把这个脚本放在了 ~/ipsec_config/leftupdown,你也可以放在你喜欢的位置。

文件内容如下。

1#!/bin/sh
2
3PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin"
4export PATH
5
6echo "updown executing"
7
8ipsec _updown
9
10case "$PLUTO_VERB:$1" in
11up-client:)
12
13iptables -C INPUT -s $PLUTO_PEER -p tcp -m tcp --dport 53 -j ACCEPT
14exist=$?
15
16if [ $exist -eq 0 ];then
17 echo "updown script rule already exists for $PLUTO_PEER"
18else
19 echo "updown script up client $PLUTO_PEER"
20 iptables -I INPUT 4 -s $PLUTO_PEER -p tcp -m tcp --dport 53 -j ACCEPT
21 iptables -I INPUT 4 -s $PLUTO_PEER -p udp -m udp --dport 53 -j ACCEPT
22 iptables -I INPUT 4 -s $PLUTO_PEER -p tcp -m tcp --sport 53 -j ACCEPT
23 iptables -I INPUT 4 -s $PLUTO_PEER -p udp -m udp --sport 53 -j ACCEPT
24fi
25;;
26
27down-client:)
28
29echo "updown script down client $PLUTO_PEER"
30
31iptables -D INPUT -s $PLUTO_PEER -p tcp -m tcp --dport 53 -j ACCEPT
32iptables -D INPUT -s $PLUTO_PEER -p udp -m udp --dport 53 -j ACCEPT
33iptables -D INPUT -s $PLUTO_PEER -p tcp -m tcp --sport 53 -j ACCEPT
34iptables -D INPUT -s $PLUTO_PEER -p udp -m udp --sport 53 -j ACCEPT
35;;
36
37esac

保存好文件后,修改文件权限 chmod 777 ~/ipsec_config/leftupdown

修改 /etc/ipsec.conf

rightdns 改成 VPS 的 IP。在 %default 里添加一行 leftupdown=/path/to/your/leftupdown,注意这里把路径换成刚才创建的 leftupdown 脚本的绝对路径。

执行 sudo ipsec reload,然后客户端重新连接一下,试试效果吧。

More articles from 宋辰文

货币的历史

我们现在用的纸币并不是货币最初的样子。 现代生活过久了,很容易忘记,我们习以为常的事情,从历史的角度看却并不是常态,先让我们来看看货币的历史。

March 25th, 2020 · 1 min read

是时候聊聊通货膨胀了

2020-03-23晚上,美联储再次加码量化宽松,为确保市场运行和货币政策传导,将不限量按需买入美债和抵押贷款支持证券。现在是时候聊聊通货膨胀了。

March 24th, 2020 · 1 min read
© 2019 宋辰文
Link to $https://mp.weixin.qq.com/s?__biz=MzAxNTI3MTUwMA==&mid=2247483701&idx=2&sn=34613cbb3252ac5eb6c31724f3109b59Link to $https://weibo.com/songchenwenLink to $https://twitter.com/songchenwenLink to $https://stackoverflow.com/users/2210682/songchenwen