DHCP源码分析-dhcp模块


一, 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);
	}else
	cip.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报文的处理流程









猜你喜欢

转载自blog.csdn.net/wuyongpeng0912/article/details/50445486
今日推荐