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報文的處理流程









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章