|
Release of leases according to IP addresses
|
Symptom
A problem may occur when releasing leases with "old" DHCP servers. This is due to the fact that some servers release leases
only according to machines' UIDs, and not according to both UIDs and IP addresses, as it is recommended in the
RFC2131. For most DHCP servers, when the DHCP client does not specify it, the UID
(number that uniquely identifies a machine) is the MAC address, so the DHCP server could confuse different leases
granted to the same machine.
The consequence to this is that the client's name could still be in the DNS entries and that the IP has not been released,
even if the request was perfectly understood.
Here is a procedure to follow to check if a server must be patched:
- put a computer in a LAN
- make a DHCP request. The machine should obtain a IP address (IP1)
- release the lease
- put the computer in another LAN
- make a new DHCP request. The machine obtains another IP address (IP2)
- release the lease
- check in the dhcpd.leases file if the last entry starts with "lease IP1". If so, the server needs to be patched.
Patch
The idea is to use a new code for the dhcprelease() function:
This function is in the server/dhcp.c file. One can directly replace the code of this function by the
one from a recent server. The following code comes from the 2.0pl2 version:
void dhcprelease (packet)
struct packet *packet;
{
struct lease *lease;
struct iaddr cip;
int i;
/* DHCPRELEASE must not specify address in requested-address
option, but old protocol specs weren't explicit about this,
so let it go. */
if (packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
note ("DHCPRELEASE from %s specified requested-address.",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
}
i = DHO_DHCP_CLIENT_IDENTIFIER;
if (packet -> options [i].len) {
lease = find_lease_by_uid (packet -> options [i].data,
packet -> options [i].len);
/* See if we can find a lease that matches the IP address
the client is claiming. */
for (; lease; lease = lease -> n_uid) {
if (!memcmp (&packet -> raw -> ciaddr,
lease -> ip_addr.iabuf, 4)) {
break;
}
}
} else {
/* The client is supposed to pass a valid client-identifier,
but the spec on this has changed historically, so try the
IP address in ciaddr if the client-identifier fails. */
cip.len = 4;
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
lease = find_lease_by_ip_addr (cip);
}
note ("DHCPRELEASE of %s from %s via %s (%sfound)",
inet_ntoa (packet -> raw -> ciaddr),
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr),
packet -> raw -> giaddr.s_addr
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name,
lease ? "" : "not ");
/* If we found a lease, release it. */
if (lease && lease -> ends > cur_time) {
release_lease (lease);
}
}
|
This code can be found in this separated file.
printable format
|