Skip to content

iOS8 不越狱翻墙方案

Posted on:October 12, 2014 at 04:00 PM
0

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

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

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

以下步骤需要你有自己的 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 可以跳过这一步。

cat /dev/net/tun

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

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

下载源码

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

安装编译所需的包

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

编译

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

非 OpenVZ 执行如下命令。

./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 参数,完整命令如下。

./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

make && sudo make install

生成证书

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

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

mkdir ~/ipsec_cert && cd ~/ipsec_cert

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

生成服务器证书

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

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

生成客户端证书

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

wget https://gist.githubusercontent.com/songchenwen/14c1c663ea65d5d4a28b/raw/54843ae2e5e6d1159134cd9a90a08c31ff5a253d/client_key.sh
sh client_key.sh gary gary@gmail.com

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

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

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

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

配置 Strongswan

编辑 /etc/ipsec.conf

sudo vi /etc/ipsec.conf
config setup
	# strictcrlpolicy=yes
	#  uniqueids = replace
	# charondebug="cfg 2, dmn 2, ike 2, net 0" #要看Log时,取消注释本行

conn %default
	keyexchange=ikev1
	dpdaction=hold
	dpddelay=600s
	dpdtimeout=5s
	lifetime=24h
	ikelifetime=240h
	rekey=no
	left=emptyzone.github.io #这里换成你登录 VPN 用的域名或 IP,与生成证书时相同
	leftsubnet=0.0.0.0/0
	leftcert=vpnHostCert.pem
	leftsendcert=always
	right=%any
	rightdns=8.8.8.8
	rightsourceip=10.0.0.0/8

conn CiscoIPSec
	rightauth=pubkey
	rightauth2=xauth
	auto=add

编辑 /etc/ipsec.secrets

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

配置防火墙 iptables

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

/etc/iptables.firewall.rules

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

*filter

#  Allow all loopback (lo0) traffic and drop all traffic to 127/8 that doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT -d 127.0.0.0/8 -j LOG --log-prefix "looback denied: " --log-level 7
-A INPUT -d 127.0.0.0/8 -j REJECT

#  Accept all established inbound connections
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

#  Allow all outbound traffic - you can modify this to only allow certain traffic
-A OUTPUT -j ACCEPT

#  Allow HTTP and HTTPS connections from anywhere (the normal ports for websites and SSL).
-A INPUT -p tcp --dport 80 -j ACCEPT

# Allow ipsec
-A INPUT -p udp --dport 4500 --j ACCEPT
-A INPUT -p udp --dport 500 --j ACCEPT
-A INPUT -p esp -j ACCEPT

#  Allow SSH connections
#
#  The -dport number should be the same port number you set in sshd_config
#
-A INPUT -p tcp -m state --state NEW --dport 1010 -j ACCEPT

#  Allow ping
-A INPUT -p icmp -j ACCEPT

#  Log iptables denied calls
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

-A INPUT -j DROP

COMMIT

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

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

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

执行

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

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

iptables -t nat -A POSTROUTING -j MASQUERADE
iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
iptables -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

charon {
  plugins {
    attr {

	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

      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

    }
  }
}

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

开机自启

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

iOS 端自动配置文件

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

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

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

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

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

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

用文本编辑器编辑。

找到这一段

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

改成下面这样

<key>OnDemandEnabled</key>
<integer>1</integer>
<key>OnDemandRules</key>
<array>
  <dict>
    <key>Action</key>
    <string>Connect</string>
  </dict>
</array>

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

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

DNS

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

安装 pdsnd

sudo apt-get install pdnsd

配置 pdnsd

编辑 /etc/pdnsd.conf

global {
	perm_cache = 8192;
	cache_dir = "/var/cache/pdnsd";
	run_as = "pdnsd";
	server_ip = 0.0.0.0;
	status_ctl = on;
	paranoid = on;
	query_method = udp_tcp;
	tcp_server = on;
	min_ttl = 1d;
	max_ttl = 52w;
	timeout = 10;

	randomize_recs = on;
	debug = off;
	daemon = on;
	verbosity = 1;
	neg_rrs_pol = on;
	neg_domain_pol = on;
	par_queries = 4;
}

server {
	label				= "Unicom Beijing";
	ip 					=  202.106.196.115, 202.106.46.151, 202.106.0.20, 202.106.195.68;
	timeout				= 10;
	proxy_only			= on;
	caching				= on;
	randomize_servers	= off;
    reject_policy		= fail;
    reject_recursively  = on;
	include				=
// Place Domains Below. Remember add a dot(".") at the start of domain, if you also want to redirect all subdomains!
		".cn",
// Place Domains Above.
		"DOMAIN.PADDING";


	exclude				=
// Place Domains Below. Remember add a dot(".") at the start of domain, if you also want to redirect all subdomains!

".darpa.mil", ".fxnetworks.com", ".hulu.com", ".huluim.com", ".muzu.tv", ".netflix.com"

// Place Domains Above.
		"DOMAIN.PADDING";

reject = 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;

}

server {
    label				= "Google"; // Primary
    timeout				= 3;
    ip					= 8.8.8.8, 8.8.4.4, 208.67.222.222, 208.67.220.220;
	proxy_only			= on;
    caching				= on;
    randomize_servers	= on;
}

rr {
	name=localhost;
	reverse=on;
	a=127.0.0.1;
	owner=localhost;
	soa=localhost,root.localhost,42,86400,900,86400,86400;
}

/* 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,你也可以放在你喜欢的位置。

文件内容如下。

#!/bin/sh

PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin"
export PATH

echo "updown executing"

ipsec _updown

case "$PLUTO_VERB:$1" in
up-client:)

iptables -C INPUT -s $PLUTO_PEER -p tcp -m tcp --dport 53 -j ACCEPT
exist=$?

if [ $exist -eq 0 ];then
	echo "updown script rule already exists for $PLUTO_PEER"
else
	echo "updown script up client $PLUTO_PEER"
	iptables -I INPUT 4 -s $PLUTO_PEER -p tcp -m tcp --dport 53 -j ACCEPT
	iptables -I INPUT 4 -s $PLUTO_PEER -p udp -m udp --dport 53 -j ACCEPT
	iptables -I INPUT 4 -s $PLUTO_PEER -p tcp -m tcp --sport 53 -j ACCEPT
	iptables -I INPUT 4 -s $PLUTO_PEER -p udp -m udp --sport 53 -j ACCEPT
fi
;;

down-client:)

echo "updown script down client $PLUTO_PEER"

iptables -D INPUT -s $PLUTO_PEER -p tcp -m tcp --dport 53 -j ACCEPT
iptables -D INPUT -s $PLUTO_PEER -p udp -m udp --dport 53 -j ACCEPT
iptables -D INPUT -s $PLUTO_PEER -p tcp -m tcp --sport 53 -j ACCEPT
iptables -D INPUT -s $PLUTO_PEER -p udp -m udp --sport 53 -j ACCEPT
;;

esac

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

修改 /etc/ipsec.conf

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

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