一、簡介
代理服務器大多被用來連接 INTERNET (國際互聯網)和 INTRANET(企業內部網)。在多個局域網中需設置不同的代理服務器參數來使浏覽器訪問網絡。在微軟 Internet Explorer ( IE )5.0 以上版本中的功能中已經具備了自動切換代理服務器的功能。網絡管理員需要事先部署代理服務器配置文件,然而用戶方的設置卻很簡單。在這一功能中使用了被稱為“WPAD”(Web Proxy Auto-Discovery protocol)的協議。
網絡代理自發現協議(Web Proxy Auto-Discovery Protocol,WPAD),通過讓浏覽器自動發現代理服務器,使代理服務器對用戶來說是透明的,進而輕松訪問互聯網。
參考:http://www.ibm.com/developerworks/cn/linux/1309_quwei_wpad/
二、實現
WPAD實現源碼
/************************************************************************* * * wpad.cpp * * CREATE ON: 2013-03-14 * BY : Wayne Qu ([email protected]) * * 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:7E 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 = 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); }