一, DHCP函數流程
二, locate_network()流程分析
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; }
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()流程分析
1, 通過client identifer或hardware確定host
通過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);
}
在代碼中,有兩個lease的hash表,分別以client identifier和hardware address爲key。從這裏可以看出,DHCP server一般情況下,都是會給client上次同樣的IP。
3,獲得client的請求地址
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。