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
|
|
|
|
|
|
|
/*
|
2022-01-25 16:24:16 +01:00
|
|
|
* Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
|
2005-03-17 20:15:29 +00:00
|
|
|
* Copyright (c) 1995-2003 by Internet Software Consortium
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
2017-07-12 09:23:23 -04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
|
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
1995-11-29 07:40:04 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* Internet Systems Consortium, Inc.
|
2022-01-19 20:13:19 +01:00
|
|
|
* PO Box 360
|
|
|
|
* Newmarket, NH 03857 USA
|
2005-03-17 20:15:29 +00:00
|
|
|
* <info@isc.org>
|
2009-07-23 18:52:21 +00:00
|
|
|
* https://www.isc.org/
|
2000-03-17 04:00:32 +00:00
|
|
|
*
|
1995-11-29 07:40:04 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dhcpd.h"
|
2007-05-19 18:47:15 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2008-02-28 23:40:45 +00:00
|
|
|
#include <sys/time.h>
|
|
|
|
|
2009-07-06 23:33:23 +00:00
|
|
|
static void maybe_return_agent_options(struct packet *packet,
|
|
|
|
struct option_state *options);
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2014-11-24 07:36:13 -05:00
|
|
|
static int reuse_lease (struct packet* packet, struct lease* new_lease,
|
|
|
|
struct lease* lease, struct lease_state *state,
|
2018-09-26 11:10:16 -04:00
|
|
|
int offer, int* same_client);
|
|
|
|
|
|
|
|
static int do_ping_check(struct packet* packet, struct lease_state* state,
|
|
|
|
struct lease* lease, TIME original_cltt,
|
|
|
|
int same_client);
|
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
static int locate_network6(struct packet *packet);
|
|
|
|
#endif
|
1995-11-29 07:40:04 +00:00
|
|
|
|
1997-03-06 18:40:22 +00:00
|
|
|
int outstanding_pings;
|
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
#if defined(DELAYED_ACK)
|
|
|
|
static void delayed_ack_enqueue(struct lease *);
|
|
|
|
static void delayed_acks_timer(void *);
|
|
|
|
|
|
|
|
|
2008-01-21 19:53:21 +00:00
|
|
|
struct leasequeue *ackqueue_head, *ackqueue_tail;
|
|
|
|
static struct leasequeue *free_ackqueue;
|
2010-03-12 01:36:57 +00:00
|
|
|
static struct timeval max_fsync;
|
|
|
|
|
2008-01-21 19:53:21 +00:00
|
|
|
int outstanding_acks;
|
|
|
|
int max_outstanding_acks = DEFAULT_DELAYED_ACK;
|
2008-02-28 23:40:45 +00:00
|
|
|
int max_ack_delay_secs = DEFAULT_ACK_DELAY_SECS;
|
|
|
|
int max_ack_delay_usecs = DEFAULT_ACK_DELAY_USECS;
|
2010-03-12 01:36:57 +00:00
|
|
|
int min_ack_delay_usecs = DEFAULT_MIN_ACK_DELAY_USECS;
|
2015-06-15 15:19:42 -04:00
|
|
|
#endif
|
2008-01-21 19:53:21 +00:00
|
|
|
|
1998-03-16 06:19:46 +00:00
|
|
|
static char dhcp_message [256];
|
2008-01-09 17:13:16 +00:00
|
|
|
static int site_code_min;
|
|
|
|
|
|
|
|
static int find_min_site_code(struct universe *);
|
|
|
|
static isc_result_t lowest_site_code(const void *, unsigned, void *);
|
1996-02-29 18:16:31 +00:00
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
static const char *dhcp_type_names [] = {
|
2001-06-27 00:31:20 +00:00
|
|
|
"DHCPDISCOVER",
|
|
|
|
"DHCPOFFER",
|
|
|
|
"DHCPREQUEST",
|
|
|
|
"DHCPDECLINE",
|
|
|
|
"DHCPACK",
|
|
|
|
"DHCPNAK",
|
|
|
|
"DHCPRELEASE",
|
2006-07-25 13:26:00 +00:00
|
|
|
"DHCPINFORM",
|
2008-07-18 01:04:58 +00:00
|
|
|
"type 9",
|
2006-07-25 13:26:00 +00:00
|
|
|
"DHCPLEASEQUERY",
|
|
|
|
"DHCPLEASEUNASSIGNED",
|
|
|
|
"DHCPLEASEUNKNOWN",
|
|
|
|
"DHCPLEASEACTIVE"
|
2001-06-27 00:31:20 +00:00
|
|
|
};
|
|
|
|
const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *));
|
|
|
|
|
2001-02-12 21:00:02 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
# define send_packet trace_packet_send
|
|
|
|
#endif
|
|
|
|
|
2017-05-10 13:11:03 -04:00
|
|
|
static TIME leaseTimeCheck(TIME calculated, TIME alternate);
|
|
|
|
|
2008-07-18 01:04:58 +00:00
|
|
|
void
|
|
|
|
dhcp (struct packet *packet) {
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp = 0;
|
2000-02-07 18:58:03 +00:00
|
|
|
struct option_cache *oc;
|
2008-07-18 01:04:58 +00:00
|
|
|
struct lease *lease = NULL;
|
2000-11-28 23:27:24 +00:00
|
|
|
const char *errmsg;
|
|
|
|
struct data_string data;
|
2000-02-07 05:12:20 +00:00
|
|
|
|
2008-07-18 01:04:58 +00:00
|
|
|
if (!locate_network(packet) &&
|
|
|
|
packet->packet_type != DHCPREQUEST &&
|
2018-09-26 11:10:16 -04:00
|
|
|
packet->packet_type != DHCPINFORM &&
|
2008-07-18 01:04:58 +00:00
|
|
|
packet->packet_type != DHCPLEASEQUERY) {
|
2000-11-28 23:27:24 +00:00
|
|
|
const char *s;
|
2008-07-18 01:04:58 +00:00
|
|
|
char typebuf[32];
|
2000-11-28 23:27:24 +00:00
|
|
|
errmsg = "unknown network segment";
|
|
|
|
bad_packet:
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2008-07-18 01:04:58 +00:00
|
|
|
if (packet->packet_type > 0 &&
|
|
|
|
packet->packet_type <= dhcp_type_name_max) {
|
|
|
|
s = dhcp_type_names[packet->packet_type - 1];
|
2000-11-28 23:27:24 +00:00
|
|
|
} else {
|
2005-03-17 20:15:29 +00:00
|
|
|
/* %Audit% Cannot exceed 28 bytes. %2004.06.17,Safe% */
|
2008-07-18 01:04:58 +00:00
|
|
|
sprintf(typebuf, "type %d", packet->packet_type);
|
2000-11-28 23:27:24 +00:00
|
|
|
s = typebuf;
|
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
log_info("DHCP4o6 %s from %s via %s: %s", s,
|
|
|
|
(packet->raw->htype
|
|
|
|
? print_hw_addr(packet->raw->htype,
|
|
|
|
packet->raw->hlen,
|
|
|
|
packet->raw->chaddr)
|
|
|
|
: "<no identifier>"),
|
|
|
|
piaddr(packet->client_addr),
|
|
|
|
errmsg);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-07-18 01:04:58 +00:00
|
|
|
log_info("%s from %s via %s: %s", s,
|
|
|
|
(packet->raw->htype
|
|
|
|
? print_hw_addr(packet->raw->htype,
|
|
|
|
packet->raw->hlen,
|
|
|
|
packet->raw->chaddr)
|
|
|
|
: "<no identifier>"),
|
|
|
|
packet->raw->giaddr.s_addr
|
|
|
|
? inet_ntoa(packet->raw->giaddr)
|
|
|
|
: packet->interface->name, errmsg);
|
2000-11-28 23:27:24 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* There is a problem with the relay agent information option,
|
2007-04-20 15:25:26 +00:00
|
|
|
* which is that in order for a normal relay agent to append
|
|
|
|
* this option, the relay agent has to have been involved in
|
|
|
|
* getting the packet from the client to the server. Note
|
|
|
|
* that this is the software entity known as the relay agent,
|
|
|
|
* _not_ the hardware entity known as a router in which the
|
|
|
|
* relay agent may be running, so the fact that a router has
|
|
|
|
* forwarded a packet does not mean that the relay agent in
|
|
|
|
* the router was involved.
|
|
|
|
*
|
|
|
|
* So when the client broadcasts (DHCPDISCOVER, or giaddr is set),
|
|
|
|
* we can be sure that there are either agent options in the
|
|
|
|
* packet, or there aren't supposed to be. When the giaddr is not
|
|
|
|
* set, it's still possible that the client is on a directly
|
|
|
|
* attached subnet, and agent options are being appended by an l2
|
|
|
|
* device that has no address, and so sets no giaddr.
|
|
|
|
*
|
|
|
|
* But in either case it's possible that the packets we receive
|
|
|
|
* from the client in RENEW state may not include the agent options,
|
|
|
|
* so if they are not in the packet we must "pretend" the last values
|
|
|
|
* we observed were provided.
|
|
|
|
*/
|
|
|
|
if (packet->packet_type == DHCPREQUEST &&
|
|
|
|
packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr &&
|
|
|
|
(packet->options->universe_count <= agent_universe.index ||
|
|
|
|
packet->options->universes[agent_universe.index] == NULL))
|
2000-11-28 23:27:24 +00:00
|
|
|
{
|
|
|
|
struct iaddr cip;
|
|
|
|
|
|
|
|
cip.len = sizeof packet -> raw -> ciaddr;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr,
|
|
|
|
sizeof packet -> raw -> ciaddr);
|
|
|
|
if (!find_lease_by_ip_addr (&lease, cip, MDL))
|
|
|
|
goto nolease;
|
|
|
|
|
|
|
|
/* If there are no agent options on the lease, it's not
|
|
|
|
interesting. */
|
|
|
|
if (!lease -> agent_options)
|
|
|
|
goto nolease;
|
|
|
|
|
|
|
|
/* The client should not be unicasting a renewal if its lease
|
|
|
|
has expired, so make it go through the process of getting
|
|
|
|
its agent options legally. */
|
|
|
|
if (lease -> ends < cur_time)
|
|
|
|
goto nolease;
|
|
|
|
|
|
|
|
if (lease -> uid_len) {
|
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (!oc)
|
|
|
|
goto nolease;
|
|
|
|
|
|
|
|
memset (&data, 0, sizeof data);
|
|
|
|
if (!evaluate_option_cache (&data,
|
|
|
|
packet, (struct lease *)0,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
|
|
|
(struct option_state *)0,
|
|
|
|
&global_scope, oc, MDL))
|
|
|
|
goto nolease;
|
|
|
|
if (lease -> uid_len != data.len ||
|
|
|
|
memcmp (lease -> uid, data.data, data.len)) {
|
|
|
|
data_string_forget (&data, MDL);
|
|
|
|
goto nolease;
|
|
|
|
}
|
|
|
|
data_string_forget (&data, MDL);
|
|
|
|
} else
|
|
|
|
if ((lease -> hardware_addr.hbuf [0] !=
|
|
|
|
packet -> raw -> htype) ||
|
|
|
|
(lease -> hardware_addr.hlen - 1 !=
|
|
|
|
packet -> raw -> hlen) ||
|
|
|
|
memcmp (&lease -> hardware_addr.hbuf [1],
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen))
|
|
|
|
goto nolease;
|
|
|
|
|
|
|
|
/* Okay, so we found a lease that matches the client. */
|
2001-01-25 08:32:26 +00:00
|
|
|
option_chain_head_reference ((struct option_chain_head **)
|
|
|
|
&(packet -> options -> universes
|
|
|
|
[agent_universe.index]),
|
|
|
|
lease -> agent_options, MDL);
|
2007-04-20 15:25:26 +00:00
|
|
|
|
|
|
|
if (packet->options->universe_count <= agent_universe.index)
|
|
|
|
packet->options->universe_count =
|
|
|
|
agent_universe.index + 1;
|
|
|
|
|
|
|
|
packet->agent_options_stashed = ISC_TRUE;
|
2000-11-28 23:27:24 +00:00
|
|
|
}
|
|
|
|
nolease:
|
1996-05-22 09:29:56 +00:00
|
|
|
|
2006-02-24 23:16:32 +00:00
|
|
|
/* If a client null terminates options it sends, it probably
|
|
|
|
* expects the server to reciprocate.
|
|
|
|
*/
|
2000-02-07 05:12:20 +00:00
|
|
|
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_HOST_NAME))) {
|
|
|
|
if (!oc -> expression)
|
2006-02-24 23:16:32 +00:00
|
|
|
ms_nulltp = oc->flags & OPTION_HAD_NULLS;
|
2000-02-07 05:12:20 +00:00
|
|
|
}
|
|
|
|
|
2006-02-24 23:16:32 +00:00
|
|
|
/* Classify the client. */
|
1998-11-06 02:59:11 +00:00
|
|
|
classify_client (packet);
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
switch (packet -> packet_type) {
|
|
|
|
case DHCPDISCOVER:
|
2000-02-07 05:12:20 +00:00
|
|
|
dhcpdiscover (packet, ms_nulltp);
|
1996-02-26 01:56:15 +00:00
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
case DHCPREQUEST:
|
2000-11-28 23:27:24 +00:00
|
|
|
dhcprequest (packet, ms_nulltp, lease);
|
1996-02-26 01:56:15 +00:00
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
case DHCPRELEASE:
|
2000-02-07 05:12:20 +00:00
|
|
|
dhcprelease (packet, ms_nulltp);
|
1996-02-26 01:56:15 +00:00
|
|
|
break;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
case DHCPDECLINE:
|
2000-02-07 05:12:20 +00:00
|
|
|
dhcpdecline (packet, ms_nulltp);
|
1996-02-29 18:16:31 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case DHCPINFORM:
|
2000-02-07 05:12:20 +00:00
|
|
|
dhcpinform (packet, ms_nulltp);
|
1996-02-29 18:16:31 +00:00
|
|
|
break;
|
|
|
|
|
2006-07-25 13:26:00 +00:00
|
|
|
case DHCPLEASEQUERY:
|
|
|
|
dhcpleasequery(packet, ms_nulltp);
|
|
|
|
break;
|
2000-11-28 23:27:24 +00:00
|
|
|
|
|
|
|
case DHCPACK:
|
|
|
|
case DHCPOFFER:
|
|
|
|
case DHCPNAK:
|
2006-07-25 13:26:00 +00:00
|
|
|
case DHCPLEASEUNASSIGNED:
|
|
|
|
case DHCPLEASEUNKNOWN:
|
|
|
|
case DHCPLEASEACTIVE:
|
1996-02-26 01:56:15 +00:00
|
|
|
break;
|
2000-11-28 23:27:24 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
errmsg = "unknown packet type";
|
|
|
|
goto bad_packet;
|
1996-02-21 12:11:09 +00:00
|
|
|
}
|
2000-11-28 23:27:24 +00:00
|
|
|
out:
|
|
|
|
if (lease)
|
|
|
|
lease_dereference (&lease, MDL);
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
1996-02-21 12:11:09 +00:00
|
|
|
|
2000-02-07 05:12:20 +00:00
|
|
|
void dhcpdiscover (packet, ms_nulltp)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
struct lease *lease = (struct lease *)0;
|
1999-11-20 18:36:32 +00:00
|
|
|
char msgbuf [1024]; /* XXX */
|
1999-11-12 17:17:16 +00:00
|
|
|
TIME when;
|
2005-03-17 20:15:29 +00:00
|
|
|
const char *s;
|
2000-05-03 23:03:50 +00:00
|
|
|
int peer_has_leases = 0;
|
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
|
|
|
dhcp_failover_state_t *peer;
|
|
|
|
#endif
|
1996-03-16 17:50:30 +00:00
|
|
|
|
2000-08-24 18:49:34 +00:00
|
|
|
find_lease (&lease, packet, packet -> shared_network,
|
2006-02-24 23:16:32 +00:00
|
|
|
0, &peer_has_leases, (struct lease *)0, MDL);
|
1998-04-19 23:34:43 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
if (lease && lease -> client_hostname) {
|
|
|
|
if ((strlen (lease -> client_hostname) <= 64) &&
|
2007-07-13 06:43:43 +00:00
|
|
|
db_printable((unsigned char *)lease->client_hostname))
|
2005-03-17 20:15:29 +00:00
|
|
|
s = lease -> client_hostname;
|
|
|
|
else
|
|
|
|
s = "Hostname Unsuitable for Printing";
|
|
|
|
} else
|
1999-11-20 18:36:32 +00:00
|
|
|
s = (char *)0;
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* %Audit% This is log output. %2004.06.17,Safe%
|
|
|
|
* If we truncate we hope the user can get a hint from the log.
|
|
|
|
*/
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
|
|
|
"DHCP4o6 DHCPDISCOVER from %s %s%s%svia %s",
|
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)
|
|
|
|
: (lease
|
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
piaddr(packet->client_addr));
|
|
|
|
} else
|
|
|
|
#endif
|
2005-03-17 20:15:29 +00:00
|
|
|
snprintf (msgbuf, sizeof msgbuf, "DHCPDISCOVER from %s %s%s%svia %s",
|
1999-11-20 18:36:32 +00:00
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
1999-11-23 19:08:24 +00:00
|
|
|
packet -> raw -> chaddr)
|
1999-11-20 18:36:32 +00:00
|
|
|
: (lease
|
2006-07-25 13:26:00 +00:00
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
1999-11-20 18:36:32 +00:00
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name);
|
|
|
|
|
1996-05-23 01:59:38 +00:00
|
|
|
/* Sourceless packets don't make sense here. */
|
|
|
|
if (!packet -> shared_network) {
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
log_info ("DHCP4o6 packet from unknown subnet: %s",
|
|
|
|
piaddr(packet->client_addr));
|
|
|
|
} else
|
|
|
|
#endif
|
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));
|
2000-05-16 23:03:49 +00:00
|
|
|
goto out;
|
1996-05-23 01:59:38 +00:00
|
|
|
}
|
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
|
|
|
if (lease && lease -> pool && lease -> pool -> failover_peer) {
|
|
|
|
peer = lease -> pool -> failover_peer;
|
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* If the lease is ours to (re)allocate, then allocate it.
|
|
|
|
*
|
2006-06-16 19:26:45 +00:00
|
|
|
* If the lease is active, it belongs to the client. This
|
2006-02-24 23:16:32 +00:00
|
|
|
* is the right lease, if we are to offer one. We decide
|
2007-05-08 23:05:22 +00:00
|
|
|
* whether or not to offer later on.
|
2010-02-03 23:25:25 +00:00
|
|
|
*
|
|
|
|
* If the lease was last active, and we've reached this
|
|
|
|
* point, then it was last active with the same client. We
|
|
|
|
* can safely re-activate the lease with this client.
|
2006-02-24 23:16:32 +00:00
|
|
|
*/
|
2006-06-16 19:26:45 +00:00
|
|
|
if (lease->binding_state == FTS_ACTIVE ||
|
2010-02-03 23:25:25 +00:00
|
|
|
lease->rewind_binding_state == FTS_ACTIVE ||
|
2006-06-16 19:26:45 +00:00
|
|
|
lease_mine_to_reallocate(lease)) {
|
2006-02-24 23:16:32 +00:00
|
|
|
; /* This space intentionally left blank. */
|
2001-06-27 00:31:20 +00:00
|
|
|
|
|
|
|
/* Otherwise, we can't let the client have this lease. */
|
2006-02-24 23:16:32 +00:00
|
|
|
} else {
|
2001-06-27 00:31:20 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_debug ("discarding %s - %s",
|
|
|
|
piaddr (lease -> ip_addr),
|
|
|
|
binding_state_print (lease -> binding_state));
|
|
|
|
#endif
|
|
|
|
lease_dereference (&lease, MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1996-02-21 12:11:09 +00:00
|
|
|
/* If we didn't find a lease, try to allocate one... */
|
|
|
|
if (!lease) {
|
2000-05-16 23:03:49 +00:00
|
|
|
if (!allocate_lease (&lease, packet,
|
2018-09-26 11:10:16 -04:00
|
|
|
packet -> shared_network -> pools,
|
2000-05-16 23:03:49 +00:00
|
|
|
&peer_has_leases)) {
|
2000-05-03 23:03:50 +00:00
|
|
|
if (peer_has_leases)
|
2005-03-17 20:15:29 +00:00
|
|
|
log_error ("%s: peer holds all free leases",
|
|
|
|
msgbuf);
|
2000-05-03 23:03:50 +00:00
|
|
|
else
|
2005-03-17 20:15:29 +00:00
|
|
|
log_error ("%s: network %s: no free leases",
|
|
|
|
msgbuf,
|
|
|
|
packet -> shared_network -> name);
|
1996-02-21 12:11:09 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-05-02 00:00:08 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
2001-01-19 11:03:56 +00:00
|
|
|
if (lease && lease -> pool && lease -> pool -> failover_peer) {
|
|
|
|
peer = lease -> pool -> failover_peer;
|
|
|
|
if (peer -> service_state == not_responding ||
|
|
|
|
peer -> service_state == service_startup) {
|
|
|
|
log_info ("%s: not responding%s",
|
|
|
|
msgbuf, peer -> nrr);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
} else
|
|
|
|
peer = (dhcp_failover_state_t *)0;
|
|
|
|
|
2000-05-02 00:00:08 +00:00
|
|
|
/* Do load balancing if configured. */
|
2006-02-24 23:16:32 +00:00
|
|
|
if (peer && (peer -> service_state == cooperating) &&
|
2005-03-17 20:15:29 +00:00
|
|
|
!load_balance_mine (packet, peer)) {
|
2006-02-24 23:16:32 +00:00
|
|
|
if (peer_has_leases) {
|
2005-03-17 20:15:29 +00:00
|
|
|
log_debug ("%s: load balance to peer %s",
|
|
|
|
msgbuf, peer -> name);
|
|
|
|
goto out;
|
|
|
|
} else {
|
2006-02-24 23:16:32 +00:00
|
|
|
log_debug ("%s: cancel load balance to peer %s - %s",
|
|
|
|
msgbuf, peer -> name, "no free leases");
|
2000-05-03 23:03:50 +00:00
|
|
|
}
|
2000-05-02 00:00:08 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-01-25 01:36:29 +00:00
|
|
|
/* If it's an expired lease, get rid of any bindings. */
|
2000-07-27 09:03:08 +00:00
|
|
|
if (lease -> ends < cur_time && lease -> scope)
|
|
|
|
binding_scope_dereference (&lease -> scope, MDL);
|
2000-01-25 01:36:29 +00:00
|
|
|
|
1999-11-12 17:17:16 +00:00
|
|
|
/* Set the lease to really expire in 2 minutes, unless it has
|
|
|
|
not yet expired, in which case leave its expiry time alone. */
|
|
|
|
when = cur_time + 120;
|
|
|
|
if (when < lease -> ends)
|
|
|
|
when = lease -> ends;
|
|
|
|
|
2005-07-07 16:39:08 +00:00
|
|
|
ack_lease (packet, lease, DHCPOFFER, when, msgbuf, ms_nulltp,
|
|
|
|
(struct host_decl *)0);
|
2000-05-16 23:03:49 +00:00
|
|
|
out:
|
|
|
|
if (lease)
|
|
|
|
lease_dereference (&lease, MDL);
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2000-11-28 23:27:24 +00:00
|
|
|
void dhcprequest (packet, ms_nulltp, ip_lease)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp;
|
2000-11-28 23:27:24 +00:00
|
|
|
struct lease *ip_lease;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
1996-05-23 01:59:38 +00:00
|
|
|
struct lease *lease;
|
1996-02-29 18:16:31 +00:00
|
|
|
struct iaddr cip;
|
2000-12-28 23:28:17 +00:00
|
|
|
struct iaddr sip;
|
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;
|
1999-11-20 18:36:32 +00:00
|
|
|
char msgbuf [1024]; /* XXX */
|
2005-03-17 20:15:29 +00:00
|
|
|
const char *s;
|
2000-12-28 23:28:17 +00:00
|
|
|
char smbuf [19];
|
2000-08-24 18:49:34 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
|
|
|
dhcp_failover_state_t *peer;
|
|
|
|
#endif
|
2001-02-12 21:00:02 +00:00
|
|
|
int have_requested_addr = 0;
|
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-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&data, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, (struct option_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
&global_scope, oc, MDL)) {
|
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);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&data, MDL);
|
2001-02-12 21:00:02 +00:00
|
|
|
have_requested_addr = 1;
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
subnet = (struct subnet *)0;
|
|
|
|
lease = (struct lease *)0;
|
|
|
|
if (find_subnet (&subnet, cip, MDL))
|
|
|
|
find_lease (&lease, packet,
|
2000-11-28 23:27:24 +00:00
|
|
|
subnet -> shared_network, &ours, 0, ip_lease, MDL);
|
2000-06-02 21:27:21 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
if (lease && lease -> client_hostname) {
|
|
|
|
if ((strlen (lease -> client_hostname) <= 64) &&
|
2007-07-13 06:43:43 +00:00
|
|
|
db_printable((unsigned char *)lease->client_hostname))
|
2005-03-17 20:15:29 +00:00
|
|
|
s = lease -> client_hostname;
|
|
|
|
else
|
|
|
|
s = "Hostname Unsuitable for Printing";
|
|
|
|
} else
|
1999-11-20 18:36:32 +00:00
|
|
|
s = (char *)0;
|
|
|
|
|
2000-12-28 23:28:17 +00:00
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_DHCP_SERVER_IDENTIFIER);
|
|
|
|
memset (&data, 0, sizeof data);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&data, packet, (struct lease *)0,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options, (struct option_state *)0,
|
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
sip.len = 4;
|
|
|
|
memcpy (sip.iabuf, data.data, 4);
|
|
|
|
data_string_forget (&data, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
/* piaddr() should not return more than a 15 byte string.
|
|
|
|
* safe.
|
|
|
|
*/
|
2000-12-28 23:28:17 +00:00
|
|
|
sprintf (smbuf, " (%s)", piaddr (sip));
|
2012-11-16 15:02:13 -08:00
|
|
|
} else {
|
2000-12-28 23:28:17 +00:00
|
|
|
smbuf [0] = 0;
|
2012-11-16 15:02:13 -08:00
|
|
|
sip.len = 0;
|
|
|
|
}
|
2000-12-28 23:28:17 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* %Audit% This is log output. %2004.06.17,Safe%
|
|
|
|
* If we truncate we hope the user can get a hint from the log.
|
|
|
|
*/
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
|
|
|
"DHCP4o6 DHCPREQUEST for %s%s from %s %s%s%svia %s",
|
|
|
|
piaddr (cip), smbuf,
|
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)
|
|
|
|
: (lease
|
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
piaddr(packet->client_addr));
|
|
|
|
} else
|
|
|
|
#endif
|
2005-03-17 20:15:29 +00:00
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
|
|
|
"DHCPREQUEST for %s%s from %s %s%s%svia %s",
|
2000-12-28 23:28:17 +00:00
|
|
|
piaddr (cip), smbuf,
|
1999-11-20 18:36:32 +00:00
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
1999-11-23 19:08:24 +00:00
|
|
|
packet -> raw -> chaddr)
|
1999-11-20 18:36:32 +00:00
|
|
|
: (lease
|
2006-07-25 13:26:00 +00:00
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
1999-11-20 18:36:32 +00:00
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
packet -> raw -> giaddr.s_addr
|
1998-11-11 08:01:49 +00:00
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
1999-11-20 18:36:32 +00:00
|
|
|
: packet -> interface -> name);
|
1996-06-01 00:18:15 +00:00
|
|
|
|
2000-06-02 21:27:21 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
2000-08-24 18:49:34 +00:00
|
|
|
if (lease && lease -> pool && lease -> pool -> failover_peer) {
|
|
|
|
peer = lease -> pool -> failover_peer;
|
|
|
|
if (peer -> service_state == not_responding ||
|
|
|
|
peer -> service_state == service_startup) {
|
|
|
|
log_info ("%s: not responding%s",
|
2001-01-19 11:03:56 +00:00
|
|
|
msgbuf, peer -> nrr);
|
2000-08-24 18:49:34 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2001-05-17 19:04:09 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* "load balance to peer" - is not done at all for request.
|
|
|
|
*
|
|
|
|
* If it's RENEWING, we are the only server to hear it, so
|
|
|
|
* we have to serve it. If it's REBINDING, it's out of
|
|
|
|
* communication with the other server, so there's no point
|
|
|
|
* in waiting to serve it. However, if the lease we're
|
|
|
|
* offering is not a free lease, then we may be the only
|
|
|
|
* server that can offer it, so we can't load balance if
|
|
|
|
* the lease isn't in the free or backup state. If it is
|
|
|
|
* in the free or backup state, then that state is what
|
|
|
|
* mandates one server or the other should perform the
|
|
|
|
* allocation, not the LBA...we know the peer cannot
|
|
|
|
* allocate a request for an address in our free state.
|
|
|
|
*
|
|
|
|
* So our only compass is lease_mine_to_reallocate(). This
|
|
|
|
* effects both load balancing, and a sanity-check that we
|
|
|
|
* are not going to try to allocate a lease that isn't ours.
|
|
|
|
*/
|
2001-06-27 00:31:20 +00:00
|
|
|
if ((lease -> binding_state == FTS_FREE ||
|
|
|
|
lease -> binding_state == FTS_BACKUP) &&
|
|
|
|
!lease_mine_to_reallocate (lease)) {
|
|
|
|
log_debug ("%s: lease owned by peer", msgbuf);
|
2001-05-17 19:04:09 +00:00
|
|
|
goto out;
|
|
|
|
}
|
2001-06-27 00:31:20 +00:00
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* If the lease is in a transitional state, we can't
|
|
|
|
* renew it unless we can rewind it to a non-transitional
|
|
|
|
* state (active, free, or backup). lease_mine_to_reallocate()
|
|
|
|
* checks for free/backup, so we only need to check for active.
|
|
|
|
*/
|
|
|
|
if ((lease->binding_state == FTS_RELEASED ||
|
|
|
|
lease->binding_state == FTS_EXPIRED) &&
|
|
|
|
lease->rewind_binding_state != FTS_ACTIVE &&
|
|
|
|
!lease_mine_to_reallocate(lease)) {
|
|
|
|
log_debug("%s: lease in transition state %s", msgbuf,
|
|
|
|
(lease->binding_state == FTS_RELEASED)
|
2005-03-17 20:15:29 +00:00
|
|
|
? "released" : "expired");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It's actually very unlikely that we'll ever get here,
|
|
|
|
but if we do, tell the client to stop using the lease,
|
|
|
|
because the administrator reset it. */
|
|
|
|
if (lease -> binding_state == FTS_RESET &&
|
|
|
|
!lease_mine_to_reallocate (lease)) {
|
|
|
|
log_debug ("%s: lease reset by administrator", msgbuf);
|
2014-10-17 07:56:01 -04:00
|
|
|
nak_lease (packet, &cip, lease->subnet->group);
|
2005-03-17 20:15:29 +00:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2014-12-08 14:56:40 -05:00
|
|
|
/* If server-id-check is enabled, verify that the client's
|
|
|
|
* server source address (sip from incoming packet) is ours.
|
|
|
|
* To avoid problems with confused clients we do some sanity
|
|
|
|
* checks to verify sip's length and that it isn't all zeros.
|
|
|
|
* We then get the server id we would likely use for this
|
|
|
|
* packet and compare them. If they don't match it we assume
|
|
|
|
* we didn't send the offer and so we don't process the
|
|
|
|
* request. */
|
|
|
|
if ((server_id_check == 1) && (sip.len == 4) &&
|
2012-11-16 15:02:13 -08:00
|
|
|
(memcmp(sip.iabuf, "\0\0\0\0", sip.len) != 0)) {
|
|
|
|
struct in_addr from;
|
2014-10-17 07:56:01 -04:00
|
|
|
struct option_state *eval_options = NULL;
|
|
|
|
|
|
|
|
eval_network_statements(&eval_options, packet, NULL);
|
2014-12-08 14:56:40 -05:00
|
|
|
get_server_source_address(&from, eval_options,
|
|
|
|
NULL, packet);
|
2014-10-17 07:56:01 -04:00
|
|
|
option_state_dereference (&eval_options, MDL);
|
2012-11-16 15:02:13 -08:00
|
|
|
if (memcmp(sip.iabuf, &from, sip.len) != 0) {
|
|
|
|
log_debug("%s: not our server id", msgbuf);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
/* At this point it's possible that we will get a broadcast
|
|
|
|
DHCPREQUEST for a lease that we didn't offer, because
|
|
|
|
both we and the peer are in a position to offer it.
|
|
|
|
In that case, we probably shouldn't answer. In order
|
|
|
|
to not answer, we would have to compare the server
|
|
|
|
identifier sent by the client with the list of possible
|
|
|
|
server identifiers we can send, and if the client's
|
|
|
|
identifier isn't on the list, drop the DHCPREQUEST.
|
|
|
|
We aren't currently doing that for two reasons - first,
|
|
|
|
it's not clear that all clients do the right thing
|
|
|
|
with respect to sending the client identifier, which
|
|
|
|
could mean that we might simply not respond to a client
|
|
|
|
that is depending on us to respond. Secondly, we allow
|
|
|
|
the user to specify the server identifier to send, and
|
|
|
|
we don't enforce that the server identifier should be
|
|
|
|
one of our IP addresses. This is probably not a big
|
|
|
|
deal, but it's theoretically an issue.
|
|
|
|
|
|
|
|
The reason we care about this is that if both servers
|
|
|
|
send a DHCPACK to the DHCPREQUEST, they are then going
|
|
|
|
to send dueling BNDUPD messages, which could cause
|
|
|
|
trouble. I think it causes no harm, but it seems
|
|
|
|
wrong. */
|
2000-08-24 18:49:34 +00:00
|
|
|
} else
|
|
|
|
peer = (dhcp_failover_state_t *)0;
|
2000-06-02 21:27:21 +00:00
|
|
|
#endif
|
|
|
|
|
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
|
2000-09-08 01:23:43 +00:00
|
|
|
IP router, we'll just have to assume that it's cool.
|
1996-05-23 01:59:38 +00:00
|
|
|
|
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 ||
|
2000-11-30 14:04:06 +00:00
|
|
|
(packet -> raw -> ciaddr.s_addr &&
|
|
|
|
packet -> raw -> giaddr.s_addr) ||
|
2001-02-12 21:00:02 +00:00
|
|
|
(have_requested_addr && !packet -> raw -> ciaddr.s_addr)) {
|
2018-09-26 11:10:16 -04:00
|
|
|
|
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
|
2000-09-08 01:23:43 +00:00
|
|
|
from there. */
|
1996-05-23 01:59:38 +00:00
|
|
|
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);
|
2014-10-17 07:56:01 -04:00
|
|
|
nak_lease (packet, &cip, NULL);
|
2000-09-08 01:23:43 +00:00
|
|
|
goto out;
|
1996-05-23 01:59:38 +00:00
|
|
|
}
|
1996-08-27 09:37:50 +00:00
|
|
|
/* Otherwise, ignore it. */
|
2001-01-08 08:23:21 +00:00
|
|
|
log_info ("%s: ignored (%s).", msgbuf,
|
|
|
|
(subnet
|
|
|
|
? "not authoritative" : "unknown subnet"));
|
2000-05-16 23:03:49 +00:00
|
|
|
goto out;
|
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. */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (subnet)
|
|
|
|
subnet_dereference (&subnet, MDL);
|
|
|
|
if (!find_grouped_subnet (&subnet, packet -> shared_network,
|
|
|
|
cip, MDL)) {
|
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);
|
2014-10-17 07:56:01 -04:00
|
|
|
nak_lease (packet, &cip, NULL);
|
2000-09-08 01:23:43 +00:00
|
|
|
goto out;
|
1999-02-14 19:27:56 +00:00
|
|
|
}
|
1999-10-08 22:21:34 +00:00
|
|
|
log_info ("%s: ignored (not authoritative).", 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
|
2007-11-02 22:09:02 +00:00
|
|
|
available for the client, NAK it. */
|
1997-12-06 04:04:50 +00:00
|
|
|
if (!lease && ours) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: lease %s unavailable.", msgbuf, piaddr (cip));
|
2014-10-17 07:56:01 -04:00
|
|
|
nak_lease (packet, &cip, (subnet ? subnet->group : NULL));
|
2000-05-16 23:03:49 +00:00
|
|
|
goto out;
|
1997-12-06 04:04:50 +00:00
|
|
|
}
|
|
|
|
|
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) {
|
2005-07-07 16:39:08 +00:00
|
|
|
ack_lease (packet, lease, DHCPACK, 0, msgbuf, ms_nulltp,
|
|
|
|
(struct host_decl *)0);
|
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));
|
2000-05-16 23:03:49 +00:00
|
|
|
|
|
|
|
out:
|
|
|
|
if (subnet)
|
|
|
|
subnet_dereference (&subnet, MDL);
|
|
|
|
if (lease)
|
|
|
|
lease_dereference (&lease, MDL);
|
|
|
|
return;
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2000-02-07 05:12:20 +00:00
|
|
|
void dhcprelease (packet, ms_nulltp)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
2001-03-15 23:22:33 +00:00
|
|
|
struct lease *lease = (struct lease *)0, *next = (struct lease *)0;
|
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;
|
2005-03-17 20:15:29 +00:00
|
|
|
const char *s;
|
|
|
|
char msgbuf [1024], cstr[16]; /* XXX */
|
1997-06-08 03:55:58 +00:00
|
|
|
|
2000-08-24 18:49:34 +00:00
|
|
|
|
1997-11-29 07:57:02 +00:00
|
|
|
/* DHCPRELEASE must not specify address in requested-address
|
2007-11-02 22:09:02 +00:00
|
|
|
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-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&data, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, (struct option_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
&global_scope, oc, MDL)) {
|
2000-05-16 23:03:49 +00:00
|
|
|
find_lease_by_uid (&lease, data.data, data.len, MDL);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&data, MDL);
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1999-10-15 15:14:31 +00:00
|
|
|
/* See if we can find a lease that matches the IP address
|
|
|
|
the client is claiming. */
|
2001-03-22 21:36:49 +00:00
|
|
|
while (lease) {
|
2001-03-15 23:22:33 +00:00
|
|
|
if (lease -> n_uid)
|
|
|
|
lease_reference (&next, lease -> n_uid, MDL);
|
1999-10-15 15:14:31 +00:00
|
|
|
if (!memcmp (&packet -> raw -> ciaddr,
|
|
|
|
lease -> ip_addr.iabuf, 4)) {
|
|
|
|
break;
|
|
|
|
}
|
2001-03-15 23:22:33 +00:00
|
|
|
lease_dereference (&lease, MDL);
|
|
|
|
if (next) {
|
|
|
|
lease_reference (&lease, next, MDL);
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
}
|
1999-10-15 15:14:31 +00:00
|
|
|
}
|
2001-03-15 23:22:33 +00:00
|
|
|
if (next)
|
|
|
|
lease_dereference (&next, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
}
|
2000-01-25 01:36:29 +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) {
|
1999-10-24 18:54:11 +00:00
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
2000-05-16 23:03:49 +00:00
|
|
|
find_lease_by_ip_addr (&lease, cip, MDL);
|
1997-11-29 07:57:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* If the hardware address doesn't match, don't do the release. */
|
|
|
|
if (lease &&
|
|
|
|
(lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 ||
|
|
|
|
lease -> hardware_addr.hbuf [0] != packet -> raw -> htype ||
|
|
|
|
memcmp (&lease -> hardware_addr.hbuf [1],
|
|
|
|
packet -> raw -> chaddr, packet -> raw -> hlen)))
|
|
|
|
lease_dereference (&lease, MDL);
|
|
|
|
|
|
|
|
if (lease && lease -> client_hostname) {
|
|
|
|
if ((strlen (lease -> client_hostname) <= 64) &&
|
2007-07-13 06:43:43 +00:00
|
|
|
db_printable((unsigned char *)lease->client_hostname))
|
2005-03-17 20:15:29 +00:00
|
|
|
s = lease -> client_hostname;
|
|
|
|
else
|
|
|
|
s = "Hostname Unsuitable for Printing";
|
|
|
|
} else
|
1999-11-20 18:36:32 +00:00
|
|
|
s = (char *)0;
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe%
|
|
|
|
* We copy this out to stack because we actually want to log two
|
|
|
|
* inet_ntoa()'s in this message.
|
|
|
|
*/
|
|
|
|
strncpy(cstr, inet_ntoa (packet -> raw -> ciaddr), 15);
|
|
|
|
cstr[15] = '\0';
|
|
|
|
|
|
|
|
/* %Audit% This is log output. %2004.06.17,Safe%
|
|
|
|
* If we truncate we hope the user can get a hint from the log.
|
|
|
|
*/
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
|
|
|
"DHCP4o6 DHCPRELEASE of %s from %s %s%s%svia "
|
|
|
|
"%s (%sfound)",
|
|
|
|
cstr,
|
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)
|
|
|
|
: (lease
|
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
piaddr(packet->client_addr),
|
|
|
|
lease ? "" : "not ");
|
|
|
|
} else
|
|
|
|
#endif
|
2005-03-17 20:15:29 +00:00
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
2000-06-02 21:27:21 +00:00
|
|
|
"DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
|
2005-03-17 20:15:29 +00:00
|
|
|
cstr,
|
2000-06-02 21:27:21 +00:00
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)
|
|
|
|
: (lease
|
2006-07-25 13:26:00 +00:00
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
2000-06-02 21:27:21 +00:00
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name,
|
|
|
|
lease ? "" : "not ");
|
|
|
|
|
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
2000-08-24 18:49:34 +00:00
|
|
|
if (lease && lease -> pool && lease -> pool -> failover_peer) {
|
|
|
|
dhcp_failover_state_t *peer = lease -> pool -> failover_peer;
|
|
|
|
if (peer -> service_state == not_responding ||
|
|
|
|
peer -> service_state == service_startup) {
|
|
|
|
log_info ("%s: ignored%s",
|
|
|
|
peer -> name, peer -> nrr);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2000-06-02 21:27:21 +00:00
|
|
|
/* DHCPRELEASE messages are unicast, so if the client
|
|
|
|
sent the DHCPRELEASE to us, it's not going to send it
|
|
|
|
to the peer. Not sure why this would happen, and
|
|
|
|
if it does happen I think we still have to change the
|
2000-08-24 18:49:34 +00:00
|
|
|
lease state, so that's what we're doing.
|
2000-06-02 21:27:21 +00:00
|
|
|
XXX See what it says in the draft about this. */
|
|
|
|
}
|
|
|
|
#endif
|
1996-03-16 17:50:30 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* If we found a lease, release it. */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (lease && lease -> ends > cur_time) {
|
1999-10-05 02:46:17 +00:00
|
|
|
release_lease (lease, packet);
|
2018-09-26 11:10:16 -04:00
|
|
|
}
|
2001-03-14 15:44:39 +00:00
|
|
|
log_info ("%s", msgbuf);
|
2008-02-28 21:21:56 +00:00
|
|
|
#if defined(FAILOVER_PROTOCOL)
|
2000-06-02 21:27:21 +00:00
|
|
|
out:
|
2008-02-28 21:21:56 +00:00
|
|
|
#endif
|
2000-06-02 21:27:21 +00:00
|
|
|
if (lease)
|
|
|
|
lease_dereference (&lease, MDL);
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2000-02-07 05:12:20 +00:00
|
|
|
void dhcpdecline (packet, ms_nulltp)
|
1996-02-29 18:16:31 +00:00
|
|
|
struct packet *packet;
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp;
|
1996-02-29 18:16:31 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
struct lease *lease = (struct lease *)0;
|
1999-10-21 02:42:57 +00:00
|
|
|
struct option_state *options = (struct option_state *)0;
|
2000-08-24 18:49:34 +00:00
|
|
|
int ignorep = 0;
|
1999-10-21 02:42:57 +00:00
|
|
|
int i;
|
|
|
|
const char *status;
|
2005-03-17 20:15:29 +00:00
|
|
|
const char *s;
|
2000-06-02 21:27:21 +00:00
|
|
|
char msgbuf [1024]; /* XXX */
|
2000-11-28 23:27:24 +00:00
|
|
|
struct iaddr cip;
|
|
|
|
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-31 18:08:28 +00:00
|
|
|
if (!evaluate_option_cache (&data, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options,
|
|
|
|
(struct option_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
&global_scope, oc, MDL))
|
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);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&data, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
find_lease_by_ip_addr (&lease, cip, MDL);
|
1997-06-08 03:55:58 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
if (lease && lease -> client_hostname) {
|
|
|
|
if ((strlen (lease -> client_hostname) <= 64) &&
|
2007-07-13 06:43:43 +00:00
|
|
|
db_printable((unsigned char *)lease->client_hostname))
|
2005-03-17 20:15:29 +00:00
|
|
|
s = lease -> client_hostname;
|
|
|
|
else
|
|
|
|
s = "Hostname Unsuitable for Printing";
|
|
|
|
} else
|
2000-06-02 21:27:21 +00:00
|
|
|
s = (char *)0;
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* %Audit% This is log output. %2004.06.17,Safe%
|
|
|
|
* If we truncate we hope the user can get a hint from the log.
|
|
|
|
*/
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
|
|
|
"DHCP4o6 DHCPDECLINE of %s from %s %s%s%svia %s",
|
|
|
|
piaddr (cip),
|
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)
|
|
|
|
: (lease
|
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
piaddr(packet->client_addr));
|
|
|
|
} else
|
|
|
|
#endif
|
2005-03-17 20:15:29 +00:00
|
|
|
snprintf (msgbuf, sizeof msgbuf,
|
|
|
|
"DHCPDECLINE of %s from %s %s%s%svia %s",
|
2000-06-02 21:27:21 +00:00
|
|
|
piaddr (cip),
|
|
|
|
(packet -> raw -> htype
|
|
|
|
? print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)
|
|
|
|
: (lease
|
2006-07-25 13:26:00 +00:00
|
|
|
? print_hex_1(lease->uid_len, lease->uid, 60)
|
2000-06-02 21:27:21 +00:00
|
|
|
: "<no identifier>")),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
packet -> raw -> giaddr.s_addr
|
|
|
|
? inet_ntoa (packet -> raw -> giaddr)
|
|
|
|
: packet -> interface -> name);
|
|
|
|
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_allocate (&options, MDL);
|
1996-06-01 00:18:15 +00:00
|
|
|
|
1999-10-21 02:42:57 +00:00
|
|
|
/* Execute statements in scope starting with the subnet scope. */
|
|
|
|
if (lease)
|
2013-08-27 13:40:47 -07:00
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, options,
|
|
|
|
&global_scope,
|
|
|
|
lease->subnet->group,
|
|
|
|
NULL, NULL);
|
1999-10-21 02:42:57 +00:00
|
|
|
|
|
|
|
/* Execute statements in the class scopes. */
|
|
|
|
for (i = packet -> class_count; i > 0; i--) {
|
|
|
|
execute_statements_in_scope
|
2013-08-27 13:40:47 -07:00
|
|
|
(NULL, packet, NULL, NULL, packet->options, options,
|
|
|
|
&global_scope, packet->classes[i - 1]->group,
|
|
|
|
lease ? lease->subnet->group : NULL, NULL);
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
1999-10-21 02:42:57 +00:00
|
|
|
|
|
|
|
/* Drop the request if dhcpdeclines are being ignored. */
|
|
|
|
oc = lookup_option (&server_universe, options, SV_DECLINES);
|
|
|
|
if (!oc ||
|
2000-01-25 01:36:29 +00:00
|
|
|
evaluate_boolean_option_cache (&ignorep, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
packet -> options, options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
2000-08-24 18:49:34 +00:00
|
|
|
/* If we found a lease, mark it as unusable and complain. */
|
|
|
|
if (lease) {
|
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
|
|
|
if (lease -> pool && lease -> pool -> failover_peer) {
|
|
|
|
dhcp_failover_state_t *peer =
|
|
|
|
lease -> pool -> failover_peer;
|
|
|
|
if (peer -> service_state == not_responding ||
|
|
|
|
peer -> service_state == service_startup) {
|
|
|
|
if (!ignorep)
|
|
|
|
log_info ("%s: ignored%s",
|
|
|
|
peer -> name, peer -> nrr);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* DHCPDECLINE messages are broadcast, so we can safely
|
|
|
|
ignore the DHCPDECLINE if the peer has the lease.
|
|
|
|
XXX Of course, at this point that information has been
|
|
|
|
lost. */
|
1999-10-21 02:42:57 +00:00
|
|
|
}
|
2000-08-24 18:49:34 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
abandon_lease (lease, "declined.");
|
|
|
|
status = "abandoned";
|
2008-09-11 16:11:46 +00:00
|
|
|
} else {
|
|
|
|
status = "not found";
|
2000-08-24 18:49:34 +00:00
|
|
|
}
|
1999-10-21 02:42:57 +00:00
|
|
|
} else
|
2000-08-24 18:49:34 +00:00
|
|
|
status = "ignored";
|
1999-10-21 02:42:57 +00:00
|
|
|
|
2000-06-02 21:27:21 +00:00
|
|
|
if (!ignorep)
|
|
|
|
log_info ("%s: %s", msgbuf, status);
|
2008-02-28 21:21:56 +00:00
|
|
|
|
|
|
|
#if defined(FAILOVER_PROTOCOL)
|
2000-06-02 21:27:21 +00:00
|
|
|
out:
|
2008-02-28 21:21:56 +00:00
|
|
|
#endif
|
2000-06-02 21:27:21 +00:00
|
|
|
if (options)
|
|
|
|
option_state_dereference (&options, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
if (lease)
|
|
|
|
lease_dereference (&lease, MDL);
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
|
|
|
|
2017-12-23 01:18:23 +01:00
|
|
|
#if defined(RELAY_PORT)
|
|
|
|
u_int16_t dhcp_check_relayport(packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
|
|
|
if (lookup_option(&agent_universe,
|
|
|
|
packet->options,
|
|
|
|
RAI_RELAY_PORT) != NULL) {
|
|
|
|
return (packet->client_port);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-02-07 05:12:20 +00:00
|
|
|
void dhcpinform (packet, ms_nulltp)
|
1996-02-29 18:16:31 +00:00
|
|
|
struct packet *packet;
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp;
|
1996-02-29 18:16:31 +00:00
|
|
|
{
|
2013-12-13 12:52:17 -08:00
|
|
|
char msgbuf[1024], *addr_type;
|
|
|
|
struct data_string d1, prl, fixed_addr;
|
1999-04-12 22:18:58 +00:00
|
|
|
struct option_cache *oc;
|
2013-12-13 12:52:17 -08:00
|
|
|
struct option_state *options = NULL;
|
1999-04-12 22:18:58 +00:00
|
|
|
struct dhcp_packet raw;
|
|
|
|
struct packet outgoing;
|
1999-07-13 18:00:22 +00:00
|
|
|
unsigned char dhcpack = DHCPACK;
|
2008-01-08 16:09:32 +00:00
|
|
|
struct subnet *subnet = NULL;
|
2013-12-13 12:52:17 -08:00
|
|
|
struct iaddr cip, gip, sip;
|
2007-07-13 06:43:43 +00:00
|
|
|
unsigned i;
|
1999-10-07 06:36:35 +00:00
|
|
|
int nulltp;
|
1999-04-12 22:18:58 +00:00
|
|
|
struct sockaddr_in to;
|
|
|
|
struct in_addr from;
|
2008-01-08 16:09:32 +00:00
|
|
|
isc_boolean_t zeroed_ciaddr;
|
2012-03-09 11:18:14 +00:00
|
|
|
struct interface_info *interface;
|
2013-12-13 12:52:17 -08:00
|
|
|
int result, h_m_client_ip = 0;
|
|
|
|
struct host_decl *host = NULL, *hp = NULL, *h;
|
2017-12-30 14:15:12 +01:00
|
|
|
#if defined(RELAY_PORT)
|
2017-12-23 01:18:23 +01:00
|
|
|
u_int16_t relay_port = 0;
|
2017-12-30 14:15:12 +01:00
|
|
|
#endif
|
2013-12-13 12:52:17 -08:00
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
int h_w_fixed_addr = 0;
|
|
|
|
#endif
|
2008-01-08 16:09:32 +00:00
|
|
|
|
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. */
|
2013-12-13 12:52:17 -08:00
|
|
|
if (!packet->raw->ciaddr.s_addr) {
|
2008-01-08 16:09:32 +00:00
|
|
|
zeroed_ciaddr = ISC_TRUE;
|
2016-02-23 10:40:10 +01:00
|
|
|
/* With DHCPv4-over-DHCPv6 it can be an IPv6 address
|
|
|
|
so we check its length. */
|
|
|
|
if (packet->client_addr.len == 4) {
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy(cip.iabuf, &packet->client_addr.iabuf, 4);
|
|
|
|
addr_type = "source";
|
|
|
|
} else {
|
|
|
|
cip.len = 0;
|
|
|
|
memset(cip.iabuf, 0, 4);
|
|
|
|
addr_type = "v4o6";
|
|
|
|
}
|
1999-05-06 20:35:48 +00:00
|
|
|
} else {
|
2008-01-08 16:09:32 +00:00
|
|
|
zeroed_ciaddr = ISC_FALSE;
|
1999-05-06 20:35:48 +00:00
|
|
|
cip.len = 4;
|
2013-12-13 12:52:17 -08:00
|
|
|
memcpy(cip.iabuf, &packet->raw->ciaddr, 4);
|
|
|
|
addr_type = "client";
|
1999-05-06 20:35:48 +00:00
|
|
|
}
|
2013-12-13 12:52:17 -08:00
|
|
|
sip.len = 4;
|
|
|
|
memcpy(sip.iabuf, cip.iabuf, 4);
|
1999-05-06 20:35:48 +00:00
|
|
|
|
2006-02-24 23:16:32 +00:00
|
|
|
if (packet->raw->giaddr.s_addr) {
|
|
|
|
gip.len = 4;
|
|
|
|
memcpy(gip.iabuf, &packet->raw->giaddr, 4);
|
2013-12-13 12:52:17 -08:00
|
|
|
if (zeroed_ciaddr == ISC_TRUE) {
|
|
|
|
addr_type = "relay";
|
|
|
|
memcpy(sip.iabuf, gip.iabuf, 4);
|
|
|
|
}
|
2006-02-24 23:16:32 +00:00
|
|
|
} else
|
|
|
|
gip.len = 0;
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* %Audit% This is log output. %2004.06.17,Safe%
|
|
|
|
* If we truncate we hope the user can get a hint from the log.
|
|
|
|
*/
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
snprintf(msgbuf, sizeof(msgbuf),
|
|
|
|
"DHCP4o6 DHCPINFORM from %s via %s",
|
|
|
|
piaddr(cip),
|
|
|
|
piaddr(packet->client_addr));
|
|
|
|
} else
|
|
|
|
#endif
|
2013-12-13 12:52:17 -08:00
|
|
|
snprintf(msgbuf, sizeof(msgbuf), "DHCPINFORM from %s via %s",
|
|
|
|
piaddr(cip),
|
|
|
|
packet->raw->giaddr.s_addr ?
|
|
|
|
inet_ntoa(packet->raw->giaddr) :
|
|
|
|
packet->interface->name);
|
1999-05-06 20:35:48 +00:00
|
|
|
|
|
|
|
/* If the IP source address is zero, don't respond. */
|
2013-12-13 12:52:17 -08:00
|
|
|
if (!memcmp(cip.iabuf, "\0\0\0", 4)) {
|
|
|
|
log_info("%s: ignored (null source address).", msgbuf);
|
1999-05-06 20:35:48 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-04-12 22:18:58 +00:00
|
|
|
|
2017-12-23 01:18:23 +01:00
|
|
|
#if defined(RELAY_PORT)
|
|
|
|
relay_port = dhcp_check_relayport(packet);
|
|
|
|
#endif
|
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
/* Find the subnet that the client is on.
|
2013-12-13 12:52:17 -08:00
|
|
|
* CC: Do the link selection / subnet selection
|
|
|
|
*/
|
|
|
|
|
|
|
|
option_state_allocate(&options, MDL);
|
|
|
|
|
|
|
|
if ((oc = lookup_option(&agent_universe, packet->options,
|
|
|
|
RAI_LINK_SELECT)) == NULL)
|
|
|
|
oc = lookup_option(&dhcp_universe, packet->options,
|
|
|
|
DHO_SUBNET_SELECTION);
|
2008-01-08 16:09:32 +00:00
|
|
|
|
2013-12-13 12:52:17 -08:00
|
|
|
memset(&d1, 0, sizeof d1);
|
|
|
|
if (oc && evaluate_option_cache(&d1, packet, NULL, NULL,
|
|
|
|
packet->options, NULL,
|
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
struct option_cache *noc = NULL;
|
|
|
|
|
|
|
|
if (d1.len != 4) {
|
|
|
|
log_info("%s: ignored (invalid subnet selection option).", msgbuf);
|
|
|
|
option_state_dereference(&options, MDL);
|
2019-11-22 13:39:45 -05:00
|
|
|
data_string_forget(&d1, MDL);
|
2008-01-08 16:09:32 +00:00
|
|
|
return;
|
|
|
|
}
|
1999-04-12 22:18:58 +00:00
|
|
|
|
2013-12-13 12:52:17 -08:00
|
|
|
memcpy(sip.iabuf, d1.data, 4);
|
|
|
|
data_string_forget(&d1, MDL);
|
|
|
|
|
|
|
|
/* Make a copy of the data. */
|
|
|
|
if (option_cache_allocate(&noc, MDL)) {
|
|
|
|
if (oc->data.len)
|
|
|
|
data_string_copy(&noc->data, &oc->data, MDL);
|
|
|
|
if (oc->expression)
|
|
|
|
expression_reference(&noc->expression,
|
|
|
|
oc->expression, MDL);
|
|
|
|
if (oc->option)
|
|
|
|
option_reference(&(noc->option), oc->option,
|
|
|
|
MDL);
|
2008-01-08 16:09:32 +00:00
|
|
|
}
|
2013-12-13 12:52:17 -08:00
|
|
|
save_option(&dhcp_universe, options, noc);
|
|
|
|
option_cache_dereference(&noc, MDL);
|
|
|
|
|
|
|
|
if ((zeroed_ciaddr == ISC_TRUE) && (gip.len != 0))
|
|
|
|
addr_type = "relay link select";
|
|
|
|
else
|
|
|
|
addr_type = "selected";
|
|
|
|
}
|
|
|
|
|
|
|
|
find_subnet(&subnet, sip, MDL);
|
|
|
|
|
|
|
|
if (subnet == NULL) {
|
|
|
|
log_info("%s: unknown subnet for %s address %s",
|
|
|
|
msgbuf, addr_type, piaddr(sip));
|
2014-08-28 07:56:20 -04:00
|
|
|
option_state_dereference(&options, MDL);
|
2013-12-13 12:52:17 -08:00
|
|
|
return;
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
1999-10-08 22:21:34 +00:00
|
|
|
/* We don't respond to DHCPINFORM packets if we're not authoritative.
|
|
|
|
It would be nice if a per-host value could override this, but
|
|
|
|
there's overhead involved in checking this, so let's see how people
|
|
|
|
react first. */
|
2014-08-28 07:56:20 -04:00
|
|
|
if (!subnet->group->authoritative) {
|
2000-05-16 23:03:49 +00:00
|
|
|
static int eso = 0;
|
2014-08-28 07:56:20 -04:00
|
|
|
log_info("%s: not authoritative for subnet %s",
|
1999-10-08 22:21:34 +00:00
|
|
|
msgbuf, piaddr (subnet -> net));
|
2000-05-16 23:03:49 +00:00
|
|
|
if (!eso) {
|
2014-08-28 07:56:20 -04:00
|
|
|
log_info("If this DHCP server is authoritative for%s",
|
2000-05-16 23:03:49 +00:00
|
|
|
" that subnet,");
|
2014-08-28 07:56:20 -04:00
|
|
|
log_info("please write an `authoritative;' directi%s",
|
2000-05-16 23:03:49 +00:00
|
|
|
"ve either in the");
|
2014-08-28 07:56:20 -04:00
|
|
|
log_info("subnet declaration or in some scope that%s",
|
2005-03-17 20:15:29 +00:00
|
|
|
" encloses the");
|
2014-08-28 07:56:20 -04:00
|
|
|
log_info("subnet declaration - for example, write %s",
|
2000-05-16 23:03:49 +00:00
|
|
|
"it at the top");
|
2014-08-28 07:56:20 -04:00
|
|
|
log_info("of the dhcpd.conf file.");
|
2000-05-16 23:03:49 +00:00
|
|
|
}
|
|
|
|
if (eso++ == 100)
|
|
|
|
eso = 0;
|
2014-08-28 07:56:20 -04:00
|
|
|
subnet_dereference(&subnet, MDL);
|
|
|
|
option_state_dereference(&options, MDL);
|
1999-10-08 22:21:34 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2014-08-28 07:56:20 -04:00
|
|
|
memset(&outgoing, 0, sizeof outgoing);
|
|
|
|
memset(&raw, 0, sizeof raw);
|
1999-04-12 22:18:58 +00:00
|
|
|
outgoing.raw = &raw;
|
|
|
|
|
2009-07-06 23:33:23 +00:00
|
|
|
maybe_return_agent_options(packet, options);
|
|
|
|
|
2017-04-12 11:44:59 -04:00
|
|
|
/* Execute statements network statements starting at the subnet level */
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, options,
|
|
|
|
&global_scope, subnet->group,
|
|
|
|
NULL, NULL);
|
|
|
|
|
2016-11-01 14:05:24 -04:00
|
|
|
/* If we have ciaddr, find its lease so we can find its pool. */
|
|
|
|
if (zeroed_ciaddr == ISC_FALSE) {
|
2017-04-12 11:44:59 -04:00
|
|
|
struct lease* cip_lease = NULL;
|
|
|
|
|
2016-11-01 14:05:24 -04:00
|
|
|
find_lease_by_ip_addr (&cip_lease, cip, MDL);
|
2018-09-26 11:10:16 -04:00
|
|
|
|
|
|
|
/* Overlay with pool options if ciaddr mapped to a lease. */
|
2017-04-12 11:44:59 -04:00
|
|
|
if (cip_lease) {
|
|
|
|
if (cip_lease->pool && cip_lease->pool->group) {
|
|
|
|
execute_statements_in_scope(
|
|
|
|
NULL, packet, NULL, NULL,
|
|
|
|
packet->options, options,
|
|
|
|
&global_scope,
|
|
|
|
cip_lease->pool->group,
|
|
|
|
cip_lease->pool->shared_network->group,
|
|
|
|
NULL);
|
|
|
|
}
|
2016-11-01 14:05:24 -04:00
|
|
|
|
2017-04-12 11:44:59 -04:00
|
|
|
lease_dereference (&cip_lease, MDL);
|
|
|
|
}
|
2016-11-01 14:05:24 -04:00
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1999-04-12 22:18:58 +00:00
|
|
|
/* Execute statements in the class scopes. */
|
2014-08-28 07:56:20 -04:00
|
|
|
for (i = packet->class_count; i > 0; i--) {
|
2013-08-27 13:40:47 -07:00
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, options,
|
|
|
|
&global_scope,
|
|
|
|
packet->classes[i - 1]->group,
|
2014-08-28 07:56:20 -04:00
|
|
|
subnet->group,
|
2013-08-27 13:40:47 -07:00
|
|
|
NULL);
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
2013-12-13 12:52:17 -08:00
|
|
|
/*
|
2018-09-26 11:10:16 -04:00
|
|
|
* Process host declarations during DHCPINFORM,
|
2013-12-13 12:52:17 -08:00
|
|
|
* Try to find a matching host declaration by cli ID or HW addr.
|
|
|
|
*
|
|
|
|
* Look through the host decls for one that matches the
|
|
|
|
* client identifer or the hardware address. The preference
|
|
|
|
* order is:
|
|
|
|
* client id with matching ip address
|
|
|
|
* hardware address with matching ip address
|
|
|
|
* client id without a ip fixed address
|
|
|
|
* hardware address without a fixed ip address
|
|
|
|
* If found, set host to use its option definitions.
|
|
|
|
*/
|
|
|
|
oc = lookup_option(&dhcp_universe, packet->options,
|
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
memset(&d1, 0, sizeof(d1));
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache(&d1, packet, NULL, NULL,
|
|
|
|
packet->options, NULL,
|
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
find_hosts_by_uid(&hp, d1.data, d1.len, MDL);
|
|
|
|
data_string_forget(&d1, MDL);
|
|
|
|
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
if (hp)
|
|
|
|
log_debug ("dhcpinform: found host by ID "
|
|
|
|
"-- checking fixed-address match");
|
|
|
|
#endif
|
|
|
|
/* check if we have one with fixed-address
|
|
|
|
* matching the client ip first */
|
|
|
|
for (h = hp; !h_m_client_ip && h; h = h->n_ipaddr) {
|
|
|
|
if (!h->fixed_addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
memset(&fixed_addr, 0, sizeof(fixed_addr));
|
|
|
|
if (!evaluate_option_cache (&fixed_addr, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
&global_scope,
|
|
|
|
h->fixed_addr, MDL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
h_w_fixed_addr++;
|
|
|
|
#endif
|
|
|
|
for (i = 0;
|
|
|
|
(i + cip.len) <= fixed_addr.len;
|
|
|
|
i += cip.len) {
|
|
|
|
if (memcmp(fixed_addr.data + i,
|
|
|
|
cip.iabuf, cip.len) == 0) {
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
log_debug ("dhcpinform: found "
|
|
|
|
"host with matching "
|
|
|
|
"fixed-address by ID");
|
|
|
|
#endif
|
|
|
|
host_reference(&host, h, MDL);
|
|
|
|
h_m_client_ip = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data_string_forget(&fixed_addr, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fallback to a host without fixed-address */
|
|
|
|
for (h = hp; !host && h; h = h->n_ipaddr) {
|
|
|
|
if (h->fixed_addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
log_debug ("dhcpinform: found host "
|
|
|
|
"without fixed-address by ID");
|
|
|
|
#endif
|
|
|
|
host_reference(&host, h, MDL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (hp)
|
|
|
|
host_dereference (&hp, MDL);
|
|
|
|
}
|
|
|
|
if (!host || !h_m_client_ip) {
|
|
|
|
find_hosts_by_haddr(&hp, packet->raw->htype,
|
|
|
|
packet->raw->chaddr,
|
|
|
|
packet->raw->hlen, MDL);
|
|
|
|
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
if (hp)
|
|
|
|
log_debug ("dhcpinform: found host by HW "
|
|
|
|
"-- checking fixed-address match");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* check if we have one with fixed-address
|
|
|
|
* matching the client ip first */
|
|
|
|
for (h = hp; !h_m_client_ip && h; h = h->n_ipaddr) {
|
|
|
|
if (!h->fixed_addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
memset (&fixed_addr, 0, sizeof(fixed_addr));
|
|
|
|
if (!evaluate_option_cache (&fixed_addr, NULL,
|
|
|
|
NULL, NULL, NULL, NULL,
|
|
|
|
&global_scope,
|
|
|
|
h->fixed_addr, MDL))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
h_w_fixed_addr++;
|
|
|
|
#endif
|
|
|
|
for (i = 0;
|
|
|
|
(i + cip.len) <= fixed_addr.len;
|
|
|
|
i += cip.len) {
|
|
|
|
if (memcmp(fixed_addr.data + i,
|
|
|
|
cip.iabuf, cip.len) == 0) {
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
log_debug ("dhcpinform: found "
|
|
|
|
"host with matching "
|
|
|
|
"fixed-address by HW");
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Hmm.. we've found one
|
|
|
|
* without IP by ID and now
|
|
|
|
* (better) one with IP by HW.
|
|
|
|
*/
|
|
|
|
if(host)
|
|
|
|
host_dereference(&host, MDL);
|
|
|
|
host_reference(&host, h, MDL);
|
|
|
|
h_m_client_ip = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data_string_forget(&fixed_addr, MDL);
|
|
|
|
}
|
|
|
|
/* fallback to a host without fixed-address */
|
|
|
|
for (h = hp; !host && h; h = h->n_ipaddr) {
|
|
|
|
if (h->fixed_addr)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
log_debug ("dhcpinform: found host without "
|
|
|
|
"fixed-address by HW");
|
|
|
|
#endif
|
|
|
|
host_reference (&host, h, MDL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hp)
|
|
|
|
host_dereference (&hp, MDL);
|
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2013-12-13 12:52:17 -08:00
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
/* Hmm..: what when there is a host with a fixed-address,
|
|
|
|
* that matches by hw or id, but the fixed-addresses
|
|
|
|
* didn't match client ip?
|
|
|
|
*/
|
|
|
|
if (h_w_fixed_addr && !h_m_client_ip) {
|
|
|
|
log_info ("dhcpinform: matching host with "
|
|
|
|
"fixed-address different than "
|
|
|
|
"client IP detected?!");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* If we have a host_decl structure, run the options
|
|
|
|
* associated with its group. Whether the host decl
|
|
|
|
* struct is old or not. */
|
|
|
|
if (host) {
|
|
|
|
#if defined (DEBUG_INFORM_HOST)
|
|
|
|
log_info ("dhcpinform: applying host (group) options");
|
|
|
|
#endif
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, options,
|
|
|
|
&global_scope, host->group,
|
2014-12-10 12:16:56 -08:00
|
|
|
subnet->group,
|
2013-12-13 12:52:17 -08:00
|
|
|
NULL);
|
|
|
|
host_dereference (&host, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* CC: end of host entry processing.... */
|
2018-09-26 11:10:16 -04:00
|
|
|
|
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-31 18:08:28 +00:00
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, (struct option_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
&global_scope, oc, MDL)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
i = d1.len;
|
2010-09-08 22:13:05 +00:00
|
|
|
if (i >= sizeof(raw.file)) {
|
|
|
|
log_info("file name longer than packet field "
|
2018-09-26 11:10:16 -04:00
|
|
|
"truncated - field: %lu name: %d %.*s",
|
2011-02-16 03:22:56 +00:00
|
|
|
(unsigned long)sizeof(raw.file), i,
|
|
|
|
(int)i, d1.data);
|
2010-09-08 22:13:05 +00:00
|
|
|
i = sizeof(raw.file);
|
|
|
|
} else
|
|
|
|
raw.file[i] = 0;
|
1999-04-12 22:18:58 +00:00
|
|
|
memcpy (raw.file, d1.data, i);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
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-31 18:08:28 +00:00
|
|
|
if (oc &&
|
2000-11-28 23:27:24 +00:00
|
|
|
evaluate_option_cache (&d1, packet, (struct lease *)0,
|
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, (struct option_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
&global_scope, oc, MDL)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
i = d1.len;
|
2010-09-08 22:13:05 +00:00
|
|
|
if (i >= sizeof(raw.sname)) {
|
|
|
|
log_info("server name longer than packet field "
|
2018-09-26 11:10:16 -04:00
|
|
|
"truncated - field: %lu name: %d %.*s",
|
2011-02-16 03:22:56 +00:00
|
|
|
(unsigned long)sizeof(raw.sname), i,
|
|
|
|
(int)i, d1.data);
|
2010-09-08 22:13:05 +00:00
|
|
|
i = sizeof(raw.sname);
|
|
|
|
} else
|
|
|
|
raw.sname[i] = 0;
|
1999-04-12 22:18:58 +00:00
|
|
|
memcpy (raw.sname, d1.data, i);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
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))) {
|
2006-02-24 23:16:32 +00:00
|
|
|
if (!oc->expression)
|
|
|
|
nulltp = oc->flags & OPTION_HAD_NULLS;
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Put in DHCP-specific options. */
|
|
|
|
i = DHO_DHCP_MESSAGE_TYPE;
|
|
|
|
oc = (struct option_cache *)0;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
2001-06-27 00:31:20 +00:00
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
&dhcpack, 1, 0, 0, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-12 22:18:58 +00:00
|
|
|
save_option (&dhcp_universe, options, oc);
|
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
|
2012-11-16 15:02:13 -08:00
|
|
|
get_server_source_address(&from, options, options, packet);
|
1999-04-12 22:18:58 +00:00
|
|
|
|
|
|
|
/* 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;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
1999-04-12 22:18:58 +00:00
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
subnet -> netmask.iabuf,
|
2001-06-27 00:31:20 +00:00
|
|
|
subnet -> netmask.len,
|
|
|
|
0, 0, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-12 22:18:58 +00:00
|
|
|
save_option (&dhcp_universe, options, oc);
|
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
1999-04-12 22:18:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&d1, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
packet -> options, options,
|
|
|
|
&global_scope, oc, MDL)) {
|
2000-05-16 23:03:49 +00:00
|
|
|
struct universe *u = (struct universe *)0;
|
2012-03-09 11:18:14 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
if (!universe_hash_lookup (&u, universe_hash,
|
2000-05-17 16:04:26 +00:00
|
|
|
(const char *)d1.data, d1.len,
|
|
|
|
MDL)) {
|
1999-04-23 23:17:52 +00:00
|
|
|
log_error ("unknown option space %s.", d1.data);
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_dereference (&options, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
if (subnet)
|
|
|
|
subnet_dereference (&subnet, MDL);
|
2019-11-22 13:39:45 -05:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-04-23 23:17:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
options -> site_universe = u -> index;
|
2008-01-09 17:13:16 +00:00
|
|
|
options->site_code_min = find_min_site_code(u);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-04-23 23:17:52 +00:00
|
|
|
} 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-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&prl, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
packet -> options, options,
|
|
|
|
&global_scope, oc, MDL);
|
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. */
|
|
|
|
if ((oc =
|
|
|
|
lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
packet -> options, options,
|
|
|
|
&global_scope, oc, MDL)) {
|
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);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-04-23 23:17:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-20 23:20:20 +00:00
|
|
|
/*
|
|
|
|
* Remove any time options, per section 3.4 RFC 2131
|
|
|
|
*/
|
|
|
|
delete_option(&dhcp_universe, options, DHO_DHCP_LEASE_TIME);
|
|
|
|
delete_option(&dhcp_universe, options, DHO_DHCP_RENEWAL_TIME);
|
|
|
|
delete_option(&dhcp_universe, options, DHO_DHCP_REBINDING_TIME);
|
|
|
|
|
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,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
0, packet -> options, options, &global_scope,
|
|
|
|
0, nulltp, 0,
|
2000-10-10 23:07:24 +00:00
|
|
|
prl.len ? &prl : (struct data_string *)0,
|
|
|
|
(char *)0);
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_dereference (&options, MDL);
|
|
|
|
data_string_forget (&prl, MDL);
|
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;
|
|
|
|
|
|
|
|
#ifdef DEBUG_PACKET
|
|
|
|
dump_packet (&outgoing);
|
|
|
|
dump_raw ((unsigned char *)&raw, outgoing.packet_length);
|
|
|
|
#endif
|
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
/* Report what we're sending. */
|
|
|
|
snprintf(msgbuf, sizeof msgbuf,
|
|
|
|
"DHCP4o6 DHCPACK to %s (%s) via", piaddr(cip),
|
|
|
|
(packet->raw->htype && packet->raw->hlen) ?
|
|
|
|
print_hw_addr(packet->raw->htype, packet->raw->hlen,
|
|
|
|
packet->raw->chaddr) :
|
|
|
|
"<no client hardware address>");
|
|
|
|
log_info("%s %s", msgbuf, piaddr(packet->client_addr));
|
|
|
|
|
|
|
|
/* fill dhcp4o6_response */
|
|
|
|
packet->dhcp4o6_response->len = outgoing.packet_length;
|
|
|
|
packet->dhcp4o6_response->buffer = NULL;
|
|
|
|
if (!buffer_allocate(&packet->dhcp4o6_response->buffer,
|
|
|
|
outgoing.packet_length, MDL)) {
|
|
|
|
log_fatal("No memory to store DHCP4o6 reply.");
|
|
|
|
}
|
|
|
|
packet->dhcp4o6_response->data =
|
|
|
|
packet->dhcp4o6_response->buffer->data;
|
|
|
|
memcpy(packet->dhcp4o6_response->buffer->data,
|
|
|
|
outgoing.raw, outgoing.packet_length);
|
|
|
|
|
|
|
|
/* done */
|
|
|
|
if (subnet)
|
|
|
|
subnet_dereference (&subnet, MDL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-04-12 22:18:58 +00:00
|
|
|
/* 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);
|
|
|
|
|
2015-07-09 15:12:23 +02:00
|
|
|
/* RFC2131 states the server SHOULD unicast to ciaddr.
|
2006-02-24 23:16:32 +00:00
|
|
|
* There are two wrinkles - relays, and when ciaddr is zero.
|
2006-08-22 17:13:25 +00:00
|
|
|
* There's actually no mention of relays at all in rfc2131 in
|
|
|
|
* regard to DHCPINFORM, except to say we might get packets from
|
|
|
|
* clients via them. Note: relays unicast to clients to the
|
|
|
|
* "yiaddr" address, which servers are forbidden to set when
|
|
|
|
* answering an inform.
|
2006-02-24 23:16:32 +00:00
|
|
|
*
|
2006-08-22 17:13:25 +00:00
|
|
|
* The solution: If ciaddr is zero, and giaddr is set, go via the
|
|
|
|
* relay with the broadcast flag set to help the relay (with no
|
|
|
|
* yiaddr and very likely no chaddr, it will have no idea where to
|
|
|
|
* send the packet).
|
2006-02-24 23:16:32 +00:00
|
|
|
*
|
2006-08-22 17:13:25 +00:00
|
|
|
* If the ciaddr is zero and giaddr is not set, go via the source
|
|
|
|
* IP address (but you are permitted to barf on their shoes).
|
2006-02-24 23:16:32 +00:00
|
|
|
*
|
2006-08-22 17:13:25 +00:00
|
|
|
* If ciaddr is not zero, send the packet there always.
|
2006-02-24 23:16:32 +00:00
|
|
|
*/
|
2006-08-22 17:13:25 +00:00
|
|
|
if (!raw.ciaddr.s_addr && gip.len) {
|
2006-02-24 23:16:32 +00:00
|
|
|
memcpy(&to.sin_addr, gip.iabuf, 4);
|
2017-12-30 14:15:12 +01:00
|
|
|
#if defined(RELAY_PORT)
|
2017-12-23 01:18:23 +01:00
|
|
|
to.sin_port = relay_port ? relay_port : local_port;
|
2017-12-30 14:15:12 +01:00
|
|
|
#else
|
|
|
|
to.sin_port = local_port;
|
|
|
|
#endif
|
2006-08-22 17:13:25 +00:00
|
|
|
raw.flags |= htons(BOOTP_BROADCAST);
|
2006-02-24 23:16:32 +00:00
|
|
|
} else {
|
2006-08-22 17:13:25 +00:00
|
|
|
gip.len = 0;
|
2006-02-24 23:16:32 +00:00
|
|
|
memcpy(&to.sin_addr, cip.iabuf, 4);
|
|
|
|
to.sin_port = remote_port;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Report what we're sending. */
|
|
|
|
snprintf(msgbuf, sizeof msgbuf, "DHCPACK to %s (%s) via", piaddr(cip),
|
|
|
|
(packet->raw->htype && packet->raw->hlen) ?
|
|
|
|
print_hw_addr(packet->raw->htype, packet->raw->hlen,
|
|
|
|
packet->raw->chaddr) :
|
|
|
|
"<no client hardware address>");
|
|
|
|
log_info("%s %s", msgbuf, gip.len ? piaddr(gip) :
|
|
|
|
packet->interface->name);
|
1999-04-12 22:18:58 +00:00
|
|
|
|
|
|
|
errno = 0;
|
2012-03-09 11:18:14 +00:00
|
|
|
interface = (fallback_interface ? fallback_interface
|
|
|
|
: packet -> interface);
|
|
|
|
result = send_packet(interface, &outgoing, &raw,
|
|
|
|
outgoing.packet_length, from, &to, NULL);
|
|
|
|
if (result < 0) {
|
|
|
|
log_error ("%s:%d: Failed to send %d byte long packet over %s "
|
|
|
|
"interface.", MDL, outgoing.packet_length,
|
|
|
|
interface->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
if (subnet)
|
|
|
|
subnet_dereference (&subnet, MDL);
|
1996-02-29 18:16:31 +00:00
|
|
|
}
|
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/*!
|
|
|
|
* \brief Constructs and sends a DHCP Nak
|
|
|
|
*
|
|
|
|
* In order to populate options such as dhcp-server-id and
|
|
|
|
* dhcp-client-identifier, the function creates a temporary option cache
|
|
|
|
* and evaluates options based on the packet's shared-network or the
|
|
|
|
* network_group in its absence, as well as the packet->clasess (if any).
|
|
|
|
*
|
|
|
|
* \param packet inbound packet received from the client
|
|
|
|
* \param cip address requested by the client
|
|
|
|
* \param network_group optional scope for use in setting up options
|
|
|
|
*/
|
|
|
|
void nak_lease (packet, cip, network_group)
|
1996-02-26 01:56:15 +00:00
|
|
|
struct packet *packet;
|
1996-03-16 17:50:30 +00:00
|
|
|
struct iaddr *cip;
|
2014-10-17 07:56:01 -04:00
|
|
|
struct group *network_group; /* scope to use for options */
|
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;
|
2000-05-16 23:03:49 +00:00
|
|
|
unsigned i;
|
2017-12-30 14:15:12 +01:00
|
|
|
#if defined(RELAY_PORT)
|
2017-12-23 01:18:23 +01:00
|
|
|
u_int16_t relay_port = 0;
|
2017-12-30 14:15:12 +01:00
|
|
|
#endif
|
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 option_cache *oc = (struct option_cache *)0;
|
2014-10-17 07:56:01 -04:00
|
|
|
struct option_state *eval_options = NULL;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_allocate (&options, MDL);
|
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 */
|
2000-01-26 14:56:18 +00:00
|
|
|
if (!option_cache_allocate (&oc, MDL)) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for DHCPNAK message type.");
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_dereference (&options, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2001-06-27 00:31:20 +00:00
|
|
|
if (!make_const_data (&oc -> expression, &nak, sizeof nak,
|
|
|
|
0, 0, MDL)) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for expr_const expression.");
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
|
|
|
option_state_dereference (&options, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-06-01 20:23:18 +00:00
|
|
|
i = DHO_DHCP_MESSAGE_TYPE;
|
|
|
|
option_code_hash_lookup(&oc->option, dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe, options, oc);
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2017-12-23 01:18:23 +01:00
|
|
|
#if defined(RELAY_PORT)
|
|
|
|
relay_port = dhcp_check_relayport(packet);
|
|
|
|
#endif
|
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* Set DHCP_MESSAGE to whatever the message is */
|
2000-01-26 14:56:18 +00:00
|
|
|
if (!option_cache_allocate (&oc, MDL)) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for DHCPNAK message type.");
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_dereference (&options, MDL);
|
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,
|
2001-06-27 00:31:20 +00:00
|
|
|
strlen (dhcp_message), 1, 0, MDL)) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("No memory for expr_const expression.");
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
|
|
|
option_state_dereference (&options, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2006-06-01 20:23:18 +00:00
|
|
|
i = DHO_DHCP_MESSAGE;
|
|
|
|
option_code_hash_lookup(&oc->option, dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe, options, oc);
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
2012-11-02 16:37:03 -07:00
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/* Setup the options at the global and subnet scopes. These
|
|
|
|
* may be used to locate sever id option if enabled as well
|
|
|
|
* for echo-client-id further on. (This allocates eval_options). */
|
|
|
|
eval_network_statements(&eval_options, packet, network_group);
|
|
|
|
|
2012-11-16 15:02:13 -08:00
|
|
|
#if defined(SERVER_ID_FOR_NAK)
|
2014-10-17 07:56:01 -04:00
|
|
|
/* Pass in the evaluated options so they can be searched for
|
|
|
|
* server-id, otherwise source address comes from the interface
|
|
|
|
* address. */
|
|
|
|
get_server_source_address(&from, eval_options, options, packet);
|
2012-11-16 15:02:13 -08:00
|
|
|
#else
|
2014-10-17 07:56:01 -04:00
|
|
|
/* Get server source address from the interface address */
|
2012-11-16 15:02:13 -08:00
|
|
|
get_server_source_address(&from, NULL, options, packet);
|
2012-11-02 16:37:03 -07:00
|
|
|
#endif /* if defined(SERVER_ID_FOR_NAK) */
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* If there were agent options in the incoming packet, return
|
2007-03-27 03:48:06 +00:00
|
|
|
* them. We do not check giaddr to detect the presence of a
|
|
|
|
* relay, as this excludes "l2" relay agents which have no
|
|
|
|
* giaddr to set.
|
|
|
|
*/
|
|
|
|
if (packet->options->universe_count > agent_universe.index &&
|
|
|
|
packet->options->universes [agent_universe.index]) {
|
2005-03-17 20:15:29 +00:00
|
|
|
option_chain_head_reference
|
|
|
|
((struct option_chain_head **)
|
|
|
|
&(options -> universes [agent_universe.index]),
|
|
|
|
(struct option_chain_head *)
|
|
|
|
packet -> options -> universes [agent_universe.index],
|
|
|
|
MDL);
|
|
|
|
}
|
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/* echo-client-id can specified at the class level so add class-scoped
|
|
|
|
* options into eval_options. */
|
|
|
|
for (i = packet->class_count; i > 0; i--) {
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, eval_options,
|
|
|
|
&global_scope,
|
|
|
|
packet->classes[i - 1]->group,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Echo client id if we received and it's enabled */
|
|
|
|
echo_client_id(packet, NULL, eval_options, options);
|
|
|
|
option_state_dereference (&eval_options, MDL);
|
|
|
|
|
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,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
0, packet -> options, options, &global_scope,
|
2000-10-10 23:07:24 +00:00
|
|
|
0, 0, 0, (struct data_string *)0, (char *)0);
|
2000-01-26 14:56:18 +00:00
|
|
|
option_state_dereference (&options, MDL);
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1996-02-29 18:16:31 +00:00
|
|
|
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
|
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;
|
|
|
|
|
2016-02-23 10:40:10 +01: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-05-22 07:21:50 +00:00
|
|
|
/* Report what we're sending... */
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
log_info ("DHCP4o6 DHCPNAK on %s to %s via %s",
|
|
|
|
piaddr (*cip),
|
|
|
|
print_hw_addr (packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr),
|
|
|
|
piaddr(packet->client_addr));
|
|
|
|
} else
|
|
|
|
#endif
|
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
|
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
/* fill dhcp4o6_response */
|
|
|
|
packet->dhcp4o6_response->len = outgoing.packet_length;
|
|
|
|
packet->dhcp4o6_response->buffer = NULL;
|
|
|
|
if (!buffer_allocate(&packet->dhcp4o6_response->buffer,
|
|
|
|
outgoing.packet_length, MDL)) {
|
|
|
|
log_fatal("No memory to store DHCP4o6 reply.");
|
|
|
|
}
|
|
|
|
packet->dhcp4o6_response->data =
|
|
|
|
packet->dhcp4o6_response->buffer->data;
|
|
|
|
memcpy(packet->dhcp4o6_response->buffer->data,
|
|
|
|
outgoing.raw, outgoing.packet_length);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* 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);
|
|
|
|
|
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;
|
2001-01-25 08:32:26 +00:00
|
|
|
if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK))
|
2017-12-30 14:15:12 +01:00
|
|
|
#if defined(RELAY_PORT)
|
2017-12-23 01:18:23 +01:00
|
|
|
to.sin_port = relay_port ? relay_port : local_port;
|
2017-12-30 14:15:12 +01:00
|
|
|
#else
|
|
|
|
to.sin_port = local_port;
|
|
|
|
#endif
|
1999-10-24 19:38:53 +00:00
|
|
|
else
|
|
|
|
to.sin_port = remote_port; /* for testing. */
|
1996-05-22 07:21:50 +00:00
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
if (fallback_interface) {
|
2010-02-01 22:03:15 +00:00
|
|
|
result = send_packet(fallback_interface, packet, &raw,
|
|
|
|
outgoing.packet_length, from, &to,
|
|
|
|
NULL);
|
2012-03-09 11:18:14 +00:00
|
|
|
if (result < 0) {
|
|
|
|
log_error ("%s:%d: Failed to send %d byte long "
|
|
|
|
"packet over %s interface.", MDL,
|
|
|
|
outgoing.packet_length,
|
|
|
|
fallback_interface->name);
|
|
|
|
}
|
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
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;
|
2010-02-01 22:03:15 +00:00
|
|
|
result = send_packet(packet->interface, packet, &raw,
|
|
|
|
outgoing.packet_length, from, &to, NULL);
|
2012-03-09 11:18:14 +00:00
|
|
|
if (result < 0) {
|
|
|
|
log_error ("%s:%d: Failed to send %d byte long packet over %s "
|
|
|
|
"interface.", MDL, outgoing.packet_length,
|
|
|
|
packet->interface->name);
|
|
|
|
}
|
|
|
|
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/*!
|
|
|
|
* \brief Adds a dhcp-client-id option to a set of options
|
|
|
|
* Given a set of input options, it searches for echo-client-id. If it is
|
|
|
|
* defined and enabled, the given packet is searched for dhcp-client-id. If
|
|
|
|
* the option is found it is replicated into the given set of output options.
|
|
|
|
* This allows us to provide compliance with RFC 6842. It is called when we ack
|
|
|
|
* or nak a lease. In the latter case we may or may not have created the
|
|
|
|
* requisite scope to lookup echo-client-id.
|
|
|
|
*
|
|
|
|
* Note the flag packet.sv_echo_client_id is set to reflect the configuration
|
|
|
|
* option. This bypases inaccessiblity of server_universe in cons_options()
|
|
|
|
* which must amend the PRL (when not empty) if echoing is enabled.
|
|
|
|
*
|
|
|
|
* \param packet inbound packet received from the client
|
|
|
|
* \param lease lease associated with this client (if one)
|
|
|
|
* \param in_options options in which to search for echo-client-id
|
|
|
|
* \param out_options options to which to save the client-id
|
|
|
|
*/
|
|
|
|
void echo_client_id(packet, lease, in_options, out_options)
|
|
|
|
struct packet *packet;
|
|
|
|
struct lease *lease;
|
|
|
|
struct option_state *in_options;
|
|
|
|
struct option_state *out_options;
|
|
|
|
{
|
|
|
|
struct option_cache *oc;
|
|
|
|
int ignorep;
|
|
|
|
|
|
|
|
/* Check if echo-client-id is enabled */
|
|
|
|
oc = lookup_option(&server_universe, in_options, SV_ECHO_CLIENT_ID);
|
|
|
|
if (oc && evaluate_boolean_option_cache(&ignorep, packet, lease,
|
|
|
|
NULL, packet->options,
|
|
|
|
in_options,
|
|
|
|
(lease ? &lease->scope : NULL),
|
|
|
|
oc, MDL)) {
|
|
|
|
struct data_string client_id;
|
|
|
|
unsigned int opcode = DHO_DHCP_CLIENT_IDENTIFIER;
|
|
|
|
|
|
|
|
/* Save knowledge that echo is enabled to the packet */
|
|
|
|
packet->sv_echo_client_id = ISC_TRUE;
|
|
|
|
|
|
|
|
/* Now see if inbound packet contains client-id */
|
|
|
|
oc = lookup_option(&dhcp_universe, packet->options, opcode);
|
|
|
|
memset(&client_id, 0, sizeof client_id);
|
|
|
|
if (oc && evaluate_option_cache(&client_id,
|
|
|
|
packet, NULL, NULL,
|
|
|
|
packet->options, NULL,
|
|
|
|
(lease ? &lease->scope : NULL),
|
|
|
|
oc, MDL)) {
|
|
|
|
/* Packet contained client-id, add it to out_options. */
|
|
|
|
oc = NULL;
|
|
|
|
if (option_cache_allocate(&oc, MDL)) {
|
|
|
|
if (make_const_data(&oc->expression,
|
|
|
|
client_id.data,
|
|
|
|
client_id.len,
|
|
|
|
1, 0, MDL)) {
|
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.
|
|
|
|
code_hash,
|
|
|
|
&opcode,
|
|
|
|
0, MDL);
|
|
|
|
save_option(&dhcp_universe,
|
|
|
|
out_options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference(&oc, MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-05 14:55:01 -07:00
|
|
|
void check_pool_threshold (packet, lease, state)
|
|
|
|
struct packet *packet;
|
|
|
|
struct lease *lease;
|
|
|
|
struct lease_state *state;
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
struct pool *pool = lease->pool;
|
|
|
|
int used, count, high_threshold, poolhigh = 0, poollow = 0;
|
|
|
|
char *shared_name = "no name";
|
|
|
|
|
|
|
|
if (pool == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* get a pointer to the name if we have one */
|
|
|
|
if ((pool->shared_network != NULL) &&
|
|
|
|
(pool->shared_network->name != NULL)) {
|
|
|
|
shared_name = pool->shared_network->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
count = pool->lease_count;
|
|
|
|
used = count - (pool->free_leases + pool->backup_leases);
|
|
|
|
|
|
|
|
/* The logged flag indicates if we have already crossed the high
|
|
|
|
* threshold and emitted a log message. If it is set we check to
|
|
|
|
* see if we have re-crossed the low threshold and need to reset
|
|
|
|
* things. When we cross the high threshold we determine what
|
|
|
|
* the low threshold is and save it into the low_threshold value.
|
|
|
|
* When we cross that threshold we reset the logged flag and
|
|
|
|
* the low_threshold to 0 which allows the high threshold message
|
|
|
|
* to be emitted once again.
|
|
|
|
* if we haven't recrossed the boundry we don't need to do anything.
|
|
|
|
*/
|
|
|
|
if (pool->logged !=0) {
|
|
|
|
if (used <= pool->low_threshold) {
|
|
|
|
pool->low_threshold = 0;
|
|
|
|
pool->logged = 0;
|
|
|
|
log_error("Pool threshold reset - shared subnet: %s; "
|
|
|
|
"address: %s; low threshold %d/%d.",
|
|
|
|
shared_name, piaddr(lease->ip_addr),
|
|
|
|
used, count);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find the high threshold */
|
|
|
|
if (get_option_int(&poolhigh, &server_universe, packet, lease, NULL,
|
|
|
|
packet->options, state->options, state->options,
|
|
|
|
&lease->scope, SV_LOG_THRESHOLD_HIGH, MDL) == 0) {
|
|
|
|
/* no threshold bail out */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We do have a threshold for this pool, see if its valid */
|
|
|
|
if ((poolhigh <= 0) || (poolhigh > 100)) {
|
|
|
|
/* not valid */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we have a valid value, have we exceeded it */
|
|
|
|
high_threshold = FIND_PERCENT(count, poolhigh);
|
|
|
|
if (used < high_threshold) {
|
|
|
|
/* nope, no more to do */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we've exceeded it, output a message */
|
|
|
|
log_error("Pool threshold exceeded - shared subnet: %s; "
|
|
|
|
"address: %s; high threshold %d%% %d/%d.",
|
|
|
|
shared_name, piaddr(lease->ip_addr),
|
|
|
|
poolhigh, used, count);
|
|
|
|
|
|
|
|
/* handle the low threshold now, if we don't
|
|
|
|
* have a valid one we default to 0. */
|
|
|
|
if ((get_option_int(&poollow, &server_universe, packet, lease, NULL,
|
|
|
|
packet->options, state->options, state->options,
|
|
|
|
&lease->scope, SV_LOG_THRESHOLD_LOW, MDL) == 0) ||
|
|
|
|
(poollow > 100)) {
|
|
|
|
poollow = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the low theshold is higher than the high threshold we continue to log
|
|
|
|
* If it isn't then we set the flag saying we already logged and determine
|
|
|
|
* what the reset threshold is.
|
|
|
|
*/
|
|
|
|
if (poollow < poolhigh) {
|
|
|
|
pool->logged = 1;
|
|
|
|
pool->low_threshold = FIND_PERCENT(count, poollow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-07 16:39:08 +00:00
|
|
|
void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
|
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;
|
2000-02-07 05:12:20 +00:00
|
|
|
int ms_nulltp;
|
2005-07-07 16:39:08 +00:00
|
|
|
struct host_decl *hp;
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
struct lease *lt;
|
1997-03-06 07:02:00 +00:00
|
|
|
struct lease_state *state;
|
2001-03-15 23:22:33 +00:00
|
|
|
struct lease *next;
|
2005-03-17 20:15:29 +00:00
|
|
|
struct host_decl *host = (struct host_decl *)0;
|
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;
|
2000-05-16 23:03:49 +00:00
|
|
|
isc_result_t result;
|
2018-09-26 11:10:16 -04:00
|
|
|
TIME original_cltt;
|
2006-07-25 13:26:00 +00:00
|
|
|
struct in_addr from;
|
2007-10-31 19:13:33 +00:00
|
|
|
TIME remaining_time;
|
|
|
|
struct iaddr cip;
|
2017-12-19 06:25:12 -05:00
|
|
|
#if defined(DELAYED_ACK)
|
2013-08-27 11:09:12 -07:00
|
|
|
/* By default we don't do the enqueue */
|
|
|
|
isc_boolean_t enqueue = ISC_FALSE;
|
2011-05-12 13:26:55 +00:00
|
|
|
#endif
|
|
|
|
int use_old_lease = 0;
|
2018-09-26 11:10:16 -04:00
|
|
|
int same_client = 0;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
1999-10-07 06:36:35 +00:00
|
|
|
unsigned i, j;
|
2007-07-13 06:43:43 +00:00
|
|
|
int s1;
|
1999-10-21 02:42:57 +00:00
|
|
|
int ignorep;
|
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;
|
|
|
|
|
2006-07-25 13:26:00 +00:00
|
|
|
/* Save original cltt for comparison later. */
|
2018-09-26 11:10:16 -04:00
|
|
|
original_cltt = lease->cltt;
|
2006-07-25 13:26:00 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* If the lease carries a host record, remember it. */
|
2005-07-07 16:39:08 +00:00
|
|
|
if (hp)
|
|
|
|
host_reference (&host, hp, MDL);
|
|
|
|
else if (lease -> host)
|
2005-03-17 20:15:29 +00:00
|
|
|
host_reference (&host, lease -> host, MDL);
|
|
|
|
|
1997-09-16 18:20:30 +00:00
|
|
|
/* Allocate a lease state structure... */
|
2000-01-26 14:56:18 +00:00
|
|
|
state = new_lease_state (MDL);
|
1997-09-16 18:20:30 +00:00
|
|
|
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;
|
2000-05-16 23:03:49 +00:00
|
|
|
shared_network_reference (&state -> shared_network,
|
|
|
|
packet -> interface -> shared_network, MDL);
|
1999-05-06 20:35:48 +00:00
|
|
|
|
|
|
|
/* 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
|
|
|
|
2009-07-06 23:33:23 +00:00
|
|
|
maybe_return_agent_options(packet, state->options);
|
1998-06-25 03:56:24 +00:00
|
|
|
|
1999-11-20 18:36:32 +00:00
|
|
|
/* If we are offering a lease that is still currently valid, preserve
|
|
|
|
the events. We need to do this because if the client does not
|
|
|
|
REQUEST our offer, it will expire in 2 minutes, overriding the
|
|
|
|
expire time in the currently in force lease. We want the expire
|
|
|
|
events to be executed at that point. */
|
2013-08-27 13:40:47 -07:00
|
|
|
if (lease->ends <= cur_time && offer != DHCPOFFER) {
|
1999-11-20 18:36:32 +00:00
|
|
|
/* Get rid of any old expiry or release statements - by
|
|
|
|
executing the statements below, we will be inserting new
|
|
|
|
ones if there are any to insert. */
|
2013-08-27 13:40:47 -07:00
|
|
|
if (lease->on_star.on_expiry)
|
|
|
|
executable_statement_dereference
|
|
|
|
(&lease->on_star.on_expiry, MDL);
|
|
|
|
if (lease->on_star.on_commit)
|
|
|
|
executable_statement_dereference
|
|
|
|
(&lease->on_star.on_commit, MDL);
|
|
|
|
if (lease->on_star.on_release)
|
|
|
|
executable_statement_dereference
|
|
|
|
(&lease->on_star.on_release, MDL);
|
1999-11-20 18:36:32 +00:00
|
|
|
}
|
1999-09-22 17:30:33 +00:00
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* Execute statements in scope starting with the subnet scope. */
|
2013-08-27 13:40:47 -07:00
|
|
|
execute_statements_in_scope (NULL, packet, lease,
|
|
|
|
NULL, packet->options,
|
|
|
|
state->options, &lease->scope,
|
|
|
|
lease->subnet->group, NULL, NULL);
|
1998-06-25 03:56:24 +00:00
|
|
|
|
1999-04-23 23:17:52 +00:00
|
|
|
/* If the lease is from a pool, run the pool scope. */
|
2013-08-27 13:40:47 -07:00
|
|
|
if (lease->pool)
|
|
|
|
(execute_statements_in_scope(NULL, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, lease->pool->group,
|
|
|
|
lease->pool->
|
|
|
|
shared_network->group,
|
|
|
|
NULL));
|
1999-04-23 23:17:52 +00:00
|
|
|
|
|
|
|
/* Execute statements from class scopes. */
|
1999-06-10 00:36:27 +00:00
|
|
|
for (i = packet -> class_count; i > 0; i--) {
|
2013-08-27 13:40:47 -07:00
|
|
|
execute_statements_in_scope(NULL, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope,
|
|
|
|
packet->classes[i - 1]->group,
|
|
|
|
(lease->pool ? lease->pool->group
|
|
|
|
: lease->subnet->group),
|
|
|
|
NULL);
|
1998-06-25 03:56:24 +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. */
|
1999-10-04 23:51:45 +00:00
|
|
|
if (packet -> packet_type == DHCPREQUEST &&
|
1999-07-02 17:10:51 +00:00
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_ONE_LEASE_PER_CLIENT)) &&
|
1999-10-21 02:42:57 +00:00
|
|
|
evaluate_boolean_option_cache (&ignorep,
|
2000-11-28 23:27:24 +00:00
|
|
|
packet, lease,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options, &lease -> scope,
|
|
|
|
oc, MDL)) {
|
2001-06-27 00:31:20 +00:00
|
|
|
struct lease *seek;
|
|
|
|
if (lease -> uid_len) {
|
|
|
|
do {
|
|
|
|
seek = (struct lease *)0;
|
|
|
|
find_lease_by_uid (&seek, lease -> uid,
|
|
|
|
lease -> uid_len, MDL);
|
|
|
|
if (!seek)
|
|
|
|
break;
|
|
|
|
if (seek == lease && !seek -> n_uid) {
|
|
|
|
lease_dereference (&seek, MDL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
next = (struct lease *)0;
|
|
|
|
|
|
|
|
/* Don't release expired leases, and don't
|
|
|
|
release the lease we're going to assign. */
|
|
|
|
next = (struct lease *)0;
|
|
|
|
while (seek) {
|
|
|
|
if (seek -> n_uid)
|
|
|
|
lease_reference (&next, seek -> n_uid, MDL);
|
|
|
|
if (seek != lease &&
|
|
|
|
seek -> binding_state != FTS_RELEASED &&
|
|
|
|
seek -> binding_state != FTS_EXPIRED &&
|
|
|
|
seek -> binding_state != FTS_RESET &&
|
|
|
|
seek -> binding_state != FTS_FREE &&
|
|
|
|
seek -> binding_state != FTS_BACKUP)
|
|
|
|
break;
|
|
|
|
lease_dereference (&seek, MDL);
|
|
|
|
if (next) {
|
|
|
|
lease_reference (&seek, next, MDL);
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (next)
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
if (seek) {
|
|
|
|
release_lease (seek, packet);
|
|
|
|
lease_dereference (&seek, MDL);
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
}
|
|
|
|
if (!lease -> uid_len ||
|
2005-03-17 20:15:29 +00:00
|
|
|
(host &&
|
|
|
|
!host -> client_identifier.len &&
|
2001-06-27 00:31:20 +00:00
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_DUPLICATES)) &&
|
|
|
|
!evaluate_boolean_option_cache (&ignorep, packet, lease,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
|
|
|
state -> options,
|
|
|
|
&lease -> scope,
|
|
|
|
oc, MDL))) {
|
|
|
|
do {
|
|
|
|
seek = (struct lease *)0;
|
|
|
|
find_lease_by_hw_addr
|
|
|
|
(&seek, lease -> hardware_addr.hbuf,
|
|
|
|
lease -> hardware_addr.hlen, MDL);
|
|
|
|
if (!seek)
|
|
|
|
break;
|
|
|
|
if (seek == lease && !seek -> n_hw) {
|
|
|
|
lease_dereference (&seek, MDL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
next = (struct lease *)0;
|
|
|
|
while (seek) {
|
|
|
|
if (seek -> n_hw)
|
|
|
|
lease_reference (&next, seek -> n_hw, MDL);
|
|
|
|
if (seek != lease &&
|
|
|
|
seek -> binding_state != FTS_RELEASED &&
|
|
|
|
seek -> binding_state != FTS_EXPIRED &&
|
|
|
|
seek -> binding_state != FTS_RESET &&
|
|
|
|
seek -> binding_state != FTS_FREE &&
|
|
|
|
seek -> binding_state != FTS_BACKUP)
|
|
|
|
break;
|
|
|
|
lease_dereference (&seek, MDL);
|
|
|
|
if (next) {
|
|
|
|
lease_reference (&seek, next, MDL);
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (next)
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
if (seek) {
|
|
|
|
release_lease (seek, packet);
|
|
|
|
lease_dereference (&seek, MDL);
|
|
|
|
} else
|
|
|
|
break;
|
|
|
|
} while (1);
|
|
|
|
}
|
1999-07-02 17:10:51 +00:00
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1999-07-02 17:10:51 +00:00
|
|
|
|
1998-06-25 03:56:24 +00:00
|
|
|
/* Make sure this packet satisfies the configured minimum
|
|
|
|
number of seconds. */
|
2000-07-06 10:16:54 +00:00
|
|
|
memset (&d1, 0, sizeof d1);
|
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))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL)) {
|
2001-03-14 15:44:39 +00:00
|
|
|
if (d1.len &&
|
|
|
|
ntohs (packet -> raw -> secs) < d1.data [0]) {
|
2007-12-13 16:56:24 +00:00
|
|
|
log_info("%s: configured min-secs value (%d) "
|
|
|
|
"is greater than secs field (%d). "
|
|
|
|
"message dropped.", msg, d1.data[0],
|
|
|
|
ntohs(packet->raw->secs));
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
|
|
|
free_lease_state (state, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
return;
|
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* Try to find a matching host declaration for this lease.
|
|
|
|
*/
|
|
|
|
if (!host) {
|
2000-06-02 21:27:21 +00:00
|
|
|
struct host_decl *hp = (struct host_decl *)0;
|
|
|
|
struct host_decl *h;
|
1998-11-05 18:54:55 +00:00
|
|
|
|
|
|
|
/* 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 &&
|
1999-07-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL)) {
|
2000-05-16 23:03:49 +00:00
|
|
|
find_hosts_by_uid (&hp, d1.data, d1.len, MDL);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
for (h = hp; h; h = h -> n_ipaddr) {
|
|
|
|
if (!h -> fixed_addr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h)
|
|
|
|
host_reference (&host, h, MDL);
|
2009-07-24 17:21:52 +00:00
|
|
|
if (hp != NULL)
|
|
|
|
host_dereference(&hp, MDL);
|
2000-06-02 21:27:21 +00:00
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
if (!host) {
|
2000-06-02 21:27:21 +00:00
|
|
|
find_hosts_by_haddr (&hp,
|
|
|
|
packet -> raw -> htype,
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
for (h = hp; h; h = h -> n_ipaddr) {
|
|
|
|
if (!h -> fixed_addr)
|
1998-11-05 18:54:55 +00:00
|
|
|
break;
|
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
if (h)
|
2005-03-17 20:15:29 +00:00
|
|
|
host_reference (&host, h, MDL);
|
2009-07-24 17:21:52 +00:00
|
|
|
if (hp != NULL)
|
|
|
|
host_dereference(&hp, MDL);
|
2000-06-02 21:27:21 +00:00
|
|
|
}
|
2009-11-10 21:12:23 +00:00
|
|
|
if (!host) {
|
2013-08-27 13:40:47 -07:00
|
|
|
find_hosts_by_option(&hp, packet,
|
|
|
|
packet->options, MDL);
|
2009-11-10 21:12:23 +00:00
|
|
|
for (h = hp; h; h = h -> n_ipaddr) {
|
|
|
|
if (!h -> fixed_addr)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (h)
|
|
|
|
host_reference (&host, h, MDL);
|
|
|
|
if (hp != NULL)
|
|
|
|
host_dereference(&hp, MDL);
|
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* If we have a host_decl structure, run the options associated
|
2006-04-27 17:26:42 +00:00
|
|
|
with its group. Whether the host decl struct is old or not. */
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host)
|
2013-08-27 13:40:47 -07:00
|
|
|
execute_statements_in_scope (NULL, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, host->group,
|
|
|
|
(lease->pool
|
|
|
|
? lease->pool->group
|
|
|
|
: lease->subnet->group),
|
|
|
|
NULL);
|
2005-03-17 20:15:29 +00:00
|
|
|
|
1999-10-20 16:52:25 +00:00
|
|
|
/* Drop the request if it's not allowed for this client. By
|
|
|
|
default, unknown clients are allowed. */
|
2005-03-17 20:15:29 +00:00
|
|
|
if (!host &&
|
1999-04-05 16:46:13 +00:00
|
|
|
(oc = lookup_option (&server_universe, state -> options,
|
1999-10-20 16:52:25 +00:00
|
|
|
SV_BOOT_UNKNOWN_CLIENTS)) &&
|
1999-10-21 02:42:57 +00:00
|
|
|
!evaluate_boolean_option_cache (&ignorep,
|
2000-11-28 23:27:24 +00:00
|
|
|
packet, lease,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
1999-10-21 02:42:57 +00:00
|
|
|
if (!ignorep)
|
|
|
|
log_info ("%s: unknown client", msg);
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
1999-10-20 16:52:25 +00:00
|
|
|
return;
|
2018-09-26 11:10:16 -04:00
|
|
|
}
|
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,
|
1999-10-20 16:52:25 +00:00
|
|
|
SV_ALLOW_BOOTP)) &&
|
1999-10-21 02:42:57 +00:00
|
|
|
!evaluate_boolean_option_cache (&ignorep,
|
2000-11-28 23:27:24 +00:00
|
|
|
packet, lease,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
1999-10-21 02:42:57 +00:00
|
|
|
if (!ignorep)
|
|
|
|
log_info ("%s: bootp disallowed", msg);
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
1999-10-20 16:52:25 +00:00
|
|
|
return;
|
2018-09-26 11:10:16 -04:00
|
|
|
}
|
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-10-21 02:42:57 +00:00
|
|
|
!evaluate_boolean_option_cache (&ignorep,
|
2000-11-28 23:27:24 +00:00
|
|
|
packet, lease,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
1999-10-21 02:42:57 +00:00
|
|
|
if (!ignorep)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: booting disallowed", msg);
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
1999-10-21 02:42:57 +00:00
|
|
|
return;
|
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. */
|
2000-09-01 18:30:36 +00:00
|
|
|
if (have_billing_classes && !(lease -> flags & STATIC_LEASE)) {
|
1998-11-11 08:01:49 +00:00
|
|
|
/* 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;
|
2014-11-24 07:36:13 -05:00
|
|
|
if (i == packet -> class_count) {
|
2015-07-29 08:32:50 -04:00
|
|
|
unbill_class(lease);
|
2014-11-24 07:36:13 -05:00
|
|
|
/* Active lease billing change negates reuse */
|
|
|
|
if (lease->binding_state == FTS_ACTIVE) {
|
|
|
|
lease->cannot_reuse = 1;
|
|
|
|
}
|
|
|
|
}
|
1998-11-11 08:01:49 +00:00
|
|
|
}
|
2007-11-02 22:09:02 +00:00
|
|
|
|
1998-11-11 08:01:49 +00:00
|
|
|
/* If we don't have an active billing, see if we need
|
|
|
|
one, and if we do, try to do so. */
|
2007-11-02 22:09:02 +00:00
|
|
|
if (lease->billing_class == NULL) {
|
2012-06-06 23:55:01 +00:00
|
|
|
char *cname = "";
|
2007-11-02 22:09:02 +00:00
|
|
|
int bill = 0;
|
2012-06-06 23:55:01 +00:00
|
|
|
|
2007-11-02 22:09:02 +00:00
|
|
|
for (i = 0; i < packet->class_count; i++) {
|
2019-05-07 15:36:54 -04:00
|
|
|
struct class *billclass, *superclass;
|
2012-06-06 23:55:01 +00:00
|
|
|
|
|
|
|
billclass = packet->classes[i];
|
|
|
|
if (billclass->lease_limit) {
|
2007-11-02 22:09:02 +00:00
|
|
|
bill++;
|
2012-06-06 23:55:01 +00:00
|
|
|
if (bill_class(lease, billclass))
|
1998-11-11 08:01:49 +00:00
|
|
|
break;
|
2012-06-06 23:55:01 +00:00
|
|
|
|
2019-05-07 15:36:54 -04:00
|
|
|
superclass = billclass->superclass;
|
|
|
|
if (superclass != NULL)
|
|
|
|
cname = superclass->name;
|
2012-06-06 23:55:01 +00:00
|
|
|
else
|
|
|
|
cname = billclass->name;
|
1998-11-11 08:01:49 +00:00
|
|
|
}
|
|
|
|
}
|
2007-11-02 22:09:02 +00:00
|
|
|
if (bill != 0 && i == packet->class_count) {
|
|
|
|
log_info("%s: no available billing: lease "
|
|
|
|
"limit reached in all matching "
|
2012-06-06 23:55:01 +00:00
|
|
|
"classes (last: '%s')", msg, cname);
|
2007-11-02 22:09:02 +00:00
|
|
|
free_lease_state(state, MDL);
|
|
|
|
if (host)
|
|
|
|
host_dereference(&host, MDL);
|
|
|
|
return;
|
|
|
|
}
|
2006-06-15 17:52:06 +00:00
|
|
|
|
2012-06-06 23:55:01 +00:00
|
|
|
/*
|
|
|
|
* If this is an offer, undo the billing. We go
|
2006-06-15 17:52:06 +00:00
|
|
|
* through all the steps above to bill a class so
|
|
|
|
* we can hit the 'no available billing' mark and
|
|
|
|
* abort without offering. But it just doesn't make
|
|
|
|
* sense to permanently bill a class for a non-active
|
|
|
|
* lease. This means on REQUEST, we will bill this
|
|
|
|
* lease again (if there is a REQUEST).
|
|
|
|
*/
|
|
|
|
if (offer == DHCPOFFER &&
|
|
|
|
lease->billing_class != NULL &&
|
2006-06-19 20:39:28 +00:00
|
|
|
lease->binding_state != FTS_ACTIVE)
|
2015-07-29 08:32:50 -04:00
|
|
|
unbill_class(lease);
|
2014-11-24 07:36:13 -05:00
|
|
|
|
|
|
|
/* Lease billing change negates reuse */
|
|
|
|
if (lease->billing_class != NULL) {
|
|
|
|
lease->cannot_reuse = 1;
|
|
|
|
}
|
1998-11-11 08:01:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)
|
1999-07-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&state -> filename, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL);
|
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)
|
1999-07-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&state -> server_name, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL);
|
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. */
|
2000-05-16 23:03:49 +00:00
|
|
|
lt = (struct lease *)0;
|
|
|
|
result = lease_allocate (<, MDL);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
log_info ("%s: can't allocate temporary lease structure: %s",
|
|
|
|
msg, isc_result_totext (result));
|
|
|
|
free_lease_state (state, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
return;
|
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1996-02-21 12:11:09 +00:00
|
|
|
/* Use the ip address of the lease that we finally found in
|
|
|
|
the database. */
|
2000-05-16 23:03:49 +00:00
|
|
|
lt -> ip_addr = lease -> ip_addr;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
|
|
|
/* Start now. */
|
2000-05-16 23:03:49 +00:00
|
|
|
lt -> starts = cur_time;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
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) {
|
2006-04-27 17:26:42 +00:00
|
|
|
lt->flags &= ~BOOTP_LEASE;
|
|
|
|
|
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))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
1999-03-09 23:45:04 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
default_lease_time =
|
|
|
|
getULong (d1.data);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-03-09 23:45:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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)))
|
1999-07-31 18:08:28 +00:00
|
|
|
s1 = evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL);
|
1998-11-06 01:04:32 +00:00
|
|
|
else
|
|
|
|
s1 = 0;
|
2005-03-17 20:15:29 +00:00
|
|
|
|
2006-04-27 17:26:42 +00:00
|
|
|
if (s1 && (d1.len == 4)) {
|
|
|
|
u_int32_t ones = 0xffffffff;
|
|
|
|
|
|
|
|
/* One potential use of reserved leases is to allow
|
|
|
|
* clients to signal reservation of their lease. They
|
|
|
|
* can kinda sorta do this, if you squint hard enough,
|
|
|
|
* by supplying an 'infinite' requested-lease-time
|
|
|
|
* option. This is generally bad practice...you want
|
|
|
|
* clients to return to the server on at least some
|
|
|
|
* period (days, months, years) to get up-to-date
|
|
|
|
* config state. So;
|
|
|
|
*
|
|
|
|
* 1) A client requests 0xffffffff lease-time.
|
|
|
|
* 2) The server reserves the lease, and assigns a
|
|
|
|
* <= max_lease_time lease-time to the client, which
|
|
|
|
* we presume is much smaller than 0xffffffff.
|
|
|
|
* 3) The client ultimately fails to renew its lease
|
|
|
|
* (all clients go offline at some point).
|
|
|
|
* 4) The server retains the reservation, although
|
|
|
|
* the lease expires and passes through those states
|
|
|
|
* as normal, it's placed in the 'reserved' queue,
|
|
|
|
* and is under no circumstances allocated to any
|
|
|
|
* clients.
|
|
|
|
*
|
|
|
|
* Whether the client knows its reserving its lease or
|
|
|
|
* not, this can be a handy tool for a sysadmin.
|
|
|
|
*/
|
|
|
|
if ((memcmp(d1.data, &ones, 4) == 0) &&
|
|
|
|
(oc = lookup_option(&server_universe,
|
|
|
|
state->options,
|
|
|
|
SV_RESERVE_INFINITE)) &&
|
|
|
|
evaluate_boolean_option_cache(&ignorep, packet,
|
|
|
|
lease, NULL, packet->options,
|
|
|
|
state->options, &lease->scope,
|
|
|
|
oc, MDL)) {
|
|
|
|
lt->flags |= RESERVED_LEASE;
|
|
|
|
if (!ignorep)
|
|
|
|
log_info("Infinite-leasetime "
|
|
|
|
"reservation made on %s.",
|
|
|
|
piaddr(lt->ip_addr));
|
|
|
|
}
|
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
lease_time = getULong (d1.data);
|
2006-04-27 17:26:42 +00:00
|
|
|
} else
|
1999-03-09 23:45:04 +00:00
|
|
|
lease_time = default_lease_time;
|
2006-04-27 17:26:42 +00:00
|
|
|
|
|
|
|
if (s1)
|
|
|
|
data_string_forget(&d1, MDL);
|
2005-03-17 20:15:29 +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))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-06 20:35:54 +00:00
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
1999-07-06 20:35:54 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
max_lease_time =
|
|
|
|
getULong (d1.data);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-07-06 20:35:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1999-03-09 23:45:04 +00:00
|
|
|
min_lease_time = DEFAULT_MIN_LEASE_TIME;
|
1999-08-19 18:59:13 +00:00
|
|
|
if (min_lease_time > max_lease_time)
|
|
|
|
min_lease_time = max_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))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
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);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1998-04-09 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
2006-07-31 23:17:24 +00:00
|
|
|
/* CC: If there are less than
|
|
|
|
adaptive-lease-time-threshold % free leases,
|
|
|
|
hand out only short term leases */
|
|
|
|
|
|
|
|
memset(&d1, 0, sizeof(d1));
|
|
|
|
if (lease->pool &&
|
|
|
|
(oc = lookup_option(&server_universe, state->options,
|
|
|
|
SV_ADAPTIVE_LEASE_TIME_THRESHOLD)) &&
|
|
|
|
evaluate_option_cache(&d1, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL)) {
|
|
|
|
if (d1.len == 1 && d1.data[0] > 0 &&
|
|
|
|
d1.data[0] < 100) {
|
|
|
|
TIME adaptive_time;
|
|
|
|
int poolfilled, total, count;
|
|
|
|
|
|
|
|
if (min_lease_time)
|
|
|
|
adaptive_time = min_lease_time;
|
|
|
|
else
|
|
|
|
adaptive_time = DEFAULT_MIN_LEASE_TIME;
|
|
|
|
|
|
|
|
/* Allow the client to keep its lease. */
|
|
|
|
if (lease->ends - cur_time > adaptive_time)
|
|
|
|
adaptive_time = lease->ends - cur_time;
|
|
|
|
|
|
|
|
count = lease->pool->lease_count;
|
|
|
|
total = count - (lease->pool->free_leases +
|
|
|
|
lease->pool->backup_leases);
|
|
|
|
|
|
|
|
poolfilled = (total > (INT_MAX / 100)) ?
|
|
|
|
total / (count / 100) :
|
|
|
|
(total * 100) / count;
|
|
|
|
|
|
|
|
log_debug("Adap-lease: Total: %d, Free: %d, "
|
|
|
|
"Ends: %d, Adaptive: %d, Fill: %d, "
|
|
|
|
"Threshold: %d",
|
|
|
|
lease->pool->lease_count,
|
|
|
|
lease->pool->free_leases,
|
|
|
|
(int)(lease->ends - cur_time),
|
|
|
|
(int)adaptive_time, poolfilled,
|
|
|
|
d1.data[0]);
|
|
|
|
|
|
|
|
if (poolfilled >= d1.data[0] &&
|
|
|
|
lease_time > adaptive_time) {
|
|
|
|
log_info("Pool over threshold, time "
|
|
|
|
"for %s reduced from %d to "
|
|
|
|
"%d.", piaddr(lease->ip_addr),
|
|
|
|
(int)lease_time,
|
|
|
|
(int)adaptive_time);
|
|
|
|
|
|
|
|
lease_time = adaptive_time;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
data_string_forget(&d1, MDL);
|
|
|
|
}
|
|
|
|
|
2014-06-05 14:55:01 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is an ack check to see if we have used enough of
|
|
|
|
* the pool to want to log a message
|
|
|
|
*/
|
|
|
|
if (offer == DHCPACK)
|
|
|
|
check_pool_threshold(packet, lease, state);
|
|
|
|
|
2007-10-31 19:13:33 +00:00
|
|
|
/* a client requests an address which is not yet active*/
|
2018-09-26 11:10:16 -04:00
|
|
|
if (lease->pool && lease->pool->valid_from &&
|
2007-10-31 19:13:33 +00:00
|
|
|
cur_time < lease->pool->valid_from) {
|
|
|
|
/* NAK leases before pool activation date */
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, <->ip_addr.iabuf, 4);
|
2014-10-17 07:56:01 -04:00
|
|
|
nak_lease(packet, &cip, lease->subnet->group);
|
2007-10-31 19:13:33 +00:00
|
|
|
free_lease_state (state, MDL);
|
|
|
|
lease_dereference (<, MDL);
|
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
|
|
|
return;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2007-10-31 19:13:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* CC:
|
|
|
|
a) NAK current lease if past the expiration date
|
|
|
|
b) extend lease only up to the expiration date, but not
|
|
|
|
below min-lease-time
|
|
|
|
Setting min-lease-time is essential for this to work!
|
2014-06-05 14:55:01 -07:00
|
|
|
The value of min-lease-time determines the length
|
2007-10-31 19:13:33 +00:00
|
|
|
of the transition window:
|
|
|
|
A client renewing a second before the deadline will
|
|
|
|
get a min-lease-time lease. Since the current ip might not
|
|
|
|
be routable after the deadline, the client will
|
|
|
|
be offline until it DISCOVERS again. Otherwise it will
|
|
|
|
receive a NAK at T/2.
|
|
|
|
A min-lease-time of 6 seconds effectively switches over
|
|
|
|
all clients in this pool very quickly.
|
|
|
|
*/
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2007-10-31 19:13:33 +00:00
|
|
|
if (lease->pool && lease->pool->valid_until) {
|
|
|
|
if (cur_time >= lease->pool->valid_until) {
|
|
|
|
/* NAK leases after pool expiration date */
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, <->ip_addr.iabuf, 4);
|
2014-10-17 07:56:01 -04:00
|
|
|
nak_lease(packet, &cip, lease->subnet->group);
|
2007-10-31 19:13:33 +00:00
|
|
|
free_lease_state (state, MDL);
|
|
|
|
lease_dereference (<, MDL);
|
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
remaining_time = lease->pool->valid_until - cur_time;
|
|
|
|
if (lease_time > remaining_time)
|
|
|
|
lease_time = remaining_time;
|
|
|
|
}
|
2018-09-26 11:10:16 -04: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
|
|
|
|
2007-10-31 19:13:33 +00:00
|
|
|
|
2000-01-05 18:16:36 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
|
|
|
/* Okay, we know the lease duration. Now check the
|
|
|
|
failover state, if any. */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (lease -> pool && lease -> pool -> failover_peer) {
|
2006-02-24 23:16:32 +00:00
|
|
|
TIME new_lease_time = lease_time;
|
2000-01-05 18:16:36 +00:00
|
|
|
dhcp_failover_state_t *peer =
|
|
|
|
lease -> pool -> failover_peer;
|
|
|
|
|
2006-02-24 23:16:32 +00:00
|
|
|
/* Copy previous lease failover ack-state. */
|
|
|
|
lt->tsfp = lease->tsfp;
|
|
|
|
lt->atsfp = lease->atsfp;
|
|
|
|
|
2006-07-25 13:26:00 +00:00
|
|
|
/* cltt set below */
|
2006-02-24 23:16:32 +00:00
|
|
|
|
|
|
|
/* Lease times less than MCLT are not a concern. */
|
|
|
|
if (lease_time > peer->mclt) {
|
|
|
|
/* Each server can only offer a lease time
|
|
|
|
* that is either equal to MCLT (at least),
|
|
|
|
* or up to TSFP+MCLT. Only if the desired
|
|
|
|
* lease time falls within TSFP+MCLT, can
|
|
|
|
* the server allow it.
|
|
|
|
*/
|
|
|
|
if (lt->tsfp <= cur_time)
|
|
|
|
new_lease_time = peer->mclt;
|
|
|
|
else if ((cur_time + lease_time) >
|
|
|
|
(lt->tsfp + peer->mclt))
|
|
|
|
new_lease_time = (lt->tsfp - cur_time)
|
|
|
|
+ peer->mclt;
|
2000-01-05 18:16:36 +00:00
|
|
|
}
|
2000-06-12 22:20:43 +00:00
|
|
|
|
2006-02-24 23:16:32 +00:00
|
|
|
/* Update potential expiry. Allow for the desired
|
2007-05-08 23:05:22 +00:00
|
|
|
* lease time plus one half the actual (whether
|
2006-02-24 23:16:32 +00:00
|
|
|
* modified downward or not) lease time, which is
|
|
|
|
* actually an estimate of when the client will
|
|
|
|
* renew. This way, the client will be able to get
|
|
|
|
* the desired lease time upon renewal.
|
|
|
|
*/
|
|
|
|
if (offer == DHCPACK) {
|
2017-05-10 13:11:03 -04:00
|
|
|
if (lease_time == INFINITE_TIME) {
|
|
|
|
lt->tstp = MAX_TIME;
|
|
|
|
} else {
|
|
|
|
lt->tstp =
|
|
|
|
leaseTimeCheck(
|
|
|
|
(cur_time + lease_time
|
|
|
|
+ (new_lease_time / 2)),
|
|
|
|
MAX_TIME - 1);
|
|
|
|
}
|
2006-02-24 23:16:32 +00:00
|
|
|
|
|
|
|
/* If we reduced the potential expiry time,
|
|
|
|
* make sure we don't offer an old-expiry-time
|
|
|
|
* lease for this lease before the change is
|
|
|
|
* ack'd.
|
|
|
|
*/
|
|
|
|
if (lt->tstp < lt->tsfp)
|
|
|
|
lt->tsfp = lt->tstp;
|
|
|
|
} else
|
|
|
|
lt->tstp = lease->tstp;
|
|
|
|
|
|
|
|
/* Use failover-modified lease time. */
|
|
|
|
lease_time = new_lease_time;
|
2000-01-05 18:16:36 +00:00
|
|
|
}
|
|
|
|
#endif /* FAILOVER_PROTOCOL */
|
|
|
|
|
2017-05-10 13:11:03 -04:00
|
|
|
if (lease_time == INFINITE_TIME) {
|
|
|
|
state->offered_expiry = MAX_TIME;
|
|
|
|
} else {
|
|
|
|
/* If the lease duration causes the time value to wrap,
|
|
|
|
use the maximum expiry time. */
|
|
|
|
state->offered_expiry
|
|
|
|
= leaseTimeCheck(cur_time + lease_time,
|
|
|
|
MAX_TIME - 1);
|
|
|
|
}
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
if (when)
|
2000-05-16 23:03:49 +00:00
|
|
|
lt -> ends = when;
|
1996-05-22 07:21:50 +00:00
|
|
|
else
|
2000-05-16 23:03:49 +00:00
|
|
|
lt -> ends = state -> offered_expiry;
|
2001-06-27 00:31:20 +00:00
|
|
|
|
|
|
|
/* Don't make lease active until we actually get a
|
|
|
|
DHCPREQUEST. */
|
|
|
|
if (offer == DHCPACK)
|
|
|
|
lt -> next_binding_state = FTS_ACTIVE;
|
|
|
|
else
|
|
|
|
lt -> next_binding_state = lease -> binding_state;
|
1996-05-22 07:21:50 +00:00
|
|
|
} else {
|
2006-04-27 17:26:42 +00:00
|
|
|
lt->flags |= BOOTP_LEASE;
|
|
|
|
|
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))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options,
|
|
|
|
state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
lease_time = getULong (d1.data);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
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))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-02 20:58:48 +00:00
|
|
|
packet -> options,
|
1999-07-31 18:08:28 +00:00
|
|
|
state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int32_t))
|
|
|
|
lease_time = (getULong (d1.data) -
|
|
|
|
cur_time);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
lt -> ends = state -> offered_expiry = cur_time + lease_time;
|
2005-03-17 20:15:29 +00:00
|
|
|
lt -> next_binding_state = FTS_ACTIVE;
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
1996-02-21 12:11:09 +00:00
|
|
|
|
2006-07-25 13:26:00 +00:00
|
|
|
/* Update Client Last Transaction Time. */
|
|
|
|
lt->cltt = cur_time;
|
1996-02-21 12:11:09 +00:00
|
|
|
|
2013-12-13 12:40:45 -08:00
|
|
|
/* See if we want to record the uid for this client */
|
|
|
|
oc = lookup_option(&server_universe, state->options,
|
|
|
|
SV_IGNORE_CLIENT_UIDS);
|
|
|
|
if ((oc == NULL) ||
|
|
|
|
!evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL)) {
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2013-12-13 12:40:45 -08:00
|
|
|
/* Record the uid, if given... */
|
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_DHCP_CLIENT_IDENTIFIER);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache(&d1, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL)) {
|
|
|
|
if (d1.len <= sizeof(lt->uid_buf)) {
|
|
|
|
memcpy(lt->uid_buf, d1.data, d1.len);
|
|
|
|
lt->uid = lt->uid_buf;
|
|
|
|
lt->uid_max = sizeof(lt->uid_buf);
|
|
|
|
lt->uid_len = d1.len;
|
|
|
|
} else {
|
|
|
|
unsigned char *tuid;
|
|
|
|
lt->uid_max = d1.len;
|
|
|
|
lt->uid_len = d1.len;
|
|
|
|
tuid = (unsigned char *)dmalloc(lt->uid_max,
|
|
|
|
MDL);
|
|
|
|
/* XXX inelegant */
|
|
|
|
if (!tuid)
|
|
|
|
log_fatal ("no memory for large uid.");
|
|
|
|
memcpy(tuid, d1.data, lt->uid_len);
|
|
|
|
lt->uid = tuid;
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, MDL);
|
1997-03-05 06:37:05 +00:00
|
|
|
}
|
1996-02-21 12:11:09 +00:00
|
|
|
}
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host) {
|
|
|
|
host_reference (< -> host, host, MDL);
|
|
|
|
host_dereference (&host, MDL);
|
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
if (lease -> subnet)
|
|
|
|
subnet_reference (< -> subnet, lease -> subnet, MDL);
|
|
|
|
if (lease -> billing_class)
|
|
|
|
class_reference (< -> billing_class,
|
|
|
|
lease -> billing_class, MDL);
|
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. */
|
2000-02-07 05:12:20 +00:00
|
|
|
if (ms_nulltp)
|
|
|
|
lease -> flags |= MS_NULL_TERMINATION;
|
|
|
|
else
|
2000-05-04 18:58:16 +00:00
|
|
|
lease -> flags &= ~MS_NULL_TERMINATION;
|
1999-07-21 14:30:28 +00:00
|
|
|
|
2000-01-25 01:36:29 +00:00
|
|
|
/* Save any bindings. */
|
2000-07-27 09:03:08 +00:00
|
|
|
if (lease -> scope) {
|
|
|
|
binding_scope_reference (< -> scope, lease -> scope, MDL);
|
|
|
|
binding_scope_dereference (&lease -> scope, MDL);
|
|
|
|
}
|
2001-01-25 08:32:26 +00:00
|
|
|
if (lease -> agent_options)
|
|
|
|
option_chain_head_reference (< -> agent_options,
|
|
|
|
lease -> agent_options, MDL);
|
2000-01-25 01:36:29 +00:00
|
|
|
|
2011-04-22 13:21:35 +00:00
|
|
|
/* Save the vendor-class-identifier for DHCPLEASEQUERY. */
|
|
|
|
oc = lookup_option(&dhcp_universe, packet->options,
|
|
|
|
DHO_VENDOR_CLASS_IDENTIFIER);
|
|
|
|
if (oc != NULL &&
|
|
|
|
evaluate_option_cache(&d1, packet, NULL, NULL, packet->options,
|
2014-11-24 07:36:13 -05:00
|
|
|
NULL, <->scope, oc, MDL)) {
|
2011-04-22 13:21:35 +00:00
|
|
|
if (d1.len != 0) {
|
2014-11-24 07:36:13 -05:00
|
|
|
bind_ds_value(<->scope, "vendor-class-identifier",
|
2011-04-22 13:21:35 +00:00
|
|
|
&d1);
|
|
|
|
}
|
|
|
|
|
|
|
|
data_string_forget(&d1, MDL);
|
|
|
|
}
|
|
|
|
|
2007-04-20 15:25:26 +00:00
|
|
|
/* If we got relay agent information options from the packet, then
|
|
|
|
* cache them for renewal in case the relay agent can't supply them
|
|
|
|
* when the client unicasts. The options may be from an addressed
|
|
|
|
* "l3" relay, or from an unaddressed "l2" relay which does not set
|
|
|
|
* giaddr.
|
2007-03-27 03:48:06 +00:00
|
|
|
*/
|
2007-04-20 15:25:26 +00:00
|
|
|
if (!packet->agent_options_stashed &&
|
2011-07-19 22:13:26 +00:00
|
|
|
(packet->options != NULL) &&
|
2007-04-20 15:25:26 +00:00
|
|
|
packet->options->universe_count > agent_universe.index &&
|
|
|
|
packet->options->universes[agent_universe.index] != NULL) {
|
2000-11-28 23:27:24 +00:00
|
|
|
oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_STASH_AGENT_OPTIONS);
|
|
|
|
if (!oc ||
|
|
|
|
evaluate_boolean_option_cache (&ignorep, packet, lease,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
|
|
|
state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
2001-01-26 05:57:35 +00:00
|
|
|
if (lt -> agent_options)
|
|
|
|
option_chain_head_dereference (< -> agent_options, MDL);
|
2001-01-25 08:32:26 +00:00
|
|
|
option_chain_head_reference
|
2000-11-28 23:27:24 +00:00
|
|
|
(< -> agent_options,
|
2001-01-25 08:32:26 +00:00
|
|
|
(struct option_chain_head *)
|
2000-11-28 23:27:24 +00:00
|
|
|
packet -> options -> universes [agent_universe.index],
|
|
|
|
MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-07-06 10:16:54 +00:00
|
|
|
/* Replace the old lease hostname with the new one, if it's changed. */
|
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME);
|
|
|
|
if (oc)
|
|
|
|
s1 = evaluate_option_cache (&d1, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-07-06 10:16:54 +00:00
|
|
|
packet -> options,
|
|
|
|
(struct option_state *)0,
|
|
|
|
&global_scope, oc, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
else
|
|
|
|
s1 = 0;
|
|
|
|
|
2000-07-06 10:16:54 +00:00
|
|
|
if (oc && s1 &&
|
|
|
|
lease -> client_hostname &&
|
|
|
|
strlen (lease -> client_hostname) == d1.len &&
|
|
|
|
!memcmp (lease -> client_hostname, d1.data, d1.len)) {
|
|
|
|
/* Hasn't changed. */
|
|
|
|
data_string_forget (&d1, MDL);
|
|
|
|
lt -> client_hostname = lease -> client_hostname;
|
|
|
|
lease -> client_hostname = (char *)0;
|
|
|
|
} else if (oc && s1) {
|
|
|
|
lt -> client_hostname = dmalloc (d1.len + 1, MDL);
|
|
|
|
if (!lt -> client_hostname)
|
|
|
|
log_error ("no memory for client hostname.");
|
|
|
|
else {
|
|
|
|
memcpy (lt -> client_hostname, d1.data, d1.len);
|
|
|
|
lt -> client_hostname [d1.len] = 0;
|
|
|
|
}
|
|
|
|
data_string_forget (&d1, MDL);
|
2016-07-26 11:41:47 -07:00
|
|
|
/* hostname changed, can't reuse lease */
|
|
|
|
lease->cannot_reuse = 1;
|
2000-07-06 10:16:54 +00:00
|
|
|
}
|
|
|
|
|
DDNS implementation rewrite. DDNS should now operate according to
<draft-ietf-dhc-dhcp-dns-12.txt>.
common/options.c, common/tables.c, includes/dhcp.h:
Split the fqdn.name option into fqdn.hostname and fqdn.domainname.
includes/dhcpd.h, server/Makefile.dist, server/ddns.c, server/dhcp.c,
server/mdb.c, server/stables.c:
Added a new file (server/ddns.c) containing the DDNS updates code.
This file exports two functions: ddns_updates() and ddns_removals().
ddns_updates() is called when a lease is granted, and ddns_removals()
is called when the lease expires or is released.
server/dhcpd.c:
Remove the previous DDNS update code, and add default code for the
ddns-hostname, ddns-domainname, ddns-ttl, and ddns-rev-domainname
server options.
2000-12-11 18:56:45 +00:00
|
|
|
/* Record the hardware address, if given... */
|
|
|
|
lt -> hardware_addr.hlen = packet -> raw -> hlen + 1;
|
|
|
|
lt -> hardware_addr.hbuf [0] = packet -> raw -> htype;
|
|
|
|
memcpy (< -> hardware_addr.hbuf [1], packet -> raw -> chaddr,
|
|
|
|
sizeof packet -> raw -> chaddr);
|
|
|
|
|
2016-02-05 09:03:51 -05:00
|
|
|
/*
|
|
|
|
* If client has requested the lease become infinite, then it
|
|
|
|
* doens't qualify for reuse even if it's younger than the
|
|
|
|
* dhcp-cache-threshold.
|
|
|
|
*/
|
|
|
|
if ((lt->flags & RESERVED_LEASE) && !(lease->flags & RESERVED_LEASE)) {
|
|
|
|
log_debug ("Cannot reuse: lease is changing to RESERVED");
|
|
|
|
lease->cannot_reuse = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
lt->flags |= lease->flags & ~PERSISTENT_FLAGS;
|
2000-12-05 07:21:31 +00:00
|
|
|
|
2000-08-15 23:43:02 +00:00
|
|
|
/* If there are statements to execute when the lease is
|
|
|
|
committed, execute them. */
|
2013-08-27 13:40:47 -07:00
|
|
|
if (lease->on_star.on_commit && (!offer || offer == DHCPACK)) {
|
|
|
|
execute_statements (NULL, packet, lt, NULL, packet->options,
|
|
|
|
state->options, <->scope,
|
|
|
|
lease->on_star.on_commit, NULL);
|
|
|
|
if (lease->on_star.on_commit)
|
|
|
|
executable_statement_dereference
|
|
|
|
(&lease->on_star.on_commit, MDL);
|
2000-08-15 23:43:02 +00:00
|
|
|
}
|
|
|
|
|
DDNS implementation rewrite. DDNS should now operate according to
<draft-ietf-dhc-dhcp-dns-12.txt>.
common/options.c, common/tables.c, includes/dhcp.h:
Split the fqdn.name option into fqdn.hostname and fqdn.domainname.
includes/dhcpd.h, server/Makefile.dist, server/ddns.c, server/dhcp.c,
server/mdb.c, server/stables.c:
Added a new file (server/ddns.c) containing the DDNS updates code.
This file exports two functions: ddns_updates() and ddns_removals().
ddns_updates() is called when a lease is granted, and ddns_removals()
is called when the lease expires or is released.
server/dhcpd.c:
Remove the previous DDNS update code, and add default code for the
ddns-hostname, ddns-domainname, ddns-ttl, and ddns-rev-domainname
server options.
2000-12-11 18:56:45 +00:00
|
|
|
#ifdef NSUPDATE
|
|
|
|
/* Perform DDNS updates, if configured to. */
|
|
|
|
if ((!offer || offer == DHCPACK) &&
|
2001-01-04 00:15:50 +00:00
|
|
|
(!(oc = lookup_option (&server_universe, state -> options,
|
|
|
|
SV_DDNS_UPDATES)) ||
|
|
|
|
evaluate_boolean_option_cache (&ignorep, packet, lt,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
|
|
|
state -> options,
|
|
|
|
< -> scope, oc, MDL))) {
|
2007-05-08 23:05:22 +00:00
|
|
|
ddns_updates(packet, lt, lease, NULL, NULL, state->options);
|
DDNS implementation rewrite. DDNS should now operate according to
<draft-ietf-dhc-dhcp-dns-12.txt>.
common/options.c, common/tables.c, includes/dhcp.h:
Split the fqdn.name option into fqdn.hostname and fqdn.domainname.
includes/dhcpd.h, server/Makefile.dist, server/ddns.c, server/dhcp.c,
server/mdb.c, server/stables.c:
Added a new file (server/ddns.c) containing the DDNS updates code.
This file exports two functions: ddns_updates() and ddns_removals().
ddns_updates() is called when a lease is granted, and ddns_removals()
is called when the lease expires or is released.
server/dhcpd.c:
Remove the previous DDNS update code, and add default code for the
ddns-hostname, ddns-domainname, ddns-ttl, and ddns-rev-domainname
server options.
2000-12-11 18:56:45 +00:00
|
|
|
}
|
|
|
|
#endif /* NSUPDATE */
|
|
|
|
|
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. */
|
2000-01-05 18:16:36 +00:00
|
|
|
lease -> hardware_addr.hlen = packet -> raw -> hlen + 1;
|
|
|
|
lease -> hardware_addr.hbuf [0] = packet -> raw -> htype;
|
|
|
|
memcpy (&lease -> hardware_addr.hbuf [1],
|
|
|
|
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 {
|
2011-05-12 13:26:55 +00:00
|
|
|
int commit = (!offer || (offer == DHCPACK));
|
|
|
|
|
2014-11-24 07:36:13 -05:00
|
|
|
/* If dhcp-cache-threshold is enabled, see if "lease" can
|
|
|
|
* be reused. */
|
2018-09-26 11:10:16 -04:00
|
|
|
use_old_lease = reuse_lease(packet, lt, lease, state, offer,
|
|
|
|
&same_client);
|
2014-11-24 07:36:13 -05:00
|
|
|
if (use_old_lease == 1) {
|
|
|
|
commit = 0;
|
2011-05-12 13:26:55 +00:00
|
|
|
}
|
|
|
|
|
2017-12-19 06:25:12 -05:00
|
|
|
#if !defined(DELAYED_ACK)
|
2008-01-21 19:53:21 +00:00
|
|
|
/* Install the new information on 'lt' onto the lease at
|
2008-11-03 18:13:58 +00:00
|
|
|
* 'lease'. If this is a DHCPOFFER, it is a 'soft' promise,
|
|
|
|
* if it is a DHCPACK, it is a 'hard' binding, so it needs
|
|
|
|
* to be recorded and propogated immediately. If the update
|
|
|
|
* fails, don't ACK it (or BOOTREPLY) either; we may give
|
|
|
|
* the same lease to another client later, and that would be
|
|
|
|
* a conflict.
|
|
|
|
*/
|
2013-08-27 11:09:12 -07:00
|
|
|
if ((use_old_lease == 0) &&
|
|
|
|
!supersede_lease(lease, lt, commit,
|
2014-12-10 19:08:05 -08:00
|
|
|
offer == DHCPACK, offer == DHCPACK, 0)) {
|
2017-12-19 06:25:12 -05:00
|
|
|
#else /* defined(DELAYED_ACK) */
|
2011-05-12 13:26:55 +00:00
|
|
|
/*
|
|
|
|
* If there already isn't a need for a lease commit, and we
|
|
|
|
* can just answer right away, set a flag to indicate this.
|
|
|
|
*/
|
2013-08-27 11:09:12 -07:00
|
|
|
if (commit)
|
2011-05-12 13:26:55 +00:00
|
|
|
enqueue = ISC_TRUE;
|
|
|
|
|
2008-11-03 18:13:58 +00:00
|
|
|
/* Install the new information on 'lt' onto the lease at
|
2012-11-16 15:02:13 -08:00
|
|
|
* 'lease'. We will not 'commit' this information to disk
|
2008-11-03 18:13:58 +00:00
|
|
|
* yet (fsync()), we will 'propogate' the information if
|
|
|
|
* this is BOOTP or a DHCPACK, but we will not 'pimmediate'ly
|
|
|
|
* transmit failover binding updates (this is delayed until
|
|
|
|
* after the fsync()). If the update fails, don't ACK it (or
|
|
|
|
* BOOTREPLY either); we may give the same lease out to a
|
|
|
|
* different client, and that would be a conflict.
|
|
|
|
*/
|
2013-08-27 11:09:12 -07:00
|
|
|
if ((use_old_lease == 0) &&
|
|
|
|
!supersede_lease(lease, lt, 0,
|
2014-12-10 19:08:05 -08:00
|
|
|
!offer || offer == DHCPACK, 0, 0)) {
|
2008-11-03 18:13:58 +00:00
|
|
|
#endif
|
1999-02-24 17:56:53 +00:00
|
|
|
log_info ("%s: database update failed", msg);
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (<, MDL);
|
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
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (<, MDL);
|
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-10-21 02:42:57 +00:00
|
|
|
evaluate_boolean_option_cache (&ignorep, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL))
|
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-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
packet -> options, state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (d1.len == sizeof (u_int16_t))
|
|
|
|
state -> max_message_size = getUShort (d1.data);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
2000-09-12 20:09:14 +00:00
|
|
|
} else {
|
|
|
|
oc = lookup_option (&dhcp_universe, state -> options,
|
|
|
|
DHO_DHCP_MAX_MESSAGE_SIZE);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-09-12 20:09:14 +00:00
|
|
|
packet -> options, state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
|
|
|
if (d1.len == sizeof (u_int16_t))
|
|
|
|
state -> max_message_size =
|
|
|
|
getUShort (d1.data);
|
|
|
|
data_string_forget (&d1, MDL);
|
|
|
|
}
|
1998-02-06 01:08:38 +00:00
|
|
|
}
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* Get the Subnet Selection option from the packet, if one
|
|
|
|
was sent. */
|
|
|
|
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_SUBNET_SELECTION))) {
|
|
|
|
|
|
|
|
/* Make a copy of the data. */
|
|
|
|
struct option_cache *noc = (struct option_cache *)0;
|
|
|
|
if (option_cache_allocate (&noc, MDL)) {
|
|
|
|
if (oc -> data.len)
|
|
|
|
data_string_copy (&noc -> data,
|
|
|
|
&oc -> data, MDL);
|
|
|
|
if (oc -> expression)
|
|
|
|
expression_reference (&noc -> expression,
|
|
|
|
oc -> expression, MDL);
|
|
|
|
if (oc -> option)
|
2006-10-17 20:45:59 +00:00
|
|
|
option_reference(&(noc->option), oc->option,
|
|
|
|
MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
|
2012-11-02 16:37:03 -07:00
|
|
|
save_option (&dhcp_universe, state -> options, noc);
|
|
|
|
option_cache_dereference (&noc, MDL);
|
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
}
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Now, if appropriate, put in DHCP-specific options that
|
2007-11-02 22:09:02 +00:00
|
|
|
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;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (make_const_data (&oc -> expression,
|
2001-06-27 00:31:20 +00:00
|
|
|
&state -> offer, 1, 0, 0, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
2006-07-25 13:26:00 +00:00
|
|
|
|
2012-11-16 15:02:13 -08:00
|
|
|
get_server_source_address(&from, state->options,
|
|
|
|
state->options, packet);
|
2006-07-25 13:26:00 +00:00
|
|
|
memcpy(state->from.iabuf, &from, sizeof(from));
|
|
|
|
state->from.len = sizeof(from);
|
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
|
|
|
|
2006-05-17 20:15:32 +00:00
|
|
|
putULong(state->expiry, (u_int32_t)offered_lease_time);
|
1997-03-05 06:37:05 +00:00
|
|
|
i = DHO_DHCP_LEASE_TIME;
|
1998-11-05 18:54:55 +00:00
|
|
|
oc = (struct option_cache *)0;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
2006-05-17 20:15:32 +00:00
|
|
|
if (make_const_data(&oc->expression, state->expiry,
|
|
|
|
4, 0, 0, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
|
2009-09-11 18:13:12 +00:00
|
|
|
/*
|
|
|
|
* Validate any configured renew or rebinding times against
|
|
|
|
* the determined lease time. Do rebinding first so that
|
|
|
|
* the renew time can be validated against the rebind time.
|
|
|
|
*/
|
|
|
|
if ((oc = lookup_option(&dhcp_universe, state->options,
|
|
|
|
DHO_DHCP_REBINDING_TIME)) != NULL &&
|
|
|
|
evaluate_option_cache(&d1, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL)) {
|
|
|
|
TIME rebind_time = getULong(d1.data);
|
|
|
|
|
|
|
|
/* Drop the configured (invalid) rebinding time. */
|
|
|
|
if (rebind_time >= offered_lease_time)
|
|
|
|
delete_option(&dhcp_universe, state->options,
|
|
|
|
DHO_DHCP_REBINDING_TIME);
|
|
|
|
else /* XXX: variable is reused. */
|
|
|
|
offered_lease_time = rebind_time;
|
|
|
|
|
|
|
|
data_string_forget(&d1, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1996-09-05 23:52:10 +00:00
|
|
|
|
2009-09-11 18:13:12 +00:00
|
|
|
if ((oc = lookup_option(&dhcp_universe, state->options,
|
|
|
|
DHO_DHCP_RENEWAL_TIME)) != NULL &&
|
|
|
|
evaluate_option_cache(&d1, packet, lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL)) {
|
|
|
|
if (getULong(d1.data) >= offered_lease_time)
|
|
|
|
delete_option(&dhcp_universe, state->options,
|
|
|
|
DHO_DHCP_RENEWAL_TIME);
|
|
|
|
|
|
|
|
data_string_forget(&d1, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1999-04-23 23:17:52 +00:00
|
|
|
} else {
|
2006-07-25 13:26:00 +00:00
|
|
|
/* XXXSK: should we use get_server_source_address() here? */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (state -> ip -> address_count) {
|
|
|
|
state -> from.len =
|
|
|
|
sizeof state -> ip -> addresses [0];
|
|
|
|
memcpy (state -> from.iabuf,
|
|
|
|
&state -> ip -> addresses [0],
|
|
|
|
state -> from.len);
|
|
|
|
}
|
1999-04-23 23:17:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out the address of the boot file server. */
|
2005-03-17 20:15:29 +00:00
|
|
|
memset (&state -> siaddr, 0, sizeof state -> siaddr);
|
1999-04-23 23:17:52 +00:00
|
|
|
if ((oc =
|
|
|
|
lookup_option (&server_universe,
|
|
|
|
state -> options, SV_NEXT_SERVER))) {
|
1999-07-31 18:08:28 +00:00
|
|
|
if (evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL)) {
|
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);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-04-23 23:17:52 +00:00
|
|
|
}
|
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)) {
|
2000-03-06 23:33:52 +00:00
|
|
|
oc = (struct option_cache *)0;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
lease -> subnet -> netmask.iabuf,
|
|
|
|
lease -> subnet -> netmask.len,
|
2001-06-27 00:31:20 +00:00
|
|
|
0, 0, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
|
|
|
|
2014-10-27 14:51:20 -04:00
|
|
|
/* Use the name of the host declaration if there is one
|
2018-09-26 11:10:16 -04:00
|
|
|
and no hostname has otherwise been provided, and if the
|
1998-06-25 03:56:24 +00:00
|
|
|
use-host-decl-name flag is set. */
|
2014-10-27 14:51:20 -04:00
|
|
|
use_host_decl_name(packet, lease, state->options);
|
1998-06-25 03:56:24 +00:00
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/* Send client_id back if we received it and echo-client-id is on. */
|
|
|
|
echo_client_id(packet, lease, state->options, state->options);
|
|
|
|
|
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. */
|
2010-07-13 18:43:41 +00:00
|
|
|
i = DHO_HOST_NAME;
|
1998-11-05 18:54:55 +00:00
|
|
|
j = SV_GET_LEASE_HOSTNAMES;
|
2010-07-13 18:43:41 +00:00
|
|
|
if (!lookup_option(&dhcp_universe, state->options, i) &&
|
|
|
|
evaluate_boolean_option_cache
|
|
|
|
(&ignorep, packet, lease, NULL,
|
|
|
|
packet->options, state->options, &lease->scope,
|
|
|
|
lookup_option (&server_universe, state->options, j), MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
struct in_addr ia;
|
|
|
|
struct hostent *h;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
memcpy (&ia, lease -> ip_addr.iabuf, 4);
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
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;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
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,
|
2001-06-27 00:31:20 +00:00
|
|
|
1, 1, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
2000-01-26 14:56:18 +00:00
|
|
|
option_cache_dereference (&oc, MDL);
|
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
|
2000-11-28 23:27:24 +00:00
|
|
|
(&ignorep, packet, lease, (struct client_state *)0,
|
|
|
|
packet -> options, state -> options, &lease -> scope,
|
1999-04-05 16:46:13 +00:00
|
|
|
lookup_option (&server_universe, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE), MDL)) {
|
1998-11-05 18:54:55 +00:00
|
|
|
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;
|
2000-01-26 14:56:18 +00:00
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
1999-02-14 19:27:56 +00:00
|
|
|
if (make_const_data (&oc -> expression,
|
|
|
|
lease -> ip_addr.iabuf,
|
|
|
|
lease -> ip_addr.len,
|
2001-06-27 00:31:20 +00:00
|
|
|
0, 0, MDL)) {
|
2006-06-01 20:23:18 +00:00
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&i, 0, MDL);
|
1999-04-05 16:46:13 +00:00
|
|
|
save_option (&dhcp_universe,
|
|
|
|
state -> options, oc);
|
1999-02-14 19:27:56 +00:00
|
|
|
}
|
2018-09-26 11:10:16 -04:00
|
|
|
option_cache_dereference (&oc, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1998-06-25 03:56:24 +00:00
|
|
|
}
|
1998-04-09 04:41:52 +00:00
|
|
|
}
|
|
|
|
|
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-31 18:08:28 +00:00
|
|
|
evaluate_option_cache (&d1, packet, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
packet -> options, state -> options,
|
|
|
|
&lease -> scope, oc, MDL)) {
|
2000-05-16 23:03:49 +00:00
|
|
|
struct universe *u = (struct universe *)0;
|
|
|
|
|
|
|
|
if (!universe_hash_lookup (&u, universe_hash,
|
2000-05-17 16:04:26 +00:00
|
|
|
(const char *)d1.data, d1.len,
|
|
|
|
MDL)) {
|
1999-04-23 23:17:52 +00:00
|
|
|
log_error ("unknown option space %s.", d1.data);
|
2019-11-22 13:39:45 -05:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-04-23 23:17:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
state -> options -> site_universe = u -> index;
|
2008-01-09 17:13:16 +00:00
|
|
|
state->options->site_code_min = find_min_site_code(u);
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&d1, MDL);
|
1999-04-23 23:17:52 +00:00
|
|
|
} 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,
|
2000-11-28 23:27:24 +00:00
|
|
|
packet, lease, (struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, state -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
&lease -> scope, oc, MDL);
|
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
|
|
|
|
1999-07-31 18:08:28 +00:00
|
|
|
/* Hang the packet off the lease state. */
|
2000-01-26 14:56:18 +00:00
|
|
|
packet_reference (&lease -> state -> packet, packet, MDL);
|
1999-07-31 18:08:28 +00:00
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
/* If this is a DHCPOFFER, send a ping (if appropriate) to the
|
|
|
|
* lease address before actually we send the offer. */
|
|
|
|
if ((offer == DHCPOFFER) &&
|
|
|
|
do_ping_check(packet, state, lease, original_cltt, same_client)) {
|
1997-03-06 18:40:22 +00:00
|
|
|
++outstanding_pings;
|
|
|
|
} else {
|
2008-01-21 19:53:21 +00:00
|
|
|
lease->cltt = cur_time;
|
2017-12-19 06:25:12 -05:00
|
|
|
#if defined(DELAYED_ACK)
|
2018-02-09 09:19:54 -05:00
|
|
|
if (enqueue)
|
2008-01-21 19:53:21 +00:00
|
|
|
delayed_ack_enqueue(lease);
|
2018-09-26 11:10:16 -04:00
|
|
|
else
|
2008-11-03 18:13:58 +00:00
|
|
|
#endif
|
2008-01-21 19:53:21 +00:00
|
|
|
dhcp_reply(lease);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
/*
|
|
|
|
* \brief Sends a ping to the lease ip_addr when appropriate
|
|
|
|
*
|
|
|
|
* A ping will be sent if all of the following are true:
|
|
|
|
*
|
|
|
|
* 1. Ping checks are enabled
|
|
|
|
* 2. The lease is neither active nor static
|
|
|
|
* 3. Any of the following is true:
|
|
|
|
* a. The lease state is ABANDONED
|
|
|
|
* b. This is the first offer of this lease (CLTT = 0)
|
|
|
|
* c. The lease is being offered to a client other than its previous
|
|
|
|
* owner
|
|
|
|
* d. The lease is being offered to its previous owner and more than
|
|
|
|
* cltt-secs have elapsed since CLTT of the original lease.
|
|
|
|
*
|
|
|
|
* \param packet inbound packet received from the client
|
|
|
|
* \param state lease options state
|
|
|
|
* \param lease lease to be offered (if one)
|
|
|
|
* \param original_cltt CLTT of the original lease
|
|
|
|
* \param same_client flag indicating if the client to be offered the
|
|
|
|
* lease is its previous owner
|
|
|
|
* \return Returns 1 if ping has been sent, 0 otherwise
|
|
|
|
*/
|
|
|
|
int do_ping_check(struct packet* packet, struct lease_state* state,
|
|
|
|
struct lease* lease, TIME original_cltt,
|
|
|
|
int same_client) {
|
|
|
|
TIME ping_timeout = DEFAULT_PING_TIMEOUT;
|
2019-05-01 15:55:11 -04:00
|
|
|
TIME ping_timeout_ms = DEFAULT_PING_TIMEOUT_MS;
|
2018-09-26 11:10:16 -04:00
|
|
|
struct option_cache *oc = NULL;
|
|
|
|
struct data_string ds;
|
|
|
|
struct timeval tv;
|
|
|
|
int ignorep;
|
2019-05-01 15:55:11 -04:00
|
|
|
int timeout_secs;
|
|
|
|
int timeout_ms;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
|
|
|
// Don't go any further if lease is active or static.
|
|
|
|
if (lease->binding_state == FTS_ACTIVE || lease->flags & STATIC_LEASE) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If pings aren't enabled, punt.
|
|
|
|
oc = lookup_option (&server_universe, state -> options, SV_PING_CHECKS);
|
|
|
|
if (oc &&
|
|
|
|
!(evaluate_boolean_option_cache (&ignorep, packet, lease,
|
|
|
|
0, packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL))) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If it's not the first time for the same client and not an
|
|
|
|
// abandoned lease, we need to check the cltt threshold
|
|
|
|
if (same_client && original_cltt &&
|
|
|
|
lease->binding_state != FTS_ABANDONED) {
|
|
|
|
TIME cltt_secs = DEFAULT_PING_CLTT_SECS;
|
|
|
|
memset(&ds, 0, sizeof(ds));
|
|
|
|
oc = lookup_option (&server_universe, state->options,
|
|
|
|
SV_PING_CLTT_SECS);
|
|
|
|
if (oc &&
|
|
|
|
(evaluate_option_cache (&ds, packet, lease, 0,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL))) {
|
|
|
|
if (ds.len == sizeof (u_int32_t)) {
|
|
|
|
cltt_secs = getULong (ds.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
data_string_forget (&ds, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Punt if it is too soon.
|
|
|
|
if (cur_time - original_cltt < cltt_secs) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send the ping.
|
|
|
|
icmp_echorequest (&lease->ip_addr);
|
|
|
|
|
|
|
|
/* Determine whether to use configured or default ping timeout. */
|
|
|
|
memset(&ds, 0, sizeof(ds));
|
2019-05-01 15:55:11 -04:00
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
oc = lookup_option (&server_universe, state->options, SV_PING_TIMEOUT);
|
|
|
|
if (oc &&
|
|
|
|
(evaluate_option_cache (&ds, packet, lease, 0,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL))) {
|
|
|
|
if (ds.len == sizeof (u_int32_t)) {
|
|
|
|
ping_timeout = getULong (ds.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
data_string_forget (&ds, MDL);
|
|
|
|
}
|
|
|
|
|
2019-05-01 15:55:11 -04:00
|
|
|
oc = lookup_option (&server_universe, state->options, SV_PING_TIMEOUT_MS);
|
|
|
|
if (oc &&
|
|
|
|
(evaluate_option_cache (&ds, packet, lease, 0,
|
|
|
|
packet->options, state->options,
|
|
|
|
&lease->scope, oc, MDL))) {
|
|
|
|
if (ds.len == sizeof (u_int32_t)) {
|
|
|
|
ping_timeout_ms = getULong (ds.data);
|
|
|
|
}
|
|
|
|
|
|
|
|
data_string_forget (&ds, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the timeout for the ping to the current timeval plus
|
|
|
|
* the configured time out. Use ping-timeout-ms if it is > 0.
|
|
|
|
* This overrides ping-timeout allowing users to specify it in
|
|
|
|
* milliseconds.
|
|
|
|
*/
|
|
|
|
if (ping_timeout_ms > 0) {
|
|
|
|
timeout_secs = ping_timeout_ms / 1000;
|
|
|
|
timeout_ms = ping_timeout_ms % 1000;
|
|
|
|
} else {
|
|
|
|
timeout_secs = ping_timeout;
|
|
|
|
timeout_ms = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
tv.tv_sec = cur_tv.tv_sec + timeout_secs;
|
|
|
|
tv.tv_usec = cur_tv.tv_usec + (timeout_ms * 1000);
|
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
#ifdef DEBUG
|
|
|
|
log_debug ("Pinging:%s, state: %d, same client? %s, "
|
2019-05-01 15:55:11 -04:00
|
|
|
" orig_cltt %s, elasped: %ld, timeout in: %d.%d secs" ,
|
2018-09-26 11:10:16 -04:00
|
|
|
piaddr(lease->ip_addr),
|
|
|
|
lease->binding_state,
|
|
|
|
(same_client ? "y" : "n"),
|
|
|
|
(original_cltt ? print_time(original_cltt) : "0"),
|
2019-05-01 15:55:11 -04:00
|
|
|
(original_cltt ? (long)(cur_time - original_cltt) : 0),
|
|
|
|
timeout_secs, timeout_ms);
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2019-05-01 15:55:11 -04:00
|
|
|
#endif
|
2019-06-07 08:16:15 -04:00
|
|
|
|
|
|
|
add_timeout (&tv, lease_ping_timeout, lease, (tvref_t)lease_reference,
|
|
|
|
(tvunref_t)lease_dereference);
|
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
#if defined(DELAYED_ACK)
|
|
|
|
|
2010-03-12 01:36:57 +00:00
|
|
|
/*
|
|
|
|
* CC: queue single ACK:
|
|
|
|
* - write the lease (but do not fsync it yet)
|
|
|
|
* - add to double linked list
|
|
|
|
* - commit if more than xx ACKs pending
|
|
|
|
* - if necessary set the max timer and bump the next timer
|
|
|
|
* but only up to the max timer value.
|
2008-01-21 19:53:21 +00:00
|
|
|
*/
|
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
static void
|
2008-01-21 19:53:21 +00:00
|
|
|
delayed_ack_enqueue(struct lease *lease)
|
|
|
|
{
|
|
|
|
struct leasequeue *q;
|
2008-02-28 23:40:45 +00:00
|
|
|
|
2018-09-26 11:10:16 -04:00
|
|
|
if (!write_lease(lease))
|
2008-01-21 19:53:21 +00:00
|
|
|
return;
|
|
|
|
if (free_ackqueue) {
|
|
|
|
q = free_ackqueue;
|
|
|
|
free_ackqueue = q->next;
|
|
|
|
} else {
|
|
|
|
q = ((struct leasequeue *)
|
|
|
|
dmalloc(sizeof(struct leasequeue), MDL));
|
|
|
|
if (!q)
|
|
|
|
log_fatal("delayed_ack_enqueue: no memory!");
|
1997-03-06 18:40:22 +00:00
|
|
|
}
|
2008-01-21 19:53:21 +00:00
|
|
|
memset(q, 0, sizeof *q);
|
|
|
|
/* prepend to ackqueue*/
|
2008-01-28 18:21:06 +00:00
|
|
|
lease_reference(&q->lease, lease, MDL);
|
2008-01-21 19:53:21 +00:00
|
|
|
q->next = ackqueue_head;
|
|
|
|
ackqueue_head = q;
|
2018-09-26 11:10:16 -04:00
|
|
|
if (!ackqueue_tail)
|
2008-01-21 19:53:21 +00:00
|
|
|
ackqueue_tail = q;
|
|
|
|
else
|
|
|
|
q->next->prev = q;
|
|
|
|
|
|
|
|
outstanding_acks++;
|
2010-03-12 01:36:57 +00:00
|
|
|
if (outstanding_acks > max_outstanding_acks) {
|
2015-06-15 15:19:42 -04:00
|
|
|
/* Cancel any pending timeout and call handler directly */
|
|
|
|
cancel_timeout(delayed_acks_timer, NULL);
|
|
|
|
delayed_acks_timer(NULL);
|
2010-03-12 01:36:57 +00:00
|
|
|
} else {
|
|
|
|
struct timeval next_fsync;
|
|
|
|
|
|
|
|
if (max_fsync.tv_sec == 0 && max_fsync.tv_usec == 0) {
|
|
|
|
/* set the maximum time we'll wait */
|
|
|
|
max_fsync.tv_sec = cur_tv.tv_sec + max_ack_delay_secs;
|
|
|
|
max_fsync.tv_usec = cur_tv.tv_usec +
|
|
|
|
max_ack_delay_usecs;
|
2008-02-28 23:40:45 +00:00
|
|
|
|
2010-03-12 01:36:57 +00:00
|
|
|
if (max_fsync.tv_usec >= 1000000) {
|
|
|
|
max_fsync.tv_sec++;
|
|
|
|
max_fsync.tv_usec -= 1000000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the timeout */
|
|
|
|
next_fsync.tv_sec = cur_tv.tv_sec;
|
|
|
|
next_fsync.tv_usec = cur_tv.tv_usec + min_ack_delay_usecs;
|
2008-02-28 23:40:45 +00:00
|
|
|
if (next_fsync.tv_usec >= 1000000) {
|
|
|
|
next_fsync.tv_sec++;
|
|
|
|
next_fsync.tv_usec -= 1000000;
|
|
|
|
}
|
2010-03-12 01:36:57 +00:00
|
|
|
/* but not more than the max */
|
|
|
|
if ((next_fsync.tv_sec > max_fsync.tv_sec) ||
|
|
|
|
((next_fsync.tv_sec == max_fsync.tv_sec) &&
|
|
|
|
(next_fsync.tv_usec > max_fsync.tv_usec))) {
|
|
|
|
next_fsync.tv_sec = max_fsync.tv_sec;
|
|
|
|
next_fsync.tv_usec = max_fsync.tv_usec;
|
|
|
|
}
|
2008-02-28 23:40:45 +00:00
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
add_timeout(&next_fsync, delayed_acks_timer, NULL,
|
2008-01-21 19:53:21 +00:00
|
|
|
(tvref_t) NULL, (tvunref_t) NULL);
|
|
|
|
}
|
1997-03-05 06:37:05 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
/* Processes any delayed acks:
|
|
|
|
* Commits the leases and then for each delayed ack:
|
|
|
|
* - Update the failover peer if we're in failover
|
|
|
|
* - Send the REPLY to the client
|
|
|
|
*/
|
2008-02-28 23:40:45 +00:00
|
|
|
static void
|
2015-06-15 15:19:42 -04:00
|
|
|
delayed_acks_timer(void *foo)
|
2008-02-28 23:40:45 +00:00
|
|
|
{
|
2015-06-15 15:19:42 -04:00
|
|
|
struct leasequeue *ack, *p;
|
|
|
|
|
|
|
|
/* Reset max fsync */
|
|
|
|
memset(&max_fsync, 0, sizeof(max_fsync));
|
2008-02-28 23:40:45 +00:00
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
if (!outstanding_acks) {
|
|
|
|
/* Nothing to do, so punt, shouldn't happen? */
|
|
|
|
return;
|
2008-02-28 23:40:45 +00:00
|
|
|
}
|
2008-01-21 19:53:21 +00:00
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
/* Commit the leases first */
|
|
|
|
commit_leases();
|
|
|
|
|
|
|
|
/* Now process the delayed ACKs
|
|
|
|
- update failover peer
|
|
|
|
- send out the ACK packets
|
|
|
|
- move the queue slots to the free list
|
|
|
|
*/
|
|
|
|
|
2008-01-21 19:53:21 +00:00
|
|
|
/* process from bottom to retain packet order */
|
2018-09-26 11:10:16 -04:00
|
|
|
for (ack = ackqueue_tail ; ack ; ack = p) {
|
2008-01-21 19:53:21 +00:00
|
|
|
p = ack->prev;
|
2008-01-28 18:21:06 +00:00
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
#if defined(FAILOVER_PROTOCOL)
|
|
|
|
/* If we're in failover we need to send any deferred
|
|
|
|
* bind updates as well as the replies */
|
|
|
|
if (ack->lease->pool) {
|
|
|
|
dhcp_failover_state_t *fpeer;
|
|
|
|
|
|
|
|
fpeer = ack->lease->pool->failover_peer;
|
|
|
|
if (fpeer && fpeer->link_to_peer) {
|
|
|
|
dhcp_failover_send_updates(fpeer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-01-28 18:21:06 +00:00
|
|
|
/* dhcp_reply() requires that the reply state still be valid */
|
|
|
|
if (ack->lease->state == NULL)
|
|
|
|
log_error("delayed ack for %s has gone stale",
|
|
|
|
piaddr(ack->lease->ip_addr));
|
2015-06-15 15:19:42 -04:00
|
|
|
else {
|
2008-01-28 18:21:06 +00:00
|
|
|
dhcp_reply(ack->lease);
|
2015-06-15 15:19:42 -04:00
|
|
|
}
|
2008-01-28 18:21:06 +00:00
|
|
|
|
|
|
|
lease_dereference(&ack->lease, MDL);
|
2008-01-21 19:53:21 +00:00
|
|
|
ack->next = free_ackqueue;
|
|
|
|
free_ackqueue = ack;
|
|
|
|
}
|
2015-06-15 15:19:42 -04:00
|
|
|
|
2008-01-21 19:53:21 +00:00
|
|
|
ackqueue_head = NULL;
|
|
|
|
ackqueue_tail = NULL;
|
|
|
|
outstanding_acks = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
|
|
|
|
void
|
|
|
|
relinquish_ackqueue(void)
|
|
|
|
{
|
|
|
|
struct leasequeue *q, *n;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2009-04-07 19:55:52 +00:00
|
|
|
for (q = ackqueue_head ; q ; q = n) {
|
2008-01-21 19:53:21 +00:00
|
|
|
n = q->next;
|
|
|
|
dfree(q, MDL);
|
|
|
|
}
|
|
|
|
for (q = free_ackqueue ; q ; q = n) {
|
|
|
|
n = q->next;
|
|
|
|
dfree(q, MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2015-06-15 15:19:42 -04:00
|
|
|
#endif /* defined(DELAYED_ACK) */
|
|
|
|
|
1997-03-05 06:37:05 +00:00
|
|
|
void dhcp_reply (lease)
|
|
|
|
struct lease *lease;
|
|
|
|
{
|
|
|
|
int bufs = 0;
|
1999-10-07 06:36:35 +00:00
|
|
|
unsigned packet_length;
|
1997-03-05 06:37:05 +00:00
|
|
|
struct dhcp_packet raw;
|
|
|
|
struct sockaddr_in to;
|
|
|
|
struct in_addr from;
|
|
|
|
struct hardware hto;
|
|
|
|
int result;
|
1997-03-06 07:02:00 +00:00
|
|
|
struct lease_state *state = lease -> state;
|
2000-10-13 18:58:12 +00:00
|
|
|
int nulltp, bootpp, unicastp = 1;
|
2017-12-30 14:15:12 +01:00
|
|
|
#if defined(RELAY_PORT)
|
2017-12-23 01:18:23 +01:00
|
|
|
u_int16_t relay_port = 0;
|
2017-12-30 14:15:12 +01:00
|
|
|
#endif
|
1998-06-25 03:56:24 +00:00
|
|
|
struct data_string d1;
|
2005-03-17 20:15:29 +00:00
|
|
|
const char *s;
|
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);
|
2018-09-26 11:10:16 -04:00
|
|
|
else
|
2010-09-08 22:13:05 +00:00
|
|
|
log_info("file name longer than packet field "
|
2018-09-26 11:10:16 -04:00
|
|
|
"truncated - field: %lu name: %d %.*s",
|
2010-09-09 06:48:52 +00:00
|
|
|
(unsigned long)sizeof(raw.file),
|
2011-02-16 03:22:56 +00:00
|
|
|
state->filename.len, (int)state->filename.len,
|
2010-09-09 06:48:52 +00:00
|
|
|
state->filename.data);
|
1998-06-25 03:56:24 +00:00
|
|
|
} 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);
|
2018-09-26 11:10:16 -04:00
|
|
|
else
|
2010-09-08 22:13:05 +00:00
|
|
|
log_info("server name longer than packet field "
|
2018-09-26 11:10:16 -04:00
|
|
|
"truncated - field: %lu name: %d %.*s",
|
2010-09-09 06:48:52 +00:00
|
|
|
(unsigned long)sizeof(raw.sname),
|
|
|
|
state->server_name.len,
|
2011-02-16 03:22:56 +00:00
|
|
|
(int)state->server_name.len,
|
2010-09-08 22:13:05 +00:00
|
|
|
state->server_name.data);
|
1998-06-25 03:56:24 +00:00
|
|
|
} else
|
1997-03-05 06:37:05 +00:00
|
|
|
bufs |= 2; /* XXX */
|
|
|
|
|
2000-01-05 18:16:36 +00:00
|
|
|
memcpy (raw.chaddr,
|
|
|
|
&lease -> hardware_addr.hbuf [1], sizeof raw.chaddr);
|
|
|
|
raw.hlen = lease -> hardware_addr.hlen - 1;
|
|
|
|
raw.htype = lease -> hardware_addr.hbuf [0];
|
1997-03-05 06:37:05 +00:00
|
|
|
|
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-31 18:08:28 +00:00
|
|
|
packet_length = cons_options (state -> packet, &raw, lease,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1998-02-06 01:08:38 +00:00
|
|
|
state -> max_message_size,
|
1999-07-31 18:08:28 +00:00
|
|
|
state -> packet -> options,
|
2000-01-25 01:36:29 +00:00
|
|
|
state -> options, &global_scope,
|
1999-03-10 20:44:22 +00:00
|
|
|
bufs, nulltp, bootpp,
|
2000-10-10 23:07:24 +00:00
|
|
|
&state -> parameter_request_list,
|
|
|
|
(char *)0);
|
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;
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
if (lease -> client_hostname) {
|
|
|
|
if ((strlen (lease -> client_hostname) <= 64) &&
|
2007-07-13 06:43:43 +00:00
|
|
|
db_printable((unsigned char *)lease->client_hostname))
|
2005-03-17 20:15:29 +00:00
|
|
|
s = lease -> client_hostname;
|
|
|
|
else
|
|
|
|
s = "Hostname Unsuitable for Printing";
|
|
|
|
} else
|
1999-11-20 18:36:32 +00:00
|
|
|
s = (char *)0;
|
|
|
|
|
2016-02-23 10:40:10 +01: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;
|
|
|
|
|
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (state->packet->dhcp4o6_response != NULL)) {
|
|
|
|
/* Say what we're doing... */
|
|
|
|
log_info ("DHCP4o6 %s on %s to %s %s%s%svia %s",
|
|
|
|
(state -> offer
|
|
|
|
? (state -> offer == DHCPACK
|
|
|
|
? "DHCPACK" : "DHCPOFFER")
|
|
|
|
: "BOOTREPLY"),
|
|
|
|
piaddr (lease -> ip_addr),
|
|
|
|
(lease -> hardware_addr.hlen
|
|
|
|
? print_hw_addr (lease -> hardware_addr.hbuf [0],
|
|
|
|
lease -> hardware_addr.hlen - 1,
|
|
|
|
&lease -> hardware_addr.hbuf [1])
|
|
|
|
: print_hex_1(lease->uid_len, lease->uid, 60)),
|
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
piaddr(state->packet->client_addr));
|
|
|
|
|
|
|
|
/* fill dhcp4o6_response */
|
|
|
|
state->packet->dhcp4o6_response->len = packet_length;
|
|
|
|
state->packet->dhcp4o6_response->buffer = NULL;
|
|
|
|
if (!buffer_allocate(&state->packet->dhcp4o6_response->buffer,
|
|
|
|
packet_length, MDL)) {
|
|
|
|
log_fatal("No memory to store DHCP4o6 reply.");
|
|
|
|
}
|
|
|
|
state->packet->dhcp4o6_response->data =
|
|
|
|
state->packet->dhcp4o6_response->buffer->data;
|
|
|
|
memcpy(state->packet->dhcp4o6_response->buffer->data,
|
|
|
|
&raw, packet_length);
|
|
|
|
|
|
|
|
/* done */
|
|
|
|
free_lease_state (state, MDL);
|
|
|
|
lease -> state = (struct lease_state *)0;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Say what we're doing... */
|
1999-11-20 18:36:32 +00:00
|
|
|
log_info ("%s on %s to %s %s%s%svia %s",
|
1999-10-21 14:56:05 +00:00
|
|
|
(state -> offer
|
|
|
|
? (state -> offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
|
|
|
|
: "BOOTREPLY"),
|
|
|
|
piaddr (lease -> ip_addr),
|
2000-01-05 18:16:36 +00:00
|
|
|
(lease -> hardware_addr.hlen
|
|
|
|
? print_hw_addr (lease -> hardware_addr.hbuf [0],
|
|
|
|
lease -> hardware_addr.hlen - 1,
|
|
|
|
&lease -> hardware_addr.hbuf [1])
|
2006-07-25 13:26:00 +00:00
|
|
|
: print_hex_1(lease->uid_len, lease->uid, 60)),
|
1999-11-23 19:08:24 +00:00
|
|
|
s ? "(" : "", s ? s : "", s ? ") " : "",
|
|
|
|
(state -> giaddr.s_addr
|
|
|
|
? inet_ntoa (state -> giaddr)
|
|
|
|
: state -> ip -> name));
|
1996-05-22 07:21:50 +00:00
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#ifdef DEBUG_PACKET
|
|
|
|
dump_raw ((unsigned char *)&raw, packet_length);
|
|
|
|
#endif
|
|
|
|
|
1996-05-22 07:21:50 +00:00
|
|
|
/* Set up the hardware address... */
|
1997-03-05 06:37:05 +00:00
|
|
|
hto.hlen = lease -> hardware_addr.hlen;
|
2000-01-05 18:16:36 +00:00
|
|
|
memcpy (hto.hbuf, lease -> hardware_addr.hbuf, 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);
|
|
|
|
|
2017-12-23 01:18:23 +01:00
|
|
|
#if defined(RELAY_PORT)
|
|
|
|
relay_port = dhcp_check_relayport(state->packet);
|
|
|
|
#endif
|
|
|
|
|
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;
|
2001-01-25 08:32:26 +00:00
|
|
|
if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK))
|
2017-12-30 14:15:12 +01:00
|
|
|
#if defined(RELAY_PORT)
|
2017-12-23 01:18:23 +01:00
|
|
|
to.sin_port = relay_port ? relay_port : local_port;
|
2017-12-30 14:15:12 +01:00
|
|
|
#else
|
|
|
|
to.sin_port = local_port;
|
|
|
|
#endif
|
1999-10-24 19:38:53 +00:00
|
|
|
else
|
|
|
|
to.sin_port = remote_port; /* For debugging. */
|
1996-06-24 20:32:12 +00:00
|
|
|
|
1999-02-14 19:27:56 +00:00
|
|
|
if (fallback_interface) {
|
2012-03-09 11:18:14 +00:00
|
|
|
result = send_packet(fallback_interface, NULL, &raw,
|
|
|
|
packet_length, raw.siaddr, &to,
|
|
|
|
NULL);
|
|
|
|
if (result < 0) {
|
|
|
|
log_error ("%s:%d: Failed to send %d byte long "
|
|
|
|
"packet over %s interface.", MDL,
|
|
|
|
packet_length,
|
|
|
|
fallback_interface->name);
|
|
|
|
}
|
|
|
|
|
1997-03-06 07:02:00 +00:00
|
|
|
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
1999-02-14 19:27:56 +00:00
|
|
|
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) {
|
2012-03-09 11:18:14 +00:00
|
|
|
result = send_packet(fallback_interface, NULL, &raw,
|
|
|
|
packet_length, raw.siaddr, &to,
|
|
|
|
NULL);
|
|
|
|
if (result < 0) {
|
|
|
|
log_error("%s:%d: Failed to send %d byte long"
|
|
|
|
" packet over %s interface.", MDL,
|
|
|
|
packet_length,
|
|
|
|
fallback_interface->name);
|
|
|
|
}
|
|
|
|
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
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;
|
2000-10-13 18:58:12 +00:00
|
|
|
if (!(lease -> flags & UNICAST_BROADCAST_HACK))
|
|
|
|
unicastp = 0;
|
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
|
|
|
|
2012-03-09 11:18:14 +00:00
|
|
|
result = send_packet(state->ip, NULL, &raw, packet_length,
|
|
|
|
from, &to, unicastp ? &hto : NULL);
|
|
|
|
if (result < 0) {
|
|
|
|
log_error ("%s:%d: Failed to send %d byte long "
|
|
|
|
"packet over %s interface.", MDL,
|
|
|
|
packet_length, state->ip->name);
|
|
|
|
}
|
|
|
|
|
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. */
|
|
|
|
|
2000-01-26 14:56:18 +00:00
|
|
|
free_lease_state (state, MDL);
|
1997-03-06 07:02:00 +00:00
|
|
|
lease -> state = (struct lease_state *)0;
|
1995-11-29 07:40:04 +00:00
|
|
|
}
|
1996-02-26 01:56:15 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
int find_lease (struct lease **lp,
|
|
|
|
struct packet *packet, struct shared_network *share, int *ours,
|
2006-02-24 23:16:32 +00:00
|
|
|
int *peer_has_leases, struct lease *ip_lease_in,
|
2000-11-28 23:27:24 +00:00
|
|
|
const char *file, int line)
|
1996-02-26 01:56:15 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
struct lease *uid_lease = (struct lease *)0;
|
|
|
|
struct lease *ip_lease = (struct lease *)0;
|
|
|
|
struct lease *hw_lease = (struct lease *)0;
|
1996-05-22 07:21:50 +00:00
|
|
|
struct lease *lease = (struct lease *)0;
|
1996-02-26 01:56:15 +00:00
|
|
|
struct iaddr cip;
|
2000-05-16 23:03:49 +00:00
|
|
|
struct host_decl *hp = (struct host_decl *)0;
|
|
|
|
struct host_decl *host = (struct host_decl *)0;
|
|
|
|
struct lease *fixed_lease = (struct lease *)0;
|
2000-12-28 23:28:17 +00:00
|
|
|
struct lease *next = (struct lease *)0;
|
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;
|
2000-03-06 23:33:52 +00:00
|
|
|
struct hardware h;
|
1996-02-26 01:56:15 +00:00
|
|
|
|
2008-02-28 21:21:56 +00:00
|
|
|
#if defined(FAILOVER_PROTOCOL)
|
2006-02-24 23:16:32 +00:00
|
|
|
/* Quick check to see if the peer has leases. */
|
|
|
|
if (peer_has_leases) {
|
|
|
|
struct pool *pool;
|
|
|
|
|
|
|
|
for (pool = share->pools ; pool ; pool = pool->next) {
|
|
|
|
dhcp_failover_state_t *peer = pool->failover_peer;
|
|
|
|
|
|
|
|
if (peer &&
|
|
|
|
((peer->i_am == primary && pool->backup_leases) ||
|
|
|
|
(peer->i_am == secondary && pool->free_leases))) {
|
|
|
|
*peer_has_leases = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-02-28 21:21:56 +00:00
|
|
|
#endif /* FAILOVER_PROTOCOL */
|
2006-02-24 23:16:32 +00:00
|
|
|
|
2000-11-28 23:27:24 +00:00
|
|
|
if (packet -> raw -> ciaddr.s_addr) {
|
1999-02-25 23:30:43 +00:00
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
|
2000-11-28 23:27:24 +00:00
|
|
|
} else {
|
|
|
|
/* Look up the requested address. */
|
|
|
|
oc = lookup_option (&dhcp_universe, packet -> options,
|
|
|
|
DHO_DHCP_REQUESTED_ADDRESS);
|
|
|
|
memset (&d1, 0, sizeof d1);
|
|
|
|
if (oc &&
|
|
|
|
evaluate_option_cache (&d1, packet, (struct lease *)0,
|
|
|
|
(struct client_state *)0,
|
|
|
|
packet -> options,
|
|
|
|
(struct option_state *)0,
|
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
packet -> got_requested_address = 1;
|
|
|
|
cip.len = 4;
|
|
|
|
memcpy (cip.iabuf, d1.data, cip.len);
|
|
|
|
data_string_forget (&d1, MDL);
|
2018-09-26 11:10:16 -04:00
|
|
|
} else
|
2000-11-28 23:27:24 +00:00
|
|
|
cip.len = 0;
|
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
|
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-31 18:08:28 +00:00
|
|
|
packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
1999-07-31 18:08:28 +00:00
|
|
|
packet -> options, (struct option_state *)0,
|
2000-01-25 01:36:29 +00:00
|
|
|
&global_scope, oc, MDL)) {
|
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... */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (find_hosts_by_uid (&hp, client_identifier.data,
|
|
|
|
client_identifier.len, MDL)) {
|
1998-11-09 02:46:58 +00:00
|
|
|
/* Remember if we know of this client. */
|
|
|
|
packet -> known = 1;
|
2000-05-16 23:03:49 +00:00
|
|
|
mockup_lease (&fixed_lease, packet, share, hp);
|
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
|
|
|
|
#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
|
2001-03-16 01:55:38 +00:00
|
|
|
if (hp) {
|
|
|
|
if (!fixed_lease) /* Save the host if we found one. */
|
|
|
|
host_reference (&host, hp, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
host_dereference (&hp, MDL);
|
2001-03-16 01:55:38 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
find_lease_by_uid (&uid_lease, client_identifier.data,
|
|
|
|
client_identifier.len, MDL);
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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) {
|
2000-05-16 23:03:49 +00:00
|
|
|
if (find_hosts_by_haddr (&hp, packet -> raw -> htype,
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
packet -> raw -> hlen, MDL)) {
|
1998-11-09 02:46:58 +00:00
|
|
|
/* Remember if we know of this client. */
|
|
|
|
packet -> known = 1;
|
2000-05-16 23:03:49 +00:00
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
|
|
|
host_reference (&host, hp, MDL);
|
|
|
|
host_dereference (&hp, MDL);
|
|
|
|
mockup_lease (&fixed_lease, packet, share, host);
|
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
|
|
|
|
2009-11-10 21:12:23 +00:00
|
|
|
/* Finally, if we haven't found anything yet try again with the
|
|
|
|
* host-identifier option ... */
|
|
|
|
if (!fixed_lease && !host) {
|
|
|
|
if (find_hosts_by_option(&hp, packet,
|
|
|
|
packet->options, MDL) == 1) {
|
|
|
|
packet->known = 1;
|
|
|
|
if (host)
|
|
|
|
host_dereference(&host, MDL);
|
|
|
|
host_reference(&host, hp, MDL);
|
|
|
|
host_dereference(&hp, MDL);
|
|
|
|
mockup_lease (&fixed_lease, packet, share, host);
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
if (fixed_lease) {
|
|
|
|
log_info ("Found host via host-identifier");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* If we found leases matching the client identifier, loop through
|
2007-04-26 20:06:25 +00:00
|
|
|
* 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.
|
|
|
|
*
|
|
|
|
* Note that the n_uid lease chain is sorted in order of
|
|
|
|
* preference, so the first one is the best one.
|
|
|
|
*/
|
2000-05-16 23:03:49 +00:00
|
|
|
while (uid_lease) {
|
2016-10-04 14:25:25 -04:00
|
|
|
isc_boolean_t do_release = !packet->raw->ciaddr.s_addr;
|
1999-02-25 23:30:43 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("trying next lease matching client id: %s",
|
|
|
|
piaddr (uid_lease -> ip_addr));
|
|
|
|
#endif
|
2001-06-27 00:31:20 +00:00
|
|
|
|
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* When we lookup a lease by uid, we know the client identifier
|
|
|
|
* matches the lease's record. If it is active, or was last
|
|
|
|
* active with the same client, we can trivially extend it.
|
|
|
|
* If is not or was not active, we can allocate it to this
|
|
|
|
* client if it matches the usual free/backup criteria (which
|
|
|
|
* is contained in lease_mine_to_reallocate()).
|
|
|
|
*/
|
|
|
|
if (uid_lease->binding_state != FTS_ACTIVE &&
|
|
|
|
uid_lease->rewind_binding_state != FTS_ACTIVE &&
|
|
|
|
!lease_mine_to_reallocate(uid_lease)) {
|
2001-06-27 00:31:20 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
2010-02-03 23:25:25 +00:00
|
|
|
log_info("not active or not mine to allocate: %s",
|
|
|
|
piaddr(uid_lease->ip_addr));
|
2001-06-27 00:31:20 +00:00
|
|
|
#endif
|
|
|
|
goto n_uid;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
if (uid_lease -> subnet -> shared_network != share) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("wrong network segment: %s",
|
|
|
|
piaddr (uid_lease -> ip_addr));
|
|
|
|
#endif
|
2016-10-04 14:25:25 -04:00
|
|
|
/* Allow multiple leases using the same UID
|
|
|
|
on different subnetworks. */
|
|
|
|
do_release = ISC_FALSE;
|
2001-06-27 00:31:20 +00:00
|
|
|
goto n_uid;
|
1999-02-25 23:30:43 +00:00
|
|
|
}
|
2001-06-27 00:31:20 +00:00
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
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
|
2001-06-27 00:31:20 +00:00
|
|
|
n_uid:
|
2001-01-25 08:32:26 +00:00
|
|
|
if (uid_lease -> n_uid)
|
|
|
|
lease_reference (&next,
|
|
|
|
uid_lease -> n_uid, MDL);
|
2016-10-04 14:25:25 -04:00
|
|
|
if (do_release)
|
1999-10-05 02:46:17 +00:00
|
|
|
release_lease (uid_lease, packet);
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&uid_lease, MDL);
|
2001-01-25 08:32:26 +00:00
|
|
|
if (next) {
|
|
|
|
lease_reference (&uid_lease, next, MDL);
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
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
|
2007-04-26 20:06:25 +00:00
|
|
|
* identifier matches (or equally doesn't have one), that's
|
|
|
|
* permitted, and that's on the correct subnet.
|
|
|
|
*
|
|
|
|
* Note that the n_hw chain is sorted in order of preference, so
|
|
|
|
* the first one found is the best one.
|
|
|
|
*/
|
2000-03-06 23:33:52 +00:00
|
|
|
h.hlen = packet -> raw -> hlen + 1;
|
|
|
|
h.hbuf [0] = packet -> raw -> htype;
|
|
|
|
memcpy (&h.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
|
2000-05-16 23:03:49 +00:00
|
|
|
find_lease_by_hw_addr (&hw_lease, h.hbuf, h.hlen, MDL);
|
|
|
|
while (hw_lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("trying next lease matching hw addr: %s",
|
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
2001-06-27 00:31:20 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* When we lookup a lease by chaddr, we know the MAC address
|
|
|
|
* matches the lease record (we will check if the lease has a
|
|
|
|
* client-id the client does not next). If the lease is
|
|
|
|
* currently active or was last active with this client, we can
|
|
|
|
* trivially extend it. Otherwise, there are a set of rules
|
|
|
|
* that govern if we can reallocate this lease to any client
|
|
|
|
* ("lease_mine_to_reallocate()") including this one.
|
|
|
|
*/
|
|
|
|
if (hw_lease->binding_state != FTS_ACTIVE &&
|
|
|
|
hw_lease->rewind_binding_state != FTS_ACTIVE &&
|
|
|
|
!lease_mine_to_reallocate(hw_lease)) {
|
2001-06-27 00:31:20 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
2010-02-03 23:25:25 +00:00
|
|
|
log_info("not active or not mine to allocate: %s",
|
|
|
|
piaddr(hw_lease->ip_addr));
|
2001-06-27 00:31:20 +00:00
|
|
|
#endif
|
|
|
|
goto n_hw;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* This conditional skips "potentially active" leases (leases
|
|
|
|
* we think are expired may be extended by the peer, etc) that
|
|
|
|
* may be assigned to a differently /client-identified/ client
|
|
|
|
* with the same MAC address.
|
|
|
|
*/
|
2001-06-27 00:31:20 +00:00
|
|
|
if (hw_lease -> binding_state != FTS_FREE &&
|
|
|
|
hw_lease -> binding_state != FTS_BACKUP &&
|
1999-02-25 23:30:43 +00:00
|
|
|
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
|
2001-06-27 00:31:20 +00:00
|
|
|
goto n_hw;
|
1999-02-25 23:30:43 +00:00
|
|
|
}
|
|
|
|
if (hw_lease -> subnet -> shared_network != share) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("wrong network segment: %s",
|
|
|
|
piaddr (hw_lease -> ip_addr));
|
|
|
|
#endif
|
2001-06-27 00:31:20 +00:00
|
|
|
goto n_hw;
|
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
|
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
1999-10-05 02:46:17 +00:00
|
|
|
release_lease (hw_lease, packet);
|
2001-06-27 00:31:20 +00:00
|
|
|
n_hw:
|
|
|
|
if (hw_lease -> n_hw)
|
|
|
|
lease_reference (&next, hw_lease -> n_hw, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&hw_lease, MDL);
|
2001-01-25 08:32:26 +00:00
|
|
|
if (next) {
|
|
|
|
lease_reference (&hw_lease, next, MDL);
|
|
|
|
lease_dereference (&next, MDL);
|
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
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. */
|
2000-11-28 23:27:24 +00:00
|
|
|
if (ip_lease_in)
|
|
|
|
lease_reference (&ip_lease, ip_lease_in, MDL);
|
|
|
|
else if (cip.len)
|
2000-05-16 23:03:49 +00:00
|
|
|
find_lease_by_ip_addr (&ip_lease, cip, MDL);
|
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");
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&ip_lease, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
1996-08-27 09:37:50 +00:00
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* If the requested address is in use (or potentially in use) by
|
|
|
|
* a different client, it can't be granted.
|
|
|
|
*
|
|
|
|
* This first conditional only detects if the lease is currently
|
|
|
|
* identified to a different client (client-id and/or chaddr
|
|
|
|
* mismatch). In this case we may not want to give the client the
|
|
|
|
* lease, if doing so may potentially be an addressing conflict.
|
|
|
|
*/
|
1996-06-27 19:04:29 +00:00
|
|
|
if (ip_lease &&
|
2000-08-24 18:49:34 +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)) :
|
2000-09-01 16:57:44 +00:00
|
|
|
(ip_lease -> hardware_addr.hbuf [0] != packet -> raw -> htype ||
|
|
|
|
ip_lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 ||
|
|
|
|
memcmp (&ip_lease -> hardware_addr.hbuf [1],
|
|
|
|
packet -> raw -> chaddr,
|
|
|
|
(unsigned)(ip_lease -> hardware_addr.hlen - 1))))) {
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* A lease is unavailable for allocation to a new client if
|
|
|
|
* it is not in the FREE or BACKUP state. There may be
|
|
|
|
* leases that are in the expired state with a rewinding
|
|
|
|
* state that is free or backup, but these will be processed
|
|
|
|
* into the free or backup states by expiration processes, so
|
|
|
|
* checking for them here is superfluous.
|
|
|
|
*/
|
2001-06-27 00:31:20 +00:00
|
|
|
if (ip_lease -> binding_state != FTS_FREE &&
|
|
|
|
ip_lease -> binding_state != FTS_BACKUP) {
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_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
|
2000-06-06 23:59:18 +00:00
|
|
|
/* If we're rejecting it because the peer has
|
|
|
|
it, don't set "ours", because we shouldn't NAK. */
|
|
|
|
if (ours && ip_lease -> binding_state != FTS_ACTIVE)
|
|
|
|
*ours = 0;
|
2000-06-02 21:27:21 +00:00
|
|
|
lease_dereference (&ip_lease, MDL);
|
2006-02-24 23:16:32 +00:00
|
|
|
}
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* If we got an ip_lease and a uid_lease or hw_lease, and ip_lease
|
|
|
|
* is/was not active, and is not ours to reallocate, forget about it.
|
|
|
|
*/
|
2001-06-27 00:31:20 +00:00
|
|
|
if (ip_lease && (uid_lease || hw_lease) &&
|
2010-02-03 23:25:25 +00:00
|
|
|
ip_lease->binding_state != FTS_ACTIVE &&
|
|
|
|
ip_lease->rewind_binding_state != FTS_ACTIVE &&
|
2008-02-28 21:21:56 +00:00
|
|
|
#if defined(FAILOVER_PROTOCOL)
|
2010-02-03 23:25:25 +00:00
|
|
|
!lease_mine_to_reallocate(ip_lease) &&
|
2008-02-28 21:21:56 +00:00
|
|
|
#endif
|
2010-02-03 23:25:25 +00:00
|
|
|
packet->packet_type == DHCPDISCOVER) {
|
2001-06-27 00:31:20 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
2010-02-03 23:25:25 +00:00
|
|
|
log_info("ip lease not active or not ours to offer.");
|
2001-06-27 00:31:20 +00:00
|
|
|
#endif
|
2010-02-03 23:25:25 +00:00
|
|
|
lease_dereference(&ip_lease, MDL);
|
2001-06-27 00:31:20 +00:00
|
|
|
}
|
|
|
|
|
1998-11-05 18:54:55 +00:00
|
|
|
/* 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. */
|
2006-04-27 17:26:42 +00:00
|
|
|
if (ip_lease && ip_lease->binding_state == FTS_ACTIVE &&
|
|
|
|
ip_lease->uid && ip_lease != uid_lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
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) {
|
2006-04-27 17:26:42 +00:00
|
|
|
if (uid_lease->binding_state == FTS_ACTIVE) {
|
1999-02-25 23:30:43 +00:00
|
|
|
log_error ("client %s has duplicate%s on %s",
|
|
|
|
(print_hw_addr
|
|
|
|
(packet -> raw -> htype,
|
|
|
|
packet -> raw -> hlen,
|
|
|
|
packet -> raw -> chaddr)),
|
2000-01-25 01:36:29 +00:00
|
|
|
" leases",
|
|
|
|
(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 &&
|
2006-04-27 17:26:42 +00:00
|
|
|
uid_lease->binding_state == FTS_ACTIVE &&
|
1999-03-09 23:45:04 +00:00
|
|
|
!packet -> raw -> ciaddr.s_addr &&
|
|
|
|
(share ==
|
1999-11-07 20:32:03 +00:00
|
|
|
uid_lease -> subnet -> shared_network) &&
|
|
|
|
packet -> packet_type == DHCPREQUEST)
|
2006-02-24 23:16:32 +00:00
|
|
|
release_lease (uid_lease, packet);
|
1999-03-09 23:45:04 +00:00
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&uid_lease, MDL);
|
|
|
|
lease_reference (&uid_lease, ip_lease, MDL);
|
1999-03-09 23:45:04 +00:00
|
|
|
}
|
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) {
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&fixed_lease, MDL);
|
1999-02-25 23:30:43 +00:00
|
|
|
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)
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&ip_lease, MDL);
|
1999-02-25 23:30:43 +00:00
|
|
|
strcpy (dhcp_message,
|
|
|
|
"database conflict - call for help!");
|
|
|
|
}
|
2000-11-28 23:27:24 +00:00
|
|
|
|
|
|
|
if (ip_lease && ip_lease != uid_lease) {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("requested address not available.");
|
|
|
|
#endif
|
|
|
|
lease_dereference (&ip_lease, MDL);
|
|
|
|
}
|
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;
|
|
|
|
|
|
|
|
/* Toss extra pointers to the same lease... */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (hw_lease && hw_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 ("hardware lease and uid lease are identical.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&hw_lease, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
if (ip_lease && ip_lease == hw_lease) {
|
|
|
|
lease_dereference (&hw_lease, MDL);
|
1999-02-25 23:30:43 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("hardware lease and ip lease are identical.");
|
|
|
|
#endif
|
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
if (ip_lease && ip_lease == uid_lease) {
|
|
|
|
lease_dereference (&uid_lease, MDL);
|
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
|
|
|
|
2000-06-02 21:27:21 +00:00
|
|
|
/* 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)))) {
|
2006-02-24 23:16:32 +00:00
|
|
|
if (!packet->raw->ciaddr.s_addr &&
|
|
|
|
(ip_lease->binding_state == FTS_ACTIVE))
|
2000-06-02 21:27:21 +00:00
|
|
|
release_lease (ip_lease, packet);
|
2006-02-24 23:16:32 +00:00
|
|
|
|
2000-06-02 21:27:21 +00:00
|
|
|
lease_dereference (&ip_lease, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (uid_lease &&
|
|
|
|
((uid_lease -> pool -> prohibit_list &&
|
|
|
|
permitted (packet, uid_lease -> pool -> prohibit_list)) ||
|
|
|
|
(uid_lease -> pool -> permit_list &&
|
|
|
|
!permitted (packet, uid_lease -> pool -> permit_list)))) {
|
|
|
|
if (!packet -> raw -> ciaddr.s_addr)
|
|
|
|
release_lease (uid_lease, packet);
|
|
|
|
lease_dereference (&uid_lease, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hw_lease &&
|
|
|
|
((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 (!packet -> raw -> ciaddr.s_addr)
|
|
|
|
release_lease (hw_lease, packet);
|
|
|
|
lease_dereference (&hw_lease, MDL);
|
|
|
|
}
|
|
|
|
|
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) {
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_reference (&lease, fixed_lease, MDL);
|
|
|
|
lease_dereference (&fixed_lease, MDL);
|
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)
|
1999-10-05 02:46:17 +00:00
|
|
|
release_lease (ip_lease, packet);
|
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
|
2016-07-28 06:51:30 -04:00
|
|
|
lease_dereference (&ip_lease, MDL);
|
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
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_reference (&lease, ip_lease, MDL);
|
|
|
|
if (lease -> host)
|
|
|
|
host_dereference (&lease -> host, MDL);
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
|
|
|
}
|
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) {
|
2006-02-24 23:16:32 +00:00
|
|
|
log_error("uid lease %s for client %s is duplicate "
|
|
|
|
"on %s",
|
|
|
|
piaddr(uid_lease->ip_addr),
|
|
|
|
print_hw_addr(packet->raw->htype,
|
|
|
|
packet->raw->hlen,
|
|
|
|
packet->raw->chaddr),
|
|
|
|
uid_lease->subnet->shared_network->name);
|
|
|
|
|
1999-11-07 20:32:03 +00:00
|
|
|
if (!packet -> raw -> ciaddr.s_addr &&
|
2001-06-27 00:31:20 +00:00
|
|
|
packet -> packet_type == DHCPREQUEST &&
|
2006-04-27 17:26:42 +00:00
|
|
|
uid_lease -> binding_state == FTS_ACTIVE)
|
2006-02-24 23:16:32 +00:00
|
|
|
release_lease(uid_lease, packet);
|
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 {
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_reference (&lease, uid_lease, MDL);
|
|
|
|
if (lease -> host)
|
|
|
|
host_dereference (&lease -> host, MDL);
|
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
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&uid_lease, MDL);
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The lease that matched the hardware address is treated likewise. */
|
|
|
|
if (hw_lease) {
|
|
|
|
if (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 {
|
2001-03-16 01:55:38 +00:00
|
|
|
/* We're a little lax here - if the client didn't
|
|
|
|
send a client identifier and it's a bootp client,
|
|
|
|
but the lease has a client identifier, we still
|
|
|
|
let the client have a lease. */
|
|
|
|
if (!hw_lease -> uid_len ||
|
|
|
|
(have_client_identifier
|
|
|
|
? (hw_lease -> uid_len ==
|
|
|
|
client_identifier.len &&
|
|
|
|
!memcmp (hw_lease -> uid,
|
|
|
|
client_identifier.data,
|
|
|
|
client_identifier.len))
|
|
|
|
: packet -> packet_type == 0)) {
|
|
|
|
lease_reference (&lease, hw_lease, MDL);
|
|
|
|
if (lease -> host)
|
|
|
|
host_dereference (&lease -> host, MDL);
|
1998-11-05 18:54:55 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
2001-03-16 01:55:38 +00:00
|
|
|
log_info ("choosing hardware lease.");
|
1998-11-05 18:54:55 +00:00
|
|
|
#endif
|
2001-03-16 01:55:38 +00:00
|
|
|
} else {
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("not choosing hardware lease: %s.",
|
|
|
|
"uid mismatch");
|
|
|
|
#endif
|
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&hw_lease, MDL);
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
|
|
|
|
2010-09-07 23:55:24 +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) {
|
|
|
|
struct host_decl *p = NULL;
|
|
|
|
struct host_decl *n = NULL;
|
|
|
|
|
|
|
|
host_reference(&p, host, MDL);
|
|
|
|
while (p != NULL) {
|
|
|
|
if (!p->fixed_addr) {
|
|
|
|
/*
|
|
|
|
* If the lease is currently active, then it
|
|
|
|
* must be allocated to the present client.
|
|
|
|
* We store a reference to the host record on
|
|
|
|
* the lease to save a lookup later (in
|
|
|
|
* ack_lease()). We mustn't refer to the host
|
|
|
|
* record on non-active leases because the
|
|
|
|
* client may be denied later.
|
|
|
|
*
|
|
|
|
* XXX: Not having this reference (such as in
|
|
|
|
* DHCPDISCOVER/INIT) means ack_lease will have
|
|
|
|
* to perform this lookup a second time. This
|
|
|
|
* hopefully isn't a problem as DHCPREQUEST is
|
|
|
|
* more common than DHCPDISCOVER.
|
|
|
|
*/
|
|
|
|
if (lease->binding_state == FTS_ACTIVE)
|
|
|
|
host_reference(&lease->host, p, MDL);
|
|
|
|
|
|
|
|
host_dereference(&p, MDL);
|
1996-05-22 07:21:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-09-07 23:55:24 +00:00
|
|
|
if (p->n_ipaddr != NULL)
|
|
|
|
host_reference(&n, p->n_ipaddr, MDL);
|
|
|
|
host_dereference(&p, MDL);
|
|
|
|
if (n != NULL) {
|
|
|
|
host_reference(&p, n, MDL);
|
|
|
|
host_dereference(&n, MDL);
|
2001-04-27 21:32:48 +00:00
|
|
|
}
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
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. */
|
2000-06-02 21:27:21 +00:00
|
|
|
if (lease &&
|
|
|
|
(lease -> binding_state == FTS_ABANDONED) &&
|
|
|
|
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));
|
2000-06-02 21:27:21 +00:00
|
|
|
} else if (lease && (lease -> binding_state == FTS_ABANDONED)) {
|
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;
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&lease, MDL);
|
1998-06-25 21:24:23 +00:00
|
|
|
}
|
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
out:
|
|
|
|
if (have_client_identifier)
|
2000-01-26 14:56:18 +00:00
|
|
|
data_string_forget (&client_identifier, MDL);
|
1999-02-25 23:30:43 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
if (fixed_lease)
|
|
|
|
lease_dereference (&fixed_lease, MDL);
|
|
|
|
if (hw_lease)
|
|
|
|
lease_dereference (&hw_lease, MDL);
|
|
|
|
if (uid_lease)
|
|
|
|
lease_dereference (&uid_lease, MDL);
|
|
|
|
if (ip_lease)
|
|
|
|
lease_dereference (&ip_lease, MDL);
|
|
|
|
if (host)
|
|
|
|
host_dereference (&host, MDL);
|
|
|
|
|
|
|
|
if (lease) {
|
1999-02-25 23:30:43 +00:00
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("Returning lease: %s.",
|
|
|
|
piaddr (lease -> ip_addr));
|
|
|
|
#endif
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_reference (lp, lease, file, line);
|
|
|
|
lease_dereference (&lease, MDL);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#if defined (DEBUG_FIND_LEASE)
|
|
|
|
log_info ("Not returning a lease.");
|
|
|
|
#endif
|
|
|
|
return 0;
|
1996-02-26 01:56:15 +00:00
|
|
|
}
|
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. */
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
int mockup_lease (struct lease **lp, struct packet *packet,
|
|
|
|
struct shared_network *share, struct host_decl *hp)
|
1996-05-22 07:21:50 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
struct lease *lease = (struct lease *)0;
|
2001-04-18 18:58:39 +00:00
|
|
|
struct host_decl *rhp = (struct host_decl *)0;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
if (lease_allocate (&lease, MDL) != ISC_R_SUCCESS)
|
2000-05-16 23:03:49 +00:00
|
|
|
return 0;
|
2005-03-17 20:15:29 +00:00
|
|
|
if (host_reference (&rhp, hp, MDL) != ISC_R_SUCCESS) {
|
|
|
|
lease_dereference (&lease, MDL);
|
2001-04-18 18:58:39 +00:00
|
|
|
return 0;
|
2005-03-17 20:15:29 +00:00
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
if (!find_host_for_network (&lease -> subnet,
|
2001-04-18 18:58:39 +00:00
|
|
|
&rhp, &lease -> ip_addr, share)) {
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&lease, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
host_dereference (&rhp, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2001-04-18 18:58:39 +00:00
|
|
|
host_reference (&lease -> host, rhp, MDL);
|
|
|
|
if (rhp -> client_identifier.len > sizeof lease -> uid_buf)
|
|
|
|
lease -> uid = dmalloc (rhp -> client_identifier.len, MDL);
|
2000-01-31 23:43:11 +00:00
|
|
|
else
|
2000-05-16 23:03:49 +00:00
|
|
|
lease -> uid = lease -> uid_buf;
|
|
|
|
if (!lease -> uid) {
|
|
|
|
lease_dereference (&lease, MDL);
|
2001-04-18 18:58:39 +00:00
|
|
|
host_dereference (&rhp, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2001-04-18 18:58:39 +00:00
|
|
|
memcpy (lease -> uid, rhp -> client_identifier.data,
|
|
|
|
rhp -> client_identifier.len);
|
|
|
|
lease -> uid_len = rhp -> client_identifier.len;
|
|
|
|
lease -> hardware_addr = rhp -> interface;
|
2006-07-25 13:26:00 +00:00
|
|
|
lease -> starts = lease -> cltt = lease -> ends = MIN_TIME;
|
2000-05-16 23:03:49 +00:00
|
|
|
lease -> flags = STATIC_LEASE;
|
2000-06-02 21:27:21 +00:00
|
|
|
lease -> binding_state = FTS_FREE;
|
2005-03-17 20:15:29 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_reference (lp, lease, MDL);
|
2005-03-17 20:15:29 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
lease_dereference (&lease, MDL);
|
2001-04-18 18:58:39 +00:00
|
|
|
host_dereference (&rhp, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
return 1;
|
1996-05-22 07:21:50 +00:00
|
|
|
}
|
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. */
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
int allocate_lease (struct lease **lp, struct packet *packet,
|
2007-11-02 22:09:02 +00:00
|
|
|
struct pool *pool, int *peer_has_leases)
|
1998-11-09 02:46:58 +00:00
|
|
|
{
|
2015-05-27 13:17:46 -07:00
|
|
|
struct lease *lease = NULL;
|
|
|
|
struct lease *candl = NULL;
|
1998-11-09 02:46:58 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
for (; pool ; pool = pool -> next) {
|
|
|
|
if ((pool -> prohibit_list &&
|
|
|
|
permitted (packet, pool -> prohibit_list)) ||
|
|
|
|
(pool -> permit_list &&
|
|
|
|
!permitted (packet, pool -> permit_list)))
|
|
|
|
continue;
|
1998-11-09 02:46:58 +00:00
|
|
|
|
2000-01-05 18:16:36 +00:00
|
|
|
#if defined (FAILOVER_PROTOCOL)
|
2005-03-17 20:15:29 +00:00
|
|
|
/* Peer_has_leases just says that we found at least one
|
|
|
|
free lease. If no free lease is returned, the caller
|
|
|
|
can deduce that this means the peer is hogging all the
|
|
|
|
free leases, so we can print a better error message. */
|
|
|
|
/* XXX Do we need code here to ignore PEER_IS_OWNER and
|
|
|
|
* XXX just check tstp if we're in, e.g., PARTNER_DOWN?
|
|
|
|
* XXX Where do we deal with CONFLICT_DETECTED, et al? */
|
|
|
|
/* XXX This should be handled by the lease binding "state
|
|
|
|
* XXX machine" - that is, when we get here, if a lease
|
|
|
|
* XXX could be allocated, it will have the correct
|
|
|
|
* XXX binding state so that the following code will
|
|
|
|
* XXX result in its being allocated. */
|
|
|
|
/* Skip to the most expired lease in the pool that is not
|
|
|
|
* owned by a failover peer. */
|
2008-08-19 18:00:24 +00:00
|
|
|
if (pool->failover_peer != NULL) {
|
2015-09-25 08:39:52 -04:00
|
|
|
struct lease *peerl = NULL;
|
2008-08-19 18:00:24 +00:00
|
|
|
if (pool->failover_peer->i_am == primary) {
|
2015-05-27 13:17:46 -07:00
|
|
|
candl = LEASE_GET_FIRST(pool->free);
|
2008-08-19 18:00:24 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* In normal operation, we never want to touch
|
2018-09-26 11:10:16 -04:00
|
|
|
* the peer's leases. In partner-down
|
2008-08-19 18:00:24 +00:00
|
|
|
* operation, we need to be able to pick up
|
|
|
|
* the peer's leases after STOS+MCLT.
|
|
|
|
*/
|
2015-05-27 13:17:46 -07:00
|
|
|
peerl = LEASE_GET_FIRST(pool->backup);
|
|
|
|
if (peerl != NULL) {
|
2008-08-19 18:00:24 +00:00
|
|
|
if (((candl == NULL) ||
|
2015-05-27 13:17:46 -07:00
|
|
|
(candl->ends > peerl->ends)) &&
|
|
|
|
lease_mine_to_reallocate(peerl)) {
|
|
|
|
candl = peerl;
|
2008-08-19 18:00:24 +00:00
|
|
|
} else {
|
|
|
|
*peer_has_leases = 1;
|
|
|
|
}
|
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
} else {
|
2015-05-27 13:17:46 -07:00
|
|
|
candl = LEASE_GET_FIRST(pool->backup);
|
2008-08-19 18:00:24 +00:00
|
|
|
|
2015-05-27 13:17:46 -07:00
|
|
|
peerl = LEASE_GET_FIRST(pool->free);
|
|
|
|
if (peerl != NULL) {
|
2008-08-19 18:00:24 +00:00
|
|
|
if (((candl == NULL) ||
|
2015-05-27 13:17:46 -07:00
|
|
|
(candl->ends > peerl->ends)) &&
|
|
|
|
lease_mine_to_reallocate(peerl)) {
|
|
|
|
candl = peerl;
|
2008-08-19 18:00:24 +00:00
|
|
|
} else {
|
|
|
|
*peer_has_leases = 1;
|
|
|
|
}
|
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
}
|
2008-08-19 18:00:24 +00:00
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/* Try abandoned leases as a last resort. */
|
2015-05-27 13:17:46 -07:00
|
|
|
peerl = LEASE_GET_FIRST(pool->abandoned);
|
|
|
|
if ((candl == NULL) && (peerl != NULL) &&
|
|
|
|
lease_mine_to_reallocate(peerl))
|
|
|
|
candl = peerl;
|
2005-03-17 20:15:29 +00:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
{
|
2015-05-27 13:17:46 -07:00
|
|
|
if (LEASE_NOT_EMPTY(pool->free))
|
|
|
|
candl = LEASE_GET_FIRST(pool->free);
|
2005-03-17 20:15:29 +00:00
|
|
|
else
|
2015-05-27 13:17:46 -07:00
|
|
|
candl = LEASE_GET_FIRST(pool->abandoned);
|
2000-06-02 21:27:21 +00:00
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
|
2008-08-19 18:00:24 +00:00
|
|
|
/*
|
|
|
|
* XXX: This may not match with documented expectation.
|
|
|
|
* It's expected that when we OFFER a lease, we set its
|
|
|
|
* ends time forward 2 minutes so that it gets sorted to
|
|
|
|
* the end of its free list (avoiding a similar allocation
|
|
|
|
* to another client). It is not expected that we issue a
|
|
|
|
* "no free leases" error when the last lease has been
|
|
|
|
* offered, but it's not exactly broken either.
|
|
|
|
*/
|
2016-07-07 14:11:26 -04:00
|
|
|
if (!candl ||
|
|
|
|
(candl->binding_state != FTS_ABANDONED &&
|
|
|
|
(candl->ends > cur_time))) {
|
2005-03-17 20:15:29 +00:00
|
|
|
continue;
|
2016-07-07 14:11:26 -04:00
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
|
|
|
|
if (!lease) {
|
|
|
|
lease = candl;
|
|
|
|
continue;
|
1998-11-09 02:46:58 +00:00
|
|
|
}
|
2005-03-17 20:15:29 +00:00
|
|
|
|
2010-02-03 23:25:25 +00:00
|
|
|
/*
|
|
|
|
* There are tiers of lease state preference, listed here in
|
|
|
|
* reverse order (least to most preferential):
|
|
|
|
*
|
|
|
|
* ABANDONED
|
|
|
|
* FREE/BACKUP
|
|
|
|
*
|
|
|
|
* If the selected lease and candidate are both of the same
|
|
|
|
* state, select the oldest (longest ago) expiration time
|
|
|
|
* between the two. If the candidate lease is of a higher
|
|
|
|
* preferred grade over the selected lease, use it.
|
|
|
|
*/
|
2005-03-17 20:15:29 +00:00
|
|
|
if ((lease -> binding_state == FTS_ABANDONED) &&
|
|
|
|
((candl -> binding_state != FTS_ABANDONED) ||
|
|
|
|
(candl -> ends < lease -> ends))) {
|
|
|
|
lease = candl;
|
|
|
|
continue;
|
|
|
|
} else if (candl -> binding_state == FTS_ABANDONED)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if ((lease -> uid_len || lease -> hardware_addr.hlen) &&
|
|
|
|
((!candl -> uid_len && !candl -> hardware_addr.hlen) ||
|
|
|
|
(candl -> ends < lease -> ends))) {
|
|
|
|
lease = candl;
|
|
|
|
continue;
|
|
|
|
} else if (candl -> uid_len || candl -> hardware_addr.hlen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (candl -> ends < lease -> ends)
|
|
|
|
lease = candl;
|
1998-11-09 02:46:58 +00:00
|
|
|
}
|
|
|
|
|
2010-09-07 23:55:24 +00:00
|
|
|
if (lease != NULL) {
|
|
|
|
if (lease->binding_state == FTS_ABANDONED)
|
|
|
|
log_error("Reclaiming abandoned lease %s.",
|
|
|
|
piaddr(lease->ip_addr));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: For reliability, we go ahead and remove the host
|
|
|
|
* record and try to move on. For correctness, if there
|
|
|
|
* are any other stale host vectors, we want to find them.
|
|
|
|
*/
|
|
|
|
if (lease->host != NULL) {
|
|
|
|
log_debug("soft impossible condition (%s:%d): stale "
|
|
|
|
"host \"%s\" found on lease %s", MDL,
|
|
|
|
lease->host->name,
|
|
|
|
piaddr(lease->ip_addr));
|
|
|
|
host_dereference(&lease->host, MDL);
|
|
|
|
}
|
1998-11-09 02:46:58 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
lease_reference (lp, lease, MDL);
|
|
|
|
return 1;
|
1998-11-09 02:46:58 +00:00
|
|
|
}
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
return 0;
|
1998-11-09 02:46:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* 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;
|
2018-09-26 11:10:16 -04:00
|
|
|
|
1998-11-09 02:46:58 +00:00
|
|
|
case permit_class:
|
1999-08-19 18:59:13 +00:00
|
|
|
for (i = 0; i < packet -> class_count; i++) {
|
1998-11-09 02:46:58 +00:00
|
|
|
if (p -> class == packet -> classes [i])
|
|
|
|
return 1;
|
1999-08-19 18:59:13 +00:00
|
|
|
if (packet -> classes [i] &&
|
|
|
|
packet -> classes [i] -> superclass &&
|
|
|
|
(packet -> classes [i] -> superclass ==
|
|
|
|
p -> class))
|
|
|
|
return 1;
|
|
|
|
}
|
1998-11-09 02:46:58 +00:00
|
|
|
break;
|
2007-10-31 19:13:33 +00:00
|
|
|
|
|
|
|
case permit_after:
|
|
|
|
if (cur_time > p->after)
|
|
|
|
return 1;
|
|
|
|
break;
|
1998-11-09 02:46:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
static int locate_network6 (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
|
|
|
const struct packet *chk_packet;
|
|
|
|
const struct in6_addr *link_addr, *first_link_addr;
|
|
|
|
struct iaddr ia;
|
|
|
|
struct data_string data;
|
|
|
|
struct subnet *subnet = NULL;
|
|
|
|
struct option_cache *oc;
|
|
|
|
|
|
|
|
/* from locate_network() */
|
|
|
|
|
|
|
|
/* See if there's a Relay Agent Link Selection Option, or a
|
|
|
|
* Subnet Selection Option. The Link-Select and Subnet-Select
|
|
|
|
* are formatted and used precisely the same, but we must prefer
|
|
|
|
* the link-select over the subnet-select.
|
|
|
|
* BTW in DHCPv4 over DHCPv6 no cross version relay was specified
|
|
|
|
* so it is unlikely to see a link-select.
|
|
|
|
*/
|
|
|
|
if ((oc = lookup_option(&agent_universe, packet->options,
|
|
|
|
RAI_LINK_SELECT)) == NULL)
|
|
|
|
oc = lookup_option(&dhcp_universe, packet->options,
|
|
|
|
DHO_SUBNET_SELECTION);
|
|
|
|
|
|
|
|
/* If there's an option indicating link connection or subnet
|
|
|
|
* selection, and it's valid, use it to figure out the subnet.
|
|
|
|
* If it's not valid, fail.
|
|
|
|
*/
|
|
|
|
if (oc) {
|
|
|
|
memset(&data, 0, sizeof data);
|
|
|
|
if (!evaluate_option_cache(&data, packet, NULL, NULL,
|
|
|
|
packet->options, NULL,
|
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (data.len == 0) {
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (data.len != 4) {
|
|
|
|
data_string_forget(&data, MDL);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
ia.len = 4;
|
|
|
|
memcpy(ia.iabuf, data.data, 4);
|
|
|
|
data_string_forget(&data, MDL);
|
|
|
|
|
|
|
|
if (find_subnet(&subnet, ia, MDL)) {
|
|
|
|
shared_network_reference(&packet->shared_network,
|
|
|
|
subnet->shared_network, MDL);
|
|
|
|
subnet_dereference(&subnet, MDL);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if there is a giaddr (still unlikely), if there is one
|
|
|
|
* use it to figure out the subnet. If it's not valid, fail.
|
|
|
|
*/
|
|
|
|
if (packet->raw->giaddr.s_addr) {
|
|
|
|
ia.len = 4;
|
|
|
|
memcpy(ia.iabuf, &packet->raw->giaddr, 4);
|
|
|
|
|
|
|
|
if (find_subnet(&subnet, ia, MDL)) {
|
|
|
|
shared_network_reference(&packet->shared_network,
|
|
|
|
subnet->shared_network, MDL);
|
|
|
|
subnet_dereference(&subnet, MDL);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* from shared_network_from_packet6() */
|
|
|
|
|
|
|
|
/* First, find the link address where the packet from the client
|
|
|
|
* first appeared (if this packet was relayed).
|
|
|
|
*/
|
|
|
|
first_link_addr = NULL;
|
|
|
|
chk_packet = packet->dhcpv6_container_packet;
|
|
|
|
while (chk_packet != NULL) {
|
|
|
|
link_addr = &chk_packet->dhcpv6_link_address;
|
|
|
|
if (!IN6_IS_ADDR_UNSPECIFIED(link_addr) &&
|
|
|
|
!IN6_IS_ADDR_LINKLOCAL(link_addr)) {
|
|
|
|
first_link_addr = link_addr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
chk_packet = chk_packet->dhcpv6_container_packet;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is a relayed link address, find the subnet associated
|
|
|
|
* with that, and use that to get the appropriate shared_network.
|
|
|
|
*/
|
|
|
|
if (first_link_addr != NULL) {
|
|
|
|
ia.len = sizeof(*first_link_addr);
|
|
|
|
memcpy(ia.iabuf, first_link_addr, sizeof(*first_link_addr));
|
|
|
|
if (find_subnet (&subnet, ia, MDL)) {
|
|
|
|
shared_network_reference(&packet->shared_network,
|
|
|
|
subnet->shared_network, MDL);
|
|
|
|
subnet_dereference(&subnet, MDL);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If there is no link address, we will use the interface
|
|
|
|
* that this packet came in on to pick the shared_network.
|
|
|
|
*/
|
|
|
|
if (packet->interface != NULL) {
|
|
|
|
if (packet->interface->shared_network == NULL)
|
|
|
|
return (0);
|
|
|
|
shared_network_reference(&packet->shared_network,
|
|
|
|
packet->interface->shared_network,
|
|
|
|
MDL);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We shouldn't be able to get here but if there is no link
|
|
|
|
* address and no interface we don't know where to get the
|
|
|
|
* shared_network from, log an error and return an error.
|
|
|
|
*/
|
|
|
|
log_error("No interface and no link address "
|
|
|
|
"can't determine DHCP4o6 shared network");
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1999-09-28 23:58:17 +00:00
|
|
|
int locate_network (packet)
|
|
|
|
struct packet *packet;
|
|
|
|
{
|
|
|
|
struct iaddr ia;
|
2000-04-08 01:15:50 +00:00
|
|
|
struct data_string data;
|
2000-05-16 23:03:49 +00:00
|
|
|
struct subnet *subnet = (struct subnet *)0;
|
2000-04-08 01:15:50 +00:00
|
|
|
struct option_cache *oc;
|
1999-09-28 23:58:17 +00:00
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
#if defined(DHCPv6) && defined(DHCP4o6)
|
|
|
|
if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
|
|
|
|
return (locate_network6 (packet));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-07-17 15:16:43 +00:00
|
|
|
/* See if there's a Relay Agent Link Selection Option, or a
|
|
|
|
* Subnet Selection Option. The Link-Select and Subnet-Select
|
|
|
|
* are formatted and used precisely the same, but we must prefer
|
|
|
|
* the link-select over the subnet-select.
|
|
|
|
*/
|
|
|
|
if ((oc = lookup_option(&agent_universe, packet->options,
|
|
|
|
RAI_LINK_SELECT)) == NULL)
|
|
|
|
oc = lookup_option(&dhcp_universe, packet->options,
|
|
|
|
DHO_SUBNET_SELECTION);
|
2000-04-08 01:15:50 +00:00
|
|
|
|
|
|
|
/* If there's no SSO and no giaddr, then use the shared_network
|
|
|
|
from the interface, if there is one. If not, fail. */
|
|
|
|
if (!oc && !packet -> raw -> giaddr.s_addr) {
|
2000-05-16 23:03:49 +00:00
|
|
|
if (packet -> interface -> shared_network) {
|
|
|
|
shared_network_reference
|
|
|
|
(&packet -> shared_network,
|
|
|
|
packet -> interface -> shared_network, MDL);
|
2000-04-08 01:15:50 +00:00
|
|
|
return 1;
|
2000-05-16 23:03:49 +00:00
|
|
|
}
|
2000-04-08 01:15:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-07-17 15:16:43 +00:00
|
|
|
/* If there's an option indicating link connection, and it's valid,
|
|
|
|
* use it to figure out the subnet. If it's not valid, fail.
|
|
|
|
*/
|
2000-04-08 01:15:50 +00:00
|
|
|
if (oc) {
|
|
|
|
memset (&data, 0, sizeof data);
|
|
|
|
if (!evaluate_option_cache (&data, packet, (struct lease *)0,
|
2000-11-28 23:27:24 +00:00
|
|
|
(struct client_state *)0,
|
2000-04-08 01:15:50 +00:00
|
|
|
packet -> options,
|
|
|
|
(struct option_state *)0,
|
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
return 0;
|
|
|
|
}
|
2019-11-22 13:39:45 -05:00
|
|
|
|
2000-04-08 01:15:50 +00:00
|
|
|
if (data.len != 4) {
|
2016-02-23 10:40:10 +01:00
|
|
|
data_string_forget (&data, MDL);
|
2000-04-08 01:15:50 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2019-11-22 13:39:45 -05:00
|
|
|
|
2000-04-08 01:15:50 +00:00
|
|
|
ia.len = 4;
|
|
|
|
memcpy (ia.iabuf, data.data, 4);
|
|
|
|
data_string_forget (&data, MDL);
|
1999-09-28 23:58:17 +00:00
|
|
|
} else {
|
2000-04-08 01:15:50 +00:00
|
|
|
ia.len = 4;
|
|
|
|
memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);
|
1999-09-28 23:58:17 +00:00
|
|
|
}
|
2000-04-08 01:15:50 +00:00
|
|
|
|
|
|
|
/* If we know the subnet on which the IP address lives, use it. */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (find_subnet (&subnet, ia, MDL)) {
|
|
|
|
shared_network_reference (&packet -> shared_network,
|
|
|
|
subnet -> shared_network, MDL);
|
|
|
|
subnet_dereference (&subnet, MDL);
|
1999-09-28 23:58:17 +00:00
|
|
|
return 1;
|
2000-04-08 01:15:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Otherwise, fail. */
|
1999-09-28 23:58:17 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2006-07-25 13:26:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Try to figure out the source address to send packets from.
|
|
|
|
*
|
2012-11-16 15:02:13 -08:00
|
|
|
* from is the address structure we use to return any address
|
|
|
|
* we find.
|
|
|
|
*
|
|
|
|
* options is the option cache to search. This may include
|
|
|
|
* options from the incoming packet and configuration information.
|
2006-07-25 13:26:00 +00:00
|
|
|
*
|
2012-11-16 15:02:13 -08:00
|
|
|
* out_options is the outgoing option cache. This cache
|
2014-10-17 07:56:01 -04:00
|
|
|
* may be the same as options. If out_options isn't NULL
|
2012-11-16 15:02:13 -08:00
|
|
|
* we may save the server address option into it. We do so
|
2014-10-17 07:56:01 -04:00
|
|
|
* if out_options is different than options or if the option
|
2012-11-16 15:02:13 -08:00
|
|
|
* wasn't in options and we needed to find the address elsewhere.
|
|
|
|
*
|
|
|
|
* packet is the state structure for the incoming packet
|
|
|
|
*
|
|
|
|
* When finding the address we first check to see if it is
|
|
|
|
* in the options list. If it isn't we use the first address
|
|
|
|
* from the interface.
|
|
|
|
*
|
|
|
|
* While this is slightly more complicated than I'd like it allows
|
|
|
|
* us to use the same code in several different places. ack,
|
|
|
|
* inform and lease query use it to find the address and fill
|
|
|
|
* in the options if we get the address from the interface.
|
|
|
|
* nack uses it to find the address and copy it to the outgoing
|
|
|
|
* cache. dhcprequest uses it to find the address for comparison
|
|
|
|
* and doesn't need to add it to an outgoing list.
|
2006-07-25 13:26:00 +00:00
|
|
|
*/
|
2012-11-16 15:02:13 -08:00
|
|
|
|
2006-07-25 13:26:00 +00:00
|
|
|
void
|
|
|
|
get_server_source_address(struct in_addr *from,
|
|
|
|
struct option_state *options,
|
2012-11-16 15:02:13 -08:00
|
|
|
struct option_state *out_options,
|
2006-07-25 13:26:00 +00:00
|
|
|
struct packet *packet) {
|
2007-05-21 22:09:07 +00:00
|
|
|
unsigned option_num;
|
2012-11-16 15:02:13 -08:00
|
|
|
struct option_cache *oc = NULL;
|
2007-05-21 22:09:07 +00:00
|
|
|
struct data_string d;
|
2012-11-16 15:02:13 -08:00
|
|
|
struct in_addr *a = NULL;
|
|
|
|
isc_boolean_t found = ISC_FALSE;
|
|
|
|
int allocate = 0;
|
2007-05-21 22:09:07 +00:00
|
|
|
|
|
|
|
memset(&d, 0, sizeof(d));
|
2012-11-16 15:02:13 -08:00
|
|
|
memset(from, 0, sizeof(*from));
|
2006-07-25 13:26:00 +00:00
|
|
|
|
|
|
|
option_num = DHO_DHCP_SERVER_IDENTIFIER;
|
|
|
|
oc = lookup_option(&dhcp_universe, options, option_num);
|
2011-05-23 10:34:10 +00:00
|
|
|
if (oc != NULL) {
|
2018-09-26 11:10:16 -04:00
|
|
|
if (evaluate_option_cache(&d, packet, NULL, NULL,
|
|
|
|
packet->options, options,
|
2011-05-23 10:34:10 +00:00
|
|
|
&global_scope, oc, MDL)) {
|
|
|
|
if (d.len == sizeof(*from)) {
|
2012-11-16 15:02:13 -08:00
|
|
|
found = ISC_TRUE;
|
2011-05-23 10:34:10 +00:00
|
|
|
memcpy(from, d.data, sizeof(*from));
|
2012-11-16 15:02:13 -08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Arrange to save a copy of the data
|
|
|
|
* to the outgoing list.
|
|
|
|
*/
|
|
|
|
if ((out_options != NULL) &&
|
|
|
|
(options != out_options)) {
|
|
|
|
a = from;
|
|
|
|
allocate = 1;
|
|
|
|
}
|
2011-05-23 10:34:10 +00:00
|
|
|
}
|
2006-07-25 13:26:00 +00:00
|
|
|
data_string_forget(&d, MDL);
|
|
|
|
}
|
2011-05-23 10:34:10 +00:00
|
|
|
oc = NULL;
|
2006-07-25 13:26:00 +00:00
|
|
|
}
|
|
|
|
|
2012-11-16 15:02:13 -08:00
|
|
|
if ((found == ISC_FALSE) &&
|
|
|
|
(packet->interface->address_count > 0)) {
|
|
|
|
*from = packet->interface->addresses[0];
|
|
|
|
|
|
|
|
if (out_options != NULL) {
|
2007-05-08 23:05:22 +00:00
|
|
|
a = &packet->interface->addresses[0];
|
2006-07-25 13:26:00 +00:00
|
|
|
}
|
|
|
|
}
|
2012-11-16 15:02:13 -08:00
|
|
|
|
|
|
|
if ((a != NULL) &&
|
|
|
|
(option_cache_allocate(&oc, MDL))) {
|
|
|
|
if (make_const_data(&oc->expression,
|
|
|
|
(unsigned char *)a, sizeof(*a),
|
|
|
|
0, allocate, MDL)) {
|
2018-09-26 11:10:16 -04:00
|
|
|
option_code_hash_lookup(&oc->option,
|
2012-11-16 15:02:13 -08:00
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&option_num, 0, MDL);
|
|
|
|
save_option(&dhcp_universe, out_options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference(&oc, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/*!
|
|
|
|
* \brief Builds option set from statements at the global and network scope
|
2012-11-16 15:02:13 -08:00
|
|
|
*
|
2014-10-17 07:56:01 -04:00
|
|
|
* Set up an option state list based on the global and network scopes.
|
|
|
|
* These are primarily used by NAK logic to locate dhcp-server-id and
|
|
|
|
* echo-client-id.
|
|
|
|
*
|
|
|
|
* We don't go through all possible options - in particualr we skip the hosts
|
|
|
|
* and we don't include the lease to avoid making changes to it. This means
|
|
|
|
* that using these, we won't get the correct server id if the admin puts them
|
|
|
|
* on hosts or builds the server id with information from the lease.
|
|
|
|
*
|
|
|
|
* As this is a fallback function (used to handle NAKs or sort out server id
|
|
|
|
* mismatch in failover) and requires configuration by the admin, it should be
|
|
|
|
* okay.
|
|
|
|
*
|
|
|
|
* \param network_options option_state to which options will be added. If it
|
|
|
|
* refers to NULL, it will be allocated. Caller is responsible to delete it.
|
|
|
|
* \param packet inbound packet
|
|
|
|
* \param network_group scope group to use if packet->shared_network is null.
|
2012-11-16 15:02:13 -08:00
|
|
|
*/
|
|
|
|
void
|
2014-10-17 07:56:01 -04:00
|
|
|
eval_network_statements(struct option_state **network_options,
|
|
|
|
struct packet *packet,
|
|
|
|
struct group *network_group) {
|
2012-11-16 15:02:13 -08:00
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
if (*network_options == NULL) {
|
|
|
|
option_state_allocate (network_options, MDL);
|
|
|
|
}
|
2012-11-16 15:02:13 -08:00
|
|
|
|
2014-10-17 07:56:01 -04:00
|
|
|
/* Use the packet's shared_network if it has one. If not use
|
|
|
|
* network_group and if it is null then use global scope. */
|
2012-11-16 15:02:13 -08:00
|
|
|
if (packet->shared_network != NULL) {
|
|
|
|
/*
|
|
|
|
* If we have a subnet and group start with that else start
|
|
|
|
* with the shared network group. The first will recurse and
|
|
|
|
* include the second.
|
|
|
|
*/
|
|
|
|
if ((packet->shared_network->subnets != NULL) &&
|
|
|
|
(packet->shared_network->subnets->group != NULL)) {
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
2014-10-17 07:56:01 -04:00
|
|
|
packet->options, *network_options,
|
2012-11-16 15:02:13 -08:00
|
|
|
&global_scope,
|
|
|
|
packet->shared_network->subnets->group,
|
2013-08-27 13:40:47 -07:00
|
|
|
NULL, NULL);
|
2012-11-16 15:02:13 -08:00
|
|
|
} else {
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
2014-10-17 07:56:01 -04:00
|
|
|
packet->options, *network_options,
|
2012-11-16 15:02:13 -08:00
|
|
|
&global_scope,
|
|
|
|
packet->shared_network->group,
|
2013-08-27 13:40:47 -07:00
|
|
|
NULL, NULL);
|
2012-11-16 15:02:13 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* do the pool if there is one */
|
|
|
|
if (packet->shared_network->pools != NULL) {
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
2014-10-17 07:56:01 -04:00
|
|
|
packet->options, *network_options,
|
2012-11-16 15:02:13 -08:00
|
|
|
&global_scope,
|
|
|
|
packet->shared_network->pools->group,
|
2013-08-27 13:40:47 -07:00
|
|
|
packet->shared_network->group,
|
|
|
|
NULL);
|
2012-11-16 15:02:13 -08:00
|
|
|
}
|
2014-10-17 07:56:01 -04:00
|
|
|
} else if (network_group != NULL) {
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, *network_options,
|
|
|
|
&global_scope, network_group,
|
|
|
|
NULL, NULL);
|
|
|
|
} else {
|
|
|
|
execute_statements_in_scope(NULL, packet, NULL, NULL,
|
|
|
|
packet->options, *network_options,
|
|
|
|
&global_scope, root_group,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
2006-07-25 13:26:00 +00:00
|
|
|
}
|
|
|
|
|
2008-01-09 17:13:16 +00:00
|
|
|
/*
|
|
|
|
* Look for the lowest numbered site code number and
|
|
|
|
* apply a log warning if it is less than 224. Do not
|
|
|
|
* permit site codes less than 128 (old code never did).
|
|
|
|
*
|
|
|
|
* Note that we could search option codes 224 down to 128
|
|
|
|
* on the hash table, but the table is (probably) smaller
|
|
|
|
* than that if it was declared as a standalone table with
|
|
|
|
* defaults. So we traverse the option code hash.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
find_min_site_code(struct universe *u)
|
|
|
|
{
|
|
|
|
if (u->site_code_min)
|
|
|
|
return u->site_code_min;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that site_code_min has to be global as we can't pass an
|
|
|
|
* argument through hash_foreach(). The value 224 is taken from
|
|
|
|
* RFC 3942.
|
|
|
|
*/
|
|
|
|
site_code_min = 224;
|
|
|
|
option_code_hash_foreach(u->code_hash, lowest_site_code);
|
|
|
|
|
|
|
|
if (site_code_min < 224) {
|
|
|
|
log_error("WARNING: site-local option codes less than 224 have "
|
|
|
|
"been deprecated by RFC3942. You have options "
|
|
|
|
"listed in site local space %s that number as low as "
|
|
|
|
"%d. Please investigate if these should be declared "
|
|
|
|
"as regular options rather than site-local options, "
|
|
|
|
"or migrated up past 224.",
|
|
|
|
u->name, site_code_min);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* don't even bother logging, this is just silly, and never worked
|
|
|
|
* on any old version of software.
|
|
|
|
*/
|
|
|
|
if (site_code_min < 128)
|
|
|
|
site_code_min = 128;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cache the determined minimum site code on the universe structure.
|
|
|
|
* Note that due to the < 128 check above, a value of zero is
|
|
|
|
* impossible.
|
|
|
|
*/
|
|
|
|
u->site_code_min = site_code_min;
|
|
|
|
|
|
|
|
return site_code_min;
|
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
lowest_site_code(const void *key, unsigned len, void *object)
|
|
|
|
{
|
|
|
|
struct option *option = object;
|
|
|
|
|
|
|
|
if (option->code < site_code_min)
|
|
|
|
site_code_min = option->code;
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2009-07-06 23:33:23 +00:00
|
|
|
static void
|
|
|
|
maybe_return_agent_options(struct packet *packet, struct option_state *options)
|
|
|
|
{
|
|
|
|
/* If there were agent options in the incoming packet, return
|
|
|
|
* them. Do not return the agent options if they were stashed
|
|
|
|
* on the lease. We do not check giaddr to detect the presence of
|
|
|
|
* a relay, as this excludes "l2" relay agents which have no giaddr
|
|
|
|
* to set.
|
|
|
|
*
|
|
|
|
* XXX: If the user configures options for the relay agent information
|
|
|
|
* (state->options->universes[agent_universe.index] is not NULL),
|
|
|
|
* we're still required to duplicate other values provided by the
|
|
|
|
* relay agent. So we need to merge the old values not configured
|
|
|
|
* by the user into the new state, not just give up.
|
|
|
|
*/
|
|
|
|
if (!packet->agent_options_stashed &&
|
2011-07-19 22:13:26 +00:00
|
|
|
(packet->options != NULL) &&
|
2009-07-06 23:33:23 +00:00
|
|
|
packet->options->universe_count > agent_universe.index &&
|
|
|
|
packet->options->universes[agent_universe.index] != NULL &&
|
|
|
|
(options->universe_count <= agent_universe.index ||
|
|
|
|
options->universes[agent_universe.index] == NULL)) {
|
|
|
|
option_chain_head_reference
|
|
|
|
((struct option_chain_head **)
|
|
|
|
&(options->universes[agent_universe.index]),
|
|
|
|
(struct option_chain_head *)
|
|
|
|
packet->options->universes[agent_universe.index], MDL);
|
|
|
|
|
|
|
|
if (options->universe_count <= agent_universe.index)
|
|
|
|
options->universe_count = agent_universe.index + 1;
|
|
|
|
}
|
|
|
|
}
|
2014-10-27 14:51:20 -04:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Adds hostname option when use-host-decl-names is enabled.
|
|
|
|
*
|
|
|
|
* Constructs a hostname option from the name of the host declaration if
|
|
|
|
* there is one and no hostname has otherwise been provided and the
|
|
|
|
* use-host-decl-names flag is set, then adds the new option to the given
|
|
|
|
* option_state. This funciton is used for both bootp and dhcp.
|
|
|
|
*
|
|
|
|
* \param packet inbound packet received from the client
|
|
|
|
* \param lease lease associated with the client
|
|
|
|
* \param options option state to search and update
|
|
|
|
*/
|
|
|
|
void use_host_decl_name(struct packet* packet,
|
|
|
|
struct lease *lease,
|
|
|
|
struct option_state *options) {
|
|
|
|
unsigned int ocode = SV_USE_HOST_DECL_NAMES;
|
|
|
|
if ((lease->host && lease->host->name) &&
|
|
|
|
!lookup_option(&dhcp_universe, options, DHO_HOST_NAME) &&
|
|
|
|
(evaluate_boolean_option_cache(NULL, packet, lease, NULL,
|
|
|
|
packet->options, options,
|
|
|
|
&lease->scope,
|
|
|
|
lookup_option(&server_universe,
|
|
|
|
options, ocode),
|
|
|
|
MDL))) {
|
|
|
|
struct option_cache *oc = NULL;
|
|
|
|
if (option_cache_allocate (&oc, MDL)) {
|
|
|
|
if (make_const_data(&oc -> expression,
|
|
|
|
((unsigned char*)lease->host->name),
|
|
|
|
strlen(lease->host->name),
|
|
|
|
1, 0, MDL)) {
|
|
|
|
ocode = DHO_HOST_NAME;
|
|
|
|
option_code_hash_lookup(&oc->option,
|
|
|
|
dhcp_universe.code_hash,
|
|
|
|
&ocode, 0, MDL);
|
|
|
|
save_option(&dhcp_universe, options, oc);
|
|
|
|
}
|
|
|
|
option_cache_dereference(&oc, MDL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-24 07:36:13 -05:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* \brief Checks and preps for lease resuse based on dhcp-cache-threshold
|
|
|
|
*
|
|
|
|
* If dhcp-cache-threshold is enabled (i.e. greater than zero), this function
|
|
|
|
* determines if the current lease is young enough to be reused. If the lease
|
|
|
|
* can be resused the function returns 1, O if not. This function is called
|
|
|
|
* by ack_lease when responding to both DISCOVERs and REQUESTS.
|
|
|
|
*
|
|
|
|
* The current lease can be reused only if all of the following are true:
|
|
|
|
* a. dhcp-cache-threshold is > 0
|
|
|
|
* b. The current lease is active
|
|
|
|
* c. The lease "age" is less than that allowed by the threshold
|
|
|
|
* d. DNS updates are not being performed on the new lease.
|
|
|
|
* e. Lease has not been otherwise disqualified for reuse (Ex: billing class
|
2016-07-26 11:41:47 -07:00
|
|
|
* or hostname changed)
|
|
|
|
* f. The host declaration has changed (either a new one was added
|
|
|
|
* or an older one was found due to something like a change in the uid)
|
|
|
|
* g. The UID or hardware address have changed.
|
2014-11-24 07:36:13 -05:00
|
|
|
*
|
|
|
|
* Clients may renew leases using full DORA cycles or just RAs. This means
|
|
|
|
* that reusability must be checked when acking both DISCOVERs and REQUESTs.
|
|
|
|
* When a lease cannot be reused, ack_lease() calls supersede_lease() which
|
|
|
|
* updates the lease start time (among other things). If this occurs on the
|
|
|
|
* DISCOVER, then the lease will virtually always be seen as young enough to
|
|
|
|
* reuse on the ensuing REQUEST and the lease updates will not get committed
|
|
|
|
* to the lease file. The lease.cannot_reuse flag is used to handle this
|
|
|
|
* this situation.
|
|
|
|
*
|
|
|
|
* \param packet inbound packet received from the client
|
|
|
|
* \param new_lease candidate new lease to associate with the client
|
|
|
|
* \param lease current lease associated with the client
|
2018-09-26 11:10:16 -04:00
|
|
|
* \param lease_state lease state to search and update
|
|
|
|
* \param offer type of DHCP response we're building
|
|
|
|
* \param[out] same_client pointer to int, that will be set to 1 if
|
|
|
|
* the two leases refer to the same client, 0 if not. Must NOT be null.
|
2016-07-26 11:41:47 -07:00
|
|
|
*
|
|
|
|
* \return 1 if the lease can be reused.
|
2014-11-24 07:36:13 -05:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
reuse_lease (struct packet* packet,
|
|
|
|
struct lease* new_lease,
|
|
|
|
struct lease* lease,
|
|
|
|
struct lease_state *state,
|
2018-09-26 11:10:16 -04:00
|
|
|
int offer,
|
|
|
|
int *same_client) {
|
2014-11-24 07:36:13 -05:00
|
|
|
int reusable = 0;
|
|
|
|
|
|
|
|
/* To even consider reuse all of the following must be true:
|
|
|
|
* 1 - reuse hasn't already disqualified
|
|
|
|
* 2 - current lease is active
|
2016-07-26 11:41:47 -07:00
|
|
|
* 3 - DNS info hasn't changed
|
|
|
|
* 4 - the host declaration hasn't changed
|
|
|
|
* 5 - the uid hasn't changed
|
|
|
|
* 6 - the hardware address hasn't changed */
|
2018-09-26 11:10:16 -04:00
|
|
|
|
|
|
|
/* Check client equality separately so we can pass the result out. */
|
|
|
|
*same_client =
|
|
|
|
(((lease->host == new_lease->host) &&
|
|
|
|
(lease->uid_len == new_lease->uid_len) &&
|
|
|
|
(memcmp(lease->uid, new_lease->uid, new_lease->uid_len) == 0) &&
|
|
|
|
(lease->hardware_addr.hlen == new_lease->hardware_addr.hlen) &&
|
|
|
|
(memcmp(&lease->hardware_addr.hbuf[0],
|
|
|
|
&new_lease->hardware_addr.hbuf[0],
|
|
|
|
lease->hardware_addr.hlen) == 0)) ? 1 : 0);
|
|
|
|
|
2014-11-24 07:36:13 -05:00
|
|
|
if ((lease->cannot_reuse == 0) &&
|
|
|
|
(lease->binding_state == FTS_ACTIVE) &&
|
2018-09-26 11:10:16 -04:00
|
|
|
(new_lease->ddns_cb == NULL) && *same_client) {
|
2014-11-24 07:36:13 -05:00
|
|
|
int thresh = DEFAULT_CACHE_THRESHOLD;
|
|
|
|
struct option_cache* oc = NULL;
|
|
|
|
struct data_string d1;
|
|
|
|
|
|
|
|
/* Look up threshold value */
|
|
|
|
memset(&d1, 0, sizeof(struct data_string));
|
|
|
|
if ((oc = lookup_option(&server_universe, state->options,
|
|
|
|
SV_CACHE_THRESHOLD)) &&
|
|
|
|
(evaluate_option_cache(&d1, packet, new_lease, NULL,
|
|
|
|
packet->options, state->options,
|
|
|
|
&new_lease->scope, oc, MDL))) {
|
|
|
|
if (d1.len == 1 && (d1.data[0] < 100))
|
|
|
|
thresh = d1.data[0];
|
|
|
|
|
|
|
|
data_string_forget(&d1, MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If threshold is enabled, check lease age */
|
|
|
|
if (thresh > 0) {
|
|
|
|
int limit = 0;
|
|
|
|
int lease_length = 0;
|
|
|
|
long lease_age = 0;
|
|
|
|
|
|
|
|
/* Calculate limit in seconds */
|
|
|
|
lease_length = lease->ends - lease->starts;
|
|
|
|
if (lease_length <= (INT_MAX / thresh))
|
|
|
|
limit = lease_length * thresh / 100;
|
|
|
|
else
|
|
|
|
limit = lease_length / 100 * thresh;
|
|
|
|
|
|
|
|
/* Note new_lease->starts is really just cur_time */
|
|
|
|
lease_age = new_lease->starts - lease->starts;
|
|
|
|
|
2016-07-26 11:41:47 -07:00
|
|
|
/* Is the lease young enough to reuse? */
|
2014-11-24 07:36:13 -05:00
|
|
|
if (lease_age <= limit) {
|
|
|
|
/* Restore expiry to its original value */
|
|
|
|
state->offered_expiry = lease->ends;
|
|
|
|
|
|
|
|
/* Restore bindings. This fixes 37368. */
|
|
|
|
if (new_lease->scope != NULL) {
|
|
|
|
if (lease->scope != NULL) {
|
|
|
|
binding_scope_dereference(
|
|
|
|
&lease->scope,
|
|
|
|
MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
binding_scope_reference(&lease->scope,
|
|
|
|
new_lease->scope, MDL);
|
|
|
|
}
|
|
|
|
|
2016-07-26 11:41:47 -07:00
|
|
|
/* restore client hostname, fixes 42849. */
|
|
|
|
if (new_lease->client_hostname) {
|
|
|
|
lease->client_hostname =
|
|
|
|
new_lease->client_hostname;
|
|
|
|
new_lease->client_hostname = NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-24 07:36:13 -05:00
|
|
|
/* We're cleared to reuse it */
|
2015-02-16 13:25:25 -05:00
|
|
|
log_debug("reuse_lease: lease age %ld (secs)"
|
|
|
|
" under %d%% threshold, reply with "
|
2015-09-25 10:04:50 -04:00
|
|
|
"unaltered, existing lease for %s",
|
|
|
|
lease_age, thresh, piaddr(lease->ip_addr));
|
2015-02-16 13:25:25 -05:00
|
|
|
|
2014-11-24 07:36:13 -05:00
|
|
|
reusable = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we can't reuse it and this is an offer disqualify reuse for
|
|
|
|
* ensuing REQUEST, otherwise clear the flag. */
|
|
|
|
lease->cannot_reuse = (!reusable && offer == DHCPOFFER);
|
|
|
|
return (reusable);
|
|
|
|
}
|
2017-05-10 13:11:03 -04:00
|
|
|
|
|
|
|
/* \brief Validates a proposed value for use as a lease time
|
|
|
|
*
|
|
|
|
* Convenience function used for catching calculeated lease
|
|
|
|
* times that overflow 4-byte times used in v4 protocol.
|
|
|
|
*
|
|
|
|
* We use variables of type TIME in lots of places, which on
|
|
|
|
* 64-bit systems is 8 bytes while on 32-bit OSs it is int32_t,
|
|
|
|
* so we have all sorts of fun places to mess things up.
|
|
|
|
* This function checks a calculated lease time for and if it
|
|
|
|
* is unsuitable for use as a lease time, the given alternate
|
|
|
|
* value is returned.
|
|
|
|
* \param calculated
|
|
|
|
* \param alternate
|
|
|
|
*
|
|
|
|
* \returen either the calculated value if it is valid, or
|
|
|
|
* the alternate value supplied
|
|
|
|
*/
|
|
|
|
TIME leaseTimeCheck(TIME calculated, TIME alternate) {
|
|
|
|
if ((sizeof(TIME) > 4 && calculated >= INFINITE_TIME) ||
|
|
|
|
(calculated < cur_time)) {
|
|
|
|
return (alternate);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (calculated);
|
|
|
|
}
|