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

Fix bug introduced into dhcprequest processing. Fix core dump differently. Store client-supplied hostname. Fix ciaddr copy.

This commit is contained in:
Ted Lemon 1997-05-09 08:27:14 +00:00
parent 00d6d87c9e
commit 44b2e3adb2

View File

@ -42,7 +42,7 @@
#ifndef lint
static char copyright[] =
"$Id: dhcp.c,v 1.46 1997/03/06 20:23:27 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
"$Id: dhcp.c,v 1.47 1997/05/09 08:27:14 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@ -178,8 +178,9 @@ void dhcprequest (packet)
/* Find the lease that matches the address requested by the
client. */
if (packet -> shared_network)
lease = find_lease (packet, packet -> shared_network);
if (subnet)
lease = find_lease (packet, subnet -> shared_network);
else
lease = (struct lease *)0;
@ -192,25 +193,50 @@ void dhcprequest (packet)
? inet_ntoa (packet -> raw -> giaddr)
: packet -> interface -> name);
/* If a client on a given network wants to request a lease on
an address on a different network, NAK it. If the Requested
Address option was used, the protocol says that it must have
been broadcast, so we can trust the source network information.
/* If a client on a given network REQUESTs a lease on an
address on a different network, NAK it. If the Requested
Address option was used, the protocol says that it must
have been broadcast, so we can trust the source network
information.
If ciaddr was specified and Requested Address was not, then
we really only know for sure what network a packet came from
if it came through a BOOTP gateway - if it came through an
IP router, we'll just have to assume that it's cool.
This violates the protocol spec in the case that the client
is in the INIT-REBOOT state and broadcasts a DHCPREQUEST on
the local wire. We're supposed to check ciaddr for
validity in that case, but if the packet was unicast
through a router from a client in the RENEWING state, it
would look exactly the same to us and it would be very
bad to send a DHCPNAK. I think we just have to live with
this. */
if ((packet -> raw -> ciaddr.s_addr &&
If we don't think we know where the packet came from, it
came through a gateway from an unknown network, so it's not
from a RENEWING client. If we recognize the network it
*thinks* it's on, we can NAK it even though we don't
recognize the network it's *actually* on; otherwise we just
have to ignore it.
We don't currently try to take advantage of access to the
raw packet, because it's not available on all platforms.
So a packet that was unicast to us through a router from a
RENEWING client is going to look exactly like a packet that
was broadcast to us from an INIT-REBOOT client.
Since we can't tell the difference between these two kinds
of packets, if the packet appears to have come in off the
local wire, we have to treat it as if it's a RENEWING
client. This means that we can't NAK a RENEWING client on
the local wire that has a bogus address. The good news is
that we won't ACK it either, so it should revert to INIT
state and send us a DHCPDISCOVER, which we *can* work with.
Because we can't detect that a RENEWING client is on the
wrong wire, it's going to sit there trying to renew until
it gets to the REBIND state, when we *can* NAK it because
the packet will get to us through a BOOTP gateway. We
shouldn't actually see DHCPREQUEST packets from RENEWING
clients on the wrong wire anyway, since their idea of their
local router will be wrong. In any case, the protocol
doesn't really allow us to NAK a DHCPREQUEST from a
RENEWING client, so we can punt on this issue. */
if (!packet -> shared_network ||
(packet -> raw -> ciaddr.s_addr &&
packet -> raw -> giaddr.s_addr) ||
packet -> options [DHO_DHCP_REQUESTED_ADDRESS].len) {
@ -226,9 +252,8 @@ void dhcprequest (packet)
return;
}
/* If we do know where it came from and either we don't
know where it came from at all or it came from a different
shared network than the packet came from, send a nak. */
/* If we do know where it came from and it asked for an
address that is not on that shared network, nak it. */
subnet = find_grouped_subnet (packet -> shared_network, cip);
if (!subnet) {
nak_lease (packet, &cip);
@ -430,7 +455,7 @@ void nak_lease (packet, cip)
#endif
} else {
to.sin_addr.s_addr = htonl (INADDR_BROADCAST);
to.sin_port = packet->client_port;
to.sin_port = remote_port;
}
errno = 0;
@ -489,6 +514,31 @@ void ack_lease (packet, lease, offer, when)
user_class = (struct class *)0;
}
/* Replace the old lease hostname with the new one, if it's changed. */
if (packet -> options [DHO_HOST_NAME].len &&
lease -> client_hostname &&
(strlen (lease -> client_hostname) ==
packet -> options [DHO_HOST_NAME].len) &&
!memcmp (lease -> client_hostname,
packet -> options [DHO_HOST_NAME].data,
packet -> options [DHO_HOST_NAME].len)) {
} else if (packet -> options [DHO_HOST_NAME].len) {
if (lease -> client_hostname)
free (lease -> client_hostname);
lease -> client_hostname =
malloc (packet -> options [DHO_HOST_NAME].len + 1);
if (!lease -> client_hostname)
error ("no memory for client hostname.\n");
memcpy (lease -> client_hostname,
packet -> options [DHO_HOST_NAME].data,
packet -> options [DHO_HOST_NAME].len);
lease -> client_hostname
[packet -> options [DHO_HOST_NAME].len] = 0;
} else if (lease -> client_hostname) {
free (lease -> client_hostname);
lease -> client_hostname = 0;
}
/* Choose a filename; first from the host_decl, if any, then from
the user class, then from the vendor class. */
if (lease -> host && lease -> host -> group -> filename)
@ -633,7 +683,7 @@ void ack_lease (packet, lease, offer, when)
/* Remember the giaddr, xid, secs, flags and hops. */
state -> giaddr = packet -> raw -> giaddr;
state -> ciaddr = packet -> raw -> giaddr;
state -> ciaddr = packet -> raw -> ciaddr;
state -> xid = packet -> raw -> xid;
state -> secs = packet -> raw -> secs;
state -> bootp_flags = packet -> raw -> flags;