mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-30 05:47:45 +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:
parent
763adef103
commit
027f46cb67
224
server/dhcp.c
224
server/dhcp.c
@ -3,8 +3,8 @@
|
||||
DHCP Protocol engine. */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 1995, 1996, 1997, 1998, 1999
|
||||
* The Internet Software Consortium. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@ -42,7 +42,7 @@
|
||||
|
||||
#ifndef lint
|
||||
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 */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@ -221,7 +221,7 @@ void dhcprequest (packet)
|
||||
where it claims to have come from, it didn't come
|
||||
from there. Fry it. */
|
||||
if (!packet -> shared_network) {
|
||||
if (subnet) {
|
||||
if (subnet && subnet -> group -> authoritative) {
|
||||
note ("%s: wrong network.", msgbuf);
|
||||
nak_lease (packet, &cip);
|
||||
return;
|
||||
@ -234,8 +234,11 @@ void dhcprequest (packet)
|
||||
address that is not on that shared network, nak it. */
|
||||
subnet = find_grouped_subnet (packet -> shared_network, cip);
|
||||
if (!subnet) {
|
||||
note ("%s: wrong network.", msgbuf);
|
||||
nak_lease (packet, &cip);
|
||||
if (packet -> shared_network -> group -> authoritative)
|
||||
{
|
||||
note ("%s: wrong network.", msgbuf);
|
||||
nak_lease (packet, &cip);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -246,12 +249,12 @@ void dhcprequest (packet)
|
||||
if (lease && !addr_eq (lease -> ip_addr, cip)) {
|
||||
/* If we found the address the client asked for, but
|
||||
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) {
|
||||
note ("%s: wrong lease %s.", msgbuf, piaddr (cip));
|
||||
nak_lease (packet, &cip);
|
||||
} else
|
||||
note ("%s: unknown lease %s", msgbuf, piaddr (cip));
|
||||
note ("%s: wrong lease %s", msgbuf, piaddr (cip));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -263,30 +266,28 @@ void dhcprequest (packet)
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we own the lease that the client is asking for,
|
||||
and it's already been assigned to the client, ack it. */
|
||||
oc = lookup_option (packet -> options.dhcp_hash,
|
||||
DHO_DHCP_CLIENT_IDENTIFIER);
|
||||
if (oc)
|
||||
status = evaluate_option_cache (&data, packet,
|
||||
&packet -> options, oc);
|
||||
else
|
||||
status = 0;
|
||||
if (status && lease &&
|
||||
((lease -> uid_len && lease -> uid_len == data.len &&
|
||||
!memcmp (data.data,
|
||||
lease -> uid, lease -> uid_len)) ||
|
||||
(lease -> hardware_addr.hlen == packet -> raw -> hlen &&
|
||||
lease -> hardware_addr.htype == packet -> raw -> htype &&
|
||||
!memcmp (lease -> hardware_addr.haddr,
|
||||
packet -> raw -> chaddr,
|
||||
packet -> raw -> hlen)))) {
|
||||
data_string_forget (&data, "dhcprequest");
|
||||
ack_lease (packet, lease, DHCPACK, 0, msgbuf);
|
||||
/* If we found a lease, but the client identifier on the lease
|
||||
exists and is different than the id the client sent, then
|
||||
we can't send this lease to the client. */
|
||||
if (lease) {
|
||||
oc = lookup_option (packet -> options.dhcp_hash,
|
||||
DHO_DHCP_CLIENT_IDENTIFIER);
|
||||
if (oc)
|
||||
status = evaluate_option_cache (&data, packet,
|
||||
&packet -> options, oc);
|
||||
if (lease && oc && status && lease -> uid_len &&
|
||||
(lease -> uid_len != data.len ||
|
||||
memcmp (data.data,
|
||||
lease -> uid, lease -> uid_len))) {
|
||||
note ("%s: wrong owner %s.", msgbuf, piaddr (cip));
|
||||
nak_lease (packet, &cip);
|
||||
} else
|
||||
ack_lease (packet, lease, DHCPACK, 0, msgbuf);
|
||||
if (oc && status)
|
||||
data_string_forget (&data, "dhcprequest");
|
||||
return;
|
||||
}
|
||||
note ("%s: unknown lease %s.", msgbuf, piaddr (cip));
|
||||
data_string_forget (&data, "dhcprequest");
|
||||
}
|
||||
|
||||
void dhcprelease (packet)
|
||||
@ -502,14 +503,15 @@ void nak_lease (packet, cip)
|
||||
to.sin_addr = raw.giaddr;
|
||||
to.sin_port = local_port;
|
||||
|
||||
#ifdef USE_FALLBACK
|
||||
result = send_fallback (&fallback_interface,
|
||||
packet, &raw, outgoing.packet_length,
|
||||
from, &to, &hto);
|
||||
if (result < 0)
|
||||
warn ("send_fallback: %m");
|
||||
return;
|
||||
#endif
|
||||
if (fallback_interface) {
|
||||
result = send_packet (fallback_interface,
|
||||
packet, &raw,
|
||||
outgoing.packet_length,
|
||||
from, &to, &hto);
|
||||
if (result < 0)
|
||||
warn ("send_fallback: %m");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
|
||||
to.sin_port = remote_port;
|
||||
@ -539,6 +541,7 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
struct option_cache *oc;
|
||||
struct expression *expr;
|
||||
int status;
|
||||
int ulafdr;
|
||||
int option_tag_size = 1; /* XXX */
|
||||
|
||||
int i, j, s1, s2;
|
||||
@ -572,7 +575,7 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
lease -> client_hostname =
|
||||
dmalloc (d1.len + 1, "ack_lease");
|
||||
if (!lease -> client_hostname)
|
||||
warn ("no memory for client hostname.\n");
|
||||
warn ("no memory for client hostname.");
|
||||
else {
|
||||
memcpy (lease -> client_hostname, d1.data, d1.len);
|
||||
lease -> client_hostname [d1.len] = 0;
|
||||
@ -887,7 +890,6 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
|
||||
lt.host = lease -> host;
|
||||
lt.subnet = lease -> subnet;
|
||||
lt.shared_network = lease -> shared_network;
|
||||
lt.billing_class = lease -> billing_class;
|
||||
|
||||
/* 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,
|
||||
SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE))) {
|
||||
i = DHO_ROUTERS;
|
||||
oc = (struct option_cache *)0;
|
||||
if (option_cache_allocate (&oc, "ack_lease")) {
|
||||
if (make_const_data (&oc -> expression,
|
||||
lease -> ip_addr.iabuf,
|
||||
lease -> ip_addr.len, 0, 0)) {
|
||||
oc -> option = dhcp_universe.options [i];
|
||||
save_option (state -> options.dhcp_hash, oc);
|
||||
oc = lookup_option (state -> options.dhcp_hash, i);
|
||||
if (!oc) {
|
||||
oc = (struct option_cache *)0;
|
||||
if (option_cache_allocate (&oc, "ack_lease")) {
|
||||
if (make_const_data (&oc -> expression,
|
||||
lease -> ip_addr.iabuf,
|
||||
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
|
||||
@ -1177,11 +1187,14 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
|
||||
/* If this is a DHCPOFFER, ping the lease address before actually
|
||||
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);
|
||||
add_timeout (cur_time + 1, lease_ping_timeout, lease);
|
||||
++outstanding_pings;
|
||||
} else {
|
||||
lease -> timestamp = cur_time;
|
||||
dhcp_reply (lease);
|
||||
}
|
||||
}
|
||||
@ -1331,38 +1344,39 @@ void dhcp_reply (lease)
|
||||
to.sin_addr = raw.giaddr;
|
||||
to.sin_port = local_port;
|
||||
|
||||
#ifdef USE_FALLBACK
|
||||
result = send_fallback (&fallback_interface,
|
||||
(struct packet *)0,
|
||||
&raw, packet_length,
|
||||
raw.siaddr, &to, &hto);
|
||||
if (result < 0)
|
||||
warn ("send_fallback: %m");
|
||||
if (fallback_interface) {
|
||||
result = send_packet (fallback_interface,
|
||||
(struct packet *)0,
|
||||
&raw, packet_length,
|
||||
raw.siaddr, &to, &hto);
|
||||
if (result < 0)
|
||||
warn ("send_fallback: %m");
|
||||
|
||||
free_lease_state (state, "dhcp_reply fallback 1");
|
||||
lease -> state = (struct lease_state *)0;
|
||||
return;
|
||||
#endif
|
||||
free_lease_state (state, "dhcp_reply fallback 1");
|
||||
lease -> state = (struct lease_state *)0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* 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
|
||||
that client. */
|
||||
} 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_port = remote_port; /* XXX */
|
||||
|
||||
#ifdef USE_FALLBACK
|
||||
result = send_fallback (&fallback_interface,
|
||||
(struct packet *)0,
|
||||
&raw, packet_length,
|
||||
raw.siaddr, &to, &hto);
|
||||
if (result < 0)
|
||||
warn ("send_fallback: %m");
|
||||
free_lease_state (state, "dhcp_reply fallback 1");
|
||||
lease -> state = (struct lease_state *)0;
|
||||
return;
|
||||
#endif
|
||||
if (fallback_interface) {
|
||||
result = send_packet (fallback_interface,
|
||||
(struct packet *)0,
|
||||
&raw, packet_length,
|
||||
raw.siaddr, &to, &hto);
|
||||
if (result < 0)
|
||||
warn ("send_fallback: %m");
|
||||
free_lease_state (state, "dhcp_reply fallback 1");
|
||||
lease -> state = (struct lease_state *)0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, broadcast it on the local network. */
|
||||
} else {
|
||||
@ -1435,12 +1449,14 @@ struct lease *find_lease (packet, share, ours)
|
||||
/* Find the lease matching this uid that's on the
|
||||
network the packet came from (if any). */
|
||||
for (; uid_lease; uid_lease = uid_lease -> n_uid)
|
||||
if (uid_lease -> shared_network == share)
|
||||
if (uid_lease -> subnet -> shared_network ==
|
||||
share)
|
||||
break;
|
||||
fixed_lease = (struct lease *)0;
|
||||
#if defined (DEBUG_FIND_LEASE)
|
||||
note ("Found lease for client identifier: %s.",
|
||||
piaddr (uid_lease -> ip_addr));
|
||||
if (uid_lease)
|
||||
note ("Found lease for client identifier: %s.",
|
||||
piaddr (uid_lease -> ip_addr));
|
||||
#endif
|
||||
if (uid_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
|
||||
(if any). */
|
||||
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)
|
||||
continue;
|
||||
/* 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
|
||||
lease to be abandoned. If so, this request probably came from
|
||||
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.");
|
||||
ip_lease = (struct lease *)0;
|
||||
}
|
||||
@ -1576,7 +1592,8 @@ struct lease *find_lease (packet, share, ours)
|
||||
print_hw_addr (packet -> raw -> htype,
|
||||
packet -> raw -> hlen,
|
||||
packet -> raw -> chaddr),
|
||||
ip_lease -> shared_network -> name);
|
||||
(ip_lease -> subnet ->
|
||||
shared_network -> name));
|
||||
|
||||
/* If the client is REQUESTing the lease, it shouldn't
|
||||
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. */
|
||||
|
||||
if (packet -> packet_type == DHCPREQUEST &&
|
||||
share == uid_lease -> shared_network)
|
||||
share == uid_lease -> subnet -> shared_network)
|
||||
dissociate_lease (uid_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
|
||||
client is now doing dynamic BOOTP (and thus hasn't provided
|
||||
a uid) we let the client get away with it. */
|
||||
if (hw_lease &&
|
||||
hw_lease -> ends >= cur_time &&
|
||||
hw_lease -> uid &&
|
||||
(!have_client_identifier ||
|
||||
hw_lease -> uid_len != client_identifier.len ||
|
||||
memcmp (hw_lease -> uid, client_identifier.data,
|
||||
hw_lease -> uid_len))) {
|
||||
hw_lease = (struct lease *)0;
|
||||
while (hw_lease &&
|
||||
hw_lease -> ends >= cur_time &&
|
||||
hw_lease -> uid &&
|
||||
(!have_client_identifier ||
|
||||
hw_lease -> uid_len != client_identifier.len ||
|
||||
memcmp (hw_lease -> uid, client_identifier.data,
|
||||
hw_lease -> uid_len))) {
|
||||
hw_lease = hw_lease -> n_hw;
|
||||
#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
|
||||
}
|
||||
|
||||
@ -1640,7 +1661,7 @@ struct lease *find_lease (packet, share, ours)
|
||||
|
||||
/* Now eliminate leases that are on the wrong network... */
|
||||
if (ip_lease &&
|
||||
(share != ip_lease -> shared_network)) {
|
||||
(share != ip_lease -> subnet -> shared_network)) {
|
||||
release_lease (ip_lease);
|
||||
ip_lease = (struct lease *)0;
|
||||
#if defined (DEBUG_FIND_LEASE)
|
||||
@ -1648,7 +1669,7 @@ struct lease *find_lease (packet, share, ours)
|
||||
#endif
|
||||
}
|
||||
if (uid_lease &&
|
||||
(share != uid_lease -> shared_network)) {
|
||||
(share != uid_lease -> subnet -> shared_network)) {
|
||||
release_lease (uid_lease);
|
||||
uid_lease = (struct lease *)0;
|
||||
#if defined (DEBUG_FIND_LEASE)
|
||||
@ -1656,7 +1677,7 @@ struct lease *find_lease (packet, share, ours)
|
||||
#endif
|
||||
}
|
||||
if (hw_lease &&
|
||||
(share != hw_lease -> shared_network)) {
|
||||
(share != hw_lease -> subnet -> shared_network)) {
|
||||
release_lease (hw_lease);
|
||||
hw_lease = (struct lease *)0;
|
||||
#if defined (DEBUG_FIND_LEASE)
|
||||
@ -1752,13 +1773,23 @@ struct lease *find_lease (packet, share, ours)
|
||||
note ("Not returning a lease.");
|
||||
#endif
|
||||
|
||||
/* If we find an abandoned lease, take it, but print a
|
||||
warning message, so that if it continues to lose,
|
||||
the administrator will eventually investigate. */
|
||||
if (lease && lease -> flags & ABANDONED_LEASE) {
|
||||
warn ("Reclaiming REQUESTed abandoned IP address %s.\n",
|
||||
/* If we find an abandoned lease, but it's the one the client
|
||||
requested, we assume that previous bugginess on the part
|
||||
of the client, or a server database loss, caused the lease to
|
||||
be abandoned, so we reclaim it and let the client have it. */
|
||||
if (lease && lease -> flags & ABANDONED_LEASE && lease == ip_lease &&
|
||||
packet -> packet_type == DHCPREQUEST) {
|
||||
warn ("Reclaiming REQUESTed abandoned IP address %s.",
|
||||
piaddr (lease -> ip_addr));
|
||||
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;
|
||||
@ -1779,7 +1810,6 @@ struct lease *mockup_lease (packet, share, hp)
|
||||
if (!mock.subnet)
|
||||
return (struct lease *)0;
|
||||
mock.next = mock.prev = (struct lease *)0;
|
||||
mock.shared_network = mock.subnet -> shared_network;
|
||||
mock.host = hp;
|
||||
mock.uid = hp -> client_identifier.data;
|
||||
mock.uid_len = hp -> client_identifier.len;
|
||||
|
Loading…
x
Reference in New Issue
Block a user