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