用 Flora_Pac.py 生成自动翻墙的 pac 文件

原文:http://www.leaskh.com/2011/12/02/%e7%94%a8-flora_pac-py-%e7%94%9f%e6%88%90%e8%87%aa%e5%8a%a8%e7%bf%bb%e5%a2%99%e7%9a%84-pac-%e6%96%87%e4%bb%b6/

源于人们对自由的向往,翻 墙技术已渐趋成熟。愿意花点钱,购买海外 VPN 和 ssh 主机用于自由获取信息是目前比较有效的手段。如我之前文章中提及,这两种方式都有需要筛选出那些网站在墙外,那些网站在墙内,以较节约、高速的方式访问网 络。八仙过海,各显神通,不少帮助人们解决这一问题,降低翻墙门槛的小项目出现了。较具代表性的有 chnroutes(http://code.google.com/p/chnroutes/) 项目和 autoproxy-gfwlist(http://code.google.com/p/autoproxy-gfwlist/) 项目。前者修改路由表,配合各种 VPN 使用,后者可以配合 AutoProxy for Firefox(https://addons.mozilla.org/firefox/addon/11009) 或导出(https://autoproxy2pac.appspot.com/)为 pac 文件,配合各种代理服务器,包括 ssh -D 使用。他们的原理稍有差异,chnroutes 只区分国内外 IP 段,让国外地址全部走翻墙路线,autoproxy-gfwlist 项目则精确记录着那些网站被墙。

我以往喜欢 ssh -D 生成 SOCKS 代理后,搭配自己的 pac 文件翻墙。最近由于各种原因转到了 VPN 阵营。感觉 VPN 搭配 chnroutes 的确很舒服,不用再关心那些网站被墙,不会因为 gfwlist 更新延迟而影响访问。于是我在想,有没有办法让使用 ssh -D 或者其他翻墙代理的用户能和使用 VPN 的用户那样省心呢?于是我站在巨人的肩膀上,基于 chnroutes 项目,结合 pac 文件的 dnsResolve() 和 isInNet() 函数,开发了 Flora_Pac 这个小项目。

Flora_Pac 使用 Python 开发,能自动抓取 apnic.net 的 IP 数据,找出所有国内的 IP 地址段,生成能让浏览器自动判断国内外 IP 地址的 pac 文件,让代理用户有等价于 VPN + chnroutes 的翻墙体验。Flora_Pac 使用十分简单,兼容各种平台:

####### 获得帮助: $ python flora_pac.py -h usage: flora_pac.py [-h] [-x [PROXY]] Generate proxy auto-config rules. optional arguments:   -h, --help            show this help message and exit   -x [PROXY], --proxy [PROXY]                         Proxy Server, examples:                             SOCKS 127.0.0.1:8964;                             SOCKS5 127.0.0.1:8964;                             PROXY 127.0.0.1:8964  ####### 生成 pac 文件,国外 IP 通过代理 SOCKS 代理 127.0.0.1:8964 访问: $ python flora_pac.py -x 'SOCKS 127.0.0.1:8964' Fetching data from apnic.net, it might take a few minutes, please wait... Rules: 3460 items. Usage: Use the newly created flora_pac.pac as your web browser's automatic proxy configuration (.pac) file.  ####### 生成 pac 文件,国外 IP 通过代理 HTTP 代理 127.0.0.1:8964 访问: $ python flora_pac.py -x 'PROXY 127.0.0.1:8964' Fetching data from apnic.net, it might take a few minutes, please wait... Rules: 3460 items. Usage: Use the newly created flora_pac.pac as your web browser's automatic proxy configuration (.pac) file.

程序跑完后,就会在当前目录产生 flora_pac.pac 文件,把它设为浏览器或系统代理设置的 pac 文件即可。

项目代码我放在 github 上开源了:https://github.com/Leask/Flora_Pac,其中 fetch_ip_data 函数 fork 自 chnroutes 项目。

不方便上 github 的朋友,直接复制以下代码保存为 flora_pac.py 就可以跑了:

#!/usr/bin/env python # # Flora_Pac by @leaskh # www.leaskh.com, i@leaskh.com # # based on chnroutes project (by Numb.Majority@gmail.com) #  import re import urllib2 import argparse import math  def generate_pac(proxy):     results  = fetch_ip_data()     pacfile  = 'flora_pac.pac'     rfile    = open(pacfile, 'w')     strLines = (         "// Flora_Pac by @leaskh"         "\n// www.leaskh.com, i@leaskh.com"         "\n"         "\nfunction FindProxyForURL(url, host)"         "\n{"         "\n"         "\n    var list = ["     )     intLines = 0     for ip,mask,_ in results:         if intLines > 0:             strLines = strLines + ','         intLines = intLines + 1         strLines = strLines + "\n        ['%s', '%s']"%(ip, mask)     strLines = strLines + (         "\n    ];"         "\n"         "\n    var ip = dnsResolve(host);"         "\n"         "\n    for (var i in list) {"         "\n        if (isInNet(ip, list[i][0], list[i][1])) {"         "\n            return 'DIRECT';"         "\n        }"         "\n    }"         "\n"         "\n    return '%s';"         "\n"         "\n}"         "\n"%(proxy)     )     rfile.write(strLines)     rfile.close()     print ("Rules: %d items.\n"            "Usage: Use the newly created %s as your web browser's automatic "            "proxy configuration (.pac) file."%(intLines, pacfile))  def fetch_ip_data():     #fetch data from apnic     print "Fetching data from apnic.net, it might take a few minutes, please wait..."     url=r'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest'     data=urllib2.urlopen(url).read()      cnregex=re.compile(r'apnic\|cn\|ipv4\|[0-9\.]+\|[0-9]+\|[0-9]+\|a.*',re.IGNORECASE)     cndata=cnregex.findall(data)      results=[]      for item in cndata:         unit_items=item.split('|')         starting_ip=unit_items[3]         num_ip=int(unit_items[4])          imask=0xffffffff^(num_ip-1)         #convert to string         imask=hex(imask)[2:]         mask=[0]*4         mask[0]=imask[0:2]         mask[1]=imask[2:4]         mask[2]=imask[4:6]         mask[3]=imask[6:8]          #convert str to int         mask=[ int(i,16 ) for i in mask]         mask="%d.%d.%d.%d"%tuple(mask)          #mask in *nix format         mask2=32-int(math.log(num_ip,2))          results.append((starting_ip,mask,mask2))      return results  if __name__=='__main__':     parser=argparse.ArgumentParser(description="Generate proxy auto-config rules.")     parser.add_argument('-x', '--proxy',                         dest = 'proxy',                         default = 'SOCKS 127.0.0.1:8964',                         nargs = '?',                         help = "Proxy Server, examples: "                                "SOCKS 127.0.0.1:8964; "                                "SOCKS5 127.0.0.1:8964; "                                "PROXY 127.0.0.1:8964")      args = parser.parse_args()      generate_pac(args.proxy)

我想,应该过不了多久就要解放了。期待着有那么一天:我们能一起呼吸自由的空气,我们不再需要折腾各种翻墙玩意。那时,生活应该会更美好一些吧。


发表评论