码迷,mamicode.com
首页 > 其他好文 > 详细

DHCP分析

时间:2016-10-14 23:35:55      阅读:1007      评论:0      收藏:0      [点我收藏+]

标签:

一  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协议数据包格式
技术分享
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 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_task

void lwip_dhcp_task(void *pdata)
{
    u32 ip=0,netmask=0,gw=0;
    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成功
              /*打印获得的信息*/            
       }
else if(lwip_netif.dhcp->tries>LWIP_MAX_DHCP_TRIES) //通过DHCP服务获取IP地址失败,且超过最大尝试次数
        {  
                //获得失败,做下一步处理       
       }  
        delay_ms(250); //延时250ms
    }
    lwip_comm_dhcp_delete();//删除DHCP任务 
}

把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吧。

DHCP分析

标签:

原文地址:http://www.cnblogs.com/Rainingday/p/5962222.html

(0)
(3)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!