• WPAD 的原理及实现


    一、简介

    代理服务器大多被用来连接 INTERNET (国际互联网)和 INTRANET(企业内部网)。在多个局域网中需设置不同的代理服务器参数来使浏览器访问网络。在微软 Internet Explorer ( IE )5.0 以上版本中的功能中已经具备了自动切换代理服务器的功能。网络管理员需要事先部署代理服务器配置文件,然而用户方的设置却很简单。在这一功能中使用了被称为“WPAD”(Web Proxy Auto-Discovery protocol)的协议。

    网络代理自发现协议(Web Proxy Auto-Discovery Protocol,WPAD),通过让浏览器自动发现代理服务器,使代理服务器对用户来说是透明的,进而轻松访问互联网。

    二、实现

    WPAD实现源码

    /*************************************************************************
    *
    * 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: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);
    }
  • 相关阅读:
    第二周:If判断语句程序当中的作用简介
    普通B/S架构模式同步请求与AJAX异步请求区别(个人理解)
    第一周:Java基础知识总结(1)
    silverlight 碰撞检测
    超强silverlight绘图
    javascript 判断一个对象是否具有指定名称的属性
    关于IE的RegExp.exec
    浏览器 禁止选择
    silverlight 无限制坐标系统
    CSS Sprite样式生成器网页制作缺她不可
  • 原文地址:https://www.cnblogs.com/274914765qq/p/4729222.html
Copyright © 2020-2023  润新知