dhcp.c 175 KB
Newer Older
Ted Lemon's avatar
Ted Lemon committed
1 2
/* dhcp.c

3
   DHCP Protocol engine. */
Ted Lemon's avatar
Ted Lemon committed
4 5

/*
6
 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
7
 * Copyright (c) 1995-2003 by Internet Software Consortium
Ted Lemon's avatar
Ted Lemon committed
8
 *
9 10 11
 * 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/.
Ted Lemon's avatar
Ted Lemon committed
12
 *
13 14 15 16 17 18 19
 * 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.
Ted Lemon's avatar
Ted Lemon committed
20
 *
21 22 23 24
 *   Internet Systems Consortium, Inc.
 *   950 Charter Street
 *   Redwood City, CA 94063
 *   <info@isc.org>
25
 *   https://www.isc.org/
Ted Lemon's avatar
Ted Lemon committed
26
 *
Ted Lemon's avatar
Ted Lemon committed
27 28 29
 */

#include "dhcpd.h"
30 31
#include <errno.h>
#include <limits.h>
32 33
#include <sys/time.h>

34 35
static void maybe_return_agent_options(struct packet *packet,
				       struct option_state *options);
36 37 38
static int reuse_lease (struct packet* packet, struct lease* new_lease,
			struct lease* lease, struct lease_state *state,
			int offer);
39 40 41
#if defined(DHCPv6) && defined(DHCP4o6)
static int locate_network6(struct packet *packet);
#endif
Ted Lemon's avatar
Ted Lemon committed
42

43 44
int outstanding_pings;

45 46 47 48 49
#if defined(DELAYED_ACK)
static void delayed_ack_enqueue(struct lease *);
static void delayed_acks_timer(void *);


50 51
struct leasequeue *ackqueue_head, *ackqueue_tail;
static struct leasequeue *free_ackqueue;
52 53
static struct timeval max_fsync;

54 55
int outstanding_acks;
int max_outstanding_acks = DEFAULT_DELAYED_ACK;
56 57
int max_ack_delay_secs = DEFAULT_ACK_DELAY_SECS;
int max_ack_delay_usecs = DEFAULT_ACK_DELAY_USECS;
58
int min_ack_delay_usecs = DEFAULT_MIN_ACK_DELAY_USECS;
59
#endif
60

61
static char dhcp_message [256];
62 63 64 65
static int site_code_min;

static int find_min_site_code(struct universe *);
static isc_result_t lowest_site_code(const void *, unsigned, void *);
66

67 68 69 70 71 72 73 74
static const char *dhcp_type_names [] = { 
	"DHCPDISCOVER",
	"DHCPOFFER",
	"DHCPREQUEST",
	"DHCPDECLINE",
	"DHCPACK",
	"DHCPNAK",
	"DHCPRELEASE",
Shane Kerr's avatar
Shane Kerr committed
75
	"DHCPINFORM",
76
	"type 9",
Shane Kerr's avatar
Shane Kerr committed
77 78 79 80
	"DHCPLEASEQUERY",
	"DHCPLEASEUNASSIGNED",
	"DHCPLEASEUNKNOWN",
	"DHCPLEASEACTIVE"
81 82 83
};
const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *));

Ted Lemon's avatar
Ted Lemon committed
84 85 86 87
#if defined (TRACING)
# define send_packet trace_packet_send
#endif

88 89
static TIME leaseTimeCheck(TIME calculated, TIME alternate);

90 91
void
dhcp (struct packet *packet) {
92
	int ms_nulltp = 0;
93
	struct option_cache *oc;
94
	struct lease *lease = NULL;
95 96
	const char *errmsg;
	struct data_string data;
97

98 99 100 101
	if (!locate_network(packet) &&
	    packet->packet_type != DHCPREQUEST &&
	    packet->packet_type != DHCPINFORM && 
	    packet->packet_type != DHCPLEASEQUERY) {
102
		const char *s;
103
		char typebuf[32];
104 105 106
		errmsg = "unknown network segment";
	      bad_packet:
		
107 108 109
		if (packet->packet_type > 0 &&
		    packet->packet_type <= dhcp_type_name_max) {
			s = dhcp_type_names[packet->packet_type - 1];
110
		} else {
111
			/* %Audit% Cannot exceed 28 bytes. %2004.06.17,Safe% */
112
			sprintf(typebuf, "type %d", packet->packet_type);
113 114 115
			s = typebuf;
		}
		
116 117 118 119 120 121 122 123 124 125 126 127 128 129
#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

130 131 132 133 134 135 136 137 138
		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);
139 140 141 142
		goto out;
	}

	/* There is a problem with the relay agent information option,
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
	 * 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))
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
	{
		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. */
219 220 221 222
		option_chain_head_reference ((struct option_chain_head **)
					     &(packet -> options -> universes
					       [agent_universe.index]),
					     lease -> agent_options, MDL);
223 224 225 226 227 228

		if (packet->options->universe_count <= agent_universe.index)
			packet->options->universe_count =
						agent_universe.index + 1;

		packet->agent_options_stashed = ISC_TRUE;
229 230
	}
      nolease:
231

232 233 234
	/* If a client null terminates options it sends, it probably
	 * expects the server to reciprocate.
	 */
235 236 237
	if ((oc = lookup_option (&dhcp_universe, packet -> options,
				 DHO_HOST_NAME))) {
		if (!oc -> expression)
238
			ms_nulltp = oc->flags & OPTION_HAD_NULLS;
239 240
	}

241
	/* Classify the client. */
242 243
	classify_client (packet);

Ted Lemon's avatar
Ted Lemon committed
244 245
	switch (packet -> packet_type) {
	      case DHCPDISCOVER:
246
		dhcpdiscover (packet, ms_nulltp);
Ted Lemon's avatar
Ted Lemon committed
247
		break;
248

Ted Lemon's avatar
Ted Lemon committed
249
	      case DHCPREQUEST:
250
		dhcprequest (packet, ms_nulltp, lease);
Ted Lemon's avatar
Ted Lemon committed
251
		break;
252

Ted Lemon's avatar
Ted Lemon committed
253
	      case DHCPRELEASE:
254
		dhcprelease (packet, ms_nulltp);
Ted Lemon's avatar
Ted Lemon committed
255
		break;
256

257
	      case DHCPDECLINE:
258
		dhcpdecline (packet, ms_nulltp);
259 260 261
		break;

	      case DHCPINFORM:
262
		dhcpinform (packet, ms_nulltp);
263 264
		break;

Shane Kerr's avatar
Shane Kerr committed
265 266 267
	      case DHCPLEASEQUERY:
		dhcpleasequery(packet, ms_nulltp);
		break;
268 269 270 271

	      case DHCPACK:
	      case DHCPOFFER:
	      case DHCPNAK:
Shane Kerr's avatar
Shane Kerr committed
272 273 274
	      case DHCPLEASEUNASSIGNED:
	      case DHCPLEASEUNKNOWN:
	      case DHCPLEASEACTIVE:
Ted Lemon's avatar
Ted Lemon committed
275
		break;
276 277 278 279

	      default:
		errmsg = "unknown packet type";
		goto bad_packet;
280
	}
281 282 283
      out:
	if (lease)
		lease_dereference (&lease, MDL);
Ted Lemon's avatar
Ted Lemon committed
284
}
285

286
void dhcpdiscover (packet, ms_nulltp)
Ted Lemon's avatar
Ted Lemon committed
287
	struct packet *packet;
288
	int ms_nulltp;
