iOS开发之免改hosts翻墙

来源:http://www.keakon.net/2011/07/10/iOS%E5%BC%80%E5%8F%91%E4%B9%8B%E5%85%8D%E6%94%B9hosts%E7%BF%BB%E5%A2%99

在开发iOS的web应用时,不可避免地会遇到一些被墙的网站。使用VPN或代理服务器自然是可以解决的,不过成本比较高。而Google的大部分服务都有很多IP,可以通过修改hosts文件来翻墙访问,但在iOS设备上却需要用户去越狱才能修改,显得颇为不便。
好在HTTP请求其实也是使用socket,在请求前要用socket连接服务器,提供域名/IP和端口,这里只要改成可用的IP就能连上了。在连接之后,还要提供访问方法、路径、Host等其他头字段,这里只要把Host改成原本的域名即可。

举例来说,我们要访问"https://docs.google.com/?pli=1",那么标准的方法是这样的:
# 先连接docs.google.com:443,再发送下列HTTP头
GET /?pli=1 HTTP 1.1
Host: docs.google.com
# 其他头省略⋯
而由于GFW的存在,我们在连接docs.google.com:443时就超时或证书被劫持了,无法继续下面的步骤。

而新方法则是这样:
# 先连接docs.google.com的某个可用IP:443,再发送下列HTTP头
GET /?pli=1 HTTP 1.1
Host: docs.google.com
# 其他头省略⋯
现在连接可以顺利完成,但可能还会出现Host无法通过SSL验证的情况,这时只要不对HTTPS请求进行验证即可(因为我们信任这个IP)。

不过,要让NSURLConnection忽略SSL验证比较麻烦,想知道的可以参考《NSURLErrorDomain "bad server certificate"》,这里我就直接用第三方的ASIHTTPRequest库来演示了。

先是标准方法:
NSURL *url = [NSURL URLWithString:@"https://docs.google.com/?pli=1"]; ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request startSynchronous]; NSLog(@"%@", [request error]);
会得到如下错误,看上去GFW把证书给劫持了:
Domain=ASIHTTPRequestErrorDomain Code=1 "A connection failure occurred: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)" UserInfo=0x4c7d6e0 {NSUnderlyingError=0x4c8d520 "The operation couldn't be completed. (OSStatus error -9810.)", NSLocalizedDescription=A connection failure occurred: SSL problem (Possible causes may include a bad/expired/self-signed certificate, clock set to wrong date)}

新方法:
NSURL *url = [NSURL URLWithString:@"https://某个神秘IP/?pli=1"]; // 连接的地址改成其他其他IP ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url]; [request addRequestHeader:@"Host" value:@"docs.google.com"]; // 手动设置Host字段 [request setValidatesSecureCertificate:NO]; // 不进行验证 NSLog(@"%@", [request responseString]);
这下就能看到HTML文档了。

至于这些IP是什么我就不说了,原因你懂的。

没有评论: