DHCP源码分析-dhcp模块

来源:互联网 发布:关于网络黑客的说说 编辑:程序博客网 时间:2024/05/08 13:17


一, DHCP函数流程




        函数void dhcp (struct packet *packet)是处理DHCP包的入口函数,在进入这个函数的时候,对包的解析已经完成,已经将包的内容转换成内部结构struct packet。dhcp()函数主要做的工作就是对不同的packet -> packet_type对应的包进行处理。

二, locate_network()流程分析


        进入dhcp函数,首先就是调用int locate_network (struct packet *packet)来确定client所属subnet,以便从这个subnet下分配正确的IP
        

        1,查找link selection和subnet selection options

if ((oc = lookup_option(&agent_universe, packet->options, RAI_LINK_SELECT)) == NULL)        oc=lookup_option(&dhcp_universe,packet->options, DHO_SUBNET_SELECTION);

        首先,先查找DHCP包中是否有relay-agent-option下linkselection sub-option,这个option用于当client与server处于不同网段,需要DHCP relay转发时,client想要得到一个relay agent不同网段的IP。具体信息请参考RFC 3527。

        如果没有该option,就继续在包中查找subnet selection option。这个option用于在client与server同一网段的情况下,client需要获得不同网段的IP,具体信息参考RFC3011。

        这两个option在功能上有相似之处,都是client要求获得一个指定网段的IP。不同之处在于,relay-agent-option是用于DHCP relay的,也就说DHCP包是通过relay转发到server端的,client与server处于不同的物理网段。而subnet selection option,是client与server处于同一个物理网段,但是想要获得不同网段的IP,而由client将这个option加入到DHCP包中。


        2,使用网卡所在网段为预分配的subnet

if (!oc && !packet -> raw -> giaddr.s_addr) {    if (packet -> interface -> shared_network) {    shared_network_reference     (&packet -> shared_network,    packet -> interface -> shared_network, MDL);    return 1;  }       return 0;  }

        如果没有找到这两个option,那么通过packet -> raw -> giaddr.s_addr来判断这个包是否是由relay转发过来的。packet -> raw -> giaddr.s_addr是relay的地址,由relay填写。如果不是转发过来的包,那么到此就可以确定client与server同一网段,并且没有要求不同网段的IP。那么就确定了接收到该包网卡所属的网段,为分配IP的网段,并赋给packet->shared_network。

        3,使用option或relay地址确定subnet

if (oc) {   memset (&data, 0, sizeof data);   if (!evaluate_option_cache (&data, packet, (struct lease *)0, (struct client_state *)0,packet -> options,    (struct option_state *)0,&global_scope, oc, MDL))       {   return 0;   }   if (data.len != 4)        {    return 0;   }   ia.len = 4;   memcpy (ia.iabuf, data.data, 4);   data_string_forget (&data, MDL);   } else {   ia.len = 4;   memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);}   if (find_subnet (&subnet, ia, MDL)) {      shared_network_reference (&packet -> shared_network,subnet -> shared_network, MDL);      subnet_dereference (&subnet, MDL);      return 1;}

        在没有前面两个option的情况下,server将通过packet -> raw -> giaddr来确定分配IP的subnet。
        

        通过对locate_network的分析,我们可以确定subnet选择因素的优先级为

linkselection sub-option > subnet selection option > relay address > 网卡的subnet

三, find_lease()流程分析

        

        函数dhcpdiscover通过调用find_lease来确定分配哪个IP给client

        1, 通过client identifer或hardware确定host

        
        首先sever会尝试用DHCP请求中的client identifer或者hardware来确定该请求是否来自于一个配置文件指定的host。(通常当client的管理员没有指定client indentifier的时候,client会把自己的网卡的MAC地址作为client identifer发给server。)

        通过find_hosts_by_uid(&hp,client_identifier.data, client_identifier.len, MDL)来使用client identifier找到host即hp,通过find_hosts_by_haddr(&hp,packet->raw->htype, packet->raw->chaddr, packet->raw->hlen,MDL)来使用MAC地址来找到host。找到host后,通过host尝试查找fixedlease——即在配置文件的host中,指定的IP地址。这是通过mockup_lease (&fixed_lease, packet, share, host)这个函数实现的。这里注意的是,传入参数share为预分配IP的subnet。将它作为参数,是为了排除不在该subnet中的fixed ip,即使这个IP是host的指定IP。

       其实除了使用clientindentifer和MAC地址来查找host的方式外,还支持通过指定option来查找host,这种用法并不常见。

       通过host确定的IP,在ISC DHCP中被称为fixedIP,其对应的lease自然被称为fixedlease。


        2,通过client identifier获得fixed lease

if (find_hosts_by_uid (&hp, client_identifier.data,client_identifier.len, MDL)) {   /* Remember if we know of this client. */packet -> known = 1;mockup_lease (&fixed_lease, packet, share, hp);}

        在通过host来确定要分配IP的同时,也会使用函数find_lease_by_uid(&uid_lease,client_identifer.data, client_identifier.len, MDL)和find_lease_by_hw_addr(&hw_lease, h.hbuf, h.hlen,MDL)来直接通过client_identifier和MAC地址确定lease。

       在代码中,有两个lease的hash表,分别以client identifier和hardware address为key。从这里可以看出,DHCP server一般情况下,都是会给client上次同样的IP。


        3,获得client的请求地址

        client除了被动的接受server给分配的IP,它还可以主动向server提出要求,要求想要得到的IP。这是通过client在DHCP包中的client地址,或者使用requestedaddress option来实现的。

if (packet -> raw -> ciaddr.s_addr){cip.len = 4;  memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);} else {/* Look up the requested address. */oc = lookup_option (&dhcp_universe, packet -> ptions,DHO_DHCP_REQUESTED_ADDRESS);memset (&d1, 0, sizeof d1);if (oc &&evaluate_option_cache (&d1, packet, (struct lease *)0,(struct client_state *)0,packet -> options,(struct option_state *)0,&global_scope, oc, MDL)) {packet -> got_requested_address = 1;cip.len = 4;memcpy (cip.iabuf, d1.data, cip.len);data_string_forget (&d1, MDL);}elsecip.len = 0;}


        server会使用这个cip来分配一个lease,然后再通过一系列检查来判断是否可以使用这个lease。在不与其他配置的不冲突的情况下,尽量满足client的要求,分配给其要求的IP。
确定分配IP的优先级是fixed lease > uid lease > hw lease > ip lease,其 fixed lease是配置文件中host所配置的lease,uid lease 是通过uid确定的lease,hw lease是通过硬件地址查找到的lease,ip lease是client希望请求得到的lease。


四, DISCOVER报文的处理流程









0 0
原创粉丝点击