how to write and test proxy pac file - downgoon/hello-world GitHub Wiki
在公司访问外网,必须走企业网关,否则出不去(但是22号端口可以出去,因为能直接SSH访问云主机)。 在家,自然是直接访问,无需网关。 但是无论在家,还是在公司,要访问 google.com 都必须翻墙。
要求:
- 在公司,在家都能访问国内外网站。
- 在公司和在家用同一个PAC文件,不要两个文件切来切去。
总结下网路访问策略链路:
序号 | 目标网站 | 环境 | 网路 |
---|---|---|---|
1 | 公司内网主机 | 在家 | X(拨公司VPN) |
2 | 国内网站(比如百度) | 在家 | 直接访问 |
3 | 国外网站(比如Google) | 在家 | 私人网关 |
4 | 公司内网主机 | 在公司 | 直接访问 |
5 | 国内网站(比如百度) | 在公司 | 公司网关或私人网关 |
6 | 国外网站(比如Google) | 在公司 | 私人网关 |
备注
-
对于第5项,既可以走公司网关,又可以走私人网关。如果访问百度,先私人网关到美国节点,再从美国访问国内百度,绕路了,而且浪费私人网关的流量。
-
在公司环境时,私人网关必须是22号端口的,否则第一条就出不去。
脚本正常工作的前提是:
家里的网络IP地址是以“192.168.X.X”开头的;而公司的网络IP地址不是“192.168.X.X”开头的,比如可以是“10.X.X.X”。
/*
REFER: http://findproxyforurl.com/pac-functions/
*/
function FindProxyForURL(url, host) {
///////////////////////////////////////////////////////////////
//// Section 1: GLOBAL CONFIG
///////////////////////////////////////////////////////////////
// gateway settings
COMPANY_GATEWAY = "PROXY 10.199.45.38:8080";
OVERSEA_GATEWAY = "PROXY 12.45.55.67:22";
// direct acess for company hosts
COMPANY_HOSTS=[
"mycompany.net"
];
// outside gateway access for oversea hosts
OVERSEA_HOSTS=[
"google.com"
,"github.com","github.io","githubusercontent.com"
,"facebook.com"
];
///////////////////////////////////////////////////////////////
//// Section 2: Gateway Routing Logic
///////////////////////////////////////////////////////////////
host = host.toLowerCase();
/*
PRECONDITION REQUIRED:
my ip address in home always begins with '192.168.1.X',
while '10.X.X.X' in company.
*/
var isHome = isInNet(myIpAddress(), "192.168.1.0", "255.255.255.0" );
if (isHome) { // in home
return isInSet(host, OVERSEA_HOSTS) ? OVERSEA_GATEWAY : "DIRECT";
}
// in company
if (isInSet(host, COMPANY_HOSTS)) {
return "DIRECT";
}
if (isInSet(host, OVERSEA_HOSTS)) {
return OVERSEA_GATEWAY;
}
return COMPANY_GATEWAY;
}
///////////////////////////////////////////////////////////////
//// Section 3: User Defined Function
///////////////////////////////////////////////////////////////
/*
Hash Search
@param host: the host of url
@param set: domain string array, such as ["example.com", "helloworld.org"]
*/
function isInSet(host, set) {
return isInSetHash(host, set); // isInSetLoop(host, set)
}
function isInSetHash(host, set) {
var domain = getDomain(host);
return set.indexOf(domain) != -1;
}
/*
return 'example.com' if given host assigned to 'sub.example.com'
*/
function getDomain(host) {
var blocks = host.split(".");
if (blocks.length < 3) {
return host;
} else {
return blocks[blocks.length - 2] + "." + blocks[blocks.length - 1];
}
}
/*
another implementation: sequential search
@Depraved
*/
function isInSetLoop(host, set) {
for(i = 0; i < set.length; i++){
if( dnsDomainIs(host, set[i] ) ) {
return true;
}
}
return false;
}
简单解释下,以上脚本有四个配置项:
- COMPANY_GATEWAY: 表示企业网关(公司内部的代理服务器地址)。
- OVERSEA_GATEWAY: 访问国外网站需要的网关地址。
- COMPANY_HOSTS: 公司内网域名列表。
- OVERSEA_HOSTS: 外国网站列表。
PAC文件本质是Javascript代码,但是写完放入浏览器运行,即使错误了,也没有提示。如何调试PAC呢?
有开源项目: https://github.com/pacparser/pacparser
安装文档:https://github.com/pacparser/pacparser/blob/master/INSTALL
官方提供了C的安装和Python的安装,我们这里选Python:
$ git clone https://github.com/pacparser/pacparser
$ make -C src pymod
$ sudo make -C src install-pymod
pacparser python module:
------------------------------------------------
To compile and install pacparser python module:
=> make -C src pymod
=> sudo make -C src install-pymod
官方提供的是SDK,可以写python代码,比如:
$ python
>>> import pacparser
>>> pacparser.init()
>>> pacparser.parse_pac('examples/wpad.dat')
>>> pacparser.find_proxy('http://www.google.com', 'www.google.com')
'DIRECT'
>>> pacparser.setmyip("192.168.1.134")
>>> pacparser.find_proxy('http://www.google.com', 'www.google.com')
'PROXY proxy1.manugarg.com:3128; PROXY proxy2.manugarg.com:3128; DIRECT'
>>> pacparser.find_proxy('http://www2.manugarg.com', 'www2.manugarg.com')
'DIRECT'
>>> pacparser.cleanup()
>>>
我们期望的命令行:
$ python pactest.py -p /path/to/your/proxy.pac -u http://www.baidu.com/path/to/file.html
DIRECT
$ python pactest.py -p /path/to/your/proxy.pac -u http://google.com/path/to/file.html
12.4.12.67:8080
$ python pactest.py -p /path/to/your/proxy.pac -u http://www.baidu.com/path/to/file.html -i 192.168.1.102
DIRECT
$ python pactest.py -p /path/to/your/proxy.pac -u http://www.baidu.com/path/to/file.html -i 10.10.1.3
10.10.1.100:8080
pactest.py 代码如下:
import sys, getopt, pacparser, urllib
opts, args = getopt.getopt(sys.argv[1:], "hp:u:i:")
# opts, args = getopt.getopt(sys.argv[1:], "hp:u:i")
proxy=""
url=""
myip="192.168.1.102"
for op, value in opts:
if op == "-p":
proxy = value
elif op == "-u":
url = value
elif op == "-i":
myip = value
# if (proxy == "" or url == ""):
# print "python pactest.py <-p pac_file> <-u url> [-i myip]"
print "---"
print "pac file: " + proxy
print "url: " + url
print "myip: " + myip
print "---"
pacparser.init()
pacparser.parse_pac(proxy)
pacparser.setmyip(myip)
# get host of url
protocol, s1 = urllib.splittype(url)
host, s2= urllib.splithost(s1)
host, port = urllib.splitport(host)
# call find_proxy and return gateway
print "Routing: " + pacparser.find_proxy(url, host)
提醒
proxy.pac
与 pactest.py
两个重要文件。
访问google需注意,google会重定向到国家后缀域名。
比如 google.co.th
, google.co.xx
,这样 pac 文件如果以域名判断,google.com 就不会走代理。
但是 google 提供了人为指定不要走国别域名的方式: https://google.com/ncr
其中: ncr = no country router