WPAD 的原理及实现
WPAD 通过让浏览器自动发现代理服务器,使代理服务器对用户来说是透明的,进而轻松访问互联网。WPAD 可以借助 DNS 服务器或 DHCP 服务器来查询代理自动配置(PAC)文件的位置。
引言
代理服务器大多被用来连接 INTERNET (国际互联网)和 INTRANET(企业内部网)。在多个局域网中需设置不同的代理服务器参数来使浏览器访问网络。在微软 Internet Explorer ( IE )5.0 以上版本中的功能中已经具备了自动切换代理服务器的功能。网络管理员需要事先部署代理服务器配置文件,然而用户方的设置却很简单。在这一功能中使用了被称为“WPAD”(Web Proxy Auto-Discovery protocol)的协议。
浏览器原本具有读入并解析代理服务器的配置文件,并将其配置信息设置到浏览器中的功能。配置文件是使用 Java Script 描述的,通常具有“.js”,“.jvs”,“.pac”(proxy auto-configuration)等扩展名的文件。
自动代理检测由系统确定,Web 代理服务器代表客户端发送请求。自动代理检测启用时,系统会尝试定位到代理发送请求后返回的代理配置文件位置。若查找到代理配置文件,那么在使用 Web 代理服务器实例得到代理信息、数据请求或响应信息时,在本地计算机上进行下载,编译并运行。
被部署的大多数配置文件的格式是 Proxy auto-config (PAC)。最初,PAC 是由 Netscape 在 1996 年为 Netscape Navigator 2.0 设计的。WPAD 协议草案由 Inktomi、微软、RealNetworks、Sun Microsystems 几个公司共同提出。WPAD 可支持所有主流浏览器,首次存在于 Internet Explorer 5.0 中。
WPAD 对代理服务器的透明处理使得管理员不再需要去每台客户机上设置代理服务器参数了。自动检测受动态主机配置协议 (DHCP) 和域名系统 (DNS) 的支持,浏览器通过 DHCP 和 DNS 的查询来搜索 PAC 文件的位置。
Proxy Auto-Config(PAC)文件
在开始介绍 WPAD 原理之前,有必要首先对代理自动配置(PAC)文件有一个概念上的认识。代理自动配置(PAC)文件定义了浏览器和其他用户代理如何自动选择适当的代理服务器来访问一个 URL。要使用 PAC,我们应当在一个网页服务器上发布一个 PAC 文件,并且通过在浏览器的代理链接设置页面输入这个 PAC 文件的 URL 或者通过使用 WPAD 协议告知用户代理去使用这个文件。
一个 PAC 文件是一个至少定义了一个 JavaScript 函数的文本文件。该函数 FindProxyForURL(url, host)有 2 个参数:
url 是一个对象的 URL;
host 是一个由这个 URL 所衍生的主机名。
按照惯例,这个文件名字一般是 proxy.pac。 WPAD 标准使用 wpad.dat。一个非常简单的 PAC 文件内容如下:
function FindProxyForURL(url, host) {
if (url== 'http://www.baidu.com/') return 'DIRECT';
if (host== 'twitter.com') return 'SOCKS 127.0.0.10:7070';
if (dnsResolve(host) == '10.0.0.100') return 'PROXY 127.0.0.1:8086;DIRECT';
return 'DIRECT';
}
WPAD 的原理
DHCP 的自动检测
通过 DHCP 服务器,管理员可以集中指定全局 TCP/IP 参数和子网特定的 TCP/IP 参数,并可使用保留地址定义客户端的参数。如果客户端计算机在子网之间发生了移动,则在启动该计算机时,会自动重新配置 TCP/IP。
通过 DHCP 服务器部署 WPAD 的原理如下。首先确保 DHCP 服务器有效,然后为每个包含客户的子网建立了作用域。DHCP 服务器中的 252 选项通常被当作查询或注册用的指针,我们可以通过 252 项发现打印机、时间服务器、WPAD 主机以及其他的网络服务器。在 DHCP 服务器中添加一个用于查找 WPAD 主机的 252 项,252 项是一个字符串值,内容是部署在 WPAD 主机上 PAC 文件的 URL。为适当的作用域配置 252 项,就算只有一个作用域。具体部署 DHCP 服务器的操作,请见参考文献:ISA 防火墙之利用 DHCP 部署 WPAD。
因此 DHCP 客户机便可获得 PAC 文件的 URL,当客户机需要对浏览器或防火墙客户端进行自动配置时,就可以下载该 PAC 文件并得到代理服务器的地址。
图 1.DHCP 的自动检测示意图
在上图示意中,用户访问 laptop01.us.division.company.com 时,web 浏览器发送 DHCP INFORM 包于 DHCP 服务器来请求配置文件的位置,DHCP ACK 为 DHCP 服务器返回的数据包,其中 252 选项即为代理自动配置文件的位置。DHCP 报文格式如下图:
图 2.DHCP 报文格式
OP:消息操作代码,既可以是引导请求(1=BOOTREQUEST)也可以是引导答复(2=BOOTREPLY);
Htype:硬件地址类别,ethernet 为 1;
Hlen:硬件地址长度,ethernet 为 6;
Hops:若数据包需经过 router 传送,每站加 1,若在同一网内,为 0;
Transaction ID:事务 ID,是个随机数,用于客户和服务器之间匹配请求和相应消息;
Seconds:由用户指定的时间,指开始地址获取和更新进行后的时间;
Flags:从 0-15bits,最左一 bit 为 1 时表示 server 将以广播方式传送封包给 client,其余尚未使用;
Ciaddr:用户 IP 地址;
Yiaddr:服务器分配给客户的 IP 地址;
Siaddr:用于 bootstrap 过程中的 IP 地址;(服务器的 IP 地址)
Giaddr:转发代理(网关)IP 地址;
Chaddr:客户机的硬件地址;
Sname:可选 server 的名称,以 0x00 结尾;
File:启动文件名;
Options:厂商标识,可选的参数字段。此参数是 WPAD 实现过程中的关键参数,即相关了 PAC 文件的 URL。
DNS 的自动检测
DNS 是 TCP/IP 网络上的一组协议和服务,通过 DNS,用户可以使用分层的用户友好名称(主机)代替数字 IP 地址来搜索其他计算机。
用 DNS 来实现 WPAD,原理如下:
WPAD 工作原理是客户机向 DNS 服务器发起 WPAD+X 的查询。DNS 返回提供 WPAD 主机 IP 地址,客户机通过该 IP 的 80 端口去 WPAD 主机下载 WPAD.DAT(浏览器配置用文件)和 WSPAD.DAT(防火墙配置用文件)两个文件以实现自动配置。
客户机向 DNS 发起的 WPAD 查询的后缀是根据 WPAD 主机所处的环境决定的,如果客户机是在一个域环境下时,发起的查询便是一个“WPAD.所在域的域名”的标准域名查询,这种情况下配合 DNS 里添加 WPAD 主机的 A 或别名记录便可轻松在域环境中对 WPAD 主机的定位。
但是如果在工作组环境下时,客户机发起的查询可能是一个标准的域名查询(如果计算机名有加域名后缀)也可能只是个没有后缀的 WPAD 查询,这时就要通过创建 DNS 私有根域查询或是通过创建单标签域的方式进行 WPAD 主机查询。
从以上的原理分析,首先 WPAD 主机要在 80 端口提供 wpad.dat 和 wspad.dat,有了这两个文件,客户机上的浏览器或防火墙客户端才能实现自动配置。其次,DNS 服务器要创建相关记录,当客户机来查询时,将解析结果指向 WPAD 主机。
关于 DNS 的自动检测详细的分析,可以参考文献 工作组环境下 WPAD 部署的另类解决 。
图 3.DNS 的自动检测示意图
WPAD 的实现
通过 DNS 服务器部署 WPAD 在域的环境下比较适宜,但在工作组环境下就需要做一些改变。通过 DHCP 服务器部署 WPAD 还是更加方便,既不限制端口,又不受客户机计算机名影响,无论是工作组还是域都能很好地工作。
以下具体讨论了利用 DHCP 服务器来实现 WPAD 的 C++实例,并已通过 gcc 编译。此实例模拟了浏览器使用 DHCP 服务器实现 WPAD 的过程。同时希望能给有需要的开发人员一些关于如何实现 WPAD 的参考。
由上述通过 DHCP 服务器部署 WPAD 的原理,实现分为两大步骤,即向 DHCP 服务器发送 DHCP INFORM 包和接收 DHCP 服务器返回的 DHCP ACK 包,并解析。首先使用 Socket 实现广播(broadcast)的发送和接收来查找 WPAD 主机。广播是指在一个局域网中向所有的网上节点发送信息,是 UDP 协议的一种。在局域网中,广播 DHCP INFORM 包,当 DHCP 服务器接收到广播信息后,返回 DHCP ACK 包于客户机(本机),报文中的 252 选项即为查找的存储在 WPAD 主机上 PAC 文件的 URL。详细如下:
步骤一.查找 DHCP 服务器
- 在 WPAD 实现过程中,DHCP 报文为主要的数据结构,dhcp_send 代表 DHCP INFORM 包,dhcp_recv 代表 DHCP 服务器返回的 DHCP ACK 包。
清单 1.DHCP 报文结构
typedef struct dhcp_message_ {
uint8_t op; /* message type */
uint8_t hwtype; /* hardware address type */
uint8_t hwlen; /* hardware address length */
uint8_t hwopcount; /* should be zero in client message */
uint32_t xid; /* transaction id */
uint16_t secs; /* elapsed time in sec. from boot */
uint16_t flags;
uint32_t ciaddr; /* (previously allocated) client IP */
uint32_t yiaddr; /* 'your' client IP address */
uint32_t siaddr; /* should be zero in client's messages */
uint32_t giaddr; /* should be zero in client's messages */
uint8_t chaddr[DHCP_CHADDR_LEN]; /* client's hardware address */
uint8_t servername[SERVERNAME_LEN]; /* server host name */
uint8_t bootfile[BOOTFILE_LEN]; /* boot file name */
uint32_t cookie;
uint8_t options[DHCP_OPTION_LEN]; /* message options - cookie */
}dhcp_message; - 广播的实现首先创建 UDP 的 socket,将发送端口 socket 设置为广播类型,开启发送广播报文:
清单 2.设置发送端口 socket 的属性为广播
int bBroadcast=; setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &bBroadcast, sizeof(bBroadcast));
- 接收端口绑定地址和这组广播的端口号(DHCP 统一使用两个 IANA 分配的端口作为 BOOTP : 服务器端 使用 67/udp, 客户端 使用 68/udp),接受广播信息:
清单 3.绑定端口号
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(DHCP_CLIENT_PORT);//DHCP_CLIENT_PORT=68
addr.sin_addr.s_addr = inet_addr("10.0.2.15");//local IP
bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)); - 将本机的 IP 地址和 MAC 地址等数据封装成 DHCP INFORM 报文,定义为 dhcp_send:
清单 4.封装 DHCP 报文
void make_message(const std::string& ip_addr, const std::string& mac_addr, dhcp_message **message)
{
dhcp_message* dhcp;
dhcp = (dhcp_message*)xzalloc(sizeof (*dhcp));
bzero(dhcp, sizeof(dhcp_message));
dhcp->op = ;
dhcp->hwtype = ; //ARPHRD_ETHER
dhcp->hwlen = ; //MAC ADDR LENGTH
dhcp->xid = ; //random
dhcp->ciaddr = GetCiaddr(ip_addr);
GetChaddr(mac_addr, dhcp->chaddr);
dhcp->cookie = htonl(MAGIC_COOKIE);
uint8_t *p = dhcp->options;
//option 53
*p++ = DHO_MESSAGETYPE;
*p++ = ;
*p++ = DHCP_INFORM;
//option 55
*p++ = DHO_PARAMETERREQUESTLIST;
*p++ = ;
*p++ = DHO_PACFILELOCATION;
*p++ = DHO_END;
*message = dhcp;
} - 广播 DHCP INFORM 报文
清单 5.发送端口发送 DHCP INFORM 广播报文:
struct sockaddr_in sin;
bzero(&sin, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr=inet_addr("255.255.255.255"); //Broadcast Address
sin.sin_port = htons(DHCP_SERVER_PORT);//DHCP_server_PORT=67
sendto(send_socket_fd, (uint8_t *)dhcp_send,sizeof(*dhcp_send) ,\
(struct sockaddr *)&sin,sizeof(sin));
步骤二.接收 DHCP 服务器返回的 DHCP ACK 包,并解析,报文中的 252 项即为查找的存储在 WPAD 主机上 PAC 文件的 URL:
清单 6.将接收端口设置超时选项并接收消息:
struct timeval tv_out;
tv_out.tv_sec = ;
tv_out.tv_usec = ;
setsockopt(recv_socket_fd,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out));
recvfrom(recv_socket_fd, (uint8_t *)dhcp_recv, sizeof(*dhcp_recv), ,\
(struct sockaddr*)&addr,(socklen_t*)&addr_len);
清单 7.解析 DHCP ACK 包
std::string AutoProxyDiscovery::dhcp_parser(uint8_t* options)
{
uint8_t* p = options;
int len;
std::string url;
while( (p-options) < DHCP_OPTION_LEN )
{
if( == *p )
{
++p;
len = *p++;
for( int i=; i<len; ++i,++p)
{
url.push_back(*p);
}
break;
}
else if( == *p )
{
break;
}
else
{
++p;
len = *p++;
p+=len;
}
}
return url;
}
步骤三.找到返回的 URL 下/data/wpad.dat 代理配置文件,在本地计算机上下载,编译并运行。即完成了 DHCP 的自动检测。
总结
之前的浏览器通常使用手动代理配置和代理自动配置等,而 WPAD 协议的出现更高级别地实现了自动化。使用 DHCP 来实现 WPAD 的思想较简单,是较好的解决方案。
WPAD 的原理及实现的更多相关文章
- 基于USB网卡适配器劫持DHCP Server嗅探Windows NTLM Hash密码
catalogue . DHCP.WPAD工作过程 . python Responder . USB host/client adapter(USB Armory): 包含DHCP Server . ...
- Potato土豆win综合提权
0x01 NBNS和WDAP NBNS: 在 Windows 系统中的另外一种名称就是 NetBIOS 名称,准确的说 NetBIOS 名称并非是一种名字系统,而是 Windows 操作系统网络的一个 ...
- DHCP的若干原理解释
转自:http://blog.chinaunix.net/uid-22287947-id-1775641.html 搜罗了几种关于dhcp的原理和过程解释 DHCP(Dynamic Host Conf ...
- HTTP 代理原理及实现
本文转载自 https://imququ.com/post/web-proxy.html HTTP 代理原理及实现(一) 文章目录 普通代理 隧道代理 Web 代理是一种存在于网络中间的实体,提供各式 ...
- HTTPS中间人攻击实践(原理·实践)
前言 很早以前看过HTTPS的介绍,并了解过TLS的相关细节,也相信使用HTTPS是相对安全可靠的.直到前段时间在验证https代理通道连接时,搭建了MITM环境,才发现事实并不是我想的那样.由于 ...
- 在内网环境使用WPAD/PAC和JS攻击win10
转:https://mp.weixin.qq.com/s/qoEZE8lBbFZikKzRTwgdsw 在内网环境使用WPAD/PAC和JS攻击win10 2018-03-01 wangrin 看雪学 ...
- 奇异值分解(SVD)原理与在降维中的应用
奇异值分解(Singular Value Decomposition,以下简称SVD)是在机器学习领域广泛应用的算法,它不光可以用于降维算法中的特征分解,还可以用于推荐系统,以及自然语言处理等领域.是 ...
- node.js学习(三)简单的node程序&&模块简单使用&&commonJS规范&&深入理解模块原理
一.一个简单的node程序 1.新建一个txt文件 2.修改后缀 修改之后会弹出这个,点击"是" 3.运行test.js 源文件 使用node.js运行之后的. 如果该路径下没有该 ...
- 线性判别分析LDA原理总结
在主成分分析(PCA)原理总结中,我们对降维算法PCA做了总结.这里我们就对另外一种经典的降维方法线性判别分析(Linear Discriminant Analysis, 以下简称LDA)做一个总结. ...
随机推荐
- Android 手动显示和隐藏软键盘
1.方法一(如果输入法在窗口上已经显示,则隐藏,反之则显示) InputMethodManager imm = (InputMethodManager) getSystemService(Contex ...
- Java语言基础(七)
Java语言基础(七) 今天在公司多呆了会,回来晚了 一.自动类型转换 在Java中,数据是可以转换的 例如可以将byte类型的赋给int类型的 这里希望你了解内存的变化,例如 在这里,我想你应该知 ...
- IOS-tableView中的cellHeadView随着table滚动
IOS-tableView中的cellHeadView随着table滚动 设置table的style 首先要将table设置为UITableViewStyleGrouped类型.这样就会得到table ...
- 移动端 设置 小于12px 字体 初探
1.移动端字号规范 2. 百度字号调研 3. 绕过12px 限制 4. 缩放 5. chrome 字号
- at91sam9x5 linux 4.1.0下使能蜂鸣器驱动
测试环境: CPU: AT91SAM9X35 Linux: Atmel提供的linux-at91-linux4sam_5.3 (Linux-4.1.0) 转载请注明: 凌云物网智科嵌入式实 ...
- json、xml ---- 数据格式生成类
自己写的一个生成json/xml 格式数据的类,可用于api数据传输: <?php class Response{ /** *生成指定数据格式 *@param intval $code 状态码 ...
- SPFA 小优化*2
/* bzoj 2763 SPFA小优化 循环队列+SLF 顺面改掉自己之前手打qeueu的坏毛病*/ #include<iostream> #include<cstring> ...
- 美好头标ToolBar
ActionBar我相信是每一位合格的程序员都用过的组件,也是每一个程序员都会抱怨的组件,因为他不能实现复杂的自定义.为此Google推出了比ActionBar更为美好的组件ToolBar. 本文重点 ...
- java对象与xml相互转换 ---- xstream
XStream是一个Java对象和XML相互转换的工具,很好很强大.提供了所有的基础类型.数组.集合等类型直接转换的支持. XStream中的核心类就是XStream类,一般来说,熟悉这个类基本就够用 ...
- AppStore上架规则
1. 条款和条件1.1 为App Store开发程序,开发者必须遵守 Program License Agreement (PLA).人机交互指南(HIG)以及开发者和苹果签订的任何协议和合同.以下规 ...