Ted Lemon's avatar
Ted Lemon committed
289
{
290
	struct lease *lease = (struct lease *)0;
Ted Lemon's avatar
Ted Lemon committed
291
	char msgbuf [1024]; /* XXX */
292
	TIME when;
293
	const char *s;
294 295 296 297
	int peer_has_leases = 0;
#if defined (FAILOVER_PROTOCOL)
	dhcp_failover_state_t *peer;
#endif
Ted Lemon's avatar
Ted Lemon committed
298

299
	find_lease (&lease, packet, packet -> shared_network,
300
		    0, &peer_has_leases, (struct lease *)0, MDL);
301

302 303
	if (lease && lease -> client_hostname) {
		if ((strlen (lease -> client_hostname) <= 64) &&
304
		    db_printable((unsigned char *)lease->client_hostname))
305 306 307 308
			s = lease -> client_hostname;
		else
			s = "Hostname Unsuitable for Printing";
	} else
Ted Lemon's avatar
Ted Lemon committed
309 310
		s = (char *)0;

311 312 313
	/* %Audit% This is log output. %2004.06.17,Safe%
	 * If we truncate we hope the user can get a hint from the log.
	 */
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
#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
329
	snprintf (msgbuf, sizeof msgbuf, "DHCPDISCOVER from %s %s%s%svia %s",
Ted Lemon's avatar
Ted Lemon committed
330 331 332
		 (packet -> raw -> htype
		  ? print_hw_addr (packet -> raw -> htype,
				   packet -> raw -> hlen,
333
				   packet -> raw -> chaddr)
Ted Lemon's avatar
Ted Lemon committed
334
		  : (lease
Shane Kerr's avatar
Shane Kerr committed
335
		     ? print_hex_1(lease->uid_len, lease->uid, 60)
Ted Lemon's avatar
Ted Lemon committed
336 337 338 339 340 341
		     : "<no identifier>")),
		  s ? "(" : "", s ? s : "", s ? ") " : "",
		  packet -> raw -> giaddr.s_addr
		  ? inet_ntoa (packet -> raw -> giaddr)
		  : packet -> interface -> name);

342 343
	/* Sourceless packets don't make sense here. */
	if (!packet -> shared_network) {
344 345 346 347 348 349
#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
350
		log_info ("Packet from unknown subnet: %s",
351
		      inet_ntoa (packet -> raw -> giaddr));
352
		goto out;
353 354
	}

355 356 357 358
#if defined (FAILOVER_PROTOCOL)
	if (lease && lease -> pool && lease -> pool -> failover_peer) {
		peer = lease -> pool -> failover_peer;

359 360 361
		/*
		 * If the lease is ours to (re)allocate, then allocate it.
		 *
362
		 * If the lease is active, it belongs to the client.  This
363
		 * is the right lease, if we are to offer one.  We decide
David Hankins's avatar
David Hankins committed
364
		 * whether or not to offer later on.
365 366 367 368
		 *
		 * 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.
369
		 */
370
		if (lease->binding_state == FTS_ACTIVE ||
371
		    lease->rewind_binding_state == FTS_ACTIVE ||
372
		    lease_mine_to_reallocate(lease)) {
373
			; /* This space intentionally left blank. */
374 375

		/* Otherwise, we can't let the client have this lease. */
376
		} else {
377 378 379 380 381 382 383 384 385 386
#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

387 388
	/* If we didn't find a lease, try to allocate one... */
	if (!lease) {
389 390 391
		if (!allocate_lease (&lease, packet,
				     packet -> shared_network -> pools, 
				     &peer_has_leases)) {
392
			if (peer_has_leases)
393 394
				log_error ("%s: peer holds all free leases",
					   msgbuf);
395
			else
396 397 398
				log_error ("%s: network %s: no free leases",
					   msgbuf,
					   packet -> shared_network -> name);
399 400 401 402
			return;
		}
	}

403
#if defined (FAILOVER_PROTOCOL)
404 405 406 407 408 409 410 411 412 413 414
	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;

415
	/* Do load balancing if configured. */
416
	if (peer && (peer -> service_state == cooperating) &&
417
	    !load_balance_mine (packet, peer)) {
418
		if (peer_has_leases) {
419 420 421 422
			log_debug ("%s: load balance to peer %s",
				   msgbuf, peer -> name);
			goto out;
		} else {
423 424
			log_debug ("%s: cancel load balance to peer %s - %s",
				   msgbuf, peer -> name, "no free leases");
425
		}
426 427 428
	}
#endif

429
	/* If it's an expired lease, get rid of any bindings. */
430 431
	if (lease -> ends < cur_time && lease -> scope)
		binding_scope_dereference (&lease -> scope, MDL);
432

433 434 435 436 437 438
	/* 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;

439 440
	ack_lease (packet, lease, DHCPOFFER, when, msgbuf, ms_nulltp,
		   (struct host_decl *)0);
441 442 443
      out:
	if (lease)
		lease_dereference (&lease, MDL);
Ted Lemon's avatar
Ted Lemon committed
444 445
}

446
void dhcprequest (packet, ms_nulltp, ip_lease)
Ted Lemon's avatar
Ted Lemon committed
447
	struct packet *packet;
448
	int ms_nulltp;
449
	struct lease *ip_lease;
Ted Lemon's avatar
Ted Lemon committed
450
{
451
	struct lease *lease;
452
	struct iaddr cip;
453
	struct iaddr sip;
454
	struct subnet *subnet;
455
	int ours = 0;
456 457
	struct option_cache *oc;
	struct data_string data;
Ted Lemon's avatar
Ted Lemon committed
458
	char msgbuf [1024]; /* XXX */
459
	const char *s;
460
	char smbuf [19];
461 462 463
#if defined (FAILOVER_PROTOCOL)
	dhcp_failover_state_t *peer;
#endif
Ted Lemon's avatar
Ted Lemon committed
464
	int have_requested_addr = 0;
465

466
	oc = lookup_option (&dhcp_universe, packet -> options,
467 468 469
			    DHO_DHCP_REQUESTED_ADDRESS);
	memset (&data, 0, sizeof data);
	if (oc &&
470
	    evaluate_option_cache (&data, packet, (struct lease *)0,
471
				   (struct client_state *)0,
472
				   packet -> options, (struct option_state *)0,
473
				   &global_scope, oc, MDL)) {
474
		cip.len = 4;
475
		memcpy (cip.iabuf, data.data, 4);
476
		data_string_forget (&data, MDL);
Ted Lemon's avatar
Ted Lemon committed
477
		have_requested_addr = 1;
Ted Lemon's avatar
Ted Lemon committed
478
	} else {
479
		oc = (struct option_cache *)0;
Ted Lemon's avatar
Ted Lemon committed
480 481 482 483
		cip.len = 4;
		memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
	}

484 485
	/* Find the lease that matches the address requested by the
	   client. */
486

487 488 489 490
	subnet = (struct subnet *)0;
	lease = (struct lease *)0;
	if (find_subnet (&subnet, cip, MDL))
		find_lease (&lease, packet,
491
			    subnet -> shared_network, &ours, 0, ip_lease, MDL);
492

493 494
	if (lease && lease -> client_hostname) {
		if ((strlen (lease -> client_hostname) <= 64) &&
495
		    db_printable((unsigned char *)lease->client_hostname))
496 497 498 499
			s = lease -> client_hostname;
		else
			s = "Hostname Unsuitable for Printing";
	} else
Ted Lemon's avatar
Ted Lemon committed
500 501
		s = (char *)0;

502 503 504 505 506 507 508 509 510 511 512
	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);
513 514 515
		/* piaddr() should not return more than a 15 byte string.
		 * safe.
		 */
516
		sprintf (smbuf, " (%s)", piaddr (sip));
Shawn Routhier's avatar
Shawn Routhier committed
517
	} else {
518
		smbuf [0] = 0;
Shawn Routhier's avatar
Shawn Routhier committed
519 520
		sip.len = 0;
	}
521

522 523 524
	/* %Audit% This is log output. %2004.06.17,Safe%
	 * If we truncate we hope the user can get a hint from the log.
	 */
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
#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
541 542
	snprintf (msgbuf, sizeof msgbuf,
		 "DHCPREQUEST for %s%s from %s %s%s%svia %s",
543
		 piaddr (cip), smbuf,
Ted Lemon's avatar
Ted Lemon committed
544 545 546
		 (packet -> raw -> htype
		  ? print_hw_addr (packet -> raw -> htype,
				   packet -> raw -> hlen,
547
				   packet -> raw -> chaddr)
Ted Lemon's avatar
Ted Lemon committed
548
		  : (lease
Shane Kerr's avatar
Shane Kerr committed
549
		     ? print_hex_1(lease->uid_len, lease->uid, 60)
Ted Lemon's avatar
Ted Lemon committed
550 551 552
		     : "<no identifier>")),
		 s ? "(" : "", s ? s : "", s ? ") " : "",
		  packet -> raw -> giaddr.s_addr
553
		  ? inet_ntoa (packet -> raw -> giaddr)
Ted Lemon's avatar
Ted Lemon committed
554
		  : packet -> interface -> name);
555

556
#if defined (FAILOVER_PROTOCOL)
557 558 559 560 561
	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",
562
				  msgbuf, peer -> nrr);
