1995-11-29 07:40:04 +00:00
|
|
|
/* dhcp.c
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
DHCP Protocol engine. */
|
1995-11-29 07:40:04 +00:00
|
|
|
|
|
|
|
/*
|
1999-03-16 05:50:46 +00:00
|
|
|
* Copyright (c) 1996-1999 Internet Software Consortium.
|
|
|
|
* Use is subject to license terms which appear in the file named
|
|
|
|
* ISC-LICENSE that should have accompanied this file when you
|
|
|
|
* received it. If a file named ISC-LICENSE did not accompany this
|
|
|
|
* file, or you are not sure the one you have is correct, you may
|
|
|
|
* obtain an applicable copy of the license at:
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
1999-03-16 05:50:46 +00:00
|
|
|
* http://www.isc.org/isc-license-1.0.html.
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
1999-03-16 05:50:46 +00:00
|
|
|
* This file is part of the ISC DHCP distribution. The documentation
|
|
|
|
* associated with this file is listed in the file DOCUMENTATION,
|
|
|
|
* included in the top-level directory of this release.
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
1999-03-16 05:50:46 +00:00
|
|
|
* Support and other services are available for ISC products - see
|
|
|
|
* http://www.isc.org for more information.
|
1995-11-29 07:40:04 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
static char copyright[] =
|
1999-07-21 14:30:28 +00:00
|
|
|
"$Id: dhcp.c,v 1.104 1999/07/21 14:30:28 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
1995-11-29 07:40:04 +00:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#include "dhcpd.h"
|
|
|
|
|
1997-03-06 18:40:22 +00:00
|
|
|
int outstanding_pings;
|
|
|
|
|
1998-03-16 06:19:46 +00:00
|
|
|
static char dhcp_message [256];
|
1996-02-29 18:16:31 +00:00
|
|
|
|
1995-11-29 07:40:04 +00:00
|
|
|
void dhcp (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1997-02-22 10:22:05 +00:00
|
|
|
if (!locate_network (packet) && packet -> packet_type != DHCPREQUEST)
|
1996-05-22 09:29:56 +00:00
|
|
|
return;
|
|
|
|
|
1998-11-06 02:59:11 +00:00
|
|
|
/* Classify the client. */
|
|
|
|
classify_client (packet);
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
switch (packet -> packet_type) {
|
|
|
|
case DHCPDISCOVER:
|
|
|
|
dhcpdiscover (packet);
|
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
case DHCPREQUEST:
|
|
|
|
dhcprequest (packet);
|
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
case DHCPRELEASE:
|
|
|
|
dhcprelease (packet);
|
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
case DHCPDECLINE:
|
|
|
|
dhcpdecline (packet);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DHCPINFORM:
|
|
|
|
dhcpinform (packet);
|
|
|
|
break;
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
default:
|
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
void dhcpdiscover (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1998-04-19 23:34:43 +00:00
|
|
|
struct lease *lease;
|
1998-11-11 08:01:49 +00:00
|
|
|
char msgbuf [1024];
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1998-11-11 08:01:49 +00:00
|
|
|
sprintf (msgbuf, "DHCPDISCOVER from %s via %s",
|
|
|
|
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));
|
1996-03-16 17:50:30 +00:00
|
|
|
|
1998-04-19 23:34:43 +00:00
|
|
|
lease = find_lease (packet, packet -> shared_network, 0);
|
|
|
|
|
1996-05-23 01:59:38 +00:00
|
|
|
/* Sourceless packets don't make sense here. */
|
|
|
|
if (!packet -> shared_network) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("Packet from unknown subnet: %s",
|
1996-05-23 01:59:38 +00:00
|
|
|
inet_ntoa (packet -> raw -> giaddr));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1996-02-21 12:11:09 +00:00
|
|
|
/* If we didn't find a lease, try to allocate one... */
|
|
|
|
if (!lease) {
|
1998-11-09 02:46:58 +00:00
|
|
|
lease = allocate_lease (packet,
|
|
|
|
packet -> shared_network -> pools, 0);
|
|
|
|
if (!lease) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("no free leases on network %s match %s",
|
1998-11-09 02:46:58 +00:00
|
|
|
packet -> shared_network -> name,
|
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr));
|
1996-02-21 12:11:09 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-11-11 08:01:49 +00:00
|
|
|
ack_lease (packet, lease, DHCPOFFER, cur_time + 120, msgbuf);
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dhcprequest (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1996-05-23 01:59:38 +00:00
|
|
|
struct lease *lease;
|
1996-02-29 18:16:31 +00:00
|
|
|
struct iaddr cip;
|
1996-05-22 07:21:50 +00:00
|
|
|
struct subnet *subnet;
|
1997-06-08 03:55:58 +00:00
|
|
|
int ours = 0;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
|
|
|
struct data_string data;
|
|
|
|
int status;
|
1998-11-11 08:01:49 +00:00
|
|
|
char msgbuf [1024];
|
1998-11-05 18:54:55 +00:00
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_REQUESTED_ADDRESS);
|
|
|
|
memset (&data, 0, sizeof data);
|
|
|
|
if (oc &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&data, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1996-02-29 18:16:31 +00:00
|
|
|
cip.len = 4;
|
1998-11-05 18:54:55 +00:00
|
|
|
memcpy (cip.iabuf, data.data, 4);
|
|
|
|
data_string_forget (&data, "dhcprequest");
|
1996-03-16 17:50:30 +00:00
|
|
|
} else {
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
1996-03-16 17:50:30 +00:00
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
|
|
|
|
}
|
1997-02-22 10:22:05 +00:00
|
|
|
subnet = find_subnet (cip);
|
1996-03-16 17:50:30 +00:00
|
|
|
|
1996-05-23 01:59:38 +00:00
|
|
|
/* Find the lease that matches the address requested by the
|
|
|
|
client. */
|
1997-05-09 08:27:14 +00:00
|
|
|
|
|
|
|
if (subnet)
|
1997-06-08 03:55:58 +00:00
|
|
|
lease = find_lease (packet, subnet -> shared_network, &ours);
|
1997-02-22 10:22:05 +00:00
|
|
|
else
|
|
|
|
lease = (struct lease *)0;
|
1996-05-23 01:59:38 +00:00
|
|
|
|
1998-11-11 08:01:49 +00:00
|
|
|
sprintf (msgbuf, "DHCPREQUEST for %s from %s via %s",
|
|
|
|
piaddr (cip),
|
|
|
|
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));
|
1996-06-01 00:18:15 +00:00
|
|
|
|
1997-05-09 08:27:14 +00:00
|
|
|
/* 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.
|
1996-05-23 01:59:38 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
1997-05-09 08:27:14 +00:00
|
|
|
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 &&
|
1996-05-23 01:59:38 +00:00
|
|
|
packet -> raw -> giaddr.s_addr) ||
|
1999-04-23 23:17:52 +00:00
|
|
|
(oc && !packet -> raw -> ciaddr.s_addr)) {
|
1996-05-23 01:59:38 +00:00
|
|
|
|
|
|
|
/* If we don't know where it came from but we do know
|
|
|
|
where it claims to have come from, it didn't come
|
|
|
|
from there. Fry it. */
|
|
|
|
if (!packet -> shared_network) {
|
1999-02-14 19:27:56 +00:00
|
|
|
if (subnet && subnet -> group -> authoritative) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: wrong network.", msgbuf);
|
1996-05-23 01:59:38 +00:00
|
|
|
nak_lease (packet, &cip);
|
|
|
|
return;
|
|
|
|
}
|
1996-08-27 09:37:50 +00:00
|
|
|
/* Otherwise, ignore it. */
|
1999-03-09 23:45:04 +00:00
|
|
|
log_info ("%s: ignored.", msgbuf);
|
1996-08-27 09:37:50 +00:00
|
|
|
return;
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
1996-05-23 01:59:38 +00:00
|
|
|
|
1997-05-09 08:27:14 +00:00
|
|
|
/* If we do know where it came from and it asked for an
|
|
|
|
address that is not on that shared network, nak it. */
|
1996-05-22 07:21:50 +00:00
|
|
|
subnet = find_grouped_subnet (packet -> shared_network, cip);
|
|
|
|
if (!subnet) {
|
1999-02-14 19:27:56 +00:00
|
|
|
if (packet -> shared_network -> group -> authoritative)
|
|
|
|
{
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: wrong network.", msgbuf);
|
1999-02-14 19:27:56 +00:00
|
|
|
nak_lease (packet, &cip);
|
1999-03-09 23:45:04 +00:00
|
|
|
return;
|
1999-02-14 19:27:56 +00:00
|
|
|
}
|
1999-03-09 23:45:04 +00:00
|
|
|
log_info ("%s: ignored.", msgbuf);
|
1996-02-29 18:16:31 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1997-12-06 04:04:50 +00:00
|
|
|
/* If the address the client asked for is ours, but it wasn't
|
|
|
|
available for the client, NAK it. */
|
|
|
|
if (!lease && ours) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: lease %s unavailable.", msgbuf, piaddr (cip));
|
1997-12-06 04:04:50 +00:00
|
|
|
nak_lease (packet, &cip);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1999-06-22 13:28:12 +00:00
|
|
|
/* Otherwise, send the lease to the client if we found one. */
|
1999-03-09 23:45:04 +00:00
|
|
|
if (lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
ack_lease (packet, lease, DHCPACK, 0, msgbuf);
|
1999-03-09 23:45:04 +00:00
|
|
|
} else
|
1999-02-25 23:30:43 +00:00
|
|
|
log_info ("%s: unknown lease %s.", msgbuf, piaddr (cip));
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dhcprelease (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1997-06-08 03:55:58 +00:00
|
|
|
struct lease *lease;
|
1997-06-08 03:58:47 +00:00
|
|
|
struct iaddr cip;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
|
|
|
struct data_string data;
|
1997-06-08 03:55:58 +00:00
|
|
|
|
1997-11-29 07:57:02 +00:00
|
|
|
/* DHCPRELEASE must not specify address in requested-address
|
|
|
|
option, but old protocol specs weren't explicit about this,
|
|
|
|
so let it go. */
|
1999-04-05 16:46:13 +00:00
|
|
|
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_REQUESTED_ADDRESS))) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("DHCPRELEASE from %s specified requested-address.",
|
1997-11-29 07:57:02 +00:00
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr));
|
1997-06-08 03:55:58 +00:00
|
|
|
}
|
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
memset (&data, 0, sizeof data);
|
|
|
|
if (oc &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&data, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
lease = find_lease_by_uid (data.data, data.len);
|
|
|
|
data_string_forget (&data, "dhcprelease");
|
1997-11-29 07:57:02 +00:00
|
|
|
} else
|
|
|
|
lease = (struct lease *)0;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1997-11-29 07:57:02 +00:00
|
|
|
/* 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. */
|
|
|
|
if (!lease) {
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
|
|
|
lease = find_lease_by_ip_addr (cip);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("DHCPRELEASE of %s from %s via %s (%sfound)",
|
1996-05-22 07:21:50 +00:00
|
|
|
inet_ntoa (packet -> raw -> ciaddr),
|
1996-05-16 07:52:49 +00:00
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
1996-06-01 00:18:15 +00:00
|
|
|
packet -> raw -> chaddr),
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
1997-11-29 07:57:02 +00:00
|
|
|
: packet -> interface -> name,
|
|
|
|
lease ? "" : "not ");
|
1996-03-16 17:50:30 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* If we found a lease, release it. */
|
1996-02-26 01:56:15 +00:00
|
|
|
if (lease) {
|
1999-07-19 01:15:22 +00:00
|
|
|
#if defined (NSUPDATE) && 0
|
1999-07-01 19:58:12 +00:00
|
|
|
nsupdate (lease, lease -> state, packet, DELETE);
|
|
|
|
#endif
|
1999-07-18 19:39:14 +00:00
|
|
|
/* If there are statements to execute when the lease is
|
|
|
|
committed, execute them. */
|
|
|
|
if (lease -> on_release) {
|
|
|
|
execute_statements (packet, lease, packet -> options,
|
1999-07-19 01:15:22 +00:00
|
|
|
(struct option_state *)0, /* XXX */
|
1999-07-18 19:39:14 +00:00
|
|
|
lease -> on_release);
|
|
|
|
executable_statement_dereference (&lease -> on_release,
|
|
|
|
"dhcprelease");
|
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
release_lease (lease);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
void dhcpdecline (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1997-06-08 03:55:58 +00:00
|
|
|
struct lease *lease;
|
1996-03-16 17:50:30 +00:00
|
|
|
struct iaddr cip;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
|
|
|
struct data_string data;
|
1996-03-16 17:50:30 +00:00
|
|
|
|
1997-06-08 03:55:58 +00:00
|
|
|
/* DHCPDECLINE must specify address. */
|
1999-04-05 16:46:13 +00:00
|
|
|
if (!(oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_REQUESTED_ADDRESS)))
|
|
|
|
return;
|
|
|
|
memset (&data, 0, sizeof data);
|
1999-07-02 20:58:48 +00:00
|
|
|
if (!evaluate_option_cache (&data, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc))
|
1997-06-08 03:55:58 +00:00
|
|
|
return;
|
1996-03-16 17:50:30 +00:00
|
|
|
|
1997-06-08 03:55:58 +00:00
|
|
|
cip.len = 4;
|
1998-11-05 18:54:55 +00:00
|
|
|
memcpy (cip.iabuf, data.data, 4);
|
|
|
|
data_string_forget (&data, "dhcpdecline");
|
1997-06-08 03:55:58 +00:00
|
|
|
lease = find_lease_by_ip_addr (cip);
|
|
|
|
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("DHCPDECLINE on %s from %s via %s",
|
1996-05-22 07:21:50 +00:00
|
|
|
piaddr (cip),
|
1996-05-16 07:52:49 +00:00
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
1996-06-01 00:18:15 +00:00
|
|
|
packet -> raw -> chaddr),
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name);
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* If we found a lease, mark it as unusable and complain. */
|
|
|
|
if (lease) {
|
1997-03-06 18:40:22 +00:00
|
|
|
abandon_lease (lease, "declined.");
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dhcpinform (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
1999-04-12 22:18:58 +00:00
|
|
|
char msgbuf [1024];
|
|
|
|
struct data_string d1, prl;
|
|
|
|
struct option_cache *oc;
|
|
|
|
struct expression *expr;
|
|
|
|
struct option_state *options = (struct option_state *)0;
|
|
|
|
struct dhcp_packet raw;
|
|
|
|
struct packet outgoing;
|
1999-07-13 18:00:22 +00:00
|
|
|
unsigned char dhcpack = DHCPACK;
|
1999-04-12 22:18:58 +00:00
|
|
|
struct subnet *subnet;
|
|
|
|
struct iaddr cip;
|
|
|
|
int i, j, nulltp;
|
|
|
|
struct sockaddr_in to;
|
|
|
|
struct in_addr from;
|
|
|
|
|
1999-05-06 20:35:48 +00:00
|
|
|
/* The client should set ciaddr to its IP address, but apparently
|
|
|
|
it's common for clients not to do this, so we'll use their IP
|
|
|
|
source address if they didn't set ciaddr. */
|
|
|
|
if (!packet -> raw -> ciaddr.s_addr) {
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> client_addr, 4);
|
|
|
|
} else {
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
|
|
|
}
|
|
|
|
|
1999-04-12 22:18:58 +00:00
|
|
|
sprintf (msgbuf, "DHCPINFORM from %s via %s",
|
1999-05-06 20:35:48 +00:00
|
|
|
piaddr (cip), packet -> interface -> name);
|
|
|
|
|
|
|
|
/* If the IP source address is zero, don't respond. */
|
|
|
|
if (!memcmp (cip.iabuf, "\0\0\0", 4)) {
|
|
|
|
log_info ("%s: ignored.", msgbuf);
|
|
|
|
return;
|
|
|
|
}
|
1999-04-12 22:18:58 +00:00
|
|
|
|
|
|
|
/* Find the subnet that the client is on. */
|
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
subnet = find_subnet (cip);
|
|
|
|
|
|
|
|
/* Sourceless packets don't make sense here. */
|
|
|
|
if (!subnet) {
|
|
|
|
log_info ("%s: unknown subnet %s",
|
|
|
|
msgbuf, inet_ntoa (packet -> raw -> giaddr));
|
|
|
|
}
|
|
|
|
|
|
|
|
memset (&d1, 0, sizeof d1);
|
|
|
|
option_state_allocate (&options, "dhcpinform");
|
|
|
|
memset (&outgoing, 0, sizeof outgoing);
|
|
|
|
memset (&raw, 0, sizeof raw);
|
|
|
|
outgoing.raw = &raw;
|
|
|
|
|
|
|
|
/* Execute statements in scope starting with the subnet scope. */
|
1999-04-23 23:17:52 +00:00
|
|
|
if (subnet)
|
1999-07-02 20:58:48 +00:00
|
|
|
execute_statements_in_scope (packet, (struct lease *)0,
|
|
|
|
packet -> options,
|
1999-04-23 23:17:52 +00:00
|
|
|
options, subnet -> group,
|
|
|
|
(struct group *)0);
|
1999-04-12 22:18:58 +00:00
|
|
|
|
|
|
|
/* Execute statements in the class scopes. */
|
|
|
|
for (i = packet -> class_count; i > 0; i--) {
|
|
|
|
execute_statements_in_scope
|
1999-07-02 20:58:48 +00:00
|
|
|
(packet, (struct lease *)0, packet -> options,
|
1999-04-12 22:18:58 +00:00
|
|
|
options, packet -> classes [i - 1] -> group,
|
1999-04-23 23:17:52 +00:00
|
|
|
subnet ? subnet -> group : (struct group *)0);
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out the filename. */
|
1999-05-06 20:35:48 +00:00
|
|
|
memset (&d1, 0, sizeof d1);
|
1999-04-12 22:18:58 +00:00
|
|
|
oc = lookup_option (&server_universe, options, SV_FILENAME);
|
1999-07-02 20:58:48 +00:00
|
|
|
if (oc && evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
i = d1.len;
|
|
|
|
if (i > sizeof raw.file)
|
|
|
|
i = sizeof raw.file;
|
|
|
|
else
|
|
|
|
raw.file [i] = 0;
|
|
|
|
memcpy (raw.file, d1.data, i);
|
1999-05-06 20:35:48 +00:00
|
|
|
data_string_forget (&d1, "dhcpinform");
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Choose a server name as above. */
|
1999-04-23 23:17:52 +00:00
|
|
|
oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
|
1999-07-02 20:58:48 +00:00
|
|
|
if (oc && evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
i = d1.len;
|
|
|
|
if (i > sizeof raw.sname)
|
|
|
|
i = sizeof raw.sname;
|
|
|
|
else
|
|
|
|
raw.sname [i] = 0;
|
|
|
|
memcpy (raw.sname, d1.data, i);
|
1999-05-06 20:35:48 +00:00
|
|
|
data_string_forget (&d1, "dhcpinform");
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set a flag if this client is a lame Microsoft client that NUL
|
|
|
|
terminates string options and expects us to do likewise. */
|
|
|
|
nulltp = 0;
|
|
|
|
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_HOST_NAME))) {
|
1999-07-02 20:58:48 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
if (d1.data [d1.len - 1] == '\0')
|
|
|
|
nulltp = 1;
|
|
|
|
data_string_forget (&d1, "dhcpinform");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Put in DHCP-specific options. */
|
|
|
|
i = DHO_DHCP_MESSAGE_TYPE;
|
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "dhcpinform")) {
|
|
|
|
if (make_const_data (&oc -> expression, &dhcpack, 1, 0, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
|
|
|
save_option (&dhcp_universe, options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "dhcpinform");
|
|
|
|
}
|
|
|
|
|
|
|
|
i = DHO_DHCP_SERVER_IDENTIFIER;
|
|
|
|
if (!(oc = lookup_option (&dhcp_universe, options, i))) {
|
|
|
|
use_primary:
|
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "dhcpinform")) {
|
|
|
|
if (make_const_data
|
|
|
|
(&oc -> expression,
|
|
|
|
((unsigned char *)
|
|
|
|
&packet -> interface -> primary_address),
|
|
|
|
sizeof packet -> interface -> primary_address,
|
|
|
|
0, 0)) {
|
|
|
|
oc -> option =
|
|
|
|
dhcp_universe.options [i];
|
|
|
|
save_option (&dhcp_universe,
|
|
|
|
options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "dhcpinform");
|
|
|
|
}
|
|
|
|
from = packet -> interface -> primary_address;
|
|
|
|
} else {
|
1999-07-02 20:58:48 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-05-06 20:35:48 +00:00
|
|
|
if (!d1.len || d1.len != sizeof from) {
|
|
|
|
data_string_forget (&d1, "dhcpinform");
|
1999-04-12 22:18:58 +00:00
|
|
|
goto use_primary;
|
1999-05-06 20:35:48 +00:00
|
|
|
}
|
1999-04-12 22:18:58 +00:00
|
|
|
memcpy (&from, d1.data, sizeof from);
|
|
|
|
data_string_forget (&d1, "dhcpinform");
|
|
|
|
} else
|
|
|
|
goto use_primary;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use the subnet mask from the subnet declaration if no other
|
|
|
|
mask has been provided. */
|
|
|
|
i = DHO_SUBNET_MASK;
|
1999-04-23 23:17:52 +00:00
|
|
|
if (subnet && !lookup_option (&dhcp_universe, options, i)) {
|
1999-05-06 20:35:48 +00:00
|
|
|
oc = (struct option_cache *)0;
|
1999-04-12 22:18:58 +00:00
|
|
|
if (option_cache_allocate (&oc, "dhcpinform")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
subnet -> netmask.iabuf,
|
|
|
|
subnet -> netmask.len, 0, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
|
|
|
save_option (&dhcp_universe, options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "dhcpinform");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we've been given a vendor option space, and there's something
|
|
|
|
in it, and we weren't given a vendor-encapsulated-options option,
|
|
|
|
then cons one up. */
|
|
|
|
i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
|
|
|
|
j = SV_VENDOR_OPTION_SPACE;
|
|
|
|
if (!lookup_option (&dhcp_universe, options, i) &&
|
|
|
|
(oc = lookup_option (&server_universe, options, j)) &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "dhcpinform")) {
|
|
|
|
if (make_encapsulation (&oc -> expression, &d1)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
|
|
|
save_option (&dhcp_universe, options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "dhcpinform");
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, "dhcpinform");
|
|
|
|
}
|
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* If a site option space has been specified, use that for
|
|
|
|
site option codes. */
|
|
|
|
i = SV_SITE_OPTION_SPACE;
|
1999-05-27 14:56:51 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, options, i)) &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet,
|
|
|
|
packet -> options, (struct lease *)0, oc)) {
|
1999-04-23 23:17:52 +00:00
|
|
|
struct universe *u;
|
|
|
|
|
|
|
|
u = ((struct universe *)
|
|
|
|
hash_lookup (&universe_hash, d1.data, d1.len));
|
|
|
|
if (!u) {
|
|
|
|
log_error ("unknown option space %s.", d1.data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
options -> site_universe = u -> index;
|
|
|
|
options -> site_code_min = 128; /* XXX */
|
|
|
|
data_string_forget (&d1, "dhcpinform");
|
|
|
|
} else {
|
|
|
|
options -> site_universe = dhcp_universe.index;
|
|
|
|
options -> site_code_min = 0; /* Trust me, it works. */
|
|
|
|
}
|
|
|
|
|
1999-05-06 20:35:48 +00:00
|
|
|
memset (&prl, 0, sizeof prl);
|
1999-05-07 17:40:26 +00:00
|
|
|
|
|
|
|
/* Use the parameter list from the scope if there is one. */
|
|
|
|
oc = lookup_option (&dhcp_universe, options,
|
1999-04-12 22:18:58 +00:00
|
|
|
DHO_DHCP_PARAMETER_REQUEST_LIST);
|
|
|
|
|
1999-05-07 17:40:26 +00:00
|
|
|
/* Otherwise, if the client has provided a list of options
|
|
|
|
that it wishes returned, use it to prioritize. Otherwise,
|
|
|
|
prioritize based on the default priority list. */
|
|
|
|
|
1999-05-06 20:35:48 +00:00
|
|
|
if (!oc)
|
1999-05-07 17:40:26 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1999-05-06 20:35:48 +00:00
|
|
|
DHO_DHCP_PARAMETER_REQUEST_LIST);
|
|
|
|
|
|
|
|
if (oc)
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&prl, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc);
|
1999-04-12 22:18:58 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_PACKET
|
|
|
|
dump_packet (packet);
|
|
|
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
log_info ("%s", msgbuf);
|
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* Figure out the address of the boot file server. */
|
|
|
|
raw.siaddr = from;
|
|
|
|
if ((oc =
|
|
|
|
lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
|
1999-07-02 20:58:48 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-04-23 23:17:52 +00:00
|
|
|
/* If there was more than one answer,
|
|
|
|
take the first. */
|
|
|
|
if (d1.len >= 4 && d1.data)
|
|
|
|
memcpy (&raw.siaddr, d1.data, 4);
|
|
|
|
data_string_forget (&d1, "dhcpinform");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-12 22:18:58 +00:00
|
|
|
/* Set up the option buffer... */
|
|
|
|
outgoing.packet_length =
|
1999-07-02 20:58:48 +00:00
|
|
|
cons_options (packet, outgoing.raw, (struct lease *)0,
|
|
|
|
0, options, 0, nulltp, 0,
|
1999-04-12 22:18:58 +00:00
|
|
|
prl.len ? &prl : (struct data_string *)0);
|
|
|
|
option_state_dereference (&options, "dhcpinform");
|
1999-05-06 20:35:48 +00:00
|
|
|
data_string_forget (&prl, "dhcpinform");
|
1999-04-12 22:18:58 +00:00
|
|
|
|
|
|
|
/* Make sure that the packet is at least as big as a BOOTP packet. */
|
|
|
|
if (outgoing.packet_length < BOOTP_MIN_LEN)
|
|
|
|
outgoing.packet_length = BOOTP_MIN_LEN;
|
|
|
|
|
|
|
|
raw.giaddr = packet -> raw -> giaddr;
|
1999-05-06 20:35:48 +00:00
|
|
|
raw.ciaddr = packet -> raw -> ciaddr;
|
1999-04-12 22:18:58 +00:00
|
|
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
|
|
|
raw.hlen = packet -> raw -> hlen;
|
|
|
|
raw.htype = packet -> raw -> htype;
|
|
|
|
|
|
|
|
raw.xid = packet -> raw -> xid;
|
|
|
|
raw.secs = packet -> raw -> secs;
|
|
|
|
raw.flags = packet -> raw -> flags;
|
|
|
|
raw.hops = packet -> raw -> hops;
|
|
|
|
raw.op = BOOTREPLY;
|
|
|
|
|
|
|
|
/* Report what we're sending... */
|
|
|
|
log_info ("DHCPACK to %s", inet_ntoa (raw.ciaddr));
|
|
|
|
|
|
|
|
#ifdef DEBUG_PACKET
|
|
|
|
dump_packet (&outgoing);
|
|
|
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Set up the common stuff... */
|
|
|
|
to.sin_family = AF_INET;
|
|
|
|
#ifdef HAVE_SA_LEN
|
|
|
|
to.sin_len = sizeof to;
|
|
|
|
#endif
|
|
|
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
|
|
|
|
1999-07-06 17:09:03 +00:00
|
|
|
/* Use the IP address we derived for the client. */
|
1999-05-06 20:35:48 +00:00
|
|
|
memcpy (&to.sin_addr, cip.iabuf, 4);
|
1999-04-12 22:18:58 +00:00
|
|
|
to.sin_port = remote_port;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
send_packet ((fallback_interface
|
|
|
|
? fallback_interface : packet -> interface),
|
|
|
|
&outgoing, &raw, outgoing.packet_length,
|
|
|
|
from, &to, (struct hardware *)0);
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
|
|
|
|
1996-03-16 17:50:30 +00:00
|
|
|
void nak_lease (packet, cip)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
1996-03-16 17:50:30 +00:00
|
|
|
struct iaddr *cip;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_in to;
|
1996-08-27 09:37:50 +00:00
|
|
|
struct in_addr from;
|
1996-02-26 01:56:15 +00:00
|
|
|
int result;
|
|
|
|
struct dhcp_packet raw;
|
|
|
|
unsigned char nak = DHCPNAK;
|
|
|
|
struct packet outgoing;
|
1996-05-12 23:55:27 +00:00
|
|
|
struct hardware hto;
|
1998-06-25 03:56:24 +00:00
|
|
|
int i;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct data_string data;
|
1999-04-05 16:46:13 +00:00
|
|
|
struct option_state *options = (struct option_state *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct expression *expr;
|
|
|
|
struct option_cache *oc = (struct option_cache *)0;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
option_state_allocate (&options, "nak_lease");
|
1996-02-26 01:56:15 +00:00
|
|
|
memset (&outgoing, 0, sizeof outgoing);
|
|
|
|
memset (&raw, 0, sizeof raw);
|
|
|
|
outgoing.raw = &raw;
|
|
|
|
|
|
|
|
/* Set DHCP_MESSAGE_TYPE to DHCPNAK */
|
1998-11-05 18:54:55 +00:00
|
|
|
if (!option_cache_allocate (&oc, "nak_lease")) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for DHCPNAK message type.");
|
1999-04-05 16:46:13 +00:00
|
|
|
option_state_dereference (&options, "nak_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!make_const_data (&oc -> expression, &nak, sizeof nak, 0, 0)) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for expr_const expression.");
|
1998-11-05 18:54:55 +00:00
|
|
|
option_cache_dereference (&oc, "nak_lease");
|
1999-04-05 16:46:13 +00:00
|
|
|
option_state_dereference (&options, "nak_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
oc -> option = dhcp_universe.options [DHO_DHCP_MESSAGE_TYPE];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe, options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
option_cache_dereference (&oc, "nak_lease");
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* Set DHCP_MESSAGE to whatever the message is */
|
1998-11-05 18:54:55 +00:00
|
|
|
if (!option_cache_allocate (&oc, "nak_lease")) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for DHCPNAK message type.");
|
1999-04-05 16:46:13 +00:00
|
|
|
option_state_dereference (&options, "nak_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!make_const_data (&oc -> expression,
|
1999-03-16 06:37:55 +00:00
|
|
|
(unsigned char *)dhcp_message,
|
|
|
|
strlen (dhcp_message), 1, 0)) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for expr_const expression.");
|
1998-11-05 18:54:55 +00:00
|
|
|
option_cache_dereference (&oc, "nak_lease");
|
1999-04-05 16:46:13 +00:00
|
|
|
option_state_dereference (&options, "nak_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
oc -> option = dhcp_universe.options [DHO_DHCP_MESSAGE];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe, options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
option_cache_dereference (&oc, "nak_lease");
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* Do not use the client's requested parameter list. */
|
1999-04-05 16:46:13 +00:00
|
|
|
delete_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_PARAMETER_REQUEST_LIST);
|
1996-02-29 18:16:31 +00:00
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
/* Set up the option buffer... */
|
1997-02-18 14:28:54 +00:00
|
|
|
outgoing.packet_length =
|
1999-07-02 20:58:48 +00:00
|
|
|
cons_options (packet, outgoing.raw, (struct lease *)0,
|
|
|
|
0, options, 0, 0, 0,
|
1999-03-10 20:44:22 +00:00
|
|
|
(struct data_string *)0);
|
1999-04-05 16:46:13 +00:00
|
|
|
option_state_dereference (&options, "nak_lease");
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
1997-02-22 08:48:15 +00:00
|
|
|
raw.siaddr = packet -> interface -> primary_address;
|
1996-02-26 01:56:15 +00:00
|
|
|
raw.giaddr = packet -> raw -> giaddr;
|
1996-02-29 18:16:31 +00:00
|
|
|
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
|
|
|
raw.hlen = packet -> raw -> hlen;
|
|
|
|
raw.htype = packet -> raw -> htype;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
|
|
|
raw.xid = packet -> raw -> xid;
|
|
|
|
raw.secs = packet -> raw -> secs;
|
1996-02-29 18:16:31 +00:00
|
|
|
raw.flags = packet -> raw -> flags | htons (BOOTP_BROADCAST);
|
1996-02-26 01:56:15 +00:00
|
|
|
raw.hops = packet -> raw -> hops;
|
|
|
|
raw.op = BOOTREPLY;
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Report what we're sending... */
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("DHCPNAK on %s to %s via %s",
|
1996-05-22 07:21:50 +00:00
|
|
|
piaddr (*cip),
|
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
1996-06-01 00:18:15 +00:00
|
|
|
packet -> raw -> chaddr),
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name);
|
|
|
|
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_PACKET
|
|
|
|
dump_packet (packet);
|
|
|
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
|
|
|
dump_packet (&outgoing);
|
|
|
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
hto.htype = packet -> raw -> htype;
|
|
|
|
hto.hlen = packet -> raw -> hlen;
|
|
|
|
memcpy (hto.haddr, packet -> raw -> chaddr, hto.hlen);
|
|
|
|
|
|
|
|
/* Set up the common stuff... */
|
|
|
|
to.sin_family = AF_INET;
|
|
|
|
#ifdef HAVE_SA_LEN
|
|
|
|
to.sin_len = sizeof to;
|
|
|
|
#endif
|
|
|
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
|
|
|
|
1997-02-22 08:48:15 +00:00
|
|
|
from = packet -> interface -> primary_address;
|
1996-08-27 09:37:50 +00:00
|
|
|
|
1997-03-05 06:37:05 +00:00
|
|
|
/* Make sure that the packet is at least as big as a BOOTP packet. */
|
|
|
|
if (outgoing.packet_length < BOOTP_MIN_LEN)
|
|
|
|
outgoing.packet_length = BOOTP_MIN_LEN;
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* If this was gatewayed, send it back to the gateway.
|
|
|
|
Otherwise, broadcast it on the local network. */
|
|
|
|
if (raw.giaddr.s_addr) {
|
1996-02-26 01:56:15 +00:00
|
|
|
to.sin_addr = raw.giaddr;
|
1997-02-18 14:28:54 +00:00
|
|
|
to.sin_port = local_port;
|
1996-05-22 07:21:50 +00:00
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
if (fallback_interface) {
|
|
|
|
result = send_packet (fallback_interface,
|
|
|
|
packet, &raw,
|
|
|
|
outgoing.packet_length,
|
|
|
|
from, &to, &hto);
|
|
|
|
return;
|
|
|
|
}
|
1996-02-29 18:16:31 +00:00
|
|
|
} else {
|
1999-07-06 17:09:03 +00:00
|
|
|
to.sin_addr = limited_broadcast;
|
1997-05-09 08:27:14 +00:00
|
|
|
to.sin_port = remote_port;
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
|
|
|
errno = 0;
|
1996-05-12 23:55:27 +00:00
|
|
|
result = send_packet (packet -> interface,
|
|
|
|
packet, &raw, outgoing.packet_length,
|
1996-08-27 09:37:50 +00:00
|
|
|
from, &to, (struct hardware *)0);
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
1998-11-11 08:01:49 +00:00
|
|
|
void ack_lease (packet, lease, offer, when, msg)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
|
|
|
struct lease *lease;
|
1998-03-16 06:19:46 +00:00
|
|
|
unsigned int offer;
|
1996-02-26 01:56:15 +00:00
|
|
|
TIME when;
|
1998-11-11 08:01:49 +00:00
|
|
|
char *msg;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
|
|
|
struct lease lt;
|
1997-03-06 07:02:00 +00:00
|
|
|
struct lease_state *state;
|
1996-02-26 01:56:15 +00:00
|
|
|
TIME lease_time;
|
1996-09-05 23:52:10 +00:00
|
|
|
TIME offered_lease_time;
|
1998-06-25 03:56:24 +00:00
|
|
|
struct data_string d1;
|
1999-03-09 23:45:04 +00:00
|
|
|
TIME min_lease_time;
|
|
|
|
TIME max_lease_time;
|
|
|
|
TIME default_lease_time;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
|
|
|
struct expression *expr;
|
|
|
|
int status;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
int i, j, s1, s2;
|
1998-06-25 03:56:24 +00:00
|
|
|
int val;
|
1996-02-29 18:16:31 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
/* If we're already acking this lease, don't do it again. */
|
1998-11-11 08:01:49 +00:00
|
|
|
if (lease -> state)
|
1997-03-06 07:02:00 +00:00
|
|
|
return;
|
|
|
|
|
1997-09-16 18:20:30 +00:00
|
|
|
/* Allocate a lease state structure... */
|
|
|
|
state = new_lease_state ("ack_lease");
|
|
|
|
if (!state)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("unable to allocate lease state!");
|
1999-05-06 20:35:48 +00:00
|
|
|
state -> got_requested_address = packet -> got_requested_address;
|
|
|
|
state -> shared_network = packet -> interface -> shared_network;
|
|
|
|
|
|
|
|
/* See if we got a server identifier option. */
|
|
|
|
if (lookup_option (&dhcp_universe,
|
|
|
|
packet -> options, DHO_DHCP_SERVER_IDENTIFIER))
|
|
|
|
state -> got_server_identifier = 1;
|
1997-09-16 18:20:30 +00:00
|
|
|
|
1997-05-09 08:27:14 +00:00
|
|
|
/* Replace the old lease hostname with the new one, if it's changed. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME);
|
1998-11-05 18:54:55 +00:00
|
|
|
memset (&d1, 0, sizeof d1);
|
|
|
|
if (oc)
|
1999-07-02 20:58:48 +00:00
|
|
|
s1 = evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
if (oc && status &&
|
1997-05-09 08:27:14 +00:00
|
|
|
lease -> client_hostname &&
|
1998-11-05 18:54:55 +00:00
|
|
|
strlen (lease -> client_hostname) == d1.len &&
|
|
|
|
!memcmp (lease -> client_hostname, d1.data, d1.len)) {
|
|
|
|
/* Hasn't changed. */
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
} else if (oc && s1) {
|
1997-05-09 08:27:14 +00:00
|
|
|
if (lease -> client_hostname)
|
1998-11-05 18:54:55 +00:00
|
|
|
dfree (lease -> client_hostname, "ack_lease");
|
1997-05-09 08:27:14 +00:00
|
|
|
lease -> client_hostname =
|
1998-11-05 18:54:55 +00:00
|
|
|
dmalloc (d1.len + 1, "ack_lease");
|
1997-05-09 08:27:14 +00:00
|
|
|
if (!lease -> client_hostname)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("no memory for client hostname.");
|
1998-11-05 18:54:55 +00:00
|
|
|
else {
|
|
|
|
memcpy (lease -> client_hostname, d1.data, d1.len);
|
|
|
|
lease -> client_hostname [d1.len] = 0;
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1997-05-09 08:27:14 +00:00
|
|
|
} else if (lease -> client_hostname) {
|
1998-11-05 18:54:55 +00:00
|
|
|
dfree (lease -> client_hostname, "ack_lease");
|
1997-05-09 08:27:14 +00:00
|
|
|
lease -> client_hostname = 0;
|
|
|
|
}
|
|
|
|
|
1998-06-25 03:56:24 +00:00
|
|
|
/* Steal the agent options from the packet. */
|
1999-04-05 16:46:13 +00:00
|
|
|
if (packet -> options -> universes [agent_universe.index]) {
|
|
|
|
state -> options -> universes [agent_universe.index] =
|
|
|
|
packet -> options -> universes [agent_universe.index];
|
|
|
|
packet -> options -> universes [agent_universe.index] =
|
|
|
|
(struct agent_options *)0;
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* Execute statements in scope starting with the subnet scope. */
|
1999-07-02 20:58:48 +00:00
|
|
|
execute_statements_in_scope (packet, lease,
|
|
|
|
packet -> options,
|
1999-04-05 16:46:13 +00:00
|
|
|
state -> options,
|
1999-03-10 21:32:59 +00:00
|
|
|
lease -> subnet -> group,
|
1998-06-25 03:56:24 +00:00
|
|
|
(struct group *)0);
|
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* If the lease is from a pool, run the pool scope. */
|
|
|
|
if (lease -> pool)
|
1999-07-02 20:58:48 +00:00
|
|
|
execute_statements_in_scope (packet, lease,
|
|
|
|
packet -> options,
|
1999-04-23 23:17:52 +00:00
|
|
|
state -> options,
|
|
|
|
lease -> pool -> group,
|
|
|
|
lease -> subnet -> group);
|
|
|
|
|
|
|
|
/* Execute statements from class scopes. */
|
1999-06-10 00:36:27 +00:00
|
|
|
for (i = packet -> class_count; i > 0; i--) {
|
|
|
|
execute_statements_in_scope
|
1999-07-02 20:58:48 +00:00
|
|
|
(packet, lease, packet -> options, state -> options,
|
1999-06-10 00:36:27 +00:00
|
|
|
packet -> classes [i - 1] -> group,
|
|
|
|
(lease -> pool
|
|
|
|
? lease -> pool -> group
|
|
|
|
: lease -> subnet -> group));
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If we have a host_decl structure, run the options associated
|
|
|
|
with its group. */
|
|
|
|
if (lease -> host)
|
1999-07-02 20:58:48 +00:00
|
|
|
execute_statements_in_scope (packet, lease, packet -> options,
|
1999-04-05 16:46:13 +00:00
|
|
|
state -> options,
|
1998-06-25 03:56:24 +00:00
|
|
|
lease -> host -> group,
|
1999-02-25 23:30:43 +00:00
|
|
|
(lease -> pool
|
|
|
|
? lease -> pool -> group
|
|
|
|
: lease -> subnet -> group));
|
1999-07-18 19:39:14 +00:00
|
|
|
|
1999-07-02 17:10:51 +00:00
|
|
|
/* See if the client is only supposed to have one lease at a time,
|
|
|
|
and if so, find its other leases and release them. We can only
|
|
|
|
do this on DHCPREQUEST. It's a little weird to do this before
|
|
|
|
looking at permissions, because the client might not actually
|
|
|
|
_get_ a lease after we've done the permission check, but the
|
|
|
|
assumption for this option is that the client has exactly one
|
|
|
|
network interface, and will only ever remember one lease. So
|
|
|
|
if it sends a DHCPREQUEST, and doesn't get the lease, it's already
|
|
|
|
forgotten about its old lease, so we can too. */
|
|
|
|
if (offer == DHCPREQUEST &&
|
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_ONE_LEASE_PER_CLIENT)) &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_boolean_option_cache (packet,
|
|
|
|
packet -> options, lease, oc)) {
|
1999-07-02 17:10:51 +00:00
|
|
|
struct lease *seek;
|
|
|
|
if (lease -> uid_len) {
|
|
|
|
do {
|
|
|
|
seek = find_lease_by_uid (lease -> uid,
|
|
|
|
lease -> uid_len);
|
1999-07-02 17:47:42 +00:00
|
|
|
/* Don't release expired leases, and don't
|
|
|
|
release the lease we're going to assign. */
|
|
|
|
while (seek) {
|
|
|
|
if (seek != lease &&
|
|
|
|
seek -> ends > cur_time)
|
|
|
|
break;
|
1999-07-02 17:10:51 +00:00
|
|
|
seek = lease -> n_uid;
|
1999-07-02 17:47:42 +00:00
|
|
|
}
|
1999-07-02 17:10:51 +00:00
|
|
|
if (seek) {
|
|
|
|
release_lease (seek);
|
|
|
|
}
|
|
|
|
} while (seek);
|
|
|
|
} else {
|
|
|
|
do {
|
|
|
|
seek = (find_lease_by_hw_addr
|
|
|
|
(lease -> hardware_addr.haddr,
|
|
|
|
lease -> hardware_addr.hlen));
|
1999-07-02 17:47:42 +00:00
|
|
|
while (seek) {
|
|
|
|
if (seek != lease &&
|
|
|
|
seek -> ends > cur_time)
|
|
|
|
break;
|
1999-07-02 17:10:51 +00:00
|
|
|
seek = lease -> n_hw;
|
1999-07-02 17:47:42 +00:00
|
|
|
}
|
1999-07-02 17:10:51 +00:00
|
|
|
if (seek) {
|
|
|
|
release_lease (seek);
|
|
|
|
}
|
|
|
|
} while (seek);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-06-25 03:56:24 +00:00
|
|
|
/* Make sure this packet satisfies the configured minimum
|
|
|
|
number of seconds. */
|
1999-03-25 22:07:54 +00:00
|
|
|
if (offer == DHCPOFFER &&
|
1999-04-05 16:46:13 +00:00
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_MIN_SECS))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len && packet -> raw -> secs < d1.data [0]) {
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: %d secs < %d",
|
1998-11-11 08:01:49 +00:00
|
|
|
packet -> raw -> secs, d1.data [0]);
|
1999-04-05 16:46:13 +00:00
|
|
|
free_lease_state (state, "ack_lease");
|
1999-07-18 19:39:14 +00:00
|
|
|
static_lease_dereference (lease, "ack_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find a matching host declaration for this lease. */
|
|
|
|
if (!lease -> host) {
|
|
|
|
struct host_decl *hp;
|
|
|
|
|
|
|
|
/* Try to find a host_decl that matches the client
|
|
|
|
identifier or hardware address on the packet, and
|
|
|
|
has no fixed IP address. If there is one, hang
|
|
|
|
it off the lease so that its option definitions
|
|
|
|
can be used. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
hp = find_hosts_by_uid (d1.data, d1.len);
|
|
|
|
data_string_forget (&d1, "dhcpdiscover");
|
|
|
|
if (!hp)
|
|
|
|
hp = find_hosts_by_haddr
|
|
|
|
(packet -> raw -> htype,
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen);
|
|
|
|
for (; hp; hp = hp -> n_ipaddr) {
|
|
|
|
if (!hp -> fixed_addr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lease -> host = hp;
|
|
|
|
} else
|
|
|
|
lease -> host = (struct host_decl *)0;
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Drop the request if it's not allowed for this client. */
|
|
|
|
if (!lease -> host &&
|
1999-04-05 16:46:13 +00:00
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_BOOT_UNKNOWN_CLIENTS))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len && !d1.data [0]) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: unknown", msg);
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "ack_lease");
|
1999-04-05 16:46:13 +00:00
|
|
|
free_lease_state (state, "ack_lease");
|
1999-07-18 19:39:14 +00:00
|
|
|
static_lease_dereference (lease, "ack_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, "ack_lease"); /* mmm, C... */
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Drop the request if it's not allowed for this client. */
|
|
|
|
if (!offer &&
|
1999-04-05 16:46:13 +00:00
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_ALLOW_BOOTP))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len && !d1.data [0]) {
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: bootp disallowed", msg);
|
1999-04-05 16:46:13 +00:00
|
|
|
free_lease_state (state, "ack_lease");
|
1999-07-18 19:39:14 +00:00
|
|
|
static_lease_dereference (lease, "ack_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
/* Drop the request if booting is specifically denied. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_ALLOW_BOOTING);
|
1998-11-05 18:54:55 +00:00
|
|
|
if (oc &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
lease, oc)) {
|
1998-06-25 03:56:24 +00:00
|
|
|
if (d1.len && !d1.data [0]) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: booting disallowed", msg);
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "ack_lease");
|
1999-04-05 16:46:13 +00:00
|
|
|
free_lease_state (state, "ack_lease");
|
1999-07-18 19:39:14 +00:00
|
|
|
static_lease_dereference (lease, "ack_lease");
|
1998-06-25 03:56:24 +00:00
|
|
|
return;
|
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "ack_lease");
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
1998-11-11 08:01:49 +00:00
|
|
|
/* If we are configured to do per-class billing, do it. */
|
|
|
|
if (have_billing_classes) {
|
|
|
|
|
|
|
|
/* See if the lease is currently being billed to a
|
|
|
|
class, and if so, whether or not it can continue to
|
|
|
|
be billed to that class. */
|
|
|
|
if (lease -> billing_class) {
|
|
|
|
for (i = 0; i < packet -> class_count; i++)
|
|
|
|
if (packet -> classes [i] ==
|
|
|
|
lease -> billing_class)
|
|
|
|
break;
|
|
|
|
if (i == packet -> class_count)
|
|
|
|
unbill_class (lease, lease -> billing_class);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we don't have an active billing, see if we need
|
|
|
|
one, and if we do, try to do so. */
|
|
|
|
if (!lease -> billing_class) {
|
|
|
|
for (i = 0; i < packet -> class_count; i++) {
|
1999-05-27 14:56:51 +00:00
|
|
|
if (packet -> classes [i] -> lease_limit)
|
1998-11-11 08:01:49 +00:00
|
|
|
break;
|
|
|
|
}
|
1999-05-27 14:56:51 +00:00
|
|
|
if (i != packet -> class_count) {
|
1998-11-11 08:01:49 +00:00
|
|
|
for (i = 0; i < packet -> class_count; i++)
|
1999-05-27 14:56:51 +00:00
|
|
|
if ((packet ->
|
|
|
|
classes [i] -> lease_limit) &&
|
|
|
|
bill_class (lease,
|
1998-11-11 08:01:49 +00:00
|
|
|
packet -> classes [i]))
|
|
|
|
break;
|
|
|
|
if (i == packet -> class_count) {
|
1999-02-25 23:30:43 +00:00
|
|
|
log_info ("%s: no available billing",
|
|
|
|
msg);
|
1999-04-05 16:46:13 +00:00
|
|
|
free_lease_state (state, "ack_lease");
|
1999-07-18 19:39:14 +00:00
|
|
|
/* XXX probably not necessary: */
|
|
|
|
static_lease_dereference (lease,
|
|
|
|
"ack_lease");
|
1998-11-11 08:01:49 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-06-25 03:56:24 +00:00
|
|
|
/* Figure out the filename. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&server_universe, state -> options, SV_FILENAME);
|
1998-11-05 18:54:55 +00:00
|
|
|
if (oc)
|
|
|
|
evaluate_option_cache (&state -> filename,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet, packet -> options, lease, oc);
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Choose a server name as above. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_SERVER_NAME);
|
1998-11-05 18:54:55 +00:00
|
|
|
if (oc)
|
|
|
|
evaluate_option_cache (&state -> server_name, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease, oc);
|
1996-05-22 07:21:50 +00:00
|
|
|
|
1996-02-21 12:11:09 +00:00
|
|
|
/* At this point, we have a lease that we can offer the client.
|
|
|
|
Now we construct a lease structure that contains what we want,
|
|
|
|
and call supersede_lease to do the right thing with it. */
|
|
|
|
memset (<, 0, sizeof lt);
|
|
|
|
|
|
|
|
/* Use the ip address of the lease that we finally found in
|
|
|
|
the database. */
|
|
|
|
lt.ip_addr = lease -> ip_addr;
|
|
|
|
|
|
|
|
/* Start now. */
|
|
|
|
lt.starts = cur_time;
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Figure out how long a lease to assign. If this is a
|
|
|
|
dynamic BOOTP lease, its duration must be infinite. */
|
|
|
|
if (offer) {
|
1999-03-09 23:45:04 +00:00
|
|
|
default_lease_time = DEFAULT_DEFAULT_LEASE_TIME;
|
1999-04-05 16:46:13 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, state -> options,
|
1999-03-09 23:45:04 +00:00
|
|
|
SV_DEFAULT_LEASE_TIME))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
|
|
|
lease, oc)) {
|
1999-03-09 23:45:04 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
default_lease_time =
|
|
|
|
getULong (d1.data);
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-06 01:04:32 +00:00
|
|
|
DHO_DHCP_LEASE_TIME)))
|
|
|
|
s1 = evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
|
|
|
lease, oc);
|
1998-11-06 01:04:32 +00:00
|
|
|
else
|
|
|
|
s1 = 0;
|
1998-11-05 18:54:55 +00:00
|
|
|
if (s1 && d1.len == sizeof (u_int32_t)) {
|
|
|
|
lease_time = getULong (d1.data);
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
1999-07-06 20:35:54 +00:00
|
|
|
if (s1)
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1999-03-09 23:45:04 +00:00
|
|
|
lease_time = default_lease_time;
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
|
|
|
|
1999-07-06 20:35:54 +00:00
|
|
|
/* See if there's a maximum lease time. */
|
|
|
|
max_lease_time = DEFAULT_MAX_LEASE_TIME;
|
|
|
|
if ((oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_MAX_LEASE_TIME))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
|
|
|
packet -> options,
|
|
|
|
lease, oc)) {
|
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
max_lease_time =
|
|
|
|
getULong (d1.data);
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* Enforce the maximum lease length. */
|
1999-07-06 20:35:54 +00:00
|
|
|
if (lease_time < 0 /* XXX */
|
|
|
|
|| lease_time > max_lease_time)
|
1999-04-23 23:17:52 +00:00
|
|
|
lease_time = max_lease_time;
|
|
|
|
|
1999-03-09 23:45:04 +00:00
|
|
|
min_lease_time = DEFAULT_MIN_LEASE_TIME;
|
1999-04-05 16:46:13 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_MIN_LEASE_TIME))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
|
|
|
lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
1999-03-09 23:45:04 +00:00
|
|
|
min_lease_time = getULong (d1.data);
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
1998-04-09 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
1999-03-09 23:45:04 +00:00
|
|
|
if (lease_time < min_lease_time) {
|
|
|
|
if (min_lease_time)
|
|
|
|
lease_time = min_lease_time;
|
|
|
|
else
|
|
|
|
lease_time = default_lease_time;
|
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
state -> offered_expiry = cur_time + lease_time;
|
1996-05-22 07:21:50 +00:00
|
|
|
if (when)
|
|
|
|
lt.ends = when;
|
|
|
|
else
|
1997-03-06 07:02:00 +00:00
|
|
|
lt.ends = state -> offered_expiry;
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
1998-06-25 03:56:24 +00:00
|
|
|
lease_time = MAX_TIME - cur_time;
|
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_BOOTP_LEASE_LENGTH))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease,
|
|
|
|
oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
lease_time = getULong (d1.data);
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_BOOTP_LEASE_CUTOFF))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
|
|
|
lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
lease_time = (getULong (d1.data) -
|
|
|
|
cur_time);
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lt.ends = state -> offered_expiry = cur_time + lease_time;
|
1996-05-22 07:21:50 +00:00
|
|
|
lt.flags = BOOTP_LEASE;
|
|
|
|
}
|
1996-02-21 12:11:09 +00:00
|
|
|
|
|
|
|
lt.timestamp = cur_time;
|
|
|
|
|
|
|
|
/* Record the uid, if given... */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (oc &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len <= sizeof lt.uid_buf) {
|
|
|
|
memcpy (lt.uid_buf, d1.data, d1.len);
|
1997-03-05 06:37:05 +00:00
|
|
|
lt.uid = lt.uid_buf;
|
|
|
|
lt.uid_max = sizeof lt.uid_buf;
|
1998-11-05 18:54:55 +00:00
|
|
|
lt.uid_len = d1.len;
|
1997-03-05 06:37:05 +00:00
|
|
|
} else {
|
1998-11-05 18:54:55 +00:00
|
|
|
lt.uid_max = d1.len;
|
|
|
|
lt.uid_len = d1.len;
|
|
|
|
lt.uid = (unsigned char *)dmalloc (lt.uid_max,
|
|
|
|
"ack_lease");
|
|
|
|
/* XXX inelegant */
|
1997-03-05 06:37:05 +00:00
|
|
|
if (!lt.uid)
|
1999-04-05 16:46:13 +00:00
|
|
|
log_fatal ("no memory for large uid.");
|
1998-11-05 18:54:55 +00:00
|
|
|
memcpy (lt.uid, d1.data, lt.uid_len);
|
1997-03-05 06:37:05 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
data_string_forget (&d1, "ack_lease");
|
1996-02-21 12:11:09 +00:00
|
|
|
}
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
lt.host = lease -> host;
|
|
|
|
lt.subnet = lease -> subnet;
|
1998-11-11 08:01:49 +00:00
|
|
|
lt.billing_class = lease -> billing_class;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1999-07-21 14:30:28 +00:00
|
|
|
/* Set a flag if this client is a broken client that NUL
|
|
|
|
terminates string options and expects us to do likewise. */
|
|
|
|
lease -> flags &= ~MS_NULL_TERMINATION;
|
|
|
|
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_HOST_NAME))) {
|
|
|
|
if (!oc -> expression)
|
|
|
|
if (oc -> data.len &&
|
|
|
|
oc -> data.data [oc -> data.len - 1] == 0) {
|
|
|
|
lease -> flags |= MS_NULL_TERMINATION;
|
|
|
|
oc -> data.len--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-07-01 19:58:12 +00:00
|
|
|
/* Do the DDNS update. It needs to be done here so that the lease
|
|
|
|
structure values for the forward and reverse names are in place for
|
|
|
|
supercede()->write_lease() to be able to write into the dhcpd.leases
|
|
|
|
file. We have to pass the "state" structure here as it is not yet
|
|
|
|
hanging off the lease. */
|
|
|
|
/* why not update for static leases too? */
|
|
|
|
/* Because static leases aren't currently recorded? */
|
1999-07-19 01:15:22 +00:00
|
|
|
/* XXX
|
1999-07-01 19:58:12 +00:00
|
|
|
#if defined (NSUPDATE)
|
|
|
|
if (!(lease -> flags & STATIC_LEASE) && offer == DHCPACK)
|
|
|
|
nsupdate (lease, state, packet, ADD);
|
|
|
|
#endif
|
1999-07-19 01:15:22 +00:00
|
|
|
*/
|
1999-07-01 19:58:12 +00:00
|
|
|
|
1999-07-18 19:39:14 +00:00
|
|
|
/* If there are statements to execute when the lease is
|
|
|
|
committed, execute them. */
|
|
|
|
if (lease -> on_commit && (!offer || offer == DHCPACK)) {
|
|
|
|
execute_statements (packet, lease, packet -> options,
|
|
|
|
state -> options, lease -> on_commit);
|
|
|
|
executable_statement_dereference (&lease -> on_commit,
|
|
|
|
"ack_lease");
|
|
|
|
}
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Don't call supersede_lease on a mocked-up lease. */
|
1997-12-02 09:07:03 +00:00
|
|
|
if (lease -> flags & STATIC_LEASE) {
|
|
|
|
/* Copy the hardware address into the static lease
|
|
|
|
structure. */
|
|
|
|
lease -> hardware_addr.hlen = packet -> raw -> hlen;
|
|
|
|
lease -> hardware_addr.htype = packet -> raw -> htype;
|
|
|
|
memcpy (lease -> hardware_addr.haddr, packet -> raw -> chaddr,
|
1998-02-06 01:08:38 +00:00
|
|
|
sizeof packet -> raw -> chaddr); /* XXX */
|
1997-12-02 09:07:03 +00:00
|
|
|
} else {
|
|
|
|
/* Record the hardware address, if given... */
|
|
|
|
lt.hardware_addr.hlen = packet -> raw -> hlen;
|
|
|
|
lt.hardware_addr.htype = packet -> raw -> htype;
|
|
|
|
memcpy (lt.hardware_addr.haddr, packet -> raw -> chaddr,
|
1998-02-06 01:08:38 +00:00
|
|
|
sizeof packet -> raw -> chaddr);
|
1997-12-02 09:07:03 +00:00
|
|
|
|
|
|
|
/* Install the new information about this lease in the
|
|
|
|
database. If this is a DHCPACK or a dynamic BOOTREPLY
|
|
|
|
and we can't write the lease, don't ACK it (or BOOTREPLY
|
|
|
|
it) either. */
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
if (!(supersede_lease (lease, <, !offer || offer == DHCPACK)
|
1998-11-11 08:01:49 +00:00
|
|
|
|| (offer && offer != DHCPACK))) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: database update failed", msg);
|
1999-04-05 16:46:13 +00:00
|
|
|
free_lease_state (state, "ack_lease");
|
1999-07-18 19:39:14 +00:00
|
|
|
static_lease_dereference (lease, "ack_lease");
|
1996-05-22 07:21:50 +00:00
|
|
|
return;
|
1998-11-11 08:01:49 +00:00
|
|
|
}
|
1997-12-02 09:07:03 +00:00
|
|
|
}
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1997-03-05 06:37:05 +00:00
|
|
|
/* Remember the interface on which the packet arrived. */
|
1997-03-06 07:02:00 +00:00
|
|
|
state -> ip = packet -> interface;
|
1996-02-21 15:16:18 +00:00
|
|
|
|
1997-03-05 06:37:05 +00:00
|
|
|
/* Remember the giaddr, xid, secs, flags and hops. */
|
1997-03-06 07:02:00 +00:00
|
|
|
state -> giaddr = packet -> raw -> giaddr;
|
1997-05-09 08:27:14 +00:00
|
|
|
state -> ciaddr = packet -> raw -> ciaddr;
|
1997-03-06 07:02:00 +00:00
|
|
|
state -> xid = packet -> raw -> xid;
|
|
|
|
state -> secs = packet -> raw -> secs;
|
|
|
|
state -> bootp_flags = packet -> raw -> flags;
|
|
|
|
state -> hops = packet -> raw -> hops;
|
|
|
|
state -> offer = offer;
|
1996-02-21 15:16:18 +00:00
|
|
|
|
1999-06-22 13:28:12 +00:00
|
|
|
/* If we're always supposed to broadcast to this client, set
|
|
|
|
the broadcast bit in the bootp flags field. */
|
1999-07-01 20:02:58 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_ALWAYS_BROADCAST)) &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_boolean_option_cache (packet, packet -> options,
|
|
|
|
lease, oc))
|
1999-06-22 13:28:12 +00:00
|
|
|
state -> bootp_flags |= htons (BOOTP_BROADCAST);
|
|
|
|
|
1998-02-06 01:08:38 +00:00
|
|
|
/* Get the Maximum Message Size option from the packet, if one
|
|
|
|
was sent. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_MAX_MESSAGE_SIZE);
|
|
|
|
if (oc &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int16_t))
|
|
|
|
state -> max_message_size = getUShort (d1.data);
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1998-02-06 01:08:38 +00:00
|
|
|
}
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Now, if appropriate, put in DHCP-specific options that
|
|
|
|
override those. */
|
1997-03-06 07:02:00 +00:00
|
|
|
if (state -> offer) {
|
1997-03-05 06:37:05 +00:00
|
|
|
i = DHO_DHCP_MESSAGE_TYPE;
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
1999-04-12 22:18:58 +00:00
|
|
|
&state -> offer, 1, 0, 0)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
oc -> option =
|
|
|
|
dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
1997-03-05 06:37:05 +00:00
|
|
|
i = DHO_DHCP_SERVER_IDENTIFIER;
|
1999-04-05 16:46:13 +00:00
|
|
|
if (!(oc = lookup_option (&dhcp_universe,
|
|
|
|
state -> options, i))) {
|
1998-11-05 18:54:55 +00:00
|
|
|
use_primary:
|
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data
|
|
|
|
(&oc -> expression,
|
|
|
|
((unsigned char *)
|
|
|
|
&state -> ip -> primary_address),
|
|
|
|
sizeof state -> ip -> primary_address,
|
|
|
|
0, 0)) {
|
|
|
|
oc -> option =
|
|
|
|
dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
|
|
|
state -> from.len =
|
|
|
|
sizeof state -> ip -> primary_address;
|
|
|
|
memcpy (state -> from.iabuf,
|
|
|
|
&state -> ip -> primary_address,
|
|
|
|
state -> from.len);
|
|
|
|
} else {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
|
|
|
lease, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (!d1.len ||
|
1999-05-06 20:35:48 +00:00
|
|
|
d1.len > sizeof state -> from.iabuf) {
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
1998-11-05 18:54:55 +00:00
|
|
|
goto use_primary;
|
1999-05-06 20:35:48 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
memcpy (state -> from.iabuf, d1.data, d1.len);
|
|
|
|
state -> from.len = d1.len;
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
} else
|
|
|
|
goto use_primary;
|
1998-04-09 04:41:52 +00:00
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
|
1998-06-25 03:56:24 +00:00
|
|
|
offered_lease_time =
|
|
|
|
state -> offered_expiry - cur_time;
|
1996-02-29 18:16:31 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
putULong ((unsigned char *)&state -> expiry,
|
1997-03-05 06:37:05 +00:00
|
|
|
offered_lease_time);
|
|
|
|
i = DHO_DHCP_LEASE_TIME;
|
1999-04-05 16:46:13 +00:00
|
|
|
if (lookup_option (&dhcp_universe, state -> options, i))
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("dhcp-lease-time option for %s overridden.",
|
1998-04-19 23:34:43 +00:00
|
|
|
inet_ntoa (state -> ciaddr));
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
(unsigned char *)&state -> expiry,
|
|
|
|
sizeof state -> expiry, 0, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
|
1996-09-05 23:52:10 +00:00
|
|
|
/* Renewal time is lease time * 0.5. */
|
|
|
|
offered_lease_time /= 2;
|
1997-03-06 07:02:00 +00:00
|
|
|
putULong ((unsigned char *)&state -> renewal,
|
1997-03-05 06:37:05 +00:00
|
|
|
offered_lease_time);
|
|
|
|
i = DHO_DHCP_RENEWAL_TIME;
|
1999-04-05 16:46:13 +00:00
|
|
|
if (lookup_option (&dhcp_universe, state -> options, i))
|
|
|
|
log_error ("overriding dhcp-renewal-time for %s.",
|
|
|
|
inet_ntoa (state -> ciaddr));
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
(unsigned char *)
|
|
|
|
&state -> renewal,
|
|
|
|
sizeof state -> renewal, 0, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
1996-09-05 23:52:10 +00:00
|
|
|
|
|
|
|
/* Rebinding time is lease time * 0.875. */
|
|
|
|
offered_lease_time += (offered_lease_time / 2
|
|
|
|
+ offered_lease_time / 4);
|
1997-03-06 07:02:00 +00:00
|
|
|
putULong ((unsigned char *)&state -> rebind,
|
1997-03-05 06:37:05 +00:00
|
|
|
offered_lease_time);
|
|
|
|
i = DHO_DHCP_REBINDING_TIME;
|
1999-04-05 16:46:13 +00:00
|
|
|
if (lookup_option (&dhcp_universe, state -> options, i))
|
|
|
|
log_error ("overriding dhcp-rebinding-time for %s.",
|
1998-04-19 23:34:43 +00:00
|
|
|
inet_ntoa (state -> ciaddr));
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
(unsigned char *)&state -> rebind,
|
|
|
|
sizeof state -> rebind, 0, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
1999-04-23 23:17:52 +00:00
|
|
|
} else {
|
|
|
|
state -> from.len =
|
|
|
|
sizeof state -> ip -> primary_address;
|
|
|
|
memcpy (state -> from.iabuf,
|
|
|
|
&state -> ip -> primary_address,
|
|
|
|
state -> from.len);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out the address of the boot file server. */
|
|
|
|
memcpy (&state -> siaddr, state -> from.iabuf, sizeof state -> siaddr);
|
|
|
|
if ((oc =
|
|
|
|
lookup_option (&server_universe,
|
|
|
|
state -> options, SV_NEXT_SERVER))) {
|
|
|
|
if (evaluate_option_cache (&d1, packet,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options, lease, oc)) {
|
1999-04-23 23:17:52 +00:00
|
|
|
/* If there was more than one answer,
|
|
|
|
take the first. */
|
|
|
|
if (d1.len >= 4 && d1.data)
|
1999-04-23 23:47:51 +00:00
|
|
|
memcpy (&state -> siaddr, d1.data, 4);
|
1999-04-23 23:17:52 +00:00
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
1996-02-21 15:16:18 +00:00
|
|
|
|
1996-09-05 23:52:10 +00:00
|
|
|
/* Use the subnet mask from the subnet declaration if no other
|
|
|
|
mask has been provided. */
|
1997-03-05 06:37:05 +00:00
|
|
|
i = DHO_SUBNET_MASK;
|
1999-04-05 16:46:13 +00:00
|
|
|
if (!lookup_option (&dhcp_universe, state -> options, i)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
lease -> subnet -> netmask.iabuf,
|
|
|
|
lease -> subnet -> netmask.len,
|
|
|
|
0, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Use the hostname from the host declaration if there is one
|
|
|
|
and no hostname has otherwise been provided, and if the
|
|
|
|
use-host-decl-name flag is set. */
|
|
|
|
i = DHO_HOST_NAME;
|
1998-11-05 18:54:55 +00:00
|
|
|
j = SV_USE_HOST_DECL_NAMES;
|
1999-04-05 16:46:13 +00:00
|
|
|
if (!lookup_option (&dhcp_universe, state -> options, i) &&
|
1998-11-05 18:54:55 +00:00
|
|
|
lease -> host && lease -> host -> name &&
|
|
|
|
(evaluate_boolean_option_cache
|
1999-07-02 20:58:48 +00:00
|
|
|
(packet, packet -> options, lease,
|
1998-11-05 18:54:55 +00:00
|
|
|
(lookup_option
|
1999-04-05 16:46:13 +00:00
|
|
|
(&server_universe, state -> options, j))))) {
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
1999-03-16 06:37:55 +00:00
|
|
|
((unsigned char *)
|
|
|
|
lease -> host -> name),
|
1998-11-05 18:54:55 +00:00
|
|
|
strlen (lease -> host -> name),
|
|
|
|
1, 0)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we don't have a hostname yet, and we've been asked to do
|
|
|
|
a reverse lookup to find the hostname, do it. */
|
1998-11-05 18:54:55 +00:00
|
|
|
j = SV_GET_LEASE_HOSTNAMES;
|
1999-05-27 14:56:51 +00:00
|
|
|
if (!lookup_option (&server_universe, state -> options, i) &&
|
1998-11-05 18:54:55 +00:00
|
|
|
(evaluate_boolean_option_cache
|
1999-07-02 20:58:48 +00:00
|
|
|
(packet, packet -> options, lease,
|
1999-04-05 16:46:13 +00:00
|
|
|
lookup_option (&server_universe, state -> options, j)))) {
|
1998-11-05 18:54:55 +00:00
|
|
|
struct in_addr ia;
|
|
|
|
struct hostent *h;
|
|
|
|
|
|
|
|
memcpy (&ia, lease -> ip_addr.iabuf, 4);
|
|
|
|
|
|
|
|
h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET);
|
|
|
|
if (!h)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No hostname for %s", inet_ntoa (ia));
|
1998-11-05 18:54:55 +00:00
|
|
|
else {
|
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_const_data (&oc -> expression,
|
1999-03-16 06:37:55 +00:00
|
|
|
((unsigned char *)
|
|
|
|
h -> h_name),
|
1998-11-05 18:54:55 +00:00
|
|
|
strlen (h -> h_name) + 1,
|
|
|
|
1, 1)) {
|
|
|
|
oc -> option =
|
|
|
|
dhcp_universe.options [i];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
}
|
1996-09-05 23:52:10 +00:00
|
|
|
}
|
|
|
|
|
1998-04-09 04:41:52 +00:00
|
|
|
/* If so directed, use the leased IP address as the router address.
|
|
|
|
This supposedly makes Win95 machines ARP for all IP addresses,
|
|
|
|
so if the local router does proxy arp, you win. */
|
1998-06-25 03:56:24 +00:00
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
if (evaluate_boolean_option_cache
|
1999-07-02 20:58:48 +00:00
|
|
|
(packet, state -> options, lease,
|
1999-04-05 16:46:13 +00:00
|
|
|
lookup_option (&server_universe, state -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE))) {
|
|
|
|
i = DHO_ROUTERS;
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, state -> options, i);
|
1999-02-14 19:27:56 +00:00
|
|
|
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];
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1999-02-14 19:27:56 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
1999-02-14 19:27:56 +00:00
|
|
|
if (oc)
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
1998-04-09 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
1999-04-05 16:46:13 +00:00
|
|
|
/* If we've been given a vendor option space, and there's something
|
|
|
|
in it, and we weren't given a vendor-encapsulated-options option,
|
|
|
|
then cons one up. */
|
|
|
|
i = DHO_VENDOR_ENCAPSULATED_OPTIONS;
|
|
|
|
j = SV_VENDOR_OPTION_SPACE;
|
|
|
|
if (!lookup_option (&dhcp_universe, state -> options, i) &&
|
|
|
|
(oc = lookup_option (&server_universe, state -> options, j)) &&
|
|
|
|
evaluate_option_cache (&d1,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet, state -> options, lease, oc)) {
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&oc, "ack_lease")) {
|
|
|
|
if (make_encapsulation (&oc -> expression, &d1)) {
|
|
|
|
oc -> option = dhcp_universe.options [i];
|
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference (&oc, "ack_lease");
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
}
|
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* If a site option space has been specified, use that for
|
|
|
|
site option codes. */
|
|
|
|
i = SV_SITE_OPTION_SPACE;
|
1999-05-27 14:56:51 +00:00
|
|
|
if ((oc = lookup_option (&server_universe, state -> options, i)) &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet, state -> options, lease, oc)) {
|
1999-04-23 23:17:52 +00:00
|
|
|
struct universe *u;
|
|
|
|
|
|
|
|
u = ((struct universe *)
|
|
|
|
hash_lookup (&universe_hash, d1.data, d1.len));
|
|
|
|
if (!u) {
|
|
|
|
log_error ("unknown option space %s.", d1.data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state -> options -> site_universe = u -> index;
|
|
|
|
state -> options -> site_code_min = 128; /* XXX */
|
|
|
|
data_string_forget (&d1, "ack_lease");
|
|
|
|
} else {
|
|
|
|
state -> options -> site_code_min = 0;
|
|
|
|
state -> options -> site_universe = dhcp_universe.index;
|
|
|
|
}
|
|
|
|
|
1999-03-10 20:44:22 +00:00
|
|
|
/* If the client has provided a list of options that it wishes
|
1999-05-07 17:40:26 +00:00
|
|
|
returned, use it to prioritize. If there's a parameter
|
|
|
|
request list in scope, use that in preference. Otherwise
|
|
|
|
use the default priority list. */
|
1999-03-10 20:44:22 +00:00
|
|
|
|
1999-05-07 17:40:26 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, state -> options,
|
1999-03-10 20:44:22 +00:00
|
|
|
DHO_DHCP_PARAMETER_REQUEST_LIST);
|
|
|
|
|
1999-05-06 20:35:48 +00:00
|
|
|
if (!oc)
|
1999-05-07 17:40:26 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1999-05-06 20:35:48 +00:00
|
|
|
DHO_DHCP_PARAMETER_REQUEST_LIST);
|
1999-03-10 20:44:22 +00:00
|
|
|
if (oc)
|
|
|
|
evaluate_option_cache (&state -> parameter_request_list,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet, packet -> options, lease, oc);
|
1999-03-10 20:44:22 +00:00
|
|
|
|
1997-03-05 06:37:05 +00:00
|
|
|
#ifdef DEBUG_PACKET
|
|
|
|
dump_packet (packet);
|
|
|
|
dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
|
|
|
|
#endif
|
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
lease -> state = state;
|
1997-03-06 18:40:22 +00:00
|
|
|
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s", msg);
|
1998-11-11 08:01:49 +00:00
|
|
|
|
1997-03-06 18:40:22 +00:00
|
|
|
/* If this is a DHCPOFFER, ping the lease address before actually
|
|
|
|
sending the offer. */
|
1999-02-14 19:27:56 +00:00
|
|
|
if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE) &&
|
|
|
|
cur_time - lease -> timestamp > 60) {
|
|
|
|
lease -> timestamp = cur_time;
|
1997-03-06 18:40:22 +00:00
|
|
|
icmp_echorequest (&lease -> ip_addr);
|
|
|
|
add_timeout (cur_time + 1, lease_ping_timeout, lease);
|
|
|
|
++outstanding_pings;
|
|
|
|
} else {
|
1999-02-14 19:27:56 +00:00
|
|
|
lease -> timestamp = cur_time;
|
1999-07-18 19:39:14 +00:00
|
|
|
static_lease_dereference (lease, "ack_lease");
|
1997-03-06 18:40:22 +00:00
|
|
|
dhcp_reply (lease);
|
|
|
|
}
|
1997-03-05 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dhcp_reply (lease)
|
|
|
|
struct lease *lease;
|
|
|
|
{
|
|
|
|
int bufs = 0;
|
|
|
|
int packet_length;
|
|
|
|
struct dhcp_packet raw;
|
|
|
|
struct sockaddr_in to;
|
|
|
|
struct in_addr from;
|
|
|
|
struct hardware hto;
|
|
|
|
int result;
|
|
|
|
int i;
|
1997-03-06 07:02:00 +00:00
|
|
|
struct lease_state *state = lease -> state;
|
1997-09-16 18:20:30 +00:00
|
|
|
int nulltp, bootpp;
|
1998-02-06 01:08:38 +00:00
|
|
|
struct agent_options *a, *na;
|
|
|
|
struct option_tag *ot, *not;
|
1998-06-25 03:56:24 +00:00
|
|
|
struct data_string d1;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
1997-03-06 07:02:00 +00:00
|
|
|
|
|
|
|
if (!state)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("dhcp_reply was supplied lease with no state!");
|
1997-03-05 06:37:05 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
/* Compose a response for the client... */
|
1997-03-05 06:37:05 +00:00
|
|
|
memset (&raw, 0, sizeof raw);
|
1998-11-05 18:54:55 +00:00
|
|
|
memset (&d1, 0, sizeof d1);
|
1997-03-05 06:37:05 +00:00
|
|
|
|
|
|
|
/* Copy in the filename if given; otherwise, flag the filename
|
|
|
|
buffer as available for options. */
|
1998-06-25 03:56:24 +00:00
|
|
|
if (state -> filename.len && state -> filename.data) {
|
|
|
|
memcpy (raw.file,
|
|
|
|
state -> filename.data,
|
|
|
|
state -> filename.len > sizeof raw.file
|
|
|
|
? sizeof raw.file : state -> filename.len);
|
|
|
|
if (sizeof raw.file > state -> filename.len)
|
|
|
|
memset (&raw.file [state -> filename.len], 0,
|
|
|
|
(sizeof raw.file) - state -> filename.len);
|
|
|
|
} else
|
1997-03-05 06:37:05 +00:00
|
|
|
bufs |= 1;
|
|
|
|
|
|
|
|
/* Copy in the server name if given; otherwise, flag the
|
|
|
|
server_name buffer as available for options. */
|
1998-06-25 03:56:24 +00:00
|
|
|
if (state -> server_name.len && state -> server_name.data) {
|
|
|
|
memcpy (raw.sname,
|
|
|
|
state -> server_name.data,
|
|
|
|
state -> server_name.len > sizeof raw.sname
|
|
|
|
? sizeof raw.sname : state -> server_name.len);
|
|
|
|
if (sizeof raw.sname > state -> server_name.len)
|
|
|
|
memset (&raw.sname [state -> server_name.len], 0,
|
|
|
|
(sizeof raw.sname) - state -> server_name.len);
|
|
|
|
} else
|
1997-03-05 06:37:05 +00:00
|
|
|
bufs |= 2; /* XXX */
|
|
|
|
|
1998-02-06 01:08:38 +00:00
|
|
|
memcpy (raw.chaddr, lease -> hardware_addr.haddr, sizeof raw.chaddr);
|
1997-03-05 06:37:05 +00:00
|
|
|
raw.hlen = lease -> hardware_addr.hlen;
|
|
|
|
raw.htype = lease -> hardware_addr.htype;
|
|
|
|
|
1996-09-11 05:52:18 +00:00
|
|
|
/* See if this is a Microsoft client that NUL-terminates its
|
|
|
|
strings and expects us to do likewise... */
|
1997-03-05 06:37:05 +00:00
|
|
|
if (lease -> flags & MS_NULL_TERMINATION)
|
1997-09-16 18:20:30 +00:00
|
|
|
nulltp = 1;
|
1996-09-11 05:52:18 +00:00
|
|
|
else
|
1997-09-16 18:20:30 +00:00
|
|
|
nulltp = 0;
|
|
|
|
|
|
|
|
/* See if this is a bootp client... */
|
|
|
|
if (state -> offer)
|
|
|
|
bootpp = 0;
|
|
|
|
else
|
|
|
|
bootpp = 1;
|
|
|
|
|
|
|
|
/* Insert such options as will fit into the buffer. */
|
1999-07-02 20:58:48 +00:00
|
|
|
packet_length = cons_options ((struct packet *)0, &raw, lease,
|
1998-02-06 01:08:38 +00:00
|
|
|
state -> max_message_size,
|
1999-04-05 16:46:13 +00:00
|
|
|
state -> options,
|
1999-03-10 20:44:22 +00:00
|
|
|
bufs, nulltp, bootpp,
|
|
|
|
&state -> parameter_request_list);
|
1997-03-05 06:37:05 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
memcpy (&raw.ciaddr, &state -> ciaddr, sizeof raw.ciaddr);
|
1996-02-21 15:16:18 +00:00
|
|
|
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
|
1999-04-23 23:17:52 +00:00
|
|
|
raw.siaddr = state -> siaddr;
|
1997-03-06 07:02:00 +00:00
|
|
|
raw.giaddr = state -> giaddr;
|
1996-02-21 15:16:18 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
raw.xid = state -> xid;
|
|
|
|
raw.secs = state -> secs;
|
|
|
|
raw.flags = state -> bootp_flags;
|
|
|
|
raw.hops = state -> hops;
|
1996-02-21 15:16:18 +00:00
|
|
|
raw.op = BOOTREPLY;
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Say what we're doing... */
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s on %s to %s via %s",
|
1997-03-06 07:02:00 +00:00
|
|
|
(state -> offer
|
|
|
|
? (state -> offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
|
1996-05-22 07:21:50 +00:00
|
|
|
: "BOOTREPLY"),
|
|
|
|
piaddr (lease -> ip_addr),
|
1997-03-05 06:37:05 +00:00
|
|
|
print_hw_addr (lease -> hardware_addr.htype,
|
|
|
|
lease -> hardware_addr.hlen,
|
|
|
|
lease -> hardware_addr.haddr),
|
1997-03-06 07:02:00 +00:00
|
|
|
state -> giaddr.s_addr
|
|
|
|
? inet_ntoa (state -> giaddr)
|
|
|
|
: state -> ip -> name);
|
1996-05-22 07:21:50 +00:00
|
|
|
|
|
|
|
/* Set up the hardware address... */
|
1997-03-05 06:37:05 +00:00
|
|
|
hto.htype = lease -> hardware_addr.htype;
|
|
|
|
hto.hlen = lease -> hardware_addr.hlen;
|
|
|
|
memcpy (hto.haddr, lease -> hardware_addr.haddr, hto.hlen);
|
1996-05-22 07:21:50 +00:00
|
|
|
|
|
|
|
to.sin_family = AF_INET;
|
|
|
|
#ifdef HAVE_SA_LEN
|
|
|
|
to.sin_len = sizeof to;
|
|
|
|
#endif
|
|
|
|
memset (to.sin_zero, 0, sizeof to.sin_zero);
|
|
|
|
|
|
|
|
#ifdef DEBUG_PACKET
|
1997-03-05 06:37:05 +00:00
|
|
|
dump_raw ((unsigned char *)&raw, packet_length);
|
1996-05-22 07:21:50 +00:00
|
|
|
#endif
|
|
|
|
|
1997-03-05 06:37:05 +00:00
|
|
|
/* Make sure outgoing packets are at least as big
|
|
|
|
as a BOOTP packet. */
|
|
|
|
if (packet_length < BOOTP_MIN_LEN)
|
|
|
|
packet_length = BOOTP_MIN_LEN;
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
/* If this was gatewayed, send it back to the gateway... */
|
1996-02-29 18:16:31 +00:00
|
|
|
if (raw.giaddr.s_addr) {
|
1996-02-26 01:56:15 +00:00
|
|
|
to.sin_addr = raw.giaddr;
|
1997-02-18 14:28:54 +00:00
|
|
|
to.sin_port = local_port;
|
1996-06-24 20:32:12 +00:00
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
if (fallback_interface) {
|
|
|
|
result = send_packet (fallback_interface,
|
|
|
|
(struct packet *)0,
|
|
|
|
&raw, packet_length,
|
1999-03-13 18:26:05 +00:00
|
|
|
raw.siaddr, &to,
|
|
|
|
(struct hardware *)0);
|
1997-03-06 07:02:00 +00:00
|
|
|
|
1999-03-10 20:44:22 +00:00
|
|
|
data_string_forget (&state -> parameter_request_list,
|
|
|
|
"dhcp_reply");
|
1999-02-14 19:27:56 +00:00
|
|
|
free_lease_state (state, "dhcp_reply fallback 1");
|
|
|
|
lease -> state = (struct lease_state *)0;
|
|
|
|
return;
|
|
|
|
}
|
1996-02-29 18:16:31 +00:00
|
|
|
|
1999-03-13 18:26:05 +00:00
|
|
|
/* If the client is RENEWING, unicast to the client using the
|
1999-05-06 20:35:48 +00:00
|
|
|
regular IP stack. Some clients, particularly those that
|
|
|
|
follow RFC1541, are buggy, and send both ciaddr and server
|
|
|
|
identifier. We deal with this situation by assuming that
|
|
|
|
if we got both dhcp-server-identifier and ciaddr, and
|
|
|
|
giaddr was not set, then the client is on the local
|
|
|
|
network, and we can therefore unicast or broadcast to it
|
|
|
|
successfully. A client in REQUESTING state on another
|
|
|
|
network that's making this mistake will have set giaddr,
|
|
|
|
and will therefore get a relayed response from the above
|
|
|
|
code. */
|
|
|
|
} else if (raw.ciaddr.s_addr &&
|
1999-05-27 14:56:51 +00:00
|
|
|
!((state -> got_server_identifier ||
|
|
|
|
(raw.flags & htons (BOOTP_BROADCAST))) &&
|
|
|
|
/* XXX This won't work if giaddr isn't zero, but it is: */
|
1999-05-06 20:35:48 +00:00
|
|
|
(state -> shared_network ==
|
|
|
|
lease -> subnet -> shared_network)) &&
|
|
|
|
state -> offer == DHCPACK) {
|
1999-03-13 18:58:00 +00:00
|
|
|
to.sin_addr = raw.ciaddr;
|
1999-03-13 18:26:05 +00:00
|
|
|
to.sin_port = remote_port;
|
1996-02-29 18:16:31 +00:00
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
if (fallback_interface) {
|
|
|
|
result = send_packet (fallback_interface,
|
|
|
|
(struct packet *)0,
|
|
|
|
&raw, packet_length,
|
1999-03-13 18:26:05 +00:00
|
|
|
raw.siaddr, &to,
|
|
|
|
(struct hardware *)0);
|
1999-03-10 20:44:22 +00:00
|
|
|
data_string_forget (&state -> parameter_request_list,
|
|
|
|
"dhcp_reply");
|
1999-03-13 18:26:05 +00:00
|
|
|
free_lease_state (state, "dhcp_reply fallback 2");
|
1999-02-14 19:27:56 +00:00
|
|
|
lease -> state = (struct lease_state *)0;
|
|
|
|
return;
|
|
|
|
}
|
1996-06-12 23:49:58 +00:00
|
|
|
|
1999-03-13 18:26:05 +00:00
|
|
|
/* If it comes from a client that already knows its address
|
|
|
|
and is not requesting a broadcast response, and we can
|
|
|
|
unicast to a client without using the ARP protocol, sent it
|
|
|
|
directly to that client. */
|
|
|
|
} else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
|
1999-03-13 18:58:00 +00:00
|
|
|
can_unicast_without_arp (state -> ip)) {
|
|
|
|
to.sin_addr = raw.yiaddr;
|
1999-03-13 18:26:05 +00:00
|
|
|
to.sin_port = remote_port;
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
/* Otherwise, broadcast it on the local network. */
|
1996-02-29 18:16:31 +00:00
|
|
|
} else {
|
1999-07-06 17:09:03 +00:00
|
|
|
to.sin_addr = limited_broadcast;
|
1999-03-13 18:26:05 +00:00
|
|
|
to.sin_port = remote_port;
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
memcpy (&from, state -> from.iabuf, sizeof from);
|
1996-05-12 23:55:27 +00:00
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
result = send_packet (state -> ip,
|
1997-03-05 06:37:05 +00:00
|
|
|
(struct packet *)0, &raw, packet_length,
|
1998-11-05 18:54:55 +00:00
|
|
|
from, &to, &hto);
|
1997-03-06 07:02:00 +00:00
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* Free all of the entries in the option_state structure
|
|
|
|
now that we're done with them. */
|
|
|
|
|
1999-03-10 20:44:22 +00:00
|
|
|
data_string_forget (&state -> parameter_request_list,
|
|
|
|
"dhcp_reply");
|
1997-03-06 07:02:00 +00:00
|
|
|
free_lease_state (state, "dhcp_reply");
|
|
|
|
lease -> state = (struct lease_state *)0;
|
1995-11-29 07:40:04 +00:00
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1997-06-08 03:55:58 +00:00
|
|
|
struct lease *find_lease (packet, share, ours)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
1996-05-23 01:59:38 +00:00
|
|
|
struct shared_network *share;
|
1997-06-08 03:55:58 +00:00
|
|
|
int *ours;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
1996-05-22 07:21:50 +00:00
|
|
|
struct lease *uid_lease, *ip_lease, *hw_lease;
|
|
|
|
struct lease *lease = (struct lease *)0;
|
1996-02-26 01:56:15 +00:00
|
|
|
struct iaddr cip;
|
1996-05-22 10:14:42 +00:00
|
|
|
struct host_decl *hp, *host = (struct host_decl *)0;
|
1999-02-25 23:30:43 +00:00
|
|
|
struct lease *fixed_lease, *next;
|
1998-11-05 18:54:55 +00:00
|
|
|
struct option_cache *oc;
|
|
|
|
struct data_string d1;
|
|
|
|
int have_client_identifier = 0;
|
|
|
|
struct data_string client_identifier;
|
|
|
|
int status;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
/* Look up the requested address. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1999-02-25 23:30:43 +00:00
|
|
|
DHO_DHCP_REQUESTED_ADDRESS);
|
|
|
|
memset (&d1, 0, sizeof d1);
|
|
|
|
if (oc &&
|
1999-07-02 20:58:48 +00:00
|
|
|
evaluate_option_cache (&d1, packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1999-05-06 20:35:48 +00:00
|
|
|
packet -> got_requested_address = 1;
|
1999-02-25 23:30:43 +00:00
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, d1.data, cip.len);
|
|
|
|
data_string_forget (&d1, "find_lease");
|
|
|
|
} else if (packet -> raw -> ciaddr.s_addr) {
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
|
|
|
} else
|
|
|
|
cip.len = 0;
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Try to find a host or lease that's been assigned to the
|
|
|
|
specified unique client identifier. */
|
1999-04-05 16:46:13 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
1998-11-05 18:54:55 +00:00
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
memset (&client_identifier, 0, sizeof client_identifier);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&client_identifier,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet, packet -> options,
|
|
|
|
(struct lease *)0, oc)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
/* Remember this for later. */
|
|
|
|
have_client_identifier = 1;
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* First, try to find a fixed host entry for the specified
|
|
|
|
client identifier... */
|
1998-11-05 18:54:55 +00:00
|
|
|
hp = find_hosts_by_uid (client_identifier.data,
|
|
|
|
client_identifier.len);
|
1996-05-22 07:21:50 +00:00
|
|
|
if (hp) {
|
1998-11-09 02:46:58 +00:00
|
|
|
/* Remember if we know of this client. */
|
|
|
|
packet -> known = 1;
|
1996-05-23 01:59:38 +00:00
|
|
|
fixed_lease = mockup_lease (packet, share, hp);
|
1998-11-05 18:54:55 +00:00
|
|
|
} else
|
|
|
|
fixed_lease = (struct lease *)0;
|
|
|
|
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-25 23:30:43 +00:00
|
|
|
if (fixed_lease) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("Found host for client identifier: %s.",
|
1998-11-05 18:54:55 +00:00
|
|
|
piaddr (fixed_lease -> ip_addr));
|
1999-02-25 23:30:43 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1999-02-25 23:30:43 +00:00
|
|
|
if (!fixed_lease)
|
1998-11-05 18:54:55 +00:00
|
|
|
host = hp; /* Save the host if we found one. */
|
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
uid_lease = find_lease_by_uid (client_identifier.data,
|
|
|
|
client_identifier.len);
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
1996-02-26 01:56:15 +00:00
|
|
|
uid_lease = (struct lease *)0;
|
1996-05-22 07:21:50 +00:00
|
|
|
fixed_lease = (struct lease *)0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we didn't find a fixed lease using the uid, try doing
|
|
|
|
it with the hardware address... */
|
1998-11-05 18:54:55 +00:00
|
|
|
if (!fixed_lease && !host) {
|
1996-05-22 07:21:50 +00:00
|
|
|
hp = find_hosts_by_haddr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen);
|
|
|
|
if (hp) {
|
1998-11-09 02:46:58 +00:00
|
|
|
/* Remember if we know of this client. */
|
|
|
|
packet -> known = 1;
|
1996-05-22 07:21:50 +00:00
|
|
|
host = hp; /* Save it for later. */
|
1996-05-23 01:59:38 +00:00
|
|
|
fixed_lease = mockup_lease (packet, share, hp);
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (fixed_lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
log_info ("Found host for link address: %s.",
|
1998-11-05 18:54:55 +00:00
|
|
|
piaddr (fixed_lease -> ip_addr));
|
|
|
|
}
|
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
/* If fixed_lease is present but does not match the requested
|
|
|
|
IP address, and this is a DHCPREQUEST, then we can't return
|
|
|
|
any other lease, so we might as well return now. */
|
|
|
|
if (packet -> packet_type == DHCPREQUEST && fixed_lease &&
|
|
|
|
(fixed_lease -> ip_addr.len != cip.len ||
|
|
|
|
memcmp (fixed_lease -> ip_addr.iabuf,
|
|
|
|
cip.iabuf, cip.len))) {
|
|
|
|
if (ours)
|
|
|
|
*ours = 1;
|
|
|
|
strcpy (dhcp_message, "requested address is incorrect");
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("Client's fixed-address %s doesn't match %s%s",
|
|
|
|
piaddr (fixed_lease -> ip_addr), "request ",
|
|
|
|
print_dotted_quads (cip.len, cip.iabuf));
|
|
|
|
#endif
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we found leases matching the client identifier, loop through
|
|
|
|
the n_uid pointer looking for one that's actually valid. We
|
|
|
|
can't do this until we get here because we depend on
|
|
|
|
packet -> known, which may be set by either the uid host
|
|
|
|
lookup or the haddr host lookup. */
|
|
|
|
for (; uid_lease; uid_lease = next) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("trying next lease matching client id: %s",
|
|
|
|
piaddr (uid_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
if (uid_lease -> subnet -> shared_network != share) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("wrong network segment: %s",
|
|
|
|
piaddr (uid_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
next = uid_lease -> n_uid;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((uid_lease -> pool -> prohibit_list &&
|
1999-04-05 16:46:13 +00:00
|
|
|
permitted (packet, uid_lease -> pool -> prohibit_list)) ||
|
1999-02-25 23:30:43 +00:00
|
|
|
(uid_lease -> pool -> permit_list &&
|
|
|
|
!permitted (packet, uid_lease -> pool -> permit_list))) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("not permitted: %s",
|
|
|
|
piaddr (uid_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
next = uid_lease -> n_uid;
|
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
|
|
|
release_lease (uid_lease);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (uid_lease)
|
|
|
|
log_info ("Found lease for client id: %s.",
|
|
|
|
piaddr (uid_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Find a lease whose hardware address matches, whose client
|
|
|
|
identifier matches, that's permitted, and that's on the
|
|
|
|
correct subnet. */
|
1996-02-26 01:56:15 +00:00
|
|
|
hw_lease = find_lease_by_hw_addr (packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen);
|
1999-02-25 23:30:43 +00:00
|
|
|
for (; hw_lease; hw_lease = next) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("trying next lease matching hw addr: %s",
|
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
if (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))) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("wrong client identifier: %s",
|
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
next = hw_lease -> n_hw;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (hw_lease -> subnet -> shared_network != share) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("wrong network segment: %s",
|
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
next = hw_lease -> n_hw;
|
|
|
|
continue;
|
1997-12-02 09:28:08 +00:00
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
if ((hw_lease -> pool -> prohibit_list &&
|
|
|
|
permitted (packet, hw_lease -> pool -> prohibit_list)) ||
|
|
|
|
(hw_lease -> pool -> permit_list &&
|
|
|
|
!permitted (packet, hw_lease -> pool -> permit_list))) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("not permitted: %s",
|
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
|
|
|
next = hw_lease -> n_hw;
|
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
|
|
|
release_lease (hw_lease);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
1997-12-02 09:28:08 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (hw_lease)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("Found lease for hardware address: %s.",
|
1998-11-05 18:54:55 +00:00
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
1996-02-26 01:56:15 +00:00
|
|
|
|
|
|
|
/* Try to find a lease that's been allocated to the client's
|
|
|
|
IP address. */
|
1999-02-25 23:30:43 +00:00
|
|
|
if (cip.len)
|
1996-02-26 01:56:15 +00:00
|
|
|
ip_lease = find_lease_by_ip_addr (cip);
|
1999-02-25 23:30:43 +00:00
|
|
|
else
|
1996-02-26 01:56:15 +00:00
|
|
|
ip_lease = (struct lease *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (ip_lease)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("Found lease for requested address: %s.",
|
1998-11-05 18:54:55 +00:00
|
|
|
piaddr (ip_lease -> ip_addr));
|
|
|
|
#endif
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1997-06-08 03:55:58 +00:00
|
|
|
/* If ip_lease is valid at this point, set ours to one, so that
|
|
|
|
even if we choose a different lease, we know that the address
|
|
|
|
the client was requesting was ours, and thus we can NAK it. */
|
1997-06-08 04:10:41 +00:00
|
|
|
if (ip_lease && ours)
|
1997-06-08 03:55:58 +00:00
|
|
|
*ours = 1;
|
|
|
|
|
1996-08-27 09:37:50 +00:00
|
|
|
/* If the requested IP address isn't on the network the packet
|
1998-06-25 21:24:23 +00:00
|
|
|
came from, don't use it. Allow abandoned leases to be matched
|
|
|
|
here - if the client is requesting it, there's a decent chance
|
|
|
|
that it's because the lease database got trashed and a client
|
|
|
|
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. */
|
1999-02-14 19:27:56 +00:00
|
|
|
if (ip_lease && (ip_lease -> subnet -> shared_network != share)) {
|
1999-02-25 23:30:43 +00:00
|
|
|
if (ours)
|
|
|
|
*ours = 1;
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("...but it was on the wrong shared network.");
|
1999-02-25 23:30:43 +00:00
|
|
|
#endif
|
|
|
|
strcpy (dhcp_message, "requested address on bad subnet");
|
1996-08-27 09:37:50 +00:00
|
|
|
ip_lease = (struct lease *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1996-08-27 09:37:50 +00:00
|
|
|
|
1999-03-09 23:45:04 +00:00
|
|
|
/* Toss ip_lease if it hasn't yet expired and doesn't belong to the
|
|
|
|
client. */
|
1996-06-27 19:04:29 +00:00
|
|
|
if (ip_lease &&
|
|
|
|
ip_lease -> ends >= cur_time &&
|
1999-03-09 23:45:04 +00:00
|
|
|
((ip_lease -> uid &&
|
|
|
|
(!have_client_identifier ||
|
|
|
|
ip_lease -> uid_len != client_identifier.len ||
|
|
|
|
memcmp (ip_lease -> uid, client_identifier.data,
|
|
|
|
ip_lease -> uid_len))) ||
|
|
|
|
(!ip_lease -> uid &&
|
|
|
|
(ip_lease -> hardware_addr.htype != packet -> raw -> htype ||
|
|
|
|
ip_lease -> hardware_addr.hlen != packet -> raw -> hlen ||
|
|
|
|
memcmp (ip_lease -> hardware_addr.haddr,
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
ip_lease -> hardware_addr.hlen))))) {
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (ip_lease)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("rejecting lease for requested address.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
|
|
|
ip_lease = (struct lease *)0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If for some reason the client has more than one lease
|
|
|
|
on the subnet that matches its uid, pick the one that
|
|
|
|
it asked for and (if we can) free the other. */
|
1999-02-25 23:30:43 +00:00
|
|
|
if (ip_lease &&
|
|
|
|
ip_lease -> ends >= cur_time &&
|
|
|
|
ip_lease -> uid && ip_lease != uid_lease) {
|
|
|
|
if (have_client_identifier &&
|
1998-11-05 18:54:55 +00:00
|
|
|
(ip_lease -> uid_len == client_identifier.len) &&
|
|
|
|
!memcmp (client_identifier.data,
|
1997-12-02 07:43:56 +00:00
|
|
|
ip_lease -> uid, ip_lease -> uid_len)) {
|
1999-03-09 23:45:04 +00:00
|
|
|
if (uid_lease) {
|
|
|
|
if (uid_lease -> ends > cur_time) {
|
1999-02-25 23:30:43 +00:00
|
|
|
log_error ("client %s has duplicate%s on %s",
|
|
|
|
" leases",
|
|
|
|
(print_hw_addr
|
|
|
|
(packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)),
|
1999-02-14 19:27:56 +00:00
|
|
|
(ip_lease -> subnet ->
|
|
|
|
shared_network -> name));
|
1998-03-17 18:14:51 +00:00
|
|
|
|
1999-03-09 23:45:04 +00:00
|
|
|
/* If the client is REQUESTing the lease,
|
|
|
|
it shouldn't still be using the old
|
|
|
|
one, so we can free it for allocation. */
|
|
|
|
if (uid_lease &&
|
|
|
|
!packet -> raw -> ciaddr.s_addr &&
|
|
|
|
(share ==
|
|
|
|
uid_lease -> subnet -> shared_network))
|
|
|
|
dissociate_lease (uid_lease);
|
|
|
|
}
|
|
|
|
uid_lease = ip_lease;
|
|
|
|
}
|
1997-12-02 07:43:56 +00:00
|
|
|
}
|
1996-06-27 19:04:29 +00:00
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
/* If we get to here and fixed_lease is not null, that means
|
|
|
|
that there are both a dynamic lease and a fixed-address
|
|
|
|
declaration for the same IP address. */
|
|
|
|
if (packet -> packet_type == DHCPREQUEST && fixed_lease) {
|
|
|
|
fixed_lease = (struct lease *)0;
|
|
|
|
db_conflict:
|
1999-03-16 06:37:55 +00:00
|
|
|
log_error ("Dynamic and static leases present for %s.",
|
|
|
|
piaddr (cip));
|
|
|
|
log_error ("Remove host declaration %s or remove %s",
|
|
|
|
(fixed_lease && fixed_lease -> host
|
|
|
|
? (fixed_lease -> host -> name
|
|
|
|
? fixed_lease -> host -> name
|
|
|
|
: piaddr (cip))
|
|
|
|
: piaddr (cip)),
|
|
|
|
piaddr (cip));
|
|
|
|
log_error ("from the dynamic address pool for %s",
|
|
|
|
ip_lease -> subnet -> shared_network -> name
|
|
|
|
);
|
1999-02-25 23:30:43 +00:00
|
|
|
if (fixed_lease)
|
|
|
|
ip_lease = (struct lease *)0;
|
|
|
|
strcpy (dhcp_message,
|
|
|
|
"database conflict - call for help!");
|
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1996-06-27 19:04:29 +00:00
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
/* If we get to here with both fixed_lease and ip_lease not
|
|
|
|
null, then we have a configuration file bug. */
|
|
|
|
if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease)
|
|
|
|
goto db_conflict;
|
|
|
|
|
|
|
|
/* Make sure the client is permitted to use the requested lease. */
|
|
|
|
if (ip_lease &&
|
|
|
|
((ip_lease -> pool -> prohibit_list &&
|
|
|
|
permitted (packet, ip_lease -> pool -> prohibit_list)) ||
|
|
|
|
(ip_lease -> pool -> permit_list &&
|
|
|
|
!permitted (packet, ip_lease -> pool -> permit_list)))) {
|
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
|
|
|
release_lease (ip_lease);
|
1996-02-26 01:56:15 +00:00
|
|
|
ip_lease = (struct lease *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
|
|
|
|
/* Toss extra pointers to the same lease... */
|
1998-11-05 18:54:55 +00:00
|
|
|
if (hw_lease == uid_lease) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("hardware lease and uid lease are identical.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-02-26 01:56:15 +00:00
|
|
|
hw_lease = (struct lease *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
if (ip_lease == hw_lease) {
|
|
|
|
hw_lease = (struct lease *)0;
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("hardware lease and ip lease are identical.");
|
|
|
|
#endif
|
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
if (ip_lease == uid_lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
uid_lease = (struct lease *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("uid lease and ip lease are identical.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* If we've already eliminated the lease, it wasn't there to
|
|
|
|
begin with. If we have come up with a matching lease,
|
|
|
|
set the message to bad network in case we have to throw it out. */
|
1999-02-25 23:30:43 +00:00
|
|
|
if (!ip_lease) {
|
1996-02-29 18:16:31 +00:00
|
|
|
strcpy (dhcp_message, "requested address not available");
|
|
|
|
}
|
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
/* If this is a DHCPREQUEST, make sure the lease we're going to return
|
|
|
|
matches the requested IP address. If it doesn't, don't return a
|
|
|
|
lease at all. */
|
|
|
|
if (packet -> packet_type == DHCPREQUEST &&
|
|
|
|
!ip_lease && !fixed_lease) {
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-25 23:30:43 +00:00
|
|
|
log_info ("no applicable lease found for DHCPREQUEST.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1999-02-25 23:30:43 +00:00
|
|
|
goto out;
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* At this point, if fixed_lease is nonzero, we can assign it to
|
1996-02-26 01:56:15 +00:00
|
|
|
this client. */
|
1996-08-27 09:37:50 +00:00
|
|
|
if (fixed_lease) {
|
1996-05-22 07:21:50 +00:00
|
|
|
lease = fixed_lease;
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("choosing fixed address.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-08-27 09:37:50 +00:00
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
|
|
|
|
/* If we got a lease that matched the ip address and don't have
|
|
|
|
a better offer, use that; otherwise, release it. */
|
|
|
|
if (ip_lease) {
|
|
|
|
if (lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
1998-04-09 04:41:52 +00:00
|
|
|
release_lease (ip_lease);
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("not choosing requested address (!).");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("choosing lease on requested address.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
lease = ip_lease;
|
|
|
|
lease -> host = (struct host_decl *)0;
|
|
|
|
}
|
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
|
|
|
/* If we got a lease that matched the client identifier, we may want
|
|
|
|
to use it, but if we already have a lease we like, we must free
|
|
|
|
the lease that matched the client identifier. */
|
|
|
|
if (uid_lease) {
|
|
|
|
if (lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
1998-04-09 04:41:52 +00:00
|
|
|
dissociate_lease (uid_lease);
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("not choosing uid lease.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
1996-02-26 01:56:15 +00:00
|
|
|
lease = uid_lease;
|
1996-05-22 07:21:50 +00:00
|
|
|
lease -> host = (struct host_decl *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("choosing uid lease.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The lease that matched the hardware address is treated likewise. */
|
|
|
|
if (hw_lease) {
|
|
|
|
if (lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
1998-04-09 04:41:52 +00:00
|
|
|
dissociate_lease (hw_lease);
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("not choosing hardware lease.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
1996-02-26 01:56:15 +00:00
|
|
|
lease = hw_lease;
|
1996-05-22 07:21:50 +00:00
|
|
|
lease -> host = (struct host_decl *)0;
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("choosing hardware lease.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we found a host_decl but no matching address, try to
|
|
|
|
find a host_decl that has no address, and if there is one,
|
|
|
|
hang it off the lease so that we can use the supplied
|
|
|
|
options. */
|
|
|
|
if (lease && host && !lease -> host) {
|
|
|
|
for (; host; host = host -> n_ipaddr) {
|
|
|
|
if (!host -> fixed_addr) {
|
|
|
|
lease -> host = host;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
/* 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. */
|
1999-05-27 14:56:51 +00:00
|
|
|
if (lease && (lease -> flags & ABANDONED_LEASE) && lease == ip_lease &&
|
1999-02-14 19:27:56 +00:00
|
|
|
packet -> packet_type == DHCPREQUEST) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("Reclaiming REQUESTed abandoned IP address %s.",
|
1998-06-25 21:24:23 +00:00
|
|
|
piaddr (lease -> ip_addr));
|
|
|
|
lease -> flags &= ~ABANDONED_LEASE;
|
1999-05-27 14:56:51 +00:00
|
|
|
} else if (lease && (lease -> flags & ABANDONED_LEASE)) {
|
1999-02-14 19:27:56 +00:00
|
|
|
/* 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;
|
1998-06-25 21:24:23 +00:00
|
|
|
}
|
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
out:
|
|
|
|
if (have_client_identifier)
|
|
|
|
data_string_forget (&client_identifier, "find_lease");
|
|
|
|
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (lease)
|
|
|
|
log_info ("Returning lease: %s.",
|
|
|
|
piaddr (lease -> ip_addr));
|
|
|
|
else
|
|
|
|
log_info ("Not returning a lease.");
|
|
|
|
#endif
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
return lease;
|
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
|
|
|
|
/* Search the provided host_decl structure list for an address that's on
|
|
|
|
the specified shared network. If one is found, mock up and return a
|
|
|
|
lease structure for it; otherwise return the null pointer. */
|
|
|
|
|
1996-05-23 01:59:38 +00:00
|
|
|
struct lease *mockup_lease (packet, share, hp)
|
1996-05-22 07:21:50 +00:00
|
|
|
struct packet *packet;
|
1996-05-23 01:59:38 +00:00
|
|
|
struct shared_network *share;
|
1996-05-22 07:21:50 +00:00
|
|
|
struct host_decl *hp;
|
|
|
|
{
|
|
|
|
static struct lease mock;
|
|
|
|
|
1996-05-23 01:59:38 +00:00
|
|
|
mock.subnet = find_host_for_network (&hp, &mock.ip_addr, share);
|
1996-05-22 07:21:50 +00:00
|
|
|
if (!mock.subnet)
|
|
|
|
return (struct lease *)0;
|
|
|
|
mock.next = mock.prev = (struct lease *)0;
|
|
|
|
mock.host = hp;
|
1998-06-25 03:56:24 +00:00
|
|
|
mock.uid = hp -> client_identifier.data;
|
|
|
|
mock.uid_len = hp -> client_identifier.len;
|
1996-05-28 18:16:04 +00:00
|
|
|
mock.hardware_addr = hp -> interface;
|
1996-05-22 07:21:50 +00:00
|
|
|
mock.starts = mock.timestamp = mock.ends = MIN_TIME;
|
|
|
|
mock.flags = STATIC_LEASE;
|
|
|
|
return &mock;
|
|
|
|
}
|
1998-11-09 02:46:58 +00:00
|
|
|
|
1999-07-18 19:39:14 +00:00
|
|
|
/* Dereference all dynamically-allocated information that may be dangling
|
|
|
|
off of a static lease. Otherwise, once ack_lease returns, the information
|
|
|
|
dangling from the lease will be lost, so reference counts will be screwed
|
|
|
|
up and memory leaks will occur. */
|
|
|
|
|
|
|
|
void static_lease_dereference (lease, name)
|
|
|
|
struct lease *lease;
|
|
|
|
char *name;
|
|
|
|
{
|
|
|
|
if (!(lease -> flags & STATIC_LEASE))
|
|
|
|
return;
|
|
|
|
if (lease -> on_release)
|
|
|
|
executable_statement_dereference (&lease -> on_release, name);
|
|
|
|
if (lease -> on_expiry)
|
|
|
|
executable_statement_dereference (&lease -> on_expiry, name);
|
|
|
|
if (lease -> on_commit)
|
|
|
|
executable_statement_dereference (&lease -> on_commit, name);
|
|
|
|
}
|
|
|
|
|
1998-11-09 02:46:58 +00:00
|
|
|
/* Look through all the pools in a list starting with the specified pool
|
|
|
|
for a free lease. We try to find a virgin lease if we can. If we
|
|
|
|
don't find a virgin lease, we try to find a non-virgin lease that's
|
|
|
|
free. If we can't find one of those, we try to reclaim an abandoned
|
|
|
|
lease. If all of these possibilities fail to pan out, we don't return
|
|
|
|
a lease at all. */
|
|
|
|
|
|
|
|
struct lease *allocate_lease (packet, pool, ok)
|
|
|
|
struct packet *packet;
|
|
|
|
struct pool *pool;
|
|
|
|
int ok;
|
|
|
|
{
|
|
|
|
struct lease *lease, *lp;
|
|
|
|
struct permit *permit;
|
|
|
|
|
|
|
|
if (!pool)
|
|
|
|
return (struct lease *)0;
|
|
|
|
|
|
|
|
/* If we aren't elegible to try this pool, try a subsequent one. */
|
|
|
|
if ((pool -> prohibit_list &&
|
|
|
|
permitted (packet, pool -> prohibit_list)) ||
|
|
|
|
(pool -> permit_list && !permitted (packet, pool -> permit_list)))
|
|
|
|
return allocate_lease (packet, pool -> next, ok);
|
|
|
|
|
|
|
|
lease = pool -> last_lease;
|
|
|
|
|
|
|
|
/* If there are no leases in the pool that have
|
|
|
|
expired, try the next one. */
|
|
|
|
if (!lease || lease -> ends > cur_time)
|
|
|
|
return allocate_lease (packet, pool -> next, ok);
|
|
|
|
|
|
|
|
/* If we find an abandoned lease, and no other lease qualifies
|
|
|
|
better, take it. */
|
1999-05-27 14:56:51 +00:00
|
|
|
if ((lease -> flags & ABANDONED_LEASE)) {
|
1998-11-09 02:46:58 +00:00
|
|
|
/* If we already have a non-abandoned lease that we didn't
|
|
|
|
love, but that's okay, don't reclaim the abandoned lease. */
|
|
|
|
if (ok)
|
|
|
|
return allocate_lease (packet, pool -> next, ok);
|
|
|
|
lp = allocate_lease (packet, pool -> next, 0);
|
|
|
|
if (!lp) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("Reclaiming abandoned IP address %s.",
|
1998-11-09 02:46:58 +00:00
|
|
|
piaddr (lease -> ip_addr));
|
|
|
|
lease -> flags &= ~ABANDONED_LEASE;
|
|
|
|
return lease;
|
|
|
|
}
|
|
|
|
return lp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there's a lease we could take, but it had previously been
|
|
|
|
allocated to a different client, try for a virgin lease before
|
|
|
|
stealing it. */
|
|
|
|
if (lease -> uid_len || lease -> hardware_addr.hlen) {
|
|
|
|
/* If we're already in that boat, no need to consider
|
|
|
|
allocating this particular lease. */
|
|
|
|
if (ok)
|
|
|
|
return allocate_lease (packet, pool -> next, ok);
|
|
|
|
|
|
|
|
lp = allocate_lease (packet, pool -> next, 1);
|
|
|
|
if (lp)
|
|
|
|
return lp;
|
|
|
|
return lease;
|
|
|
|
}
|
|
|
|
|
|
|
|
return lease;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Determine whether or not a permit exists on a particular permit list
|
|
|
|
that matches the specified packet, returning nonzero if so, zero if
|
|
|
|
not. */
|
|
|
|
|
|
|
|
int permitted (packet, permit_list)
|
|
|
|
struct packet *packet;
|
|
|
|
struct permit *permit_list;
|
|
|
|
{
|
|
|
|
struct permit *p;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (p = permit_list; p; p = p -> next) {
|
|
|
|
switch (p -> type) {
|
|
|
|
case permit_unknown_clients:
|
|
|
|
if (!packet -> known)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case permit_known_clients:
|
|
|
|
if (packet -> known)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case permit_authenticated_clients:
|
|
|
|
if (packet -> authenticated)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case permit_unauthenticated_clients:
|
|
|
|
if (!packet -> authenticated)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case permit_all_clients:
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
case permit_dynamic_bootp_clients:
|
|
|
|
if (!packet -> options_valid ||
|
|
|
|
!packet -> packet_type)
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case permit_class:
|
|
|
|
for (i = 0; i < packet -> class_count; i++)
|
|
|
|
if (p -> class == packet -> classes [i])
|
|
|
|
return 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|