dhcpd是linux下的一个DHCP服务器,下载地址:
下载完成后
tar -zxvf dhcp-4.2.1-P1.tar.gz
./configure
make
make install
编辑 /etc/dhcpd.conf 文件
ddns-update-style none;
subnet 192.168.66.0 netmask 255.255.255.0 {
option routers 192.168.66.1;
option subnet-mask 255.255.255.0;
option domain-name "wayos";
option domain-name-servers 61.139.2.69;
range 192.168.66.2 192.168.66.254;
default-lease-time 600;
max-lease-time 7200;
}
192.168.66.0 为主机所在网段
如果程序提示没有 "/var/db/dhcpd.leases" 文件,touch 一个
main
{
/* Set up the isc and dns library managers */
/* Set up the client classification system. */
/* Initialize the omapi system. */
/* Set up the OMAPI wrappers for common objects. */
/* Set up the OMAPI wrappers for various server database internal
objects. */
/* Initially, log errors to stderr as well as to syslogd. */
/* 解析命令行参数 */
/* get user and group info if those options were given */
/* get around the ISC declaration of group */
/* Default to the DHCP/BOOTP port. */
/* Set up the initial dhcp option universe. */
/* Add the ddns update style enumeration prior to parsing. */
/* Set up various hooks. */
dhcp_interface_setup_hook = dhcpd_interface_setup_hook;
bootp_packet_handler = do_packet;
/* Set up the standard name service updater routine. */
/* Initialize icmp support... */
/* Read the dhcpd.conf file... */
/* Start up the database... */
/* Discover all the network interfaces and initialize them. */
/* First part of becoming a daemon... */
/* Become session leader and get pid... */
/* Receive packets and dispatch them... */
dispatch ();
}
关键代码:
discover.c 文件中有bootp_packet_handler函数指针声明
void (*bootp_packet_handler) PROTO ((struct interface_info *,
struct dhcp_packet *, unsigned,
unsigned int,
struct iaddr, struct hardware *));
dhcpd.c 文件中 main函数对bootp_packet_handler函数指针进行了赋值,然后调用discover_interfaces函数:
bootp_packet_handler = do_packet;
discover_interfaces(DISCOVER_SERVER);
discover.c 文件有discover_interfaces函数的定义,其中关键的调用了got_one函数:
status = omapi_register_io_object((omapi_object_t *)tmp,
if_readsocket,
0, got_one, 0, 0);
discover.c 文件有got_one函数定义,其关键代码是调用了receive_packet函数,和bootp_packet_handler函数指针:
receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)
if (bootp_packet_handler) {
ifrom.len = 4;
memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
(*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
from.sin_port, ifrom, &hfrom);
}
socket.c 文件中有receive_packet函数的定义
result = recvfrom (interface -> rfdesc, (char *)buf, len, 0,
(struct sockaddr *)from, &flen);
options.c 文件中有do_packet函数的定义:
packet_allocate (&decoded_packet, MDL);
decoded_packet -> raw = packet;
decoded_packet -> packet_length = len;
decoded_packet -> client_port = from_port;
decoded_packet -> client_addr = from;
interface_reference (&decoded_packet -> interface, interface, MDL);
decoded_packet -> haddr = hfrom;
/* If there's an option buffer, try to parse it. */
if (decoded_packet -> packet_length >= DHCP_FIXED_NON_UDP + 4) {
if (!parse_options (decoded_packet)) {
if (decoded_packet -> options)
option_state_dereference
(&decoded_packet -> options, MDL);
packet_dereference (&decoded_packet, MDL);
return;
}
if (decoded_packet -> options_valid &&
(op = lookup_option (&dhcp_universe,
decoded_packet -> options,
DHO_DHCP_MESSAGE_TYPE))) {
struct data_string dp;
memset (&dp, 0, sizeof dp);
evaluate_option_cache (&dp, decoded_packet,
(struct lease *)0,
(struct client_state *)0,
decoded_packet -> options,
(struct option_state *)0,
(struct binding_scope **)0,
op, MDL);
if (dp.len > 0)
decoded_packet -> packet_type = dp.data [0];
else
decoded_packet -> packet_type = 0;
data_string_forget (&dp, MDL);
}
}
if (decoded_packet -> packet_type)
dhcp (decoded_packet);
else
bootp (decoded_packet);
dhcp.c 文件有dhcp函数的定义,主要做的工作就是对不同的packet -> packet_type对应的包进行处理:
switch (packet -> packet_type) {
case DHCPDISCOVER:
dhcpdiscover (packet, ms_nulltp);
break;
case DHCPREQUEST:
dhcprequest (packet, ms_nulltp, lease);
break;
case DHCPRELEASE:
dhcprelease (packet, ms_nulltp);
break;
case DHCPDECLINE:
dhcpdecline (packet, ms_nulltp);
break;
case DHCPINFORM:
dhcpinform (packet, ms_nulltp);
break;
case DHCPLEASEQUERY:
dhcpleasequery(packet, ms_nulltp);
break;
case DHCPACK:
case DHCPOFFER:
case DHCPNAK:
case DHCPLEASEUNASSIGNED:
case DHCPLEASEUNKNOWN:
case DHCPLEASEACTIVE:
break;
default:
errmsg = "unknown packet type";
goto bad_packet;
}
dhcp.c 文件有dhcprequest函数的定义,此函数的执行流程为:
/* Find the lease that matches the address requested by the
client. */
/*If it's RENEWING, we are the only server to hear it, so
* we have to serve it.*/
/* If we do know where it came from and it asked for an
address that is not on that shared network, nak it. */
/* If the address the client asked for is ours, but it wasn't
available for the client, NAK it. */
/* Otherwise, send the lease to the client if we found one. */