How WPAD works and how it works
I. Introduction
Most proxy servers are used to connect to the INTERNET (International INTERNET) and INTRANET (Enterprise INTRANET ). Different Proxy Server parameters need to be set in multiple LAN to allow the browser to access the network. Functions in Microsoft Internet Explorer 5.0 or later versions already provide the function of automatically switching proxy servers. The network administrator needs to deploy the configuration file of the proxy server in advance, but the user's settings are very simple. This feature uses a protocol called "WPAD" (Web Proxy Auto-Discovery protocol.
Web Proxy Auto-Discovery Protocol (WPAD) allows the browser to automatically discover Proxy servers, making the Proxy server transparent to users, making it easy to access the Internet.
Reference: http://www.ibm.com/developerworks/cn/linux/1309_quwei_wpad/
II. Implementation
WPAD source code
/*************************************************************************** wpad.cpp** CREATE ON: 2013-03-14 * BY : Wayne Qu (qwquwei@cn.ibm.com)* * This demo is for Proxy auto defection(WPAD) feature development & UT. **************************************************************************/#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#include <stdlib.h>#include <strings.h>#include <iostream>#include <string>#include <algorithm>#include <sstream>#include <sys/select.h>/* Useful definitions */#define DHCP_SERVER_PORT 67#define DHCP_CLIENT_PORT 68#define MAGIC_COOKIE 0x63825363#define DHCP_INFORM 8/* Sizes for DHCP options */#define MTU_MAX 1500#define DHCP_CHADDR_LEN 16#define SERVERNAME_LEN 64#define BOOTFILE_LEN 128#define DHCP_UDP_LEN (14 + 20 + 8)#define DHCP_FIXED_LEN (DHCP_UDP_LEN + 226)#define DHCP_OPTION_LEN (MTU_MAX - DHCP_FIXED_LEN)/* DHCP options */enum DHO { DHO_MESSAGETYPE = 53, DHO_PARAMETERREQUESTLIST = 55, DHO_PACFILELOCATION = 252, DHO_END = 255};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;void * xzalloc(size_t s){ void *value = malloc(s); if (value != NULL) { bzero(value,s); } return value;}uint32_t GetIPV4Ciaddr(const std::string& ip_addr){ if( 3!=std::count(ip_addr.begin(), ip_addr.end(), '.') ) { std::cout << "invalid IP Format : " << ip_addr; return 0; } std::string::size_type beg = 0; std::string::size_type end = 0; std::string tmp_str[4]; uint32_t tmp_int[4]; for(int i=0; i<4; i++) { end = ip_addr.find(".", beg); tmp_str[i] = ip_addr.substr(beg,end-beg); tmp_int[i] = atoi(tmp_str[i].c_str()); if( tmp_int[i] > 255) { std::cout << "invalid IP Format : " << ip_addr; return 0; } //std::cout<< tmp_int[i] << " "; beg = end+1; } return (uint8_t)tmp_int[0] | ((uint8_t)tmp_int[1]<<8) | ((uint8_t)tmp_int[2]<<16) | ((uint8_t)tmp_int[3]<<24);}uint32_t GetCiaddr(const std::string& ip_addr){ //Just Ipv4 Now return GetIPV4Ciaddr(ip_addr);}uint32_t GetChaddr(const std::string& mac_addr, uint8_t* chaddr){ if( 5!=std::count(mac_addr.begin(), mac_addr.end(), ':') ) { std::cout << "invalid MAC Format : " << mac_addr; return 0; } std::string::size_type beg = 0; std::string::size_type end = 0; std::string tmp_str[6]; uint32_t tmp_int[6]; for(int i=0; i<6; i++) { end = mac_addr.find(":", beg); tmp_str[i] = mac_addr.substr(beg,end-beg); std::stringstream tmp_stream; tmp_stream << "0x" << tmp_str[i]; tmp_stream >> std::hex >> tmp_int[i]; if( tmp_int[i] > 255) { std::cout << "invalid MAC Format : " << mac_addr; return 0; } chaddr[i] = tmp_int[i]; //std::cout<< std::hex << (int)chaddr[i] << " "; beg = end+1; }}// Format: ipaddr - 9.125.90.117 macaddr E4:1F:13:DA:12:7Evoid 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 = 1; dhcp->hwtype = 1; //ARPHRD_ETHER dhcp->hwlen = 6; //MAC ADDR LENGTH dhcp->xid = 1983; //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++ = 1; *p++ = DHCP_INFORM; //option 55 *p++ = DHO_PARAMETERREQUESTLIST; *p++ = 1; *p++ = DHO_PACFILELOCATION; *p++ = DHO_END; *message = dhcp;}int open_send_socket(){ int sockfd; struct sockaddr_in addr; if((sockfd = socket(AF_INET,SOCK_DGRAM,0))<0) { //TBI } int bBroadcast=1; setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &bBroadcast, sizeof(bBroadcast)); return sockfd;}int open_recv_socket(char* ipaddr){ int sockfd; struct sockaddr_in addr; if((sockfd = socket(AF_INET,SOCK_DGRAM,0))<0) { std::cout << "setup socket failed" << std::endl;//TBI } bzero(&addr,sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(DHCP_CLIENT_PORT); addr.sin_addr.s_addr = inet_addr(ipaddr); const int retry_cnt = 10; int retry_num = retry_cnt; while(bind(sockfd, (struct sockaddr *)&addr, sizeof(addr))<0 && (retry_num > 0)) { std::cout << "bind to " << ipaddr << ":" << DHCP_CLIENT_PORT<< " failed!"<<std::endl;//TBI sleep(3); --retry_num; } return sockfd;}int send_packet(int udp_fd, const uint8_t *data, ssize_t len){ struct sockaddr_in sin; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr=inet_addr("255.255.255.255"); sin.sin_port = htons(DHCP_SERVER_PORT); return sendto(udp_fd, data, len, 0, (struct sockaddr *)&sin, sizeof(sin));}std::string dhcp_parser(uint8_t* options){ uint8_t* p = options; int len; std::string url; while( (p-options) < DHCP_OPTION_LEN ) { if( 252 == *p ) { ++p; len = *p++; for( int i=0; i<len; ++i,++p) { url.push_back(*p); } std::cout << "find option 252 with length " << url.size() << std::endl; break; } else if( 255 == *p ) { break; } else { ++p; len = *p++; p+=len; } } return url;}int readable_timeo(int sock_fd, int sec){ struct timeval tv_out; tv_out.tv_sec = sec; tv_out.tv_usec = 0; setsockopt(sock_fd,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out));}int main(int argc, char **argv){ dhcp_message *dhcp_send; dhcp_message *dhcp_recv; struct in_addr to; struct timeval tv; int send_socket_fd = open_send_socket(); int recv_socket_fd = open_recv_socket("9.125.90.177"); std::cout << "making DHCP message" << std::endl; make_message("9.125.90.177", "E4:1F:13:DA:12:7E", &dhcp_send); dhcp_recv = (dhcp_message*)xzalloc(sizeof (*dhcp_recv)); for(int i=0; i<3; ++i) { std::cout << "sending DHCP message" << std::endl; if( -1 == send_packet(send_socket_fd, (uint8_t *)dhcp_send, sizeof(*dhcp_send))) { std::cout << "sendto() error" << std::endl; continue; } struct sockaddr_in addr; bzero(&addr, sizeof(addr)); int addr_len =sizeof(struct sockaddr_in); std::cout << "receiving DHCP message" << std::endl; readable_timeo(recv_socket_fd, 6); if( -1 == recvfrom(recv_socket_fd, (uint8_t *)dhcp_recv, sizeof(*dhcp_recv), 0, (struct sockaddr*)&addr,(socklen_t*)&addr_len)) { std::cout << "recvfrom() error" << std::endl; continue; } break; }/* for(int i=0;i<100;i++) { std::cout << std::hex << int(dhcp_recv->options[i]) << " "; }*/ std::cout << "dhcp->xid = " << dhcp_recv->xid << std::endl; std::cout << "wpad url = " << dhcp_parser(dhcp_recv->options) << std::endl; close(send_socket_fd); close(recv_socket_fd);}