返回列表

PAC脚本编写

默认分类 2017/04/11 02:51

自动代理脚本的函数说明与应用

1、 什么是代理脚本(PAC) 一个PAC文件其实就是一个文本文件, 最简单的格式就是包含一个叫FindProxyForURL的 JScript函数, IE通过传入两个变量来调用这个函数, 一个是用户浏览的地址URL全路经, 一个是这个URL中的主机名部分(host)。 这个FindProxyForURL函数有三种可能的字符串 返回值,

一、 是 "DIRECT",
就是直接连接, 不通过代理;
二、 是 "PROXY proxyaddr:port",
其中proxyaddr和port分别是代理的地址和代理的端口;
三、 是 "SOCKS socksaddr:port",
其中socksaddr和port分别是socks代理的地址和端口,

一个自动代理文件可以是多个选择的组合, 其中用分号(;) 隔开, 如:

function FindProxyForURL(url, host) {
  if (host == "www.mydomain.com")
    return "DIRECT";
  return "PROXY myproxy:80";
  PROXY myotherproxy: 8080;
  DIRECT "";
}

2、 下面是代理脚本可能用到的函数和说明:

PAC Helper Functions

dnsDomainIs(host, domain)              Returns true if the host is part of the
                                       specified domain, false otherwise.

isInNet(hostname,                      Resolves the hostname and subnet IP,
                                       subnet mask) returns true if the
                                       hostname is within the subnet specified
                                       by the IP address and the subnet mask,
                                       false otherwise.

isPlainHostName(host)                  Returns true if there are no dots in the
                                       hostname, false otherwise.

isResolvable(host)                     Internet Explorer tries to resolve the
                                       hostname through DNS and returns true if
                                       successful, false otherwise.

localHostOrDomainIs                    Returns true if the host matches (host,
                                       domain) the host portion of the domain,
                                       or if the host matches the host and
                                       domain portions of the domain, false
                                       otherwise. (Executed only for URLs in
                                       the local domain.)

dnsDomainLevels(host)                  Returns the number of dots in the
                                       hostname.

dnsResolve(host)                       Returns a string containing the IP
                                       address of the specified host.

myIPAddress( )                         Returns a string containing the local
                                       machine’s IP address.

shExpMatch(url, shexp)                 Returns true if the supplied URL matches
                                       the specified shell expression, false
                                       otherwise. 

dateRange(parmList)                    Returns true if the current date falls
                                       within the dates specified in parmList,
                                       false otherwise. 

timeRange(parmList)                    Returns true if the current time falls
                                       within the times specified in parmList,
                                       false otherwise. 

weekdayRange(parmList)                 Returns true if today is within the days
                                       of the week specified in parmList, false
                                       otherwise. 

3、 下面是各个函数应用的例子:

a、 isPlainHostName(host), 本例演示判断是否为本地主机, 如http: //myservername/的方式访问,如果是直接连接,否则使用代理

function FindProxyForURL(url, host) {
  if (isPlainHostName(host))
    return "DIRECT";
  else
    return "PROXY proxy:80";
}

b、 dnsDomainIs(host, "")、 localHostOrDomainIs(host, ""), 本例演示判断访问主机是否属于某个域和某个域名, 如果属于.company.com域的主机名, 而域名不是www.company.com和home.company.com的直接连接, 否则使用代理访问。

function FindProxyForURL(url, host) {
  if ((isPlainHostName(host) ||
      dnsDomainIs(host, ".company.com")) &&
    !localHostOrDomainIs(host, "www.company.com") &&
    !localHostOrDomainIs(host, "home.company.com"))
    return "DIRECT";
  else
    return "PROXY proxy:80";
}

c、 isResolvable(host), 本例演示主机名能否被dns服务器解析, 如果能直接访问, 否则就通过代理访问。

function FindProxyForURL(url, host) {
  if (isResolvable(host))
    return "DIRECT";
  else
    return "PROXY proxy:80";
}

d、 isInNet(host, "", ""), 本例演示访问IP是否在某个子网内, 如果是就直接访问,否则就通过代理, 例子演示访问清华IP段的主页不用代理。

function FindProxyForURL(url, host) {
  if (isInNet(host, "166.111.0.0", "255.255.0.0"))
    return "DIRECT";
  else
    return "PROXY proxy:80";
}

e、 shExpMatch(host, ""), 本例演示根据主机域名来改变连接类型, 本地主机、 *.edu、 *.com分别用不同的连接方式。

function FindProxyForURL(url, host) {
  if (isPlainHostName(host))
    return "DIRECT";
  else if (shExpMatch(host, "*.com"))
    return "PROXY comproxy:80";
  else if (shExpMatch(host, "*.edu"))
    return "PROXY eduproxy:80";
  else
    return "PROXY proxy:80";
}

f、 url.substring(), 本例演示根据不同的协议来选择不同的代理, http、 https、 ftp、gopher分别使用不同的代理。

function FindProxyForURL(url, host) {
  if (url.substring(0, 5) == "http:") {
    return "PROXY proxy:80";
  } else if (url.substring(0, 4) == "ftp:") {
    return "PROXY fproxy:80";
  } else if (url.substring(0, 7) == "gopher:") {
    return "PROXY gproxy";
  } else if (url.substring(0, 6) == "https:") {
    return "PROXY secproxy:8080";
  } else {
    return "DIRECT";
  }
}

g、 dnsResolve(host), 本例演示判断访问主机是否某个IP, 如果是就使用代理, 否则直接连接。

function FindProxyForURL(url, host) {
  if (dnsResolve(host) == "166.111.8.237") {
    return "PROXY secproxy:8080";
  } else {
    return "PROXY proxy:80";
  }
}

h、 myIpAddress(), 本例演示判断本地IP是否某个IP, 如果是就使用代理, 否则直接使用连接。

function FindProxyForURL(url, host) {
  if (myIpAddress() == "166.111.8.238") {
    return "PROXY proxy:80";
  } else {
    return "DIRECT";
  }
}

i、 dnsDomainLevels(host), 本例演示访问主机的域名级数是几级, 就是域名有几个点 如果域名中有点, 就通过代理访问, 否则直接连接。

function FindProxyForURL(url, host) {
  if (dnsDomainLevels(host) > 0) { // if number of dots in host > 0
    return "PROXY proxy:80";
  }
  return "DIRECT";
}

j、 weekdayRange(), 本例演示当前日期的范围来改变使用代理, 如果是GMT时间周三到周六, 使用代理连接, 否则直接连接。

function FindProxyForURL(url, host) {
  if (weekdayRange("WED", "SAT", "GMT"))
    return "PROXY proxy:80";
  else
    return "DIRECT";
}

k、 最后一个例子是演示随机使用代理, 这样可以好好利用代理服务器。

function FindProxyForURL(url, host) {
  return randomProxy();
}

function randomProxy() {
  switch (Math.floor(Math.random() * 5)) {
    case 0:
      return "PROXY proxy1:80";
      break;
    case 1:
      return "PROXY proxy2:80";
      break;
    case 2:
      return "PROXY proxy3:80";
      break;
    case 3:
      return "PROXY proxy4:80";
      break;
    case 4:
      return "PROXY proxy5:80";
      break;
  }
}

利用上面的函数和例子说明, 大家就可以写出比较复杂有效的自动代理脚本。

参考:http://en.wikipedia.org/wiki/Proxy_auto-config#DnsResolve


本人所在单位启用了内部OA(办公自动化)系统,由于有许多部门并不在公司总部,不处于同一个局域网内,外围单位无法直接访问内网的OA服务器,影响了OA系统在总公司的推行。为了解决这一问题曾试图通过VPN来从互联网接入,但由于外围单位分别通过不同的ISP(Internet Service Provider)接入互联网的,导致VPN服务器配置的不一致,不能全面畅通接入,最终选择了使用代理服务器的接入方案。外围单位可以从互联网通过代理服务器访问内网的OA服务器。

外网用户在访问公司OA服务器时,就需要在IE浏览器中配置代理服务器,配置方法见图1。

图1 设置代理服务器

配置好IE后就可以访问内网OA服务器了。但这样一来,就存在一个问题,就是外网用户在访问OA时需要在IE中设置代理服务器,而在访问互联网时又需要取消这一配置,不使用代理服务器而直接访问。每次都需要手动配置,十分不便,对于“菜鸟”而言就更显得繁琐了。

如何让IE浏览器自动实现配置的转换呢?这就需要用到代理自动配置脚本(PAC-file:Proxy Auto-Config file) 了。自动配置脚本也就是PAC脚本,这是一种以.PAC为扩展名的JavaScript脚本,PAC脚本其实就是定义一个名为“FindProxyForURL”的Java Script函数,该函数会被浏览器自动调用,从而实现代理服务器的自动转换。

由于我们的代理是反向(由外向内)的,脚本的具体内容如下:

function findproxyforurl(host,url) {
  if (shexpmatch(host,"*.jigang.com.cn"))
    return "proxy 218.XXX.XXX.30:8080"
  else if (shexpmatch(host,"172.16.*.*"))
    return "proxy 218.XXX.XXX.30:8080"
  else
    return "direct"
}

这段脚本的含义就是:如果是访问内网OA的请求(域名为jigang.com.cn),则使用代理,如果访问内网的某些网址(IP地址为:172.16..),则使用代理,除此之外的所有请求则不使用代理而直接连接。

将上述脚本内容保存为一个扩展名为PAC的脚本文件,如C:proxy.pac。

然后我们设置IE浏览器把“自动配置脚本选项”指向它,完成集中设置代理配置的工作。我们只需一次性配置完毕,让IE自动识别是否使用代理服务器,而无需手动转换,从而实现访问内、外网站的自动转换。

IE的代理设置里面有一个“使用自动配置脚本”的选项,这里的具体设置如下:

自动配置脚本设置:打开浏览器,选择“工具/Internet选项/连接/局域网配置”,随后勾选“使用自动脚本配置”项,最后输入自动配置脚本所存在地址即可(比如file://C:proxy.pac,如图2)。

图2 设置本机自动配置脚本

当然我们也可以将这个脚本文件放在Wrb服务器上,这样不用为每台客户机都写一个PAC文件了,只需要在“使用自动配置脚本”的地址处填入相关的IP地址就行了。比如:http://218.XXX.XXX.30/proxy.pac。在IE中的设置见图3。

图3 设置网络自动配置脚本

这样做的好处是,我们可以随意修改代理脚本从而改变代理服务器的地址或端口等而不用去修改每台客户机的PAC文件了。