2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-30 22:05:23 +00:00

- Pull up recent 2.0 changes.

- Fix some problems in DHCPREQUEST code regarding client identity.
- Update references to lease's shared network to use subnet pointer.
- If there's more than one lease matching a particular hardware address,
  examine them all for possible applicability in find_lease().
- Only recover abandoned leases on DHCPREQUEST if the request was for
  the specific abandoned lease.   Push all other abandoned lease
  recovery code out into DHCPDISCOVER/allocate_lease processing.
This commit is contained in:
Ted Lemon
1999-02-14 19:27:56 +00:00
parent 763adef103
commit 027f46cb67

View File

@@ -3,8 +3,8 @@
DHCP Protocol engine. */ DHCP Protocol engine. */
/* /*
* Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. * Copyright (c) 1995, 1996, 1997, 1998, 1999
* All rights reserved. * The Internet Software Consortium. All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions * modification, are permitted provided that the following conditions
@@ -42,7 +42,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: dhcp.c,v 1.73 1998/11/19 20:56:36 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; "$Id: dhcp.c,v 1.74 1999/02/14 19:27:56 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@@ -221,7 +221,7 @@ void dhcprequest (packet)
where it claims to have come from, it didn't come where it claims to have come from, it didn't come
from there. Fry it. */ from there. Fry it. */
if (!packet -> shared_network) { if (!packet -> shared_network) {
if (subnet) { if (subnet && subnet -> group -> authoritative) {
note ("%s: wrong network.", msgbuf); note ("%s: wrong network.", msgbuf);
nak_lease (packet, &cip); nak_lease (packet, &cip);
return; return;
@@ -234,8 +234,11 @@ void dhcprequest (packet)
address that is not on that shared network, nak it. */ address that is not on that shared network, nak it. */
subnet = find_grouped_subnet (packet -> shared_network, cip); subnet = find_grouped_subnet (packet -> shared_network, cip);
if (!subnet) { if (!subnet) {
note ("%s: wrong network.", msgbuf); if (packet -> shared_network -> group -> authoritative)
nak_lease (packet, &cip); {
note ("%s: wrong network.", msgbuf);
nak_lease (packet, &cip);
}
return; return;
} }
} }
@@ -246,12 +249,12 @@ void dhcprequest (packet)
if (lease && !addr_eq (lease -> ip_addr, cip)) { if (lease && !addr_eq (lease -> ip_addr, cip)) {
/* If we found the address the client asked for, but /* If we found the address the client asked for, but
it wasn't what got picked, the lease belongs to us, it wasn't what got picked, the lease belongs to us,
so we can tenuously justify NAKing it. */ so we should NAK it. */
if (ours) { if (ours) {
note ("%s: wrong lease %s.", msgbuf, piaddr (cip)); note ("%s: wrong lease %s.", msgbuf, piaddr (cip));
nak_lease (packet, &cip); nak_lease (packet, &cip);
} else } else
note ("%s: unknown lease %s", msgbuf, piaddr (cip)); note ("%s: wrong lease %s", msgbuf, piaddr (cip));
return; return;
} }
@@ -263,30 +266,28 @@ void dhcprequest (packet)
return; return;
} }
/* If we own the lease that the client is asking for, /* If we found a lease, but the client identifier on the lease
and it's already been assigned to the client, ack it. */ exists and is different than the id the client sent, then
oc = lookup_option (packet -> options.dhcp_hash, we can't send this lease to the client. */
DHO_DHCP_CLIENT_IDENTIFIER); if (lease) {
if (oc) oc = lookup_option (packet -> options.dhcp_hash,
status = evaluate_option_cache (&data, packet, DHO_DHCP_CLIENT_IDENTIFIER);
&packet -> options, oc); if (oc)
else status = evaluate_option_cache (&data, packet,
status = 0; &packet -> options, oc);
if (status && lease && if (lease && oc && status && lease -> uid_len &&
((lease -> uid_len && lease -> uid_len == data.len && (lease -> uid_len != data.len ||
!memcmp (data.data, memcmp (data.data,
lease -> uid, lease -> uid_len)) || lease -> uid, lease -> uid_len))) {
(lease -> hardware_addr.hlen == packet -> raw -> hlen && note ("%s: wrong owner %s.", msgbuf, piaddr (cip));
lease -> hardware_addr.htype == packet -> raw -> htype && nak_lease (packet, &cip);
!memcmp (lease -> hardware_addr.haddr, } else
packet -> raw -> chaddr, ack_lease (packet, lease, DHCPACK, 0, msgbuf);
packet -> raw -> hlen)))) { if (oc && status)
data_string_forget (&data, "dhcprequest"); data_string_forget (&data, "dhcprequest");
ack_lease (packet, lease, DHCPACK, 0, msgbuf);
return; return;
} }
note ("%s: unknown lease %s.", msgbuf, piaddr (cip)); note ("%s: unknown lease %s.", msgbuf, piaddr (cip));
data_string_forget (&data, "dhcprequest");
} }
void dhcprelease (packet) void dhcprelease (packet)
@@ -502,14 +503,15 @@ void nak_lease (packet, cip)
to.sin_addr = raw.giaddr; to.sin_addr = raw.giaddr;
to.sin_port = local_port; to.sin_port = local_port;
#ifdef USE_FALLBACK if (fallback_interface) {
result = send_fallback (&fallback_interface, result = send_packet (fallback_interface,
packet, &raw, outgoing.packet_length, packet, &raw,
from, &to, &hto); outgoing.packet_length,
if (result < 0) from, &to, &hto);
warn ("send_fallback: %m"); if (result < 0)
return; warn ("send_fallback: %m");
#endif return;
}
} else { } else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST); to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = remote_port; to.sin_port = remote_port;
@@ -539,6 +541,7 @@ void ack_lease (packet, lease, offer, when, msg)
struct option_cache *oc; struct option_cache *oc;
struct expression *expr; struct expression *expr;
int status; int status;
int ulafdr;
int option_tag_size = 1; /* XXX */ int option_tag_size = 1; /* XXX */
int i, j, s1, s2; int i, j, s1, s2;
@@ -572,7 +575,7 @@ void ack_lease (packet, lease, offer, when, msg)
lease -> client_hostname = lease -> client_hostname =
dmalloc (d1.len + 1, "ack_lease"); dmalloc (d1.len + 1, "ack_lease");
if (!lease -> client_hostname) if (!lease -> client_hostname)
warn ("no memory for client hostname.\n"); warn ("no memory for client hostname.");
else { else {
memcpy (lease -> client_hostname, d1.data, d1.len); memcpy (lease -> client_hostname, d1.data, d1.len);
lease -> client_hostname [d1.len] = 0; lease -> client_hostname [d1.len] = 0;
@@ -887,7 +890,6 @@ void ack_lease (packet, lease, offer, when, msg)
lt.host = lease -> host; lt.host = lease -> host;
lt.subnet = lease -> subnet; lt.subnet = lease -> subnet;
lt.shared_network = lease -> shared_network;
lt.billing_class = lease -> billing_class; lt.billing_class = lease -> billing_class;
/* Don't call supersede_lease on a mocked-up lease. */ /* Don't call supersede_lease on a mocked-up lease. */
@@ -1154,16 +1156,24 @@ void ack_lease (packet, lease, offer, when, msg)
lookup_option (state -> options.server_hash, lookup_option (state -> options.server_hash,
SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE))) { SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE))) {
i = DHO_ROUTERS; i = DHO_ROUTERS;
oc = (struct option_cache *)0; oc = lookup_option (state -> options.dhcp_hash, i);
if (option_cache_allocate (&oc, "ack_lease")) { if (!oc) {
if (make_const_data (&oc -> expression, oc = (struct option_cache *)0;
lease -> ip_addr.iabuf, if (option_cache_allocate (&oc, "ack_lease")) {
lease -> ip_addr.len, 0, 0)) { if (make_const_data (&oc -> expression,
oc -> option = dhcp_universe.options [i]; lease -> ip_addr.iabuf,
save_option (state -> options.dhcp_hash, oc); lease -> ip_addr.len,
0, 0)) {
oc -> option =
dhcp_universe.options [i];
save_option
(state -> options.dhcp_hash,
oc);
}
} }
option_cache_dereference (&oc, "ack_lease");
} }
if (oc)
option_cache_dereference (&oc, "ack_lease");
} }
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
@@ -1177,11 +1187,14 @@ void ack_lease (packet, lease, offer, when, msg)
/* If this is a DHCPOFFER, ping the lease address before actually /* If this is a DHCPOFFER, ping the lease address before actually
sending the offer. */ sending the offer. */
if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE)) { if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE) &&
cur_time - lease -> timestamp > 60) {
lease -> timestamp = cur_time;
icmp_echorequest (&lease -> ip_addr); icmp_echorequest (&lease -> ip_addr);
add_timeout (cur_time + 1, lease_ping_timeout, lease); add_timeout (cur_time + 1, lease_ping_timeout, lease);
++outstanding_pings; ++outstanding_pings;
} else { } else {
lease -> timestamp = cur_time;
dhcp_reply (lease); dhcp_reply (lease);
} }
} }
@@ -1331,38 +1344,39 @@ void dhcp_reply (lease)
to.sin_addr = raw.giaddr; to.sin_addr = raw.giaddr;
to.sin_port = local_port; to.sin_port = local_port;
#ifdef USE_FALLBACK if (fallback_interface) {
result = send_fallback (&fallback_interface, result = send_packet (fallback_interface,
(struct packet *)0, (struct packet *)0,
&raw, packet_length, &raw, packet_length,
raw.siaddr, &to, &hto); raw.siaddr, &to, &hto);
if (result < 0) if (result < 0)
warn ("send_fallback: %m"); warn ("send_fallback: %m");
free_lease_state (state, "dhcp_reply fallback 1"); free_lease_state (state, "dhcp_reply fallback 1");
lease -> state = (struct lease_state *)0; lease -> state = (struct lease_state *)0;
return; return;
#endif }
/* If it comes from a client who already knows its address and /* If it comes from a client that already knows its address and
is not requesting a broadcast response, sent it directly to is not requesting a broadcast response, sent it directly to
that client. */ that client. */
} else if (raw.ciaddr.s_addr && state -> offer == DHCPACK && } else if (raw.ciaddr.s_addr && state -> offer == DHCPACK &&
!(raw.flags & htons (BOOTP_BROADCAST))) { !(raw.flags & htons (BOOTP_BROADCAST)) &&
can_unicast_without_arp ()) {
to.sin_addr = state -> ciaddr; to.sin_addr = state -> ciaddr;
to.sin_port = remote_port; /* XXX */ to.sin_port = remote_port; /* XXX */
#ifdef USE_FALLBACK if (fallback_interface) {
result = send_fallback (&fallback_interface, result = send_packet (fallback_interface,
(struct packet *)0, (struct packet *)0,
&raw, packet_length, &raw, packet_length,
raw.siaddr, &to, &hto); raw.siaddr, &to, &hto);
if (result < 0) if (result < 0)
warn ("send_fallback: %m"); warn ("send_fallback: %m");
free_lease_state (state, "dhcp_reply fallback 1"); free_lease_state (state, "dhcp_reply fallback 1");
lease -> state = (struct lease_state *)0; lease -> state = (struct lease_state *)0;
return; return;
#endif }
/* Otherwise, broadcast it on the local network. */ /* Otherwise, broadcast it on the local network. */
} else { } else {
@@ -1435,12 +1449,14 @@ struct lease *find_lease (packet, share, ours)
/* Find the lease matching this uid that's on the /* Find the lease matching this uid that's on the
network the packet came from (if any). */ network the packet came from (if any). */
for (; uid_lease; uid_lease = uid_lease -> n_uid) for (; uid_lease; uid_lease = uid_lease -> n_uid)
if (uid_lease -> shared_network == share) if (uid_lease -> subnet -> shared_network ==
share)
break; break;
fixed_lease = (struct lease *)0; fixed_lease = (struct lease *)0;
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
note ("Found lease for client identifier: %s.", if (uid_lease)
piaddr (uid_lease -> ip_addr)); note ("Found lease for client identifier: %s.",
piaddr (uid_lease -> ip_addr));
#endif #endif
if (uid_lease && if (uid_lease &&
(uid_lease -> flags & ABANDONED_LEASE)) { (uid_lease -> flags & ABANDONED_LEASE)) {
@@ -1482,7 +1498,7 @@ struct lease *find_lease (packet, share, ours)
/* Find the lease that's on the network the packet came from /* Find the lease that's on the network the packet came from
(if any). */ (if any). */
for (; hw_lease; hw_lease = hw_lease -> n_hw) { for (; hw_lease; hw_lease = hw_lease -> n_hw) {
if (hw_lease -> shared_network == share) { if (hw_lease -> subnet -> shared_network == share) {
if (hw_lease -> flags & ABANDONED_LEASE) if (hw_lease -> flags & ABANDONED_LEASE)
continue; continue;
/* If we're allowed to use this lease, do so. */ /* If we're allowed to use this lease, do so. */
@@ -1542,7 +1558,7 @@ struct lease *find_lease (packet, share, ours)
that thought it had this lease answered an ARP or PING, causing the that thought it had this lease answered an ARP or PING, causing the
lease to be abandoned. If so, this request probably came from lease to be abandoned. If so, this request probably came from
that client. */ that client. */
if (ip_lease && (ip_lease -> shared_network != share)) { if (ip_lease && (ip_lease -> subnet -> shared_network != share)) {
note ("...but it was on the wrong shared network."); note ("...but it was on the wrong shared network.");
ip_lease = (struct lease *)0; ip_lease = (struct lease *)0;
} }
@@ -1576,7 +1592,8 @@ struct lease *find_lease (packet, share, ours)
print_hw_addr (packet -> raw -> htype, print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen, packet -> raw -> hlen,
packet -> raw -> chaddr), packet -> raw -> chaddr),
ip_lease -> shared_network -> name); (ip_lease -> subnet ->
shared_network -> name));
/* If the client is REQUESTing the lease, it shouldn't /* If the client is REQUESTing the lease, it shouldn't
still be using the old one, so we can free it for still be using the old one, so we can free it for
@@ -1584,7 +1601,7 @@ struct lease *find_lease (packet, share, ours)
lease is on the same network, of course. */ lease is on the same network, of course. */
if (packet -> packet_type == DHCPREQUEST && if (packet -> packet_type == DHCPREQUEST &&
share == uid_lease -> shared_network) share == uid_lease -> subnet -> shared_network)
dissociate_lease (uid_lease); dissociate_lease (uid_lease);
uid_lease = ip_lease; uid_lease = ip_lease;
@@ -1596,16 +1613,20 @@ struct lease *find_lease (packet, share, ours)
match, except that if the hardware address matches and the match, except that if the hardware address matches and the
client is now doing dynamic BOOTP (and thus hasn't provided client is now doing dynamic BOOTP (and thus hasn't provided
a uid) we let the client get away with it. */ a uid) we let the client get away with it. */
if (hw_lease && while (hw_lease &&
hw_lease -> ends >= cur_time && hw_lease -> ends >= cur_time &&
hw_lease -> uid && hw_lease -> uid &&
(!have_client_identifier || (!have_client_identifier ||
hw_lease -> uid_len != client_identifier.len || hw_lease -> uid_len != client_identifier.len ||
memcmp (hw_lease -> uid, client_identifier.data, memcmp (hw_lease -> uid, client_identifier.data,
hw_lease -> uid_len))) { hw_lease -> uid_len))) {
hw_lease = (struct lease *)0; hw_lease = hw_lease -> n_hw;
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
note ("rejecting lease for hardware address."); if (hw_lease)
note ("trying next lease matching hw addr: %s",
piaddr (hw_lease -> ip_addr));
else
note ("rejecting lease for hardware address.");
#endif #endif
} }
@@ -1640,7 +1661,7 @@ struct lease *find_lease (packet, share, ours)
/* Now eliminate leases that are on the wrong network... */ /* Now eliminate leases that are on the wrong network... */
if (ip_lease && if (ip_lease &&
(share != ip_lease -> shared_network)) { (share != ip_lease -> subnet -> shared_network)) {
release_lease (ip_lease); release_lease (ip_lease);
ip_lease = (struct lease *)0; ip_lease = (struct lease *)0;
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
@@ -1648,7 +1669,7 @@ struct lease *find_lease (packet, share, ours)
#endif #endif
} }
if (uid_lease && if (uid_lease &&
(share != uid_lease -> shared_network)) { (share != uid_lease -> subnet -> shared_network)) {
release_lease (uid_lease); release_lease (uid_lease);
uid_lease = (struct lease *)0; uid_lease = (struct lease *)0;
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
@@ -1656,7 +1677,7 @@ struct lease *find_lease (packet, share, ours)
#endif #endif
} }
if (hw_lease && if (hw_lease &&
(share != hw_lease -> shared_network)) { (share != hw_lease -> subnet -> shared_network)) {
release_lease (hw_lease); release_lease (hw_lease);
hw_lease = (struct lease *)0; hw_lease = (struct lease *)0;
#if defined (DEBUG_FIND_LEASE) #if defined (DEBUG_FIND_LEASE)
@@ -1752,13 +1773,23 @@ struct lease *find_lease (packet, share, ours)
note ("Not returning a lease."); note ("Not returning a lease.");
#endif #endif
/* If we find an abandoned lease, take it, but print a /* If we find an abandoned lease, but it's the one the client
warning message, so that if it continues to lose, requested, we assume that previous bugginess on the part
the administrator will eventually investigate. */ of the client, or a server database loss, caused the lease to
if (lease && lease -> flags & ABANDONED_LEASE) { be abandoned, so we reclaim it and let the client have it. */
warn ("Reclaiming REQUESTed abandoned IP address %s.\n", if (lease && lease -> flags & ABANDONED_LEASE && lease == ip_lease &&
packet -> packet_type == DHCPREQUEST) {
warn ("Reclaiming REQUESTed abandoned IP address %s.",
piaddr (lease -> ip_addr)); piaddr (lease -> ip_addr));
lease -> flags &= ~ABANDONED_LEASE; lease -> flags &= ~ABANDONED_LEASE;
} else if (lease && lease -> flags & ABANDONED_LEASE) {
/* Otherwise, if it's not the one the client requested, we do not
return it - instead, we claim it's ours, causing a DHCPNAK to be
sent if this lookup is for a DHCPREQUEST, and force the client
to go back through the allocation process. */
if (ours)
*ours = 1;
lease = (struct lease *)0;
} }
return lease; return lease;
@@ -1779,7 +1810,6 @@ struct lease *mockup_lease (packet, share, hp)
if (!mock.subnet) if (!mock.subnet)
return (struct lease *)0; return (struct lease *)0;
mock.next = mock.prev = (struct lease *)0; mock.next = mock.prev = (struct lease *)0;
mock.shared_network = mock.subnet -> shared_network;
mock.host = hp; mock.host = hp;
mock.uid = hp -> client_identifier.data; mock.uid = hp -> client_identifier.data;
mock.uid_len = hp -> client_identifier.len; mock.uid_len = hp -> client_identifier.len;