• DHCP分析


    一  DHCP简介

    DHCP是DynamicHostConfigurationProtocol之缩写﹐它的前身是BOOTP(用网络抓包软件过滤时,要输入bootp)。DHCP可以说是BOOTP的增强版本﹐它分为两个部份(C/S架构): 一个是服器端,而另一个是客户端。所有的IP网路设定资料都由DHCP伺服器集中管理﹐并负责处理客户端的DHCP要求﹔而客户端则会使用从伺服器分配下来的IP环境资料。比较起BOOTP,DHCP透过"租约"的概念,有效且动态的分配客户端的TCP/IP设定,而且,作为兼容考量,DHCP也完全照顾了BOOTPClient的需求。

    DHCP支持三种类型的地址分配:

    1. 自动分配方式:
    DHCP给主机指定一个永久的IP地址,一旦DHCP客户端第一次成功的从DHCP伺服器端租用到IP位址之后﹐就永远使用这个位址
    2. 动态分配方式:
    DHCP给主机指定一个有"时间限制(租约)"的IP地址,到时间(租约到期)或主机明确表示放弃这个地址(主机主动断开连接)时,这个地址可以被其他的主机使用,当然,客户端可以比其它主机更优先的延续(renew)租约,或是租用其它的IP位址
    3. 手工分配方式:
    主机的IP地址是由网络管理员指定的,它可以按照MAC地址来固定的分配IP位址﹐DHCP只是把指定的IP地址告诉主机,相当于将某个MAC和IP进行了静态绑定。
    除了分配IP之外﹐DHCP还可以帮客户端指定IP环境:
    1. gateway(默认网关)
    2. netmask(默认子网掩码)
    3. DNSServer(DNS服务器IP)
    4. WINSServer﹑等等项目
    DHCP有3个端口,其中:
    1. UDP67: DHCP Server服务端口
    2. UDP68: DHCP Client服务端口
    3. UDP546: 用于DHCPv6 Client,而不用于DHCPv4,是为DHCP failover服务,这是需要特别开启的服务,DHCP failover是用来做"双机热备"的。
    二 DHCP协议数据包格式
    DHCP报文结构
    1. 链路层头: 承载报文的链路层信息头,常见的有Ethernet_II格式、802.1Q格式、 IEEE802.3格式、令牌环链路层头格式等。
    2. IP头: 标准的IP协议头,IPV4中长度为20bytes,包括了SrcIp,DstIp等信息。
    3. UDP头: 8bytes,包括了SrcPort,DstPort,报文长度及UDP校验和等信息。
    4. DHCP报文:具体的DHCP报文内容。
    三 DHCP的作用

    在局域网中,用户电脑都需要IP地址才使用网络服务,但是客户并不都会配置IP地址,这时,可以在网络中部署一个DHCP服务器,用来给这些客户主机动态的分配IP。

    所有DHCP的客户端,在向DHCP服务器租用到地址后,会在DHCP服务器端留下租用信息,网络管理员可以根据这些分配信息统一管理这些客户。

    四 DHCP的工作流程

    根据这四个数据包来看,DHCP的工作流程如下图:

    DHCP流程

    第一步:
    DHCP客户端主动发起DHCP Discover包,用来寻找DHCP服务器,其中:

    • 源MAC是自己的MAC地址,目的MAC是FFFF.FFFF.FFFF的广播
    • 源IP是0.0.0.0(现在还没有IP,就用全0地址),目的IP是255.255.255.255的三层广播

    因为DHCP服务器在哪里还不知道,所以使用广播来寻找,广播会泛洪到整个网段中;

    第二步:
    DHCP服务器收到客户端发的DHCP Discover之后,会在自己的地址池中拿出一个没有分配的地址以及配套的参数(如:掩码、DNS、网关、域名、租期……),然后以一个DHCP Offer包发送出去。
    这个DHCP Offer数据包的地址如下:

    • 源MAC是DHCP服务器的MAC,目的MAC是FFFF.FFFF.FFFF的广播
    • 源IP是DHCP服务器的IP,目的IP是255.255.255.255的广播

    这时客户端还没有获得IP,DHCP服务器端现在还无法定位客户端,所以用广播来回应。

    这一步既可以是单播,也可以是广播。因为第一步服务器肯定知道了客户端MAC,知道MAC就可以只发个单波就可以(交换机MAC-端口表,这样就可以单波传送特定端口了)

    第三步:
    客户端收到这个DHCP Offer后,会再发出一个DHCP Request给服务器来申请这个Offer中包含的地址。
    这个时候,客户端还没有正式拿到地址,所以还需要向DHCP服务器申请。

    • 这时客户端的源IP还是0.0.0.0,目的IP还是255.255.255.255
    • 源MAC是客户端的MAC,目的MAC是FFFF.FFFF.FFFF广播包

    第四步:
    服务器收到客户端的请求后,会发出一个DHCP ACK用来确认这个IP地址可以分配给这个客户端。
    客户端收到第四个DHCP ACK数据包才算正式拿到了这个IP。

    五 LWIP中使用DHCP

    初始化IP,子网掩码,默认网关为0

    ipaddr.addr = 0;
    netmask.addr = 0;
    gw.addr = 0;

    创建DHCP任务

    void lwip_comm_dhcp_creat(void)
    {
        OS_CPU_SR cpu_sr;
        OS_ENTER_CRITICAL();  
        OSTaskCreate(lwip_dhcp_task,(void*)0,(OS_STK*)&LWIP_DHCP_TASK_STK[LWIP_DHCP_STK_SIZE-1],LWIP_DHCP_TASK_PRIO);
        OS_EXIT_CRITICAL();  
    }

    编写DHCP处理任务既lwip_dhcp_taskvoid lwip_dhcp_task(void *pdata{    u32 ip=0,netmask=0,gw=    dhcp_start(&lwip_netif);//开启DHCP 

        lwipdev.dhcpstatus=0;    //正在DHCP
        printf("正在查找DHCP服务器,请稍等...........\r\n");   
        while(1)
        { 
            printf("正在获取地址...\r\n");
            ip=lwip_netif.ip_addr.addr;        //读取新IP地址
            netmask=lwip_netif.netmask.addr;//读取子网掩码
            gw=lwip_netif.gw.addr;            //读取默认网关 
            if(ip!=0)                       //当正确读取到IP地址的时候
            {
                lwipdev.dhcpstatus=2;    //DHCP成功
                  /*打印获得的信息*/ 
           break;

    }
    else if(lwip_netif.dhcp->tries>LWIP_MAX_DHCP_TRIES) //通过DHCP服务获取IP地址失败,且超过最大尝试次数
            {  
                    //获得失败,做下一步处理      
                   break; 
             }  
            delay_ms(250); //延时250ms
        }
        lwip_comm_dhcp_delete();//删除DHCP任务  break后删除dhcp任务  并不是挂壁dchp功能
    }

    把LWIP_DHCP设置为1,即可使用LWIP的DHCP功能.

    以上代码主要的就一步:

    dhcp_start(&lwip_netif);//开启DHCP

    err_t dhcp_start(struct netif *netif)
    {
        ......
        //先检查是否已经存在DHCP客户端了,如果没有
        //则先创建,如果有,则重新利用
       /* set up local and remote port for the pcb */
          udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);
          udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);
        /* set up the recv callback and argument */
          udp_recv(dhcp->pcb, dhcp_recv, netif);
          /* (re)start the DHCP negotiation */
         result = dhcp_discover(netif);
         ......
    }

    在LWIP的DHCP中有个问题:有两个客户端同时向局域网发送DHCP请求,结果获取到的IP竟然是相同的。

    原因在于DHCP事务ID——xid。DHCP客户端生成一个随机数事务ID,并记录下来,然后把它插入到xid字段。客户端发送DHCP DISCOVER广播报文。服务器从DHCP DISCOVER消息解析得到xid值,把xid值插入到DHCP OFFER消息的xid字段,发送DHCP OFFER报文到请求客户端。如果DHCP OFFER消息中的xid值与最近发送DHCP DISCOVER消息中的xid值不同,那么客户端必须忽略这个DHCP OFFER。接收到的任何DHCPACK必须悄悄地丢弃。

    而LWIP在默认设置DHCP事务ID为static u32_t xid = 0xABCD0000;而在每创建requset信息时,简单的使其加1。这样两个客户端发送送出去的 discover报文中的Transaction ID是相同的,并且当时的那个路由器是以广播包的方式发送offer报文和回应ack报文的。那么当我的两个客户端都收到这个广播包的时候,并且发现offer和ack报文中的Transaction ID和自己发出去的是一样的,那么就理所当然的认为这个IP是分配给自己的,所以导致两者的IP是一样的。所以,如果片子没有随机数发生器的话,就根据片子的ID弄一个数替代xid = 0xABCD0000吧。

    懒惰不会让你一下子跌到 但会在不知不觉中减少你的收获; 勤奋也不会让你一夜成功 但会在不知不觉中积累你的成果 越努力,越幸运。
  • 相关阅读:
    Tomcat5配置mysql
    Eclipse完全手册
    MBR是什么
    必杀技公布——用特征码定位关键代码,秒杀MFC程序
    Google C++编程命名约定
    认识硬盘主引导扇区
    c++ const 用法详解
    主引导区
    C++ 关于struce结构体字节对齐
    Fedora 显示设备配置工具介绍
  • 原文地址:https://www.cnblogs.com/Rainingday/p/5962222.html
Copyright © 2020-2023  润新知