dhclient issue

Chris Zimmermann cbzimmermann at mac.com
Fri May 12 18:24:08 UTC 2006


Hello,
I'm seeing an issue with dhclient, where certain routes are left  
intact when they are no longer valid.  I found the issue in src/dist/ 
dhcp/client/dhclient.c (v1.1.1.4), but it is still present the latest  
from netbsd-current (src/dist/dhcp/client/dhclient.c, v1.16)

I've traced it to the situation where the dhclient attempts to renew  
the lease by sending DHCPREQUEST to a DHCP server, and receives a  
DHCPNAK in response.  What happens is that dhclient transitions to  
INIT, followed by BOUND after this situation.  Neither of these two  
states provide the proper information to dhclient-script so that it  
can delete the old routes.

What I did was to add the following code to the function dhcpnak() in  
src/dist/dhcp/client/dhclient.c.  I've provided the entire function,  
with my changes in bold.  I kicked off an EXPIRE script (after the  
client -> active parameter has been validated), because the only  
thing passes to it is "old_" parameters, before they are destroyed by  
the call to destroy_client_lease (client -> active);

void dhcpnak (packet)
	struct packet *packet;
{
	struct interface_info *ip = packet -> interface;
	struct client_state *client;

	/* Find a client state that matches the xid... */
	for (client = ip -> client; client; client = client -> next)
		if (client -> xid == packet -> raw -> xid)
			break;

	/* If we're not receptive to an offer right now, or if the offer
	   has an unrecognizable transaction id, then just drop it. */
	if (!client ||
	    (packet -> interface -> hw_address.hlen - 1 !=
	     packet -> raw -> hlen) ||
	    (memcmp (&packet -> interface -> hw_address.hbuf [1],
		     packet -> raw -> chaddr, packet -> raw -> hlen))) {
#if defined (DEBUG)
		log_debug ("DHCPNAK in wrong transaction.");
#endif
		return;
	}

	if (client -> state != S_REBOOTING &&
	    client -> state != S_REQUESTING &&
	    client -> state != S_RENEWING &&
	    client -> state != S_REBINDING) {
#if defined (DEBUG)
		log_debug ("DHCPNAK in wrong state.");
#endif
		return;
	}

	log_info ("DHCPNAK from %s", piaddr (packet -> client_addr));

	if (!client -> active) {
#if defined (DEBUG)
		log_info ("DHCPNAK with no active lease.\n");
#endif
		return;
	}

/* begin modification */
	log_debug ("DHCPNAK forces an EXPIRE.");
	script_init (client, "EXPIRE", (struct string_list *)0);
	script_write_params (client, "old_", client -> active);
	if (client -> alias)
		script_write_params (client, "alias_",
					 client -> alias);
	script_go (client);
/* end modification */
	
	destroy_client_lease (client -> active);
	client -> active = (struct client_lease *)0;

	/* Stop sending DHCPREQUEST packets... */
	cancel_timeout (send_request, client);

	client -> state = S_INIT;
	state_init (client);
}

Here's a bit f a trace of what occurred.

I got a DHCP address from 192.168.1.1

Here's the environment originally passed to BOUND:
new_network_number=192.168.1.0
new_dhcp_message_type=5
new_routers=192.168.1.1
new_ip_address=192.168.1.126
new_domain_name_servers=[REMOVED]
PATH=/usr/bin:/usr/sbin:/bin:/sbin
reason=BOUND
new_domain_name=[REMOVED]
new_broadcast_address=192.168.1.255
interface=eth1
new_expiry=1147395000
pid=153
new_dhcp_server_identifier=192.168.1.1
new_subnet_mask=255.255.255.0
new_dhcp_lease_time=300

before the lease needed to be renews, I changed the IP address of the  
DHCP server at 192.168.1.1 to be 192.168.2.1

dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 192.168.1.1 port 67
dhclient: DHCPREQUEST on eth0 to 255.255.255.255 port 67
dhclient: DHCPNAK from 192.168.2.1

here's the EXPIRE script's variables (I added this script being  
kicked off)
old_domain_name_servers=[REMOVED]
old_dhcp_message_type=5
old_expiry=1147395285
old_dhcp_lease_time=300
PATH=/usr/bin:/usr/sbin:/bin:/sbin
reason=EXPIRE
old_broadcast_address=192.168.1.255
old_ip_address=192.168.1.126
interface=eth0
old_domain_name=[REMOVED]
pid=153
old_subnet_mask=255.255.255.0
old_network_number=192.168.1.0
old_routers=192.168.1.1
old_dhcp_server_identifier=192.168.1.1

dhclient: DHCPDISCOVER on vlan1 to 255.255.255.255 port 67 interval 5
dhclient: DHCPOFFER from 192.168.2.1
dhclient: DHCPREQUEST on vlan1 to 255.255.255.255 port 67
dhclient: DHCPACK from 192.168.2.1

An here's the BOUND script' s variables:
new_network_number=192.168.2.0
new_dhcp_message_type=5
new_routers=192.168.2.1
new_ip_address=192.168.2.102
new_domain_name_servers=[REMOVED]
PATH=/usr/bin:/usr/sbin:/bin:/sbin
reason=BOUND
new_domain_name=[REMOVED]
new_broadcast_address=192.168.2.255
interface=eth0
new_expiry=1147395557
pid=153
new_dhcp_server_identifier=192.168.2.1
new_subnet_mask=255.255.255.0
new_dhcp_lease_time=300

Has anyone else seen this issue?

Thanks,
Chris

-- 
Chris Zimmermann
cbzimmermann at mac.com







More information about the dhcp-users mailing list