用 Flora_Pac.py 生成自动翻墙的 pac 文件
源于人们对自由的向往,翻墙技术已渐趋成熟。愿意花点钱,购买海外 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)
我想,应该过不了多久就要解放了。期待着有那么一天:我们能一起呼吸自由的空气,我们不再需要折腾各种翻墙玩意。那时,生活应该会更美好一些吧。