563 564
			goto out;
		}
Ted Lemon's avatar
Ted Lemon committed
565

566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583
		/* "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.
		 */
584 585 586 587
		if ((lease -> binding_state == FTS_FREE ||
		     lease -> binding_state == FTS_BACKUP) &&
		    !lease_mine_to_reallocate (lease)) {
			log_debug ("%s: lease owned by peer", msgbuf);
Ted Lemon's avatar
Ted Lemon committed
588 589
			goto out;
		}
590

591 592 593 594 595 596 597 598 599 600 601 602
		/*
		 * 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)
603 604 605 606 607 608 609 610 611 612
				   ? "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);
613
			nak_lease (packet, &cip, lease->subnet->group);
614 615 616
			goto out;
		}

617 618 619 620 621 622 623 624 625
		/* 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) &&
Shawn Routhier's avatar
Shawn Routhier committed
626 627
		    (memcmp(sip.iabuf, "\0\0\0\0", sip.len) != 0)) {
			struct in_addr from;
628 629 630
			struct option_state *eval_options = NULL;

			eval_network_statements(&eval_options, packet, NULL);
631 632
			get_server_source_address(&from, eval_options,
						  NULL, packet);
633
			option_state_dereference (&eval_options, MDL);
Shawn Routhier's avatar
Shawn Routhier committed
634 635 636 637 638 639
			if (memcmp(sip.iabuf, &from, sip.len) != 0) {
				log_debug("%s: not our server id", msgbuf);
				goto out;
			}
		}

640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
		/* 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. */
663 664
	} else
		peer = (dhcp_failover_state_t *)0;
665 666
#endif

667 668 669 670 671
	/* 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.
672 673 674 675

	   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
676
	   IP router, we'll just have to assume that it's cool.
677

678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
	   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 ||
710 711
	    (packet -> raw -> ciaddr.s_addr &&
	     packet -> raw -> giaddr.s_addr) ||
Ted Lemon's avatar
Ted Lemon committed
712
	    (have_requested_addr && !packet -> raw -> ciaddr.s_addr)) {
713 714 715
		
		/* If we don't know where it came from but we do know
		   where it claims to have come from, it didn't come
716
		   from there. */
717
		if (!packet -> shared_network) {
Ted Lemon's avatar
Ted Lemon committed
718
			if (subnet && subnet -> group -> authoritative) {
719
				log_info ("%s: wrong network.", msgbuf);
720
				nak_lease (packet, &cip, NULL);
721
				goto out;
722
			}
723
			/* Otherwise, ignore it. */
724 725 726
			log_info ("%s: ignored (%s).", msgbuf,
				  (subnet
				   ? "not authoritative" : "unknown subnet"));
727
			goto out;
728
		}
729

730 731
		/* If we do know where it came from and it asked for an
		   address that is not on that shared network, nak it. */
732 733 734 735
		if (subnet)
			subnet_dereference (&subnet, MDL);
		if (!find_grouped_subnet (&subnet, packet -> shared_network,
					  cip, MDL)) {
Ted Lemon's avatar
Ted Lemon committed
736 737
			if (packet -> shared_network -> group -> authoritative)
			{
738
				log_info ("%s: wrong network.", msgbuf);
739
				nak_lease (packet, &cip, NULL);
740
				goto out;
Ted Lemon's avatar
Ted Lemon committed
741
			}
742
			log_info ("%s: ignored (not authoritative).", msgbuf);
743 744 745
			return;
		}
	}
Ted Lemon's avatar
Ted Lemon committed
746

747
	/* If the address the client asked for is ours, but it wasn't
748
	   available for the client, NAK it. */
749
	if (!lease && ours) {
750
		log_info ("%s: lease %s unavailable.", msgbuf, piaddr (cip));
751
		nak_lease (packet, &cip, (subnet ? subnet->group : NULL));
752
		goto out;
753 754
	}

Ted Lemon's avatar
Ted Lemon committed
755
	/* Otherwise, send the lease to the client if we found one. */
756
	if (lease) {
757 758
		ack_lease (packet, lease, DHCPACK, 0, msgbuf, ms_nulltp,
			   (struct host_decl *)0);
759
	} else
760
		log_info ("%s: unknown lease %s.", msgbuf, piaddr (cip));
761 762 763 764 765 766 767

      out:
	if (subnet)
		subnet_dereference (&subnet, MDL);
	if (lease)
		lease_dereference (&lease, MDL);
	return;
Ted Lemon's avatar
Ted Lemon committed
768 769
}

770
void dhcprelease (packet, ms_nulltp)
Ted Lemon's avatar
Ted Lemon committed
771
	struct packet *packet;
772
	int ms_nulltp;
Ted Lemon's avatar
Ted Lemon committed
773
{
Ted Lemon's avatar
Ted Lemon committed
774
	struct lease *lease = (struct lease *)0, *next = (struct lease *)0;
Ted Lemon's avatar
Ted Lemon committed
775
	struct iaddr cip;
776 777
	struct option_cache *oc;
	struct data_string data;
778 779
	const char *s;
	char msgbuf [1024], cstr[16]; /* XXX */
780

781

782
	/* DHCPRELEASE must not specify address in requested-address
783 784
	   option, but old protocol specs weren't explicit about this,
	   so let it go. */
785
	if ((oc = lookup_option (&dhcp_universe, packet -> options,
786
				 DHO_DHCP_REQUESTED_ADDRESS))) {
787
		log_info ("DHCPRELEASE from %s specified requested-address.",
788 789 790
		      print_hw_addr (packet -> raw -> htype,
				     packet -> raw -> hlen,
				     packet -> raw -> chaddr));
791 792
	}

793
	oc = lookup_option (&dhcp_universe, packet -> options,
794 795 796
			    DHO_DHCP_CLIENT_IDENTIFIER);
	memset (&data, 0, sizeof data);
	if (oc &&
797
	    evaluate_option_cache (&data, packet, (struct lease *)0,
798
				   (struct client_state *)0,
799
				   packet -> options, (struct option_state *)0,
800
				   &global_scope, oc, MDL)) {
801
		find_lease_by_uid (&lease, data.data, data.len, MDL);
802
		data_string_forget (&data, MDL);
Ted Lemon's avatar
Ted Lemon committed
803

804 805
		/* See if we can find a lease that matches the IP address
		   the client is claiming. */
Ted Lemon's avatar
Ted Lemon committed
806
		while (lease) {
Ted Lemon's avatar
Ted Lemon committed
807 808
			if (lease -> n_uid)
				lease_reference (&next, lease -> n_uid, MDL);
809 810 811 812
			if (!memcmp (&packet -> raw -> ciaddr,
				     lease -> ip_addr.iabuf, 4)) {
				break;
			}
Ted Lemon's avatar
Ted Lemon committed
813 814 815 816 817
			lease_dereference (&lease, MDL);
			if (next) {
				lease_reference (&lease, next, MDL);
				lease_dereference (&next, MDL);
			}
818
		}
Ted Lemon's avatar
Ted Lemon committed
819 820
		if (next)
			lease_dereference (&next, MDL);
821
	}
822 823 824 825 826

	/* 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) {
827 828
		cip.len = 4;
		memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
829
		find_lease_by_ip_addr (&lease, cip, MDL);
830 831 832
	}


833 834 835 836 837 838 839 840 841 842
	/* 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) &&
843
		    db_printable((unsigned char *)lease->client_hostname))
844 845 846 847
			s = lease -> client_hostname;
		else
			s = "Hostname Unsuitable for Printing";
	} else
Ted Lemon's avatar
Ted Lemon committed
848 849
		s = (char *)0;

850 851 852 853 854 855 856 857 858 859
	/* %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.
	 */
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877
#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
878
	snprintf (msgbuf, sizeof msgbuf,
879
		 "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
880
		 cstr,
881 882 883 884 885
		 (packet -> raw -> htype
		  ? print_hw_addr (packet -> raw -> htype,
				   packet -> raw -> hlen,
				   packet -> raw -> chaddr)
		  : (lease
Shane Kerr's avatar
Shane Kerr committed
886
		     ? print_hex_1(lease->uid_len, lease->uid, 60)
887 888 889 890 891 892 893 894
		     : "<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)
895 896 897 898 899 900 901 902 903
	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;
		}

904 905 906 907
		/* 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
908
		   lease state, so that's what we're doing.
909 910 911
		   XXX See what it says in the draft about this. */
	}
#endif
Ted Lemon's avatar
Ted Lemon committed
912

913
	/* If we found a lease, release it. */
914
	if (lease && lease -> ends > cur_time) {
915
		release_lease (lease, packet);
Ted Lemon's avatar
Ted Lemon committed
916 917
	} 
	log_info ("%s", msgbuf);
918
#if defined(FAILOVER_PROTOCOL)
919
      out:
920
#endif
921 922
	if (lease)
		lease_dereference (&lease, MDL);
Ted Lemon's avatar
Ted Lemon committed
923 924
}

925
void dhcpdecline (packet, ms_nulltp)
926
	struct packet *packet;
927
	int ms_nulltp;
928
{
929
	struct lease *lease = (struct lease *)0;
930
	struct option_state *options = (struct option_state *)0;
931
	int ignorep = 0;
932 933
	int i;
	const char *status;
934
	const char *s;
935
	char msgbuf [1024]; /* XXX */
936 937 938
	struct iaddr cip;
	struct option_cache *oc;
	struct data_string data;
Ted Lemon's avatar
Ted Lemon committed
939

940
	/* DHCPDECLINE must specify address. */
941
	if (!(oc = lookup_option (&dhcp_universe, packet -> options,
942 943