Annotation of embedaddon/dhcp/server/dhcp.c, revision 1.1
1.1 ! misho 1: /* dhcp.c
! 2:
! 3: DHCP Protocol engine. */
! 4:
! 5: /*
! 6: * Copyright (c) 2004-2011 by Internet Systems Consortium, Inc. ("ISC")
! 7: * Copyright (c) 1995-2003 by Internet Software Consortium
! 8: *
! 9: * Permission to use, copy, modify, and distribute this software for any
! 10: * purpose with or without fee is hereby granted, provided that the above
! 11: * copyright notice and this permission notice appear in all copies.
! 12: *
! 13: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
! 14: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 15: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
! 16: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 17: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 18: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 19: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 20: *
! 21: * Internet Systems Consortium, Inc.
! 22: * 950 Charter Street
! 23: * Redwood City, CA 94063
! 24: * <info@isc.org>
! 25: * https://www.isc.org/
! 26: *
! 27: * This software has been written for Internet Systems Consortium
! 28: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
! 29: * To learn more about Internet Systems Consortium, see
! 30: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
! 31: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
! 32: * ``http://www.nominum.com''.
! 33: */
! 34:
! 35: #include "dhcpd.h"
! 36: #include <errno.h>
! 37: #include <limits.h>
! 38: #include <sys/time.h>
! 39:
! 40: static void commit_leases_ackout(void *foo);
! 41:
! 42: int outstanding_pings;
! 43:
! 44: struct leasequeue *ackqueue_head, *ackqueue_tail;
! 45: static struct leasequeue *free_ackqueue;
! 46: static struct timeval next_fsync;
! 47: int outstanding_acks;
! 48: int max_outstanding_acks = DEFAULT_DELAYED_ACK;
! 49: int max_ack_delay_secs = DEFAULT_ACK_DELAY_SECS;
! 50: int max_ack_delay_usecs = DEFAULT_ACK_DELAY_USECS;
! 51:
! 52: static char dhcp_message [256];
! 53: static int site_code_min;
! 54:
! 55: static int find_min_site_code(struct universe *);
! 56: static isc_result_t lowest_site_code(const void *, unsigned, void *);
! 57:
! 58: static const char *dhcp_type_names [] = {
! 59: "DHCPDISCOVER",
! 60: "DHCPOFFER",
! 61: "DHCPREQUEST",
! 62: "DHCPDECLINE",
! 63: "DHCPACK",
! 64: "DHCPNAK",
! 65: "DHCPRELEASE",
! 66: "DHCPINFORM",
! 67: "type 9",
! 68: "DHCPLEASEQUERY",
! 69: "DHCPLEASEUNASSIGNED",
! 70: "DHCPLEASEUNKNOWN",
! 71: "DHCPLEASEACTIVE"
! 72: };
! 73: const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *));
! 74:
! 75: #if defined (TRACING)
! 76: # define send_packet trace_packet_send
! 77: #endif
! 78:
! 79: void
! 80: dhcp (struct packet *packet) {
! 81: int ms_nulltp = 0;
! 82: struct option_cache *oc;
! 83: struct lease *lease = NULL;
! 84: const char *errmsg;
! 85: struct data_string data;
! 86:
! 87: if (!locate_network(packet) &&
! 88: packet->packet_type != DHCPREQUEST &&
! 89: packet->packet_type != DHCPINFORM &&
! 90: packet->packet_type != DHCPLEASEQUERY) {
! 91: const char *s;
! 92: char typebuf[32];
! 93: errmsg = "unknown network segment";
! 94: bad_packet:
! 95:
! 96: if (packet->packet_type > 0 &&
! 97: packet->packet_type <= dhcp_type_name_max) {
! 98: s = dhcp_type_names[packet->packet_type - 1];
! 99: } else {
! 100: /* %Audit% Cannot exceed 28 bytes. %2004.06.17,Safe% */
! 101: sprintf(typebuf, "type %d", packet->packet_type);
! 102: s = typebuf;
! 103: }
! 104:
! 105: log_info("%s from %s via %s: %s", s,
! 106: (packet->raw->htype
! 107: ? print_hw_addr(packet->raw->htype,
! 108: packet->raw->hlen,
! 109: packet->raw->chaddr)
! 110: : "<no identifier>"),
! 111: packet->raw->giaddr.s_addr
! 112: ? inet_ntoa(packet->raw->giaddr)
! 113: : packet->interface->name, errmsg);
! 114: goto out;
! 115: }
! 116:
! 117: /* There is a problem with the relay agent information option,
! 118: * which is that in order for a normal relay agent to append
! 119: * this option, the relay agent has to have been involved in
! 120: * getting the packet from the client to the server. Note
! 121: * that this is the software entity known as the relay agent,
! 122: * _not_ the hardware entity known as a router in which the
! 123: * relay agent may be running, so the fact that a router has
! 124: * forwarded a packet does not mean that the relay agent in
! 125: * the router was involved.
! 126: *
! 127: * So when the client broadcasts (DHCPDISCOVER, or giaddr is set),
! 128: * we can be sure that there are either agent options in the
! 129: * packet, or there aren't supposed to be. When the giaddr is not
! 130: * set, it's still possible that the client is on a directly
! 131: * attached subnet, and agent options are being appended by an l2
! 132: * device that has no address, and so sets no giaddr.
! 133: *
! 134: * But in either case it's possible that the packets we receive
! 135: * from the client in RENEW state may not include the agent options,
! 136: * so if they are not in the packet we must "pretend" the last values
! 137: * we observed were provided.
! 138: */
! 139: if (packet->packet_type == DHCPREQUEST &&
! 140: packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr &&
! 141: (packet->options->universe_count <= agent_universe.index ||
! 142: packet->options->universes[agent_universe.index] == NULL))
! 143: {
! 144: struct iaddr cip;
! 145:
! 146: cip.len = sizeof packet -> raw -> ciaddr;
! 147: memcpy (cip.iabuf, &packet -> raw -> ciaddr,
! 148: sizeof packet -> raw -> ciaddr);
! 149: if (!find_lease_by_ip_addr (&lease, cip, MDL))
! 150: goto nolease;
! 151:
! 152: /* If there are no agent options on the lease, it's not
! 153: interesting. */
! 154: if (!lease -> agent_options)
! 155: goto nolease;
! 156:
! 157: /* The client should not be unicasting a renewal if its lease
! 158: has expired, so make it go through the process of getting
! 159: its agent options legally. */
! 160: if (lease -> ends < cur_time)
! 161: goto nolease;
! 162:
! 163: if (lease -> uid_len) {
! 164: oc = lookup_option (&dhcp_universe, packet -> options,
! 165: DHO_DHCP_CLIENT_IDENTIFIER);
! 166: if (!oc)
! 167: goto nolease;
! 168:
! 169: memset (&data, 0, sizeof data);
! 170: if (!evaluate_option_cache (&data,
! 171: packet, (struct lease *)0,
! 172: (struct client_state *)0,
! 173: packet -> options,
! 174: (struct option_state *)0,
! 175: &global_scope, oc, MDL))
! 176: goto nolease;
! 177: if (lease -> uid_len != data.len ||
! 178: memcmp (lease -> uid, data.data, data.len)) {
! 179: data_string_forget (&data, MDL);
! 180: goto nolease;
! 181: }
! 182: data_string_forget (&data, MDL);
! 183: } else
! 184: if ((lease -> hardware_addr.hbuf [0] !=
! 185: packet -> raw -> htype) ||
! 186: (lease -> hardware_addr.hlen - 1 !=
! 187: packet -> raw -> hlen) ||
! 188: memcmp (&lease -> hardware_addr.hbuf [1],
! 189: packet -> raw -> chaddr,
! 190: packet -> raw -> hlen))
! 191: goto nolease;
! 192:
! 193: /* Okay, so we found a lease that matches the client. */
! 194: option_chain_head_reference ((struct option_chain_head **)
! 195: &(packet -> options -> universes
! 196: [agent_universe.index]),
! 197: lease -> agent_options, MDL);
! 198:
! 199: if (packet->options->universe_count <= agent_universe.index)
! 200: packet->options->universe_count =
! 201: agent_universe.index + 1;
! 202:
! 203: packet->agent_options_stashed = ISC_TRUE;
! 204: }
! 205: nolease:
! 206:
! 207: /* If a client null terminates options it sends, it probably
! 208: * expects the server to reciprocate.
! 209: */
! 210: if ((oc = lookup_option (&dhcp_universe, packet -> options,
! 211: DHO_HOST_NAME))) {
! 212: if (!oc -> expression)
! 213: ms_nulltp = oc->flags & OPTION_HAD_NULLS;
! 214: }
! 215:
! 216: /* Classify the client. */
! 217: classify_client (packet);
! 218:
! 219: switch (packet -> packet_type) {
! 220: case DHCPDISCOVER:
! 221: dhcpdiscover (packet, ms_nulltp);
! 222: break;
! 223:
! 224: case DHCPREQUEST:
! 225: dhcprequest (packet, ms_nulltp, lease);
! 226: break;
! 227:
! 228: case DHCPRELEASE:
! 229: dhcprelease (packet, ms_nulltp);
! 230: break;
! 231:
! 232: case DHCPDECLINE:
! 233: dhcpdecline (packet, ms_nulltp);
! 234: break;
! 235:
! 236: case DHCPINFORM:
! 237: dhcpinform (packet, ms_nulltp);
! 238: break;
! 239:
! 240: case DHCPLEASEQUERY:
! 241: dhcpleasequery(packet, ms_nulltp);
! 242: break;
! 243:
! 244: case DHCPACK:
! 245: case DHCPOFFER:
! 246: case DHCPNAK:
! 247: case DHCPLEASEUNASSIGNED:
! 248: case DHCPLEASEUNKNOWN:
! 249: case DHCPLEASEACTIVE:
! 250: break;
! 251:
! 252: default:
! 253: errmsg = "unknown packet type";
! 254: goto bad_packet;
! 255: }
! 256: out:
! 257: if (lease)
! 258: lease_dereference (&lease, MDL);
! 259: }
! 260:
! 261: void dhcpdiscover (packet, ms_nulltp)
! 262: struct packet *packet;
! 263: int ms_nulltp;
! 264: {
! 265: struct lease *lease = (struct lease *)0;
! 266: char msgbuf [1024]; /* XXX */
! 267: TIME when;
! 268: const char *s;
! 269: int peer_has_leases = 0;
! 270: #if defined (FAILOVER_PROTOCOL)
! 271: dhcp_failover_state_t *peer;
! 272: #endif
! 273:
! 274: find_lease (&lease, packet, packet -> shared_network,
! 275: 0, &peer_has_leases, (struct lease *)0, MDL);
! 276:
! 277: if (lease && lease -> client_hostname) {
! 278: if ((strlen (lease -> client_hostname) <= 64) &&
! 279: db_printable((unsigned char *)lease->client_hostname))
! 280: s = lease -> client_hostname;
! 281: else
! 282: s = "Hostname Unsuitable for Printing";
! 283: } else
! 284: s = (char *)0;
! 285:
! 286: /* %Audit% This is log output. %2004.06.17,Safe%
! 287: * If we truncate we hope the user can get a hint from the log.
! 288: */
! 289: snprintf (msgbuf, sizeof msgbuf, "DHCPDISCOVER from %s %s%s%svia %s",
! 290: (packet -> raw -> htype
! 291: ? print_hw_addr (packet -> raw -> htype,
! 292: packet -> raw -> hlen,
! 293: packet -> raw -> chaddr)
! 294: : (lease
! 295: ? print_hex_1(lease->uid_len, lease->uid, 60)
! 296: : "<no identifier>")),
! 297: s ? "(" : "", s ? s : "", s ? ") " : "",
! 298: packet -> raw -> giaddr.s_addr
! 299: ? inet_ntoa (packet -> raw -> giaddr)
! 300: : packet -> interface -> name);
! 301:
! 302: /* Sourceless packets don't make sense here. */
! 303: if (!packet -> shared_network) {
! 304: log_info ("Packet from unknown subnet: %s",
! 305: inet_ntoa (packet -> raw -> giaddr));
! 306: goto out;
! 307: }
! 308:
! 309: #if defined (FAILOVER_PROTOCOL)
! 310: if (lease && lease -> pool && lease -> pool -> failover_peer) {
! 311: peer = lease -> pool -> failover_peer;
! 312:
! 313: /* If the lease is ours to allocate, then allocate it.
! 314: * If the lease is active, it belongs to the client. This
! 315: * is the right lease, if we are to offer one. We decide
! 316: * whether or not to offer later on.
! 317: */
! 318: if (lease->binding_state == FTS_ACTIVE ||
! 319: lease_mine_to_reallocate(lease)) {
! 320: ; /* This space intentionally left blank. */
! 321:
! 322: /* Otherwise, we can't let the client have this lease. */
! 323: } else {
! 324: #if defined (DEBUG_FIND_LEASE)
! 325: log_debug ("discarding %s - %s",
! 326: piaddr (lease -> ip_addr),
! 327: binding_state_print (lease -> binding_state));
! 328: #endif
! 329: lease_dereference (&lease, MDL);
! 330: }
! 331: }
! 332: #endif
! 333:
! 334: /* If we didn't find a lease, try to allocate one... */
! 335: if (!lease) {
! 336: if (!allocate_lease (&lease, packet,
! 337: packet -> shared_network -> pools,
! 338: &peer_has_leases)) {
! 339: if (peer_has_leases)
! 340: log_error ("%s: peer holds all free leases",
! 341: msgbuf);
! 342: else
! 343: log_error ("%s: network %s: no free leases",
! 344: msgbuf,
! 345: packet -> shared_network -> name);
! 346: return;
! 347: }
! 348: }
! 349:
! 350: #if defined (FAILOVER_PROTOCOL)
! 351: if (lease && lease -> pool && lease -> pool -> failover_peer) {
! 352: peer = lease -> pool -> failover_peer;
! 353: if (peer -> service_state == not_responding ||
! 354: peer -> service_state == service_startup) {
! 355: log_info ("%s: not responding%s",
! 356: msgbuf, peer -> nrr);
! 357: goto out;
! 358: }
! 359: } else
! 360: peer = (dhcp_failover_state_t *)0;
! 361:
! 362: /* Do load balancing if configured. */
! 363: if (peer && (peer -> service_state == cooperating) &&
! 364: !load_balance_mine (packet, peer)) {
! 365: if (peer_has_leases) {
! 366: log_debug ("%s: load balance to peer %s",
! 367: msgbuf, peer -> name);
! 368: goto out;
! 369: } else {
! 370: log_debug ("%s: cancel load balance to peer %s - %s",
! 371: msgbuf, peer -> name, "no free leases");
! 372: }
! 373: }
! 374: #endif
! 375:
! 376: /* If it's an expired lease, get rid of any bindings. */
! 377: if (lease -> ends < cur_time && lease -> scope)
! 378: binding_scope_dereference (&lease -> scope, MDL);
! 379:
! 380: /* Set the lease to really expire in 2 minutes, unless it has
! 381: not yet expired, in which case leave its expiry time alone. */
! 382: when = cur_time + 120;
! 383: if (when < lease -> ends)
! 384: when = lease -> ends;
! 385:
! 386: ack_lease (packet, lease, DHCPOFFER, when, msgbuf, ms_nulltp,
! 387: (struct host_decl *)0);
! 388: out:
! 389: if (lease)
! 390: lease_dereference (&lease, MDL);
! 391: }
! 392:
! 393: void dhcprequest (packet, ms_nulltp, ip_lease)
! 394: struct packet *packet;
! 395: int ms_nulltp;
! 396: struct lease *ip_lease;
! 397: {
! 398: struct lease *lease;
! 399: struct iaddr cip;
! 400: struct iaddr sip;
! 401: struct subnet *subnet;
! 402: int ours = 0;
! 403: struct option_cache *oc;
! 404: struct data_string data;
! 405: char msgbuf [1024]; /* XXX */
! 406: const char *s;
! 407: char smbuf [19];
! 408: #if defined (FAILOVER_PROTOCOL)
! 409: dhcp_failover_state_t *peer;
! 410: #endif
! 411: int have_server_identifier = 0;
! 412: int have_requested_addr = 0;
! 413:
! 414: oc = lookup_option (&dhcp_universe, packet -> options,
! 415: DHO_DHCP_REQUESTED_ADDRESS);
! 416: memset (&data, 0, sizeof data);
! 417: if (oc &&
! 418: evaluate_option_cache (&data, packet, (struct lease *)0,
! 419: (struct client_state *)0,
! 420: packet -> options, (struct option_state *)0,
! 421: &global_scope, oc, MDL)) {
! 422: cip.len = 4;
! 423: memcpy (cip.iabuf, data.data, 4);
! 424: data_string_forget (&data, MDL);
! 425: have_requested_addr = 1;
! 426: } else {
! 427: oc = (struct option_cache *)0;
! 428: cip.len = 4;
! 429: memcpy (cip.iabuf, &packet -> raw -> ciaddr.s_addr, 4);
! 430: }
! 431:
! 432: /* Find the lease that matches the address requested by the
! 433: client. */
! 434:
! 435: subnet = (struct subnet *)0;
! 436: lease = (struct lease *)0;
! 437: if (find_subnet (&subnet, cip, MDL))
! 438: find_lease (&lease, packet,
! 439: subnet -> shared_network, &ours, 0, ip_lease, MDL);
! 440:
! 441: if (lease && lease -> client_hostname) {
! 442: if ((strlen (lease -> client_hostname) <= 64) &&
! 443: db_printable((unsigned char *)lease->client_hostname))
! 444: s = lease -> client_hostname;
! 445: else
! 446: s = "Hostname Unsuitable for Printing";
! 447: } else
! 448: s = (char *)0;
! 449:
! 450: oc = lookup_option (&dhcp_universe, packet -> options,
! 451: DHO_DHCP_SERVER_IDENTIFIER);
! 452: memset (&data, 0, sizeof data);
! 453: if (oc &&
! 454: evaluate_option_cache (&data, packet, (struct lease *)0,
! 455: (struct client_state *)0,
! 456: packet -> options, (struct option_state *)0,
! 457: &global_scope, oc, MDL)) {
! 458: sip.len = 4;
! 459: memcpy (sip.iabuf, data.data, 4);
! 460: data_string_forget (&data, MDL);
! 461: /* piaddr() should not return more than a 15 byte string.
! 462: * safe.
! 463: */
! 464: sprintf (smbuf, " (%s)", piaddr (sip));
! 465: have_server_identifier = 1;
! 466: } else
! 467: smbuf [0] = 0;
! 468:
! 469: /* %Audit% This is log output. %2004.06.17,Safe%
! 470: * If we truncate we hope the user can get a hint from the log.
! 471: */
! 472: snprintf (msgbuf, sizeof msgbuf,
! 473: "DHCPREQUEST for %s%s from %s %s%s%svia %s",
! 474: piaddr (cip), smbuf,
! 475: (packet -> raw -> htype
! 476: ? print_hw_addr (packet -> raw -> htype,
! 477: packet -> raw -> hlen,
! 478: packet -> raw -> chaddr)
! 479: : (lease
! 480: ? print_hex_1(lease->uid_len, lease->uid, 60)
! 481: : "<no identifier>")),
! 482: s ? "(" : "", s ? s : "", s ? ") " : "",
! 483: packet -> raw -> giaddr.s_addr
! 484: ? inet_ntoa (packet -> raw -> giaddr)
! 485: : packet -> interface -> name);
! 486:
! 487: #if defined (FAILOVER_PROTOCOL)
! 488: if (lease && lease -> pool && lease -> pool -> failover_peer) {
! 489: peer = lease -> pool -> failover_peer;
! 490: if (peer -> service_state == not_responding ||
! 491: peer -> service_state == service_startup) {
! 492: log_info ("%s: not responding%s",
! 493: msgbuf, peer -> nrr);
! 494: goto out;
! 495: }
! 496:
! 497: /* "load balance to peer" - is not done at all for request.
! 498: *
! 499: * If it's RENEWING, we are the only server to hear it, so
! 500: * we have to serve it. If it's REBINDING, it's out of
! 501: * communication with the other server, so there's no point
! 502: * in waiting to serve it. However, if the lease we're
! 503: * offering is not a free lease, then we may be the only
! 504: * server that can offer it, so we can't load balance if
! 505: * the lease isn't in the free or backup state. If it is
! 506: * in the free or backup state, then that state is what
! 507: * mandates one server or the other should perform the
! 508: * allocation, not the LBA...we know the peer cannot
! 509: * allocate a request for an address in our free state.
! 510: *
! 511: * So our only compass is lease_mine_to_reallocate(). This
! 512: * effects both load balancing, and a sanity-check that we
! 513: * are not going to try to allocate a lease that isn't ours.
! 514: */
! 515: if ((lease -> binding_state == FTS_FREE ||
! 516: lease -> binding_state == FTS_BACKUP) &&
! 517: !lease_mine_to_reallocate (lease)) {
! 518: log_debug ("%s: lease owned by peer", msgbuf);
! 519: goto out;
! 520: }
! 521:
! 522: /* If the lease is in a transitional state, we can't
! 523: renew it. */
! 524: if ((lease -> binding_state == FTS_RELEASED ||
! 525: lease -> binding_state == FTS_EXPIRED) &&
! 526: !lease_mine_to_reallocate (lease)) {
! 527: log_debug ("%s: lease in transition state %s", msgbuf,
! 528: lease -> binding_state == FTS_RELEASED
! 529: ? "released" : "expired");
! 530: goto out;
! 531: }
! 532:
! 533: /* It's actually very unlikely that we'll ever get here,
! 534: but if we do, tell the client to stop using the lease,
! 535: because the administrator reset it. */
! 536: if (lease -> binding_state == FTS_RESET &&
! 537: !lease_mine_to_reallocate (lease)) {
! 538: log_debug ("%s: lease reset by administrator", msgbuf);
! 539: nak_lease (packet, &cip);
! 540: goto out;
! 541: }
! 542:
! 543: /* At this point it's possible that we will get a broadcast
! 544: DHCPREQUEST for a lease that we didn't offer, because
! 545: both we and the peer are in a position to offer it.
! 546: In that case, we probably shouldn't answer. In order
! 547: to not answer, we would have to compare the server
! 548: identifier sent by the client with the list of possible
! 549: server identifiers we can send, and if the client's
! 550: identifier isn't on the list, drop the DHCPREQUEST.
! 551: We aren't currently doing that for two reasons - first,
! 552: it's not clear that all clients do the right thing
! 553: with respect to sending the client identifier, which
! 554: could mean that we might simply not respond to a client
! 555: that is depending on us to respond. Secondly, we allow
! 556: the user to specify the server identifier to send, and
! 557: we don't enforce that the server identifier should be
! 558: one of our IP addresses. This is probably not a big
! 559: deal, but it's theoretically an issue.
! 560:
! 561: The reason we care about this is that if both servers
! 562: send a DHCPACK to the DHCPREQUEST, they are then going
! 563: to send dueling BNDUPD messages, which could cause
! 564: trouble. I think it causes no harm, but it seems
! 565: wrong. */
! 566: } else
! 567: peer = (dhcp_failover_state_t *)0;
! 568: #endif
! 569:
! 570: /* If a client on a given network REQUESTs a lease on an
! 571: address on a different network, NAK it. If the Requested
! 572: Address option was used, the protocol says that it must
! 573: have been broadcast, so we can trust the source network
! 574: information.
! 575:
! 576: If ciaddr was specified and Requested Address was not, then
! 577: we really only know for sure what network a packet came from
! 578: if it came through a BOOTP gateway - if it came through an
! 579: IP router, we'll just have to assume that it's cool.
! 580:
! 581: If we don't think we know where the packet came from, it
! 582: came through a gateway from an unknown network, so it's not
! 583: from a RENEWING client. If we recognize the network it
! 584: *thinks* it's on, we can NAK it even though we don't
! 585: recognize the network it's *actually* on; otherwise we just
! 586: have to ignore it.
! 587:
! 588: We don't currently try to take advantage of access to the
! 589: raw packet, because it's not available on all platforms.
! 590: So a packet that was unicast to us through a router from a
! 591: RENEWING client is going to look exactly like a packet that
! 592: was broadcast to us from an INIT-REBOOT client.
! 593:
! 594: Since we can't tell the difference between these two kinds
! 595: of packets, if the packet appears to have come in off the
! 596: local wire, we have to treat it as if it's a RENEWING
! 597: client. This means that we can't NAK a RENEWING client on
! 598: the local wire that has a bogus address. The good news is
! 599: that we won't ACK it either, so it should revert to INIT
! 600: state and send us a DHCPDISCOVER, which we *can* work with.
! 601:
! 602: Because we can't detect that a RENEWING client is on the
! 603: wrong wire, it's going to sit there trying to renew until
! 604: it gets to the REBIND state, when we *can* NAK it because
! 605: the packet will get to us through a BOOTP gateway. We
! 606: shouldn't actually see DHCPREQUEST packets from RENEWING
! 607: clients on the wrong wire anyway, since their idea of their
! 608: local router will be wrong. In any case, the protocol
! 609: doesn't really allow us to NAK a DHCPREQUEST from a
! 610: RENEWING client, so we can punt on this issue. */
! 611:
! 612: if (!packet -> shared_network ||
! 613: (packet -> raw -> ciaddr.s_addr &&
! 614: packet -> raw -> giaddr.s_addr) ||
! 615: (have_requested_addr && !packet -> raw -> ciaddr.s_addr)) {
! 616:
! 617: /* If we don't know where it came from but we do know
! 618: where it claims to have come from, it didn't come
! 619: from there. */
! 620: if (!packet -> shared_network) {
! 621: if (subnet && subnet -> group -> authoritative) {
! 622: log_info ("%s: wrong network.", msgbuf);
! 623: nak_lease (packet, &cip);
! 624: goto out;
! 625: }
! 626: /* Otherwise, ignore it. */
! 627: log_info ("%s: ignored (%s).", msgbuf,
! 628: (subnet
! 629: ? "not authoritative" : "unknown subnet"));
! 630: goto out;
! 631: }
! 632:
! 633: /* If we do know where it came from and it asked for an
! 634: address that is not on that shared network, nak it. */
! 635: if (subnet)
! 636: subnet_dereference (&subnet, MDL);
! 637: if (!find_grouped_subnet (&subnet, packet -> shared_network,
! 638: cip, MDL)) {
! 639: if (packet -> shared_network -> group -> authoritative)
! 640: {
! 641: log_info ("%s: wrong network.", msgbuf);
! 642: nak_lease (packet, &cip);
! 643: goto out;
! 644: }
! 645: log_info ("%s: ignored (not authoritative).", msgbuf);
! 646: return;
! 647: }
! 648: }
! 649:
! 650: /* If the address the client asked for is ours, but it wasn't
! 651: available for the client, NAK it. */
! 652: if (!lease && ours) {
! 653: log_info ("%s: lease %s unavailable.", msgbuf, piaddr (cip));
! 654: nak_lease (packet, &cip);
! 655: goto out;
! 656: }
! 657:
! 658: /* Otherwise, send the lease to the client if we found one. */
! 659: if (lease) {
! 660: ack_lease (packet, lease, DHCPACK, 0, msgbuf, ms_nulltp,
! 661: (struct host_decl *)0);
! 662: } else
! 663: log_info ("%s: unknown lease %s.", msgbuf, piaddr (cip));
! 664:
! 665: out:
! 666: if (subnet)
! 667: subnet_dereference (&subnet, MDL);
! 668: if (lease)
! 669: lease_dereference (&lease, MDL);
! 670: return;
! 671: }
! 672:
! 673: void dhcprelease (packet, ms_nulltp)
! 674: struct packet *packet;
! 675: int ms_nulltp;
! 676: {
! 677: struct lease *lease = (struct lease *)0, *next = (struct lease *)0;
! 678: struct iaddr cip;
! 679: struct option_cache *oc;
! 680: struct data_string data;
! 681: const char *s;
! 682: char msgbuf [1024], cstr[16]; /* XXX */
! 683:
! 684:
! 685: /* DHCPRELEASE must not specify address in requested-address
! 686: option, but old protocol specs weren't explicit about this,
! 687: so let it go. */
! 688: if ((oc = lookup_option (&dhcp_universe, packet -> options,
! 689: DHO_DHCP_REQUESTED_ADDRESS))) {
! 690: log_info ("DHCPRELEASE from %s specified requested-address.",
! 691: print_hw_addr (packet -> raw -> htype,
! 692: packet -> raw -> hlen,
! 693: packet -> raw -> chaddr));
! 694: }
! 695:
! 696: oc = lookup_option (&dhcp_universe, packet -> options,
! 697: DHO_DHCP_CLIENT_IDENTIFIER);
! 698: memset (&data, 0, sizeof data);
! 699: if (oc &&
! 700: evaluate_option_cache (&data, packet, (struct lease *)0,
! 701: (struct client_state *)0,
! 702: packet -> options, (struct option_state *)0,
! 703: &global_scope, oc, MDL)) {
! 704: find_lease_by_uid (&lease, data.data, data.len, MDL);
! 705: data_string_forget (&data, MDL);
! 706:
! 707: /* See if we can find a lease that matches the IP address
! 708: the client is claiming. */
! 709: while (lease) {
! 710: if (lease -> n_uid)
! 711: lease_reference (&next, lease -> n_uid, MDL);
! 712: if (!memcmp (&packet -> raw -> ciaddr,
! 713: lease -> ip_addr.iabuf, 4)) {
! 714: break;
! 715: }
! 716: lease_dereference (&lease, MDL);
! 717: if (next) {
! 718: lease_reference (&lease, next, MDL);
! 719: lease_dereference (&next, MDL);
! 720: }
! 721: }
! 722: if (next)
! 723: lease_dereference (&next, MDL);
! 724: }
! 725:
! 726: /* The client is supposed to pass a valid client-identifier,
! 727: but the spec on this has changed historically, so try the
! 728: IP address in ciaddr if the client-identifier fails. */
! 729: if (!lease) {
! 730: cip.len = 4;
! 731: memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
! 732: find_lease_by_ip_addr (&lease, cip, MDL);
! 733: }
! 734:
! 735:
! 736: /* If the hardware address doesn't match, don't do the release. */
! 737: if (lease &&
! 738: (lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 ||
! 739: lease -> hardware_addr.hbuf [0] != packet -> raw -> htype ||
! 740: memcmp (&lease -> hardware_addr.hbuf [1],
! 741: packet -> raw -> chaddr, packet -> raw -> hlen)))
! 742: lease_dereference (&lease, MDL);
! 743:
! 744: if (lease && lease -> client_hostname) {
! 745: if ((strlen (lease -> client_hostname) <= 64) &&
! 746: db_printable((unsigned char *)lease->client_hostname))
! 747: s = lease -> client_hostname;
! 748: else
! 749: s = "Hostname Unsuitable for Printing";
! 750: } else
! 751: s = (char *)0;
! 752:
! 753: /* %Audit% Cannot exceed 16 bytes. %2004.06.17,Safe%
! 754: * We copy this out to stack because we actually want to log two
! 755: * inet_ntoa()'s in this message.
! 756: */
! 757: strncpy(cstr, inet_ntoa (packet -> raw -> ciaddr), 15);
! 758: cstr[15] = '\0';
! 759:
! 760: /* %Audit% This is log output. %2004.06.17,Safe%
! 761: * If we truncate we hope the user can get a hint from the log.
! 762: */
! 763: snprintf (msgbuf, sizeof msgbuf,
! 764: "DHCPRELEASE of %s from %s %s%s%svia %s (%sfound)",
! 765: cstr,
! 766: (packet -> raw -> htype
! 767: ? print_hw_addr (packet -> raw -> htype,
! 768: packet -> raw -> hlen,
! 769: packet -> raw -> chaddr)
! 770: : (lease
! 771: ? print_hex_1(lease->uid_len, lease->uid, 60)
! 772: : "<no identifier>")),
! 773: s ? "(" : "", s ? s : "", s ? ") " : "",
! 774: packet -> raw -> giaddr.s_addr
! 775: ? inet_ntoa (packet -> raw -> giaddr)
! 776: : packet -> interface -> name,
! 777: lease ? "" : "not ");
! 778:
! 779: #if defined (FAILOVER_PROTOCOL)
! 780: if (lease && lease -> pool && lease -> pool -> failover_peer) {
! 781: dhcp_failover_state_t *peer = lease -> pool -> failover_peer;
! 782: if (peer -> service_state == not_responding ||
! 783: peer -> service_state == service_startup) {
! 784: log_info ("%s: ignored%s",
! 785: peer -> name, peer -> nrr);
! 786: goto out;
! 787: }
! 788:
! 789: /* DHCPRELEASE messages are unicast, so if the client
! 790: sent the DHCPRELEASE to us, it's not going to send it
! 791: to the peer. Not sure why this would happen, and
! 792: if it does happen I think we still have to change the
! 793: lease state, so that's what we're doing.
! 794: XXX See what it says in the draft about this. */
! 795: }
! 796: #endif
! 797:
! 798: /* If we found a lease, release it. */
! 799: if (lease && lease -> ends > cur_time) {
! 800: release_lease (lease, packet);
! 801: }
! 802: log_info ("%s", msgbuf);
! 803: #if defined(FAILOVER_PROTOCOL)
! 804: out:
! 805: #endif
! 806: if (lease)
! 807: lease_dereference (&lease, MDL);
! 808: }
! 809:
! 810: void dhcpdecline (packet, ms_nulltp)
! 811: struct packet *packet;
! 812: int ms_nulltp;
! 813: {
! 814: struct lease *lease = (struct lease *)0;
! 815: struct option_state *options = (struct option_state *)0;
! 816: int ignorep = 0;
! 817: int i;
! 818: const char *status;
! 819: const char *s;
! 820: char msgbuf [1024]; /* XXX */
! 821: struct iaddr cip;
! 822: struct option_cache *oc;
! 823: struct data_string data;
! 824:
! 825: /* DHCPDECLINE must specify address. */
! 826: if (!(oc = lookup_option (&dhcp_universe, packet -> options,
! 827: DHO_DHCP_REQUESTED_ADDRESS)))
! 828: return;
! 829: memset (&data, 0, sizeof data);
! 830: if (!evaluate_option_cache (&data, packet, (struct lease *)0,
! 831: (struct client_state *)0,
! 832: packet -> options,
! 833: (struct option_state *)0,
! 834: &global_scope, oc, MDL))
! 835: return;
! 836:
! 837: cip.len = 4;
! 838: memcpy (cip.iabuf, data.data, 4);
! 839: data_string_forget (&data, MDL);
! 840: find_lease_by_ip_addr (&lease, cip, MDL);
! 841:
! 842: if (lease && lease -> client_hostname) {
! 843: if ((strlen (lease -> client_hostname) <= 64) &&
! 844: db_printable((unsigned char *)lease->client_hostname))
! 845: s = lease -> client_hostname;
! 846: else
! 847: s = "Hostname Unsuitable for Printing";
! 848: } else
! 849: s = (char *)0;
! 850:
! 851: /* %Audit% This is log output. %2004.06.17,Safe%
! 852: * If we truncate we hope the user can get a hint from the log.
! 853: */
! 854: snprintf (msgbuf, sizeof msgbuf,
! 855: "DHCPDECLINE of %s from %s %s%s%svia %s",
! 856: piaddr (cip),
! 857: (packet -> raw -> htype
! 858: ? print_hw_addr (packet -> raw -> htype,
! 859: packet -> raw -> hlen,
! 860: packet -> raw -> chaddr)
! 861: : (lease
! 862: ? print_hex_1(lease->uid_len, lease->uid, 60)
! 863: : "<no identifier>")),
! 864: s ? "(" : "", s ? s : "", s ? ") " : "",
! 865: packet -> raw -> giaddr.s_addr
! 866: ? inet_ntoa (packet -> raw -> giaddr)
! 867: : packet -> interface -> name);
! 868:
! 869: option_state_allocate (&options, MDL);
! 870:
! 871: /* Execute statements in scope starting with the subnet scope. */
! 872: if (lease)
! 873: execute_statements_in_scope ((struct binding_value **)0,
! 874: packet, (struct lease *)0,
! 875: (struct client_state *)0,
! 876: packet -> options, options,
! 877: &global_scope,
! 878: lease -> subnet -> group,
! 879: (struct group *)0);
! 880:
! 881: /* Execute statements in the class scopes. */
! 882: for (i = packet -> class_count; i > 0; i--) {
! 883: execute_statements_in_scope
! 884: ((struct binding_value **)0, packet, (struct lease *)0,
! 885: (struct client_state *)0, packet -> options, options,
! 886: &global_scope, packet -> classes [i - 1] -> group,
! 887: lease ? lease -> subnet -> group : (struct group *)0);
! 888: }
! 889:
! 890: /* Drop the request if dhcpdeclines are being ignored. */
! 891: oc = lookup_option (&server_universe, options, SV_DECLINES);
! 892: if (!oc ||
! 893: evaluate_boolean_option_cache (&ignorep, packet, lease,
! 894: (struct client_state *)0,
! 895: packet -> options, options,
! 896: &lease -> scope, oc, MDL)) {
! 897: /* If we found a lease, mark it as unusable and complain. */
! 898: if (lease) {
! 899: #if defined (FAILOVER_PROTOCOL)
! 900: if (lease -> pool && lease -> pool -> failover_peer) {
! 901: dhcp_failover_state_t *peer =
! 902: lease -> pool -> failover_peer;
! 903: if (peer -> service_state == not_responding ||
! 904: peer -> service_state == service_startup) {
! 905: if (!ignorep)
! 906: log_info ("%s: ignored%s",
! 907: peer -> name, peer -> nrr);
! 908: goto out;
! 909: }
! 910:
! 911: /* DHCPDECLINE messages are broadcast, so we can safely
! 912: ignore the DHCPDECLINE if the peer has the lease.
! 913: XXX Of course, at this point that information has been
! 914: lost. */
! 915: }
! 916: #endif
! 917:
! 918: abandon_lease (lease, "declined.");
! 919: status = "abandoned";
! 920: } else {
! 921: status = "not found";
! 922: }
! 923: } else
! 924: status = "ignored";
! 925:
! 926: if (!ignorep)
! 927: log_info ("%s: %s", msgbuf, status);
! 928:
! 929: #if defined(FAILOVER_PROTOCOL)
! 930: out:
! 931: #endif
! 932: if (options)
! 933: option_state_dereference (&options, MDL);
! 934: if (lease)
! 935: lease_dereference (&lease, MDL);
! 936: }
! 937:
! 938: void dhcpinform (packet, ms_nulltp)
! 939: struct packet *packet;
! 940: int ms_nulltp;
! 941: {
! 942: char msgbuf [1024];
! 943: struct data_string d1, prl;
! 944: struct option_cache *oc;
! 945: struct option_state *options = (struct option_state *)0;
! 946: struct dhcp_packet raw;
! 947: struct packet outgoing;
! 948: unsigned char dhcpack = DHCPACK;
! 949: struct subnet *subnet = NULL;
! 950: struct iaddr cip, gip;
! 951: unsigned i;
! 952: int nulltp;
! 953: struct sockaddr_in to;
! 954: struct in_addr from;
! 955: isc_boolean_t zeroed_ciaddr;
! 956:
! 957: /* The client should set ciaddr to its IP address, but apparently
! 958: it's common for clients not to do this, so we'll use their IP
! 959: source address if they didn't set ciaddr. */
! 960: if (!packet -> raw -> ciaddr.s_addr) {
! 961: zeroed_ciaddr = ISC_TRUE;
! 962: cip.len = 4;
! 963: memcpy (cip.iabuf, &packet -> client_addr.iabuf, 4);
! 964: } else {
! 965: zeroed_ciaddr = ISC_FALSE;
! 966: cip.len = 4;
! 967: memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
! 968: }
! 969:
! 970: if (packet->raw->giaddr.s_addr) {
! 971: gip.len = 4;
! 972: memcpy(gip.iabuf, &packet->raw->giaddr, 4);
! 973: } else
! 974: gip.len = 0;
! 975:
! 976: /* %Audit% This is log output. %2004.06.17,Safe%
! 977: * If we truncate we hope the user can get a hint from the log.
! 978: */
! 979: snprintf (msgbuf, sizeof msgbuf, "DHCPINFORM from %s via %s",
! 980: piaddr (cip), packet->raw->giaddr.s_addr ?
! 981: inet_ntoa(packet->raw->giaddr) :
! 982: packet -> interface -> name);
! 983:
! 984: /* If the IP source address is zero, don't respond. */
! 985: if (!memcmp (cip.iabuf, "\0\0\0", 4)) {
! 986: log_info ("%s: ignored (null source address).", msgbuf);
! 987: return;
! 988: }
! 989:
! 990: /* Find the subnet that the client is on. */
! 991: if (zeroed_ciaddr && (gip.len != 0)) {
! 992: /* XXX - do subnet selection relay agent suboption here */
! 993: find_subnet(&subnet, gip, MDL);
! 994:
! 995: if (subnet == NULL) {
! 996: log_info("%s: unknown subnet for relay address %s",
! 997: msgbuf, piaddr(gip));
! 998: return;
! 999: }
! 1000: } else {
! 1001: /* XXX - do subnet selection (not relay agent) option here */
! 1002: find_subnet(&subnet, cip, MDL);
! 1003:
! 1004: if (subnet == NULL) {
! 1005: log_info("%s: unknown subnet for %s address %s",
! 1006: msgbuf, zeroed_ciaddr ? "source" : "client",
! 1007: piaddr(cip));
! 1008: return;
! 1009: }
! 1010: }
! 1011:
! 1012: /* We don't respond to DHCPINFORM packets if we're not authoritative.
! 1013: It would be nice if a per-host value could override this, but
! 1014: there's overhead involved in checking this, so let's see how people
! 1015: react first. */
! 1016: if (subnet && !subnet -> group -> authoritative) {
! 1017: static int eso = 0;
! 1018: log_info ("%s: not authoritative for subnet %s",
! 1019: msgbuf, piaddr (subnet -> net));
! 1020: if (!eso) {
! 1021: log_info ("If this DHCP server is authoritative for%s",
! 1022: " that subnet,");
! 1023: log_info ("please write an `authoritative;' directi%s",
! 1024: "ve either in the");
! 1025: log_info ("subnet declaration or in some scope that%s",
! 1026: " encloses the");
! 1027: log_info ("subnet declaration - for example, write %s",
! 1028: "it at the top");
! 1029: log_info ("of the dhcpd.conf file.");
! 1030: }
! 1031: if (eso++ == 100)
! 1032: eso = 0;
! 1033: subnet_dereference (&subnet, MDL);
! 1034: return;
! 1035: }
! 1036:
! 1037: option_state_allocate (&options, MDL);
! 1038: memset (&outgoing, 0, sizeof outgoing);
! 1039: memset (&raw, 0, sizeof raw);
! 1040: outgoing.raw = &raw;
! 1041:
! 1042: /* Execute statements in scope starting with the subnet scope. */
! 1043: if (subnet)
! 1044: execute_statements_in_scope ((struct binding_value **)0,
! 1045: packet, (struct lease *)0,
! 1046: (struct client_state *)0,
! 1047: packet -> options, options,
! 1048: &global_scope, subnet -> group,
! 1049: (struct group *)0);
! 1050:
! 1051: /* Execute statements in the class scopes. */
! 1052: for (i = packet -> class_count; i > 0; i--) {
! 1053: execute_statements_in_scope
! 1054: ((struct binding_value **)0, packet, (struct lease *)0,
! 1055: (struct client_state *)0, packet -> options, options,
! 1056: &global_scope, packet -> classes [i - 1] -> group,
! 1057: subnet ? subnet -> group : (struct group *)0);
! 1058: }
! 1059:
! 1060: /* Figure out the filename. */
! 1061: memset (&d1, 0, sizeof d1);
! 1062: oc = lookup_option (&server_universe, options, SV_FILENAME);
! 1063: if (oc &&
! 1064: evaluate_option_cache (&d1, packet, (struct lease *)0,
! 1065: (struct client_state *)0,
! 1066: packet -> options, (struct option_state *)0,
! 1067: &global_scope, oc, MDL)) {
! 1068: i = d1.len;
! 1069: if (i >= sizeof(raw.file)) {
! 1070: log_info("file name longer than packet field "
! 1071: "truncated - field: %lu name: %d %.*s",
! 1072: (unsigned long)sizeof(raw.file), i, i,
! 1073: d1.data);
! 1074: i = sizeof(raw.file);
! 1075: } else
! 1076: raw.file[i] = 0;
! 1077: memcpy (raw.file, d1.data, i);
! 1078: data_string_forget (&d1, MDL);
! 1079: }
! 1080:
! 1081: /* Choose a server name as above. */
! 1082: oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
! 1083: if (oc &&
! 1084: evaluate_option_cache (&d1, packet, (struct lease *)0,
! 1085: (struct client_state *)0,
! 1086: packet -> options, (struct option_state *)0,
! 1087: &global_scope, oc, MDL)) {
! 1088: i = d1.len;
! 1089: if (i >= sizeof(raw.sname)) {
! 1090: log_info("server name longer than packet field "
! 1091: "truncated - field: %lu name: %d %.*s",
! 1092: (unsigned long)sizeof(raw.sname), i, i,
! 1093: d1.data);
! 1094: i = sizeof(raw.sname);
! 1095: } else
! 1096: raw.sname[i] = 0;
! 1097: memcpy (raw.sname, d1.data, i);
! 1098: data_string_forget (&d1, MDL);
! 1099: }
! 1100:
! 1101: /* Set a flag if this client is a lame Microsoft client that NUL
! 1102: terminates string options and expects us to do likewise. */
! 1103: nulltp = 0;
! 1104: if ((oc = lookup_option (&dhcp_universe, packet -> options,
! 1105: DHO_HOST_NAME))) {
! 1106: if (!oc->expression)
! 1107: nulltp = oc->flags & OPTION_HAD_NULLS;
! 1108: }
! 1109:
! 1110: /* Put in DHCP-specific options. */
! 1111: i = DHO_DHCP_MESSAGE_TYPE;
! 1112: oc = (struct option_cache *)0;
! 1113: if (option_cache_allocate (&oc, MDL)) {
! 1114: if (make_const_data (&oc -> expression,
! 1115: &dhcpack, 1, 0, 0, MDL)) {
! 1116: option_code_hash_lookup(&oc->option,
! 1117: dhcp_universe.code_hash,
! 1118: &i, 0, MDL);
! 1119: save_option (&dhcp_universe, options, oc);
! 1120: }
! 1121: option_cache_dereference (&oc, MDL);
! 1122: }
! 1123:
! 1124: get_server_source_address(&from, options, packet);
! 1125:
! 1126: /* Use the subnet mask from the subnet declaration if no other
! 1127: mask has been provided. */
! 1128: i = DHO_SUBNET_MASK;
! 1129: if (subnet && !lookup_option (&dhcp_universe, options, i)) {
! 1130: oc = (struct option_cache *)0;
! 1131: if (option_cache_allocate (&oc, MDL)) {
! 1132: if (make_const_data (&oc -> expression,
! 1133: subnet -> netmask.iabuf,
! 1134: subnet -> netmask.len,
! 1135: 0, 0, MDL)) {
! 1136: option_code_hash_lookup(&oc->option,
! 1137: dhcp_universe.code_hash,
! 1138: &i, 0, MDL);
! 1139: save_option (&dhcp_universe, options, oc);
! 1140: }
! 1141: option_cache_dereference (&oc, MDL);
! 1142: }
! 1143: }
! 1144:
! 1145: /* If a site option space has been specified, use that for
! 1146: site option codes. */
! 1147: i = SV_SITE_OPTION_SPACE;
! 1148: if ((oc = lookup_option (&server_universe, options, i)) &&
! 1149: evaluate_option_cache (&d1, packet, (struct lease *)0,
! 1150: (struct client_state *)0,
! 1151: packet -> options, options,
! 1152: &global_scope, oc, MDL)) {
! 1153: struct universe *u = (struct universe *)0;
! 1154:
! 1155: if (!universe_hash_lookup (&u, universe_hash,
! 1156: (const char *)d1.data, d1.len,
! 1157: MDL)) {
! 1158: log_error ("unknown option space %s.", d1.data);
! 1159: option_state_dereference (&options, MDL);
! 1160: if (subnet)
! 1161: subnet_dereference (&subnet, MDL);
! 1162: return;
! 1163: }
! 1164:
! 1165: options -> site_universe = u -> index;
! 1166: options->site_code_min = find_min_site_code(u);
! 1167: data_string_forget (&d1, MDL);
! 1168: } else {
! 1169: options -> site_universe = dhcp_universe.index;
! 1170: options -> site_code_min = 0; /* Trust me, it works. */
! 1171: }
! 1172:
! 1173: memset (&prl, 0, sizeof prl);
! 1174:
! 1175: /* Use the parameter list from the scope if there is one. */
! 1176: oc = lookup_option (&dhcp_universe, options,
! 1177: DHO_DHCP_PARAMETER_REQUEST_LIST);
! 1178:
! 1179: /* Otherwise, if the client has provided a list of options
! 1180: that it wishes returned, use it to prioritize. Otherwise,
! 1181: prioritize based on the default priority list. */
! 1182:
! 1183: if (!oc)
! 1184: oc = lookup_option (&dhcp_universe, packet -> options,
! 1185: DHO_DHCP_PARAMETER_REQUEST_LIST);
! 1186:
! 1187: if (oc)
! 1188: evaluate_option_cache (&prl, packet, (struct lease *)0,
! 1189: (struct client_state *)0,
! 1190: packet -> options, options,
! 1191: &global_scope, oc, MDL);
! 1192:
! 1193: #ifdef DEBUG_PACKET
! 1194: dump_packet (packet);
! 1195: dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
! 1196: #endif
! 1197:
! 1198: log_info ("%s", msgbuf);
! 1199:
! 1200: /* Figure out the address of the boot file server. */
! 1201: if ((oc =
! 1202: lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
! 1203: if (evaluate_option_cache (&d1, packet, (struct lease *)0,
! 1204: (struct client_state *)0,
! 1205: packet -> options, options,
! 1206: &global_scope, oc, MDL)) {
! 1207: /* If there was more than one answer,
! 1208: take the first. */
! 1209: if (d1.len >= 4 && d1.data)
! 1210: memcpy (&raw.siaddr, d1.data, 4);
! 1211: data_string_forget (&d1, MDL);
! 1212: }
! 1213: }
! 1214:
! 1215: /*
! 1216: * Remove any time options, per section 3.4 RFC 2131
! 1217: */
! 1218: delete_option(&dhcp_universe, options, DHO_DHCP_LEASE_TIME);
! 1219: delete_option(&dhcp_universe, options, DHO_DHCP_RENEWAL_TIME);
! 1220: delete_option(&dhcp_universe, options, DHO_DHCP_REBINDING_TIME);
! 1221:
! 1222: /* Set up the option buffer... */
! 1223: outgoing.packet_length =
! 1224: cons_options (packet, outgoing.raw, (struct lease *)0,
! 1225: (struct client_state *)0,
! 1226: 0, packet -> options, options, &global_scope,
! 1227: 0, nulltp, 0,
! 1228: prl.len ? &prl : (struct data_string *)0,
! 1229: (char *)0);
! 1230: option_state_dereference (&options, MDL);
! 1231: data_string_forget (&prl, MDL);
! 1232:
! 1233: /* Make sure that the packet is at least as big as a BOOTP packet. */
! 1234: if (outgoing.packet_length < BOOTP_MIN_LEN)
! 1235: outgoing.packet_length = BOOTP_MIN_LEN;
! 1236:
! 1237: raw.giaddr = packet -> raw -> giaddr;
! 1238: raw.ciaddr = packet -> raw -> ciaddr;
! 1239: memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
! 1240: raw.hlen = packet -> raw -> hlen;
! 1241: raw.htype = packet -> raw -> htype;
! 1242:
! 1243: raw.xid = packet -> raw -> xid;
! 1244: raw.secs = packet -> raw -> secs;
! 1245: raw.flags = packet -> raw -> flags;
! 1246: raw.hops = packet -> raw -> hops;
! 1247: raw.op = BOOTREPLY;
! 1248:
! 1249: #ifdef DEBUG_PACKET
! 1250: dump_packet (&outgoing);
! 1251: dump_raw ((unsigned char *)&raw, outgoing.packet_length);
! 1252: #endif
! 1253:
! 1254: /* Set up the common stuff... */
! 1255: to.sin_family = AF_INET;
! 1256: #ifdef HAVE_SA_LEN
! 1257: to.sin_len = sizeof to;
! 1258: #endif
! 1259: memset (to.sin_zero, 0, sizeof to.sin_zero);
! 1260:
! 1261: /* RFC2131 states the server SHOULD unciast to ciaddr.
! 1262: * There are two wrinkles - relays, and when ciaddr is zero.
! 1263: * There's actually no mention of relays at all in rfc2131 in
! 1264: * regard to DHCPINFORM, except to say we might get packets from
! 1265: * clients via them. Note: relays unicast to clients to the
! 1266: * "yiaddr" address, which servers are forbidden to set when
! 1267: * answering an inform.
! 1268: *
! 1269: * The solution: If ciaddr is zero, and giaddr is set, go via the
! 1270: * relay with the broadcast flag set to help the relay (with no
! 1271: * yiaddr and very likely no chaddr, it will have no idea where to
! 1272: * send the packet).
! 1273: *
! 1274: * If the ciaddr is zero and giaddr is not set, go via the source
! 1275: * IP address (but you are permitted to barf on their shoes).
! 1276: *
! 1277: * If ciaddr is not zero, send the packet there always.
! 1278: */
! 1279: if (!raw.ciaddr.s_addr && gip.len) {
! 1280: memcpy(&to.sin_addr, gip.iabuf, 4);
! 1281: to.sin_port = local_port;
! 1282: raw.flags |= htons(BOOTP_BROADCAST);
! 1283: } else {
! 1284: gip.len = 0;
! 1285: memcpy(&to.sin_addr, cip.iabuf, 4);
! 1286: to.sin_port = remote_port;
! 1287: }
! 1288:
! 1289: /* Report what we're sending. */
! 1290: snprintf(msgbuf, sizeof msgbuf, "DHCPACK to %s (%s) via", piaddr(cip),
! 1291: (packet->raw->htype && packet->raw->hlen) ?
! 1292: print_hw_addr(packet->raw->htype, packet->raw->hlen,
! 1293: packet->raw->chaddr) :
! 1294: "<no client hardware address>");
! 1295: log_info("%s %s", msgbuf, gip.len ? piaddr(gip) :
! 1296: packet->interface->name);
! 1297:
! 1298: errno = 0;
! 1299: send_packet ((fallback_interface
! 1300: ? fallback_interface : packet -> interface),
! 1301: &outgoing, &raw, outgoing.packet_length,
! 1302: from, &to, (struct hardware *)0);
! 1303: if (subnet)
! 1304: subnet_dereference (&subnet, MDL);
! 1305: }
! 1306:
! 1307: void nak_lease (packet, cip)
! 1308: struct packet *packet;
! 1309: struct iaddr *cip;
! 1310: {
! 1311: struct sockaddr_in to;
! 1312: struct in_addr from;
! 1313: int result;
! 1314: struct dhcp_packet raw;
! 1315: unsigned char nak = DHCPNAK;
! 1316: struct packet outgoing;
! 1317: struct hardware hto;
! 1318: unsigned i;
! 1319: struct option_state *options = (struct option_state *)0;
! 1320: struct option_cache *oc = (struct option_cache *)0;
! 1321:
! 1322: option_state_allocate (&options, MDL);
! 1323: memset (&outgoing, 0, sizeof outgoing);
! 1324: memset (&raw, 0, sizeof raw);
! 1325: outgoing.raw = &raw;
! 1326:
! 1327: /* Set DHCP_MESSAGE_TYPE to DHCPNAK */
! 1328: if (!option_cache_allocate (&oc, MDL)) {
! 1329: log_error ("No memory for DHCPNAK message type.");
! 1330: option_state_dereference (&options, MDL);
! 1331: return;
! 1332: }
! 1333: if (!make_const_data (&oc -> expression, &nak, sizeof nak,
! 1334: 0, 0, MDL)) {
! 1335: log_error ("No memory for expr_const expression.");
! 1336: option_cache_dereference (&oc, MDL);
! 1337: option_state_dereference (&options, MDL);
! 1338: return;
! 1339: }
! 1340: i = DHO_DHCP_MESSAGE_TYPE;
! 1341: option_code_hash_lookup(&oc->option, dhcp_universe.code_hash,
! 1342: &i, 0, MDL);
! 1343: save_option (&dhcp_universe, options, oc);
! 1344: option_cache_dereference (&oc, MDL);
! 1345:
! 1346: /* Set DHCP_MESSAGE to whatever the message is */
! 1347: if (!option_cache_allocate (&oc, MDL)) {
! 1348: log_error ("No memory for DHCPNAK message type.");
! 1349: option_state_dereference (&options, MDL);
! 1350: return;
! 1351: }
! 1352: if (!make_const_data (&oc -> expression,
! 1353: (unsigned char *)dhcp_message,
! 1354: strlen (dhcp_message), 1, 0, MDL)) {
! 1355: log_error ("No memory for expr_const expression.");
! 1356: option_cache_dereference (&oc, MDL);
! 1357: option_state_dereference (&options, MDL);
! 1358: return;
! 1359: }
! 1360: i = DHO_DHCP_MESSAGE;
! 1361: option_code_hash_lookup(&oc->option, dhcp_universe.code_hash,
! 1362: &i, 0, MDL);
! 1363: save_option (&dhcp_universe, options, oc);
! 1364: option_cache_dereference (&oc, MDL);
! 1365:
! 1366: get_server_source_address(&from, options, packet);
! 1367:
! 1368: /* If there were agent options in the incoming packet, return
! 1369: * them. We do not check giaddr to detect the presence of a
! 1370: * relay, as this excludes "l2" relay agents which have no
! 1371: * giaddr to set.
! 1372: */
! 1373: if (packet->options->universe_count > agent_universe.index &&
! 1374: packet->options->universes [agent_universe.index]) {
! 1375: option_chain_head_reference
! 1376: ((struct option_chain_head **)
! 1377: &(options -> universes [agent_universe.index]),
! 1378: (struct option_chain_head *)
! 1379: packet -> options -> universes [agent_universe.index],
! 1380: MDL);
! 1381: }
! 1382:
! 1383: /* Do not use the client's requested parameter list. */
! 1384: delete_option (&dhcp_universe, packet -> options,
! 1385: DHO_DHCP_PARAMETER_REQUEST_LIST);
! 1386:
! 1387: /* Set up the option buffer... */
! 1388: outgoing.packet_length =
! 1389: cons_options (packet, outgoing.raw, (struct lease *)0,
! 1390: (struct client_state *)0,
! 1391: 0, packet -> options, options, &global_scope,
! 1392: 0, 0, 0, (struct data_string *)0, (char *)0);
! 1393: option_state_dereference (&options, MDL);
! 1394:
! 1395: /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
! 1396: if (packet->interface->address_count)
! 1397: raw.siaddr = packet->interface->addresses[0];
! 1398: raw.giaddr = packet -> raw -> giaddr;
! 1399: memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
! 1400: raw.hlen = packet -> raw -> hlen;
! 1401: raw.htype = packet -> raw -> htype;
! 1402:
! 1403: raw.xid = packet -> raw -> xid;
! 1404: raw.secs = packet -> raw -> secs;
! 1405: raw.flags = packet -> raw -> flags | htons (BOOTP_BROADCAST);
! 1406: raw.hops = packet -> raw -> hops;
! 1407: raw.op = BOOTREPLY;
! 1408:
! 1409: /* Report what we're sending... */
! 1410: log_info ("DHCPNAK on %s to %s via %s",
! 1411: piaddr (*cip),
! 1412: print_hw_addr (packet -> raw -> htype,
! 1413: packet -> raw -> hlen,
! 1414: packet -> raw -> chaddr),
! 1415: packet -> raw -> giaddr.s_addr
! 1416: ? inet_ntoa (packet -> raw -> giaddr)
! 1417: : packet -> interface -> name);
! 1418:
! 1419:
! 1420:
! 1421: #ifdef DEBUG_PACKET
! 1422: dump_packet (packet);
! 1423: dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
! 1424: dump_packet (&outgoing);
! 1425: dump_raw ((unsigned char *)&raw, outgoing.packet_length);
! 1426: #endif
! 1427:
! 1428: #if 0
! 1429: hto.hbuf [0] = packet -> raw -> htype;
! 1430: hto.hlen = packet -> raw -> hlen;
! 1431: memcpy (&hto.hbuf [1], packet -> raw -> chaddr, hto.hlen);
! 1432: hto.hlen++;
! 1433: #endif
! 1434:
! 1435: /* Set up the common stuff... */
! 1436: to.sin_family = AF_INET;
! 1437: #ifdef HAVE_SA_LEN
! 1438: to.sin_len = sizeof to;
! 1439: #endif
! 1440: memset (to.sin_zero, 0, sizeof to.sin_zero);
! 1441:
! 1442: /* Make sure that the packet is at least as big as a BOOTP packet. */
! 1443: if (outgoing.packet_length < BOOTP_MIN_LEN)
! 1444: outgoing.packet_length = BOOTP_MIN_LEN;
! 1445:
! 1446: /* If this was gatewayed, send it back to the gateway.
! 1447: Otherwise, broadcast it on the local network. */
! 1448: if (raw.giaddr.s_addr) {
! 1449: to.sin_addr = raw.giaddr;
! 1450: if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK))
! 1451: to.sin_port = local_port;
! 1452: else
! 1453: to.sin_port = remote_port; /* for testing. */
! 1454:
! 1455: if (fallback_interface) {
! 1456: result = send_packet (fallback_interface,
! 1457: packet, &raw,
! 1458: outgoing.packet_length,
! 1459: from, &to, &hto);
! 1460: return;
! 1461: }
! 1462: } else {
! 1463: to.sin_addr = limited_broadcast;
! 1464: to.sin_port = remote_port;
! 1465: }
! 1466:
! 1467: errno = 0;
! 1468: result = send_packet (packet -> interface,
! 1469: packet, &raw, outgoing.packet_length,
! 1470: from, &to, (struct hardware *)0);
! 1471: }
! 1472:
! 1473: void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
! 1474: struct packet *packet;
! 1475: struct lease *lease;
! 1476: unsigned int offer;
! 1477: TIME when;
! 1478: char *msg;
! 1479: int ms_nulltp;
! 1480: struct host_decl *hp;
! 1481: {
! 1482: struct lease *lt;
! 1483: struct lease_state *state;
! 1484: struct lease *next;
! 1485: struct host_decl *host = (struct host_decl *)0;
! 1486: TIME lease_time;
! 1487: TIME offered_lease_time;
! 1488: struct data_string d1;
! 1489: TIME min_lease_time;
! 1490: TIME max_lease_time;
! 1491: TIME default_lease_time;
! 1492: struct option_cache *oc;
! 1493: isc_result_t result;
! 1494: TIME ping_timeout;
! 1495: TIME lease_cltt;
! 1496: struct in_addr from;
! 1497: TIME remaining_time;
! 1498: struct iaddr cip;
! 1499:
! 1500: unsigned i, j;
! 1501: int s1;
! 1502: int ignorep;
! 1503: struct timeval tv;
! 1504:
! 1505: /* If we're already acking this lease, don't do it again. */
! 1506: if (lease -> state)
! 1507: return;
! 1508:
! 1509: /* Save original cltt for comparison later. */
! 1510: lease_cltt = lease->cltt;
! 1511:
! 1512: /* If the lease carries a host record, remember it. */
! 1513: if (hp)
! 1514: host_reference (&host, hp, MDL);
! 1515: else if (lease -> host)
! 1516: host_reference (&host, lease -> host, MDL);
! 1517:
! 1518: /* Allocate a lease state structure... */
! 1519: state = new_lease_state (MDL);
! 1520: if (!state)
! 1521: log_fatal ("unable to allocate lease state!");
! 1522: state -> got_requested_address = packet -> got_requested_address;
! 1523: shared_network_reference (&state -> shared_network,
! 1524: packet -> interface -> shared_network, MDL);
! 1525:
! 1526: /* See if we got a server identifier option. */
! 1527: if (lookup_option (&dhcp_universe,
! 1528: packet -> options, DHO_DHCP_SERVER_IDENTIFIER))
! 1529: state -> got_server_identifier = 1;
! 1530:
! 1531: /* If there were agent options in the incoming packet, return
! 1532: * them. Do not return the agent options if they were stashed
! 1533: * on the lease. We do not check giaddr to detect the presence of
! 1534: * a relay, as this excludes "l2" relay agents which have no giaddr
! 1535: * to set.
! 1536: *
! 1537: * XXX: If the user configures options for the relay agent information
! 1538: * (state->options->universes[agent_universe.index] is not NULL),
! 1539: * we're still required to duplicate other values provided by the
! 1540: * relay agent. So we need to merge the old values not configured
! 1541: * by the user into the new state, not just give up.
! 1542: */
! 1543: if (!packet->agent_options_stashed &&
! 1544: (packet->options != NULL) &&
! 1545: packet->options->universe_count > agent_universe.index &&
! 1546: packet->options->universes[agent_universe.index] != NULL &&
! 1547: (state->options->universe_count <= agent_universe.index ||
! 1548: state->options->universes[agent_universe.index] == NULL)) {
! 1549: option_chain_head_reference
! 1550: ((struct option_chain_head **)
! 1551: &(state -> options -> universes [agent_universe.index]),
! 1552: (struct option_chain_head *)
! 1553: packet -> options -> universes [agent_universe.index],
! 1554: MDL);
! 1555:
! 1556: if (state->options->universe_count <= agent_universe.index)
! 1557: state->options->universe_count =
! 1558: agent_universe.index + 1;
! 1559: }
! 1560:
! 1561: /* If we are offering a lease that is still currently valid, preserve
! 1562: the events. We need to do this because if the client does not
! 1563: REQUEST our offer, it will expire in 2 minutes, overriding the
! 1564: expire time in the currently in force lease. We want the expire
! 1565: events to be executed at that point. */
! 1566: if (lease -> ends <= cur_time && offer != DHCPOFFER) {
! 1567: /* Get rid of any old expiry or release statements - by
! 1568: executing the statements below, we will be inserting new
! 1569: ones if there are any to insert. */
! 1570: if (lease -> on_expiry)
! 1571: executable_statement_dereference (&lease -> on_expiry,
! 1572: MDL);
! 1573: if (lease -> on_commit)
! 1574: executable_statement_dereference (&lease -> on_commit,
! 1575: MDL);
! 1576: if (lease -> on_release)
! 1577: executable_statement_dereference (&lease -> on_release,
! 1578: MDL);
! 1579: }
! 1580:
! 1581: /* Execute statements in scope starting with the subnet scope. */
! 1582: execute_statements_in_scope ((struct binding_value **)0,
! 1583: packet, lease, (struct client_state *)0,
! 1584: packet -> options,
! 1585: state -> options, &lease -> scope,
! 1586: lease -> subnet -> group,
! 1587: (struct group *)0);
! 1588:
! 1589: /* If the lease is from a pool, run the pool scope. */
! 1590: if (lease -> pool)
! 1591: (execute_statements_in_scope
! 1592: ((struct binding_value **)0, packet, lease,
! 1593: (struct client_state *)0, packet -> options,
! 1594: state -> options, &lease -> scope, lease -> pool -> group,
! 1595: lease -> pool -> shared_network -> group));
! 1596:
! 1597: /* Execute statements from class scopes. */
! 1598: for (i = packet -> class_count; i > 0; i--) {
! 1599: execute_statements_in_scope
! 1600: ((struct binding_value **)0,
! 1601: packet, lease, (struct client_state *)0,
! 1602: packet -> options, state -> options,
! 1603: &lease -> scope, packet -> classes [i - 1] -> group,
! 1604: (lease -> pool
! 1605: ? lease -> pool -> group
! 1606: : lease -> subnet -> group));
! 1607: }
! 1608:
! 1609: /* See if the client is only supposed to have one lease at a time,
! 1610: and if so, find its other leases and release them. We can only
! 1611: do this on DHCPREQUEST. It's a little weird to do this before
! 1612: looking at permissions, because the client might not actually
! 1613: _get_ a lease after we've done the permission check, but the
! 1614: assumption for this option is that the client has exactly one
! 1615: network interface, and will only ever remember one lease. So
! 1616: if it sends a DHCPREQUEST, and doesn't get the lease, it's already
! 1617: forgotten about its old lease, so we can too. */
! 1618: if (packet -> packet_type == DHCPREQUEST &&
! 1619: (oc = lookup_option (&server_universe, state -> options,
! 1620: SV_ONE_LEASE_PER_CLIENT)) &&
! 1621: evaluate_boolean_option_cache (&ignorep,
! 1622: packet, lease,
! 1623: (struct client_state *)0,
! 1624: packet -> options,
! 1625: state -> options, &lease -> scope,
! 1626: oc, MDL)) {
! 1627: struct lease *seek;
! 1628: if (lease -> uid_len) {
! 1629: do {
! 1630: seek = (struct lease *)0;
! 1631: find_lease_by_uid (&seek, lease -> uid,
! 1632: lease -> uid_len, MDL);
! 1633: if (!seek)
! 1634: break;
! 1635: if (seek == lease && !seek -> n_uid) {
! 1636: lease_dereference (&seek, MDL);
! 1637: break;
! 1638: }
! 1639: next = (struct lease *)0;
! 1640:
! 1641: /* Don't release expired leases, and don't
! 1642: release the lease we're going to assign. */
! 1643: next = (struct lease *)0;
! 1644: while (seek) {
! 1645: if (seek -> n_uid)
! 1646: lease_reference (&next, seek -> n_uid, MDL);
! 1647: if (seek != lease &&
! 1648: seek -> binding_state != FTS_RELEASED &&
! 1649: seek -> binding_state != FTS_EXPIRED &&
! 1650: seek -> binding_state != FTS_RESET &&
! 1651: seek -> binding_state != FTS_FREE &&
! 1652: seek -> binding_state != FTS_BACKUP)
! 1653: break;
! 1654: lease_dereference (&seek, MDL);
! 1655: if (next) {
! 1656: lease_reference (&seek, next, MDL);
! 1657: lease_dereference (&next, MDL);
! 1658: }
! 1659: }
! 1660: if (next)
! 1661: lease_dereference (&next, MDL);
! 1662: if (seek) {
! 1663: release_lease (seek, packet);
! 1664: lease_dereference (&seek, MDL);
! 1665: } else
! 1666: break;
! 1667: } while (1);
! 1668: }
! 1669: if (!lease -> uid_len ||
! 1670: (host &&
! 1671: !host -> client_identifier.len &&
! 1672: (oc = lookup_option (&server_universe, state -> options,
! 1673: SV_DUPLICATES)) &&
! 1674: !evaluate_boolean_option_cache (&ignorep, packet, lease,
! 1675: (struct client_state *)0,
! 1676: packet -> options,
! 1677: state -> options,
! 1678: &lease -> scope,
! 1679: oc, MDL))) {
! 1680: do {
! 1681: seek = (struct lease *)0;
! 1682: find_lease_by_hw_addr
! 1683: (&seek, lease -> hardware_addr.hbuf,
! 1684: lease -> hardware_addr.hlen, MDL);
! 1685: if (!seek)
! 1686: break;
! 1687: if (seek == lease && !seek -> n_hw) {
! 1688: lease_dereference (&seek, MDL);
! 1689: break;
! 1690: }
! 1691: next = (struct lease *)0;
! 1692: while (seek) {
! 1693: if (seek -> n_hw)
! 1694: lease_reference (&next, seek -> n_hw, MDL);
! 1695: if (seek != lease &&
! 1696: seek -> binding_state != FTS_RELEASED &&
! 1697: seek -> binding_state != FTS_EXPIRED &&
! 1698: seek -> binding_state != FTS_RESET &&
! 1699: seek -> binding_state != FTS_FREE &&
! 1700: seek -> binding_state != FTS_BACKUP)
! 1701: break;
! 1702: lease_dereference (&seek, MDL);
! 1703: if (next) {
! 1704: lease_reference (&seek, next, MDL);
! 1705: lease_dereference (&next, MDL);
! 1706: }
! 1707: }
! 1708: if (next)
! 1709: lease_dereference (&next, MDL);
! 1710: if (seek) {
! 1711: release_lease (seek, packet);
! 1712: lease_dereference (&seek, MDL);
! 1713: } else
! 1714: break;
! 1715: } while (1);
! 1716: }
! 1717: }
! 1718:
! 1719:
! 1720: /* Make sure this packet satisfies the configured minimum
! 1721: number of seconds. */
! 1722: memset (&d1, 0, sizeof d1);
! 1723: if (offer == DHCPOFFER &&
! 1724: (oc = lookup_option (&server_universe, state -> options,
! 1725: SV_MIN_SECS))) {
! 1726: if (evaluate_option_cache (&d1, packet, lease,
! 1727: (struct client_state *)0,
! 1728: packet -> options, state -> options,
! 1729: &lease -> scope, oc, MDL)) {
! 1730: if (d1.len &&
! 1731: ntohs (packet -> raw -> secs) < d1.data [0]) {
! 1732: log_info("%s: configured min-secs value (%d) "
! 1733: "is greater than secs field (%d). "
! 1734: "message dropped.", msg, d1.data[0],
! 1735: ntohs(packet->raw->secs));
! 1736: data_string_forget (&d1, MDL);
! 1737: free_lease_state (state, MDL);
! 1738: if (host)
! 1739: host_dereference (&host, MDL);
! 1740: return;
! 1741: }
! 1742: data_string_forget (&d1, MDL);
! 1743: }
! 1744: }
! 1745:
! 1746: /* Try to find a matching host declaration for this lease.
! 1747: */
! 1748: if (!host) {
! 1749: struct host_decl *hp = (struct host_decl *)0;
! 1750: struct host_decl *h;
! 1751:
! 1752: /* Try to find a host_decl that matches the client
! 1753: identifier or hardware address on the packet, and
! 1754: has no fixed IP address. If there is one, hang
! 1755: it off the lease so that its option definitions
! 1756: can be used. */
! 1757: oc = lookup_option (&dhcp_universe, packet -> options,
! 1758: DHO_DHCP_CLIENT_IDENTIFIER);
! 1759: if (oc &&
! 1760: evaluate_option_cache (&d1, packet, lease,
! 1761: (struct client_state *)0,
! 1762: packet -> options, state -> options,
! 1763: &lease -> scope, oc, MDL)) {
! 1764: find_hosts_by_uid (&hp, d1.data, d1.len, MDL);
! 1765: data_string_forget (&d1, MDL);
! 1766: for (h = hp; h; h = h -> n_ipaddr) {
! 1767: if (!h -> fixed_addr)
! 1768: break;
! 1769: }
! 1770: if (h)
! 1771: host_reference (&host, h, MDL);
! 1772: if (hp != NULL)
! 1773: host_dereference(&hp, MDL);
! 1774: }
! 1775: if (!host) {
! 1776: find_hosts_by_haddr (&hp,
! 1777: packet -> raw -> htype,
! 1778: packet -> raw -> chaddr,
! 1779: packet -> raw -> hlen,
! 1780: MDL);
! 1781: for (h = hp; h; h = h -> n_ipaddr) {
! 1782: if (!h -> fixed_addr)
! 1783: break;
! 1784: }
! 1785: if (h)
! 1786: host_reference (&host, h, MDL);
! 1787: if (hp != NULL)
! 1788: host_dereference(&hp, MDL);
! 1789: }
! 1790: }
! 1791:
! 1792: /* If we have a host_decl structure, run the options associated
! 1793: with its group. Whether the host decl struct is old or not. */
! 1794: if (host)
! 1795: execute_statements_in_scope ((struct binding_value **)0,
! 1796: packet, lease,
! 1797: (struct client_state *)0,
! 1798: packet -> options,
! 1799: state -> options, &lease -> scope,
! 1800: host -> group,
! 1801: (lease -> pool
! 1802: ? lease -> pool -> group
! 1803: : lease -> subnet -> group));
! 1804:
! 1805: /* Drop the request if it's not allowed for this client. By
! 1806: default, unknown clients are allowed. */
! 1807: if (!host &&
! 1808: (oc = lookup_option (&server_universe, state -> options,
! 1809: SV_BOOT_UNKNOWN_CLIENTS)) &&
! 1810: !evaluate_boolean_option_cache (&ignorep,
! 1811: packet, lease,
! 1812: (struct client_state *)0,
! 1813: packet -> options,
! 1814: state -> options,
! 1815: &lease -> scope, oc, MDL)) {
! 1816: if (!ignorep)
! 1817: log_info ("%s: unknown client", msg);
! 1818: free_lease_state (state, MDL);
! 1819: if (host)
! 1820: host_dereference (&host, MDL);
! 1821: return;
! 1822: }
! 1823:
! 1824: /* Drop the request if it's not allowed for this client. */
! 1825: if (!offer &&
! 1826: (oc = lookup_option (&server_universe, state -> options,
! 1827: SV_ALLOW_BOOTP)) &&
! 1828: !evaluate_boolean_option_cache (&ignorep,
! 1829: packet, lease,
! 1830: (struct client_state *)0,
! 1831: packet -> options,
! 1832: state -> options,
! 1833: &lease -> scope, oc, MDL)) {
! 1834: if (!ignorep)
! 1835: log_info ("%s: bootp disallowed", msg);
! 1836: free_lease_state (state, MDL);
! 1837: if (host)
! 1838: host_dereference (&host, MDL);
! 1839: return;
! 1840: }
! 1841:
! 1842: /* Drop the request if booting is specifically denied. */
! 1843: oc = lookup_option (&server_universe, state -> options,
! 1844: SV_ALLOW_BOOTING);
! 1845: if (oc &&
! 1846: !evaluate_boolean_option_cache (&ignorep,
! 1847: packet, lease,
! 1848: (struct client_state *)0,
! 1849: packet -> options,
! 1850: state -> options,
! 1851: &lease -> scope, oc, MDL)) {
! 1852: if (!ignorep)
! 1853: log_info ("%s: booting disallowed", msg);
! 1854: free_lease_state (state, MDL);
! 1855: if (host)
! 1856: host_dereference (&host, MDL);
! 1857: return;
! 1858: }
! 1859:
! 1860: /* If we are configured to do per-class billing, do it. */
! 1861: if (have_billing_classes && !(lease -> flags & STATIC_LEASE)) {
! 1862: /* See if the lease is currently being billed to a
! 1863: class, and if so, whether or not it can continue to
! 1864: be billed to that class. */
! 1865: if (lease -> billing_class) {
! 1866: for (i = 0; i < packet -> class_count; i++)
! 1867: if (packet -> classes [i] ==
! 1868: lease -> billing_class)
! 1869: break;
! 1870: if (i == packet -> class_count)
! 1871: unbill_class (lease, lease -> billing_class);
! 1872: }
! 1873:
! 1874: /* If we don't have an active billing, see if we need
! 1875: one, and if we do, try to do so. */
! 1876: if (lease->billing_class == NULL) {
! 1877: int bill = 0;
! 1878: for (i = 0; i < packet->class_count; i++) {
! 1879: if (packet->classes[i]->lease_limit) {
! 1880: bill++;
! 1881: if (bill_class(lease,
! 1882: packet->classes[i]))
! 1883: break;
! 1884: }
! 1885: }
! 1886: if (bill != 0 && i == packet->class_count) {
! 1887: log_info("%s: no available billing: lease "
! 1888: "limit reached in all matching "
! 1889: "classes", msg);
! 1890: free_lease_state(state, MDL);
! 1891: if (host)
! 1892: host_dereference(&host, MDL);
! 1893: return;
! 1894: }
! 1895:
! 1896: /* If this is an offer, undo the billing. We go
! 1897: * through all the steps above to bill a class so
! 1898: * we can hit the 'no available billing' mark and
! 1899: * abort without offering. But it just doesn't make
! 1900: * sense to permanently bill a class for a non-active
! 1901: * lease. This means on REQUEST, we will bill this
! 1902: * lease again (if there is a REQUEST).
! 1903: */
! 1904: if (offer == DHCPOFFER &&
! 1905: lease->billing_class != NULL &&
! 1906: lease->binding_state != FTS_ACTIVE)
! 1907: unbill_class(lease, lease->billing_class);
! 1908: }
! 1909: }
! 1910:
! 1911: /* Figure out the filename. */
! 1912: oc = lookup_option (&server_universe, state -> options, SV_FILENAME);
! 1913: if (oc)
! 1914: evaluate_option_cache (&state -> filename, packet, lease,
! 1915: (struct client_state *)0,
! 1916: packet -> options, state -> options,
! 1917: &lease -> scope, oc, MDL);
! 1918:
! 1919: /* Choose a server name as above. */
! 1920: oc = lookup_option (&server_universe, state -> options,
! 1921: SV_SERVER_NAME);
! 1922: if (oc)
! 1923: evaluate_option_cache (&state -> server_name, packet, lease,
! 1924: (struct client_state *)0,
! 1925: packet -> options, state -> options,
! 1926: &lease -> scope, oc, MDL);
! 1927:
! 1928: /* At this point, we have a lease that we can offer the client.
! 1929: Now we construct a lease structure that contains what we want,
! 1930: and call supersede_lease to do the right thing with it. */
! 1931: lt = (struct lease *)0;
! 1932: result = lease_allocate (<, MDL);
! 1933: if (result != ISC_R_SUCCESS) {
! 1934: log_info ("%s: can't allocate temporary lease structure: %s",
! 1935: msg, isc_result_totext (result));
! 1936: free_lease_state (state, MDL);
! 1937: if (host)
! 1938: host_dereference (&host, MDL);
! 1939: return;
! 1940: }
! 1941:
! 1942: /* Use the ip address of the lease that we finally found in
! 1943: the database. */
! 1944: lt -> ip_addr = lease -> ip_addr;
! 1945:
! 1946: /* Start now. */
! 1947: lt -> starts = cur_time;
! 1948:
! 1949: /* Figure out how long a lease to assign. If this is a
! 1950: dynamic BOOTP lease, its duration must be infinite. */
! 1951: if (offer) {
! 1952: lt->flags &= ~BOOTP_LEASE;
! 1953:
! 1954: default_lease_time = DEFAULT_DEFAULT_LEASE_TIME;
! 1955: if ((oc = lookup_option (&server_universe, state -> options,
! 1956: SV_DEFAULT_LEASE_TIME))) {
! 1957: if (evaluate_option_cache (&d1, packet, lease,
! 1958: (struct client_state *)0,
! 1959: packet -> options,
! 1960: state -> options,
! 1961: &lease -> scope, oc, MDL)) {
! 1962: if (d1.len == sizeof (u_int32_t))
! 1963: default_lease_time =
! 1964: getULong (d1.data);
! 1965: data_string_forget (&d1, MDL);
! 1966: }
! 1967: }
! 1968:
! 1969: if ((oc = lookup_option (&dhcp_universe, packet -> options,
! 1970: DHO_DHCP_LEASE_TIME)))
! 1971: s1 = evaluate_option_cache (&d1, packet, lease,
! 1972: (struct client_state *)0,
! 1973: packet -> options,
! 1974: state -> options,
! 1975: &lease -> scope, oc, MDL);
! 1976: else
! 1977: s1 = 0;
! 1978:
! 1979: if (s1 && (d1.len == 4)) {
! 1980: u_int32_t ones = 0xffffffff;
! 1981:
! 1982: /* One potential use of reserved leases is to allow
! 1983: * clients to signal reservation of their lease. They
! 1984: * can kinda sorta do this, if you squint hard enough,
! 1985: * by supplying an 'infinite' requested-lease-time
! 1986: * option. This is generally bad practice...you want
! 1987: * clients to return to the server on at least some
! 1988: * period (days, months, years) to get up-to-date
! 1989: * config state. So;
! 1990: *
! 1991: * 1) A client requests 0xffffffff lease-time.
! 1992: * 2) The server reserves the lease, and assigns a
! 1993: * <= max_lease_time lease-time to the client, which
! 1994: * we presume is much smaller than 0xffffffff.
! 1995: * 3) The client ultimately fails to renew its lease
! 1996: * (all clients go offline at some point).
! 1997: * 4) The server retains the reservation, although
! 1998: * the lease expires and passes through those states
! 1999: * as normal, it's placed in the 'reserved' queue,
! 2000: * and is under no circumstances allocated to any
! 2001: * clients.
! 2002: *
! 2003: * Whether the client knows its reserving its lease or
! 2004: * not, this can be a handy tool for a sysadmin.
! 2005: */
! 2006: if ((memcmp(d1.data, &ones, 4) == 0) &&
! 2007: (oc = lookup_option(&server_universe,
! 2008: state->options,
! 2009: SV_RESERVE_INFINITE)) &&
! 2010: evaluate_boolean_option_cache(&ignorep, packet,
! 2011: lease, NULL, packet->options,
! 2012: state->options, &lease->scope,
! 2013: oc, MDL)) {
! 2014: lt->flags |= RESERVED_LEASE;
! 2015: if (!ignorep)
! 2016: log_info("Infinite-leasetime "
! 2017: "reservation made on %s.",
! 2018: piaddr(lt->ip_addr));
! 2019: }
! 2020:
! 2021: lease_time = getULong (d1.data);
! 2022: } else
! 2023: lease_time = default_lease_time;
! 2024:
! 2025: if (s1)
! 2026: data_string_forget(&d1, MDL);
! 2027:
! 2028: /* See if there's a maximum lease time. */
! 2029: max_lease_time = DEFAULT_MAX_LEASE_TIME;
! 2030: if ((oc = lookup_option (&server_universe, state -> options,
! 2031: SV_MAX_LEASE_TIME))) {
! 2032: if (evaluate_option_cache (&d1, packet, lease,
! 2033: (struct client_state *)0,
! 2034: packet -> options,
! 2035: state -> options,
! 2036: &lease -> scope, oc, MDL)) {
! 2037: if (d1.len == sizeof (u_int32_t))
! 2038: max_lease_time =
! 2039: getULong (d1.data);
! 2040: data_string_forget (&d1, MDL);
! 2041: }
! 2042: }
! 2043:
! 2044: /* Enforce the maximum lease length. */
! 2045: if (lease_time < 0 /* XXX */
! 2046: || lease_time > max_lease_time)
! 2047: lease_time = max_lease_time;
! 2048:
! 2049: min_lease_time = DEFAULT_MIN_LEASE_TIME;
! 2050: if (min_lease_time > max_lease_time)
! 2051: min_lease_time = max_lease_time;
! 2052:
! 2053: if ((oc = lookup_option (&server_universe, state -> options,
! 2054: SV_MIN_LEASE_TIME))) {
! 2055: if (evaluate_option_cache (&d1, packet, lease,
! 2056: (struct client_state *)0,
! 2057: packet -> options,
! 2058: state -> options,
! 2059: &lease -> scope, oc, MDL)) {
! 2060: if (d1.len == sizeof (u_int32_t))
! 2061: min_lease_time = getULong (d1.data);
! 2062: data_string_forget (&d1, MDL);
! 2063: }
! 2064: }
! 2065:
! 2066: /* CC: If there are less than
! 2067: adaptive-lease-time-threshold % free leases,
! 2068: hand out only short term leases */
! 2069:
! 2070: memset(&d1, 0, sizeof(d1));
! 2071: if (lease->pool &&
! 2072: (oc = lookup_option(&server_universe, state->options,
! 2073: SV_ADAPTIVE_LEASE_TIME_THRESHOLD)) &&
! 2074: evaluate_option_cache(&d1, packet, lease, NULL,
! 2075: packet->options, state->options,
! 2076: &lease->scope, oc, MDL)) {
! 2077: if (d1.len == 1 && d1.data[0] > 0 &&
! 2078: d1.data[0] < 100) {
! 2079: TIME adaptive_time;
! 2080: int poolfilled, total, count;
! 2081:
! 2082: if (min_lease_time)
! 2083: adaptive_time = min_lease_time;
! 2084: else
! 2085: adaptive_time = DEFAULT_MIN_LEASE_TIME;
! 2086:
! 2087: /* Allow the client to keep its lease. */
! 2088: if (lease->ends - cur_time > adaptive_time)
! 2089: adaptive_time = lease->ends - cur_time;
! 2090:
! 2091: count = lease->pool->lease_count;
! 2092: total = count - (lease->pool->free_leases +
! 2093: lease->pool->backup_leases);
! 2094:
! 2095: poolfilled = (total > (INT_MAX / 100)) ?
! 2096: total / (count / 100) :
! 2097: (total * 100) / count;
! 2098:
! 2099: log_debug("Adap-lease: Total: %d, Free: %d, "
! 2100: "Ends: %d, Adaptive: %d, Fill: %d, "
! 2101: "Threshold: %d",
! 2102: lease->pool->lease_count,
! 2103: lease->pool->free_leases,
! 2104: (int)(lease->ends - cur_time),
! 2105: (int)adaptive_time, poolfilled,
! 2106: d1.data[0]);
! 2107:
! 2108: if (poolfilled >= d1.data[0] &&
! 2109: lease_time > adaptive_time) {
! 2110: log_info("Pool over threshold, time "
! 2111: "for %s reduced from %d to "
! 2112: "%d.", piaddr(lease->ip_addr),
! 2113: (int)lease_time,
! 2114: (int)adaptive_time);
! 2115:
! 2116: lease_time = adaptive_time;
! 2117: }
! 2118: }
! 2119: data_string_forget(&d1, MDL);
! 2120: }
! 2121:
! 2122: /* a client requests an address which is not yet active*/
! 2123: if (lease->pool && lease->pool->valid_from &&
! 2124: cur_time < lease->pool->valid_from) {
! 2125: /* NAK leases before pool activation date */
! 2126: cip.len = 4;
! 2127: memcpy (cip.iabuf, <->ip_addr.iabuf, 4);
! 2128: nak_lease(packet, &cip);
! 2129: free_lease_state (state, MDL);
! 2130: lease_dereference (<, MDL);
! 2131: if (host)
! 2132: host_dereference (&host, MDL);
! 2133: return;
! 2134:
! 2135: }
! 2136:
! 2137: /* CC:
! 2138: a) NAK current lease if past the expiration date
! 2139: b) extend lease only up to the expiration date, but not
! 2140: below min-lease-time
! 2141: Setting min-lease-time is essential for this to work!
! 2142: The value of min-lease-time determines the lenght
! 2143: of the transition window:
! 2144: A client renewing a second before the deadline will
! 2145: get a min-lease-time lease. Since the current ip might not
! 2146: be routable after the deadline, the client will
! 2147: be offline until it DISCOVERS again. Otherwise it will
! 2148: receive a NAK at T/2.
! 2149: A min-lease-time of 6 seconds effectively switches over
! 2150: all clients in this pool very quickly.
! 2151: */
! 2152:
! 2153: if (lease->pool && lease->pool->valid_until) {
! 2154: if (cur_time >= lease->pool->valid_until) {
! 2155: /* NAK leases after pool expiration date */
! 2156: cip.len = 4;
! 2157: memcpy (cip.iabuf, <->ip_addr.iabuf, 4);
! 2158: nak_lease(packet, &cip);
! 2159: free_lease_state (state, MDL);
! 2160: lease_dereference (<, MDL);
! 2161: if (host)
! 2162: host_dereference (&host, MDL);
! 2163: return;
! 2164: }
! 2165: remaining_time = lease->pool->valid_until - cur_time;
! 2166: if (lease_time > remaining_time)
! 2167: lease_time = remaining_time;
! 2168: }
! 2169:
! 2170: if (lease_time < min_lease_time) {
! 2171: if (min_lease_time)
! 2172: lease_time = min_lease_time;
! 2173: else
! 2174: lease_time = default_lease_time;
! 2175: }
! 2176:
! 2177:
! 2178: #if defined (FAILOVER_PROTOCOL)
! 2179: /* Okay, we know the lease duration. Now check the
! 2180: failover state, if any. */
! 2181: if (lease -> pool && lease -> pool -> failover_peer) {
! 2182: TIME new_lease_time = lease_time;
! 2183: dhcp_failover_state_t *peer =
! 2184: lease -> pool -> failover_peer;
! 2185:
! 2186: /* Copy previous lease failover ack-state. */
! 2187: lt->tsfp = lease->tsfp;
! 2188: lt->atsfp = lease->atsfp;
! 2189:
! 2190: /* cltt set below */
! 2191:
! 2192: /* Lease times less than MCLT are not a concern. */
! 2193: if (lease_time > peer->mclt) {
! 2194: /* Each server can only offer a lease time
! 2195: * that is either equal to MCLT (at least),
! 2196: * or up to TSFP+MCLT. Only if the desired
! 2197: * lease time falls within TSFP+MCLT, can
! 2198: * the server allow it.
! 2199: */
! 2200: if (lt->tsfp <= cur_time)
! 2201: new_lease_time = peer->mclt;
! 2202: else if ((cur_time + lease_time) >
! 2203: (lt->tsfp + peer->mclt))
! 2204: new_lease_time = (lt->tsfp - cur_time)
! 2205: + peer->mclt;
! 2206: }
! 2207:
! 2208: /* Update potential expiry. Allow for the desired
! 2209: * lease time plus one half the actual (whether
! 2210: * modified downward or not) lease time, which is
! 2211: * actually an estimate of when the client will
! 2212: * renew. This way, the client will be able to get
! 2213: * the desired lease time upon renewal.
! 2214: */
! 2215: if (offer == DHCPACK) {
! 2216: lt->tstp = cur_time + lease_time +
! 2217: (new_lease_time / 2);
! 2218:
! 2219: /* If we reduced the potential expiry time,
! 2220: * make sure we don't offer an old-expiry-time
! 2221: * lease for this lease before the change is
! 2222: * ack'd.
! 2223: */
! 2224: if (lt->tstp < lt->tsfp)
! 2225: lt->tsfp = lt->tstp;
! 2226: } else
! 2227: lt->tstp = lease->tstp;
! 2228:
! 2229: /* Use failover-modified lease time. */
! 2230: lease_time = new_lease_time;
! 2231: }
! 2232: #endif /* FAILOVER_PROTOCOL */
! 2233:
! 2234: /* If the lease duration causes the time value to wrap,
! 2235: use the maximum expiry time. */
! 2236: if (cur_time + lease_time < cur_time)
! 2237: state -> offered_expiry = MAX_TIME - 1;
! 2238: else
! 2239: state -> offered_expiry = cur_time + lease_time;
! 2240: if (when)
! 2241: lt -> ends = when;
! 2242: else
! 2243: lt -> ends = state -> offered_expiry;
! 2244:
! 2245: /* Don't make lease active until we actually get a
! 2246: DHCPREQUEST. */
! 2247: if (offer == DHCPACK)
! 2248: lt -> next_binding_state = FTS_ACTIVE;
! 2249: else
! 2250: lt -> next_binding_state = lease -> binding_state;
! 2251: } else {
! 2252: lt->flags |= BOOTP_LEASE;
! 2253:
! 2254: lease_time = MAX_TIME - cur_time;
! 2255:
! 2256: if ((oc = lookup_option (&server_universe, state -> options,
! 2257: SV_BOOTP_LEASE_LENGTH))) {
! 2258: if (evaluate_option_cache (&d1, packet, lease,
! 2259: (struct client_state *)0,
! 2260: packet -> options,
! 2261: state -> options,
! 2262: &lease -> scope, oc, MDL)) {
! 2263: if (d1.len == sizeof (u_int32_t))
! 2264: lease_time = getULong (d1.data);
! 2265: data_string_forget (&d1, MDL);
! 2266: }
! 2267: }
! 2268:
! 2269: if ((oc = lookup_option (&server_universe, state -> options,
! 2270: SV_BOOTP_LEASE_CUTOFF))) {
! 2271: if (evaluate_option_cache (&d1, packet, lease,
! 2272: (struct client_state *)0,
! 2273: packet -> options,
! 2274: state -> options,
! 2275: &lease -> scope, oc, MDL)) {
! 2276: if (d1.len == sizeof (u_int32_t))
! 2277: lease_time = (getULong (d1.data) -
! 2278: cur_time);
! 2279: data_string_forget (&d1, MDL);
! 2280: }
! 2281: }
! 2282:
! 2283: lt -> ends = state -> offered_expiry = cur_time + lease_time;
! 2284: lt -> next_binding_state = FTS_ACTIVE;
! 2285: }
! 2286:
! 2287: /* Update Client Last Transaction Time. */
! 2288: lt->cltt = cur_time;
! 2289:
! 2290: /* Record the uid, if given... */
! 2291: oc = lookup_option (&dhcp_universe, packet -> options,
! 2292: DHO_DHCP_CLIENT_IDENTIFIER);
! 2293: if (oc &&
! 2294: evaluate_option_cache (&d1, packet, lease,
! 2295: (struct client_state *)0,
! 2296: packet -> options, state -> options,
! 2297: &lease -> scope, oc, MDL)) {
! 2298: if (d1.len <= sizeof lt -> uid_buf) {
! 2299: memcpy (lt -> uid_buf, d1.data, d1.len);
! 2300: lt -> uid = lt -> uid_buf;
! 2301: lt -> uid_max = sizeof lt -> uid_buf;
! 2302: lt -> uid_len = d1.len;
! 2303: } else {
! 2304: unsigned char *tuid;
! 2305: lt -> uid_max = d1.len;
! 2306: lt -> uid_len = d1.len;
! 2307: tuid = (unsigned char *)dmalloc (lt -> uid_max, MDL);
! 2308: /* XXX inelegant */
! 2309: if (!tuid)
! 2310: log_fatal ("no memory for large uid.");
! 2311: memcpy (tuid, d1.data, lt -> uid_len);
! 2312: lt -> uid = tuid;
! 2313: }
! 2314: data_string_forget (&d1, MDL);
! 2315: }
! 2316:
! 2317: if (host) {
! 2318: host_reference (< -> host, host, MDL);
! 2319: host_dereference (&host, MDL);
! 2320: }
! 2321: if (lease -> subnet)
! 2322: subnet_reference (< -> subnet, lease -> subnet, MDL);
! 2323: if (lease -> billing_class)
! 2324: class_reference (< -> billing_class,
! 2325: lease -> billing_class, MDL);
! 2326:
! 2327: /* Set a flag if this client is a broken client that NUL
! 2328: terminates string options and expects us to do likewise. */
! 2329: if (ms_nulltp)
! 2330: lease -> flags |= MS_NULL_TERMINATION;
! 2331: else
! 2332: lease -> flags &= ~MS_NULL_TERMINATION;
! 2333:
! 2334: /* Save any bindings. */
! 2335: if (lease -> scope) {
! 2336: binding_scope_reference (< -> scope, lease -> scope, MDL);
! 2337: binding_scope_dereference (&lease -> scope, MDL);
! 2338: }
! 2339: if (lease -> agent_options)
! 2340: option_chain_head_reference (< -> agent_options,
! 2341: lease -> agent_options, MDL);
! 2342:
! 2343: /* Save the vendor-class-identifier for DHCPLEASEQUERY. */
! 2344: oc = lookup_option(&dhcp_universe, packet->options,
! 2345: DHO_VENDOR_CLASS_IDENTIFIER);
! 2346: if (oc != NULL &&
! 2347: evaluate_option_cache(&d1, packet, NULL, NULL, packet->options,
! 2348: NULL, &lease->scope, oc, MDL)) {
! 2349: if (d1.len != 0) {
! 2350: bind_ds_value(&lease->scope, "vendor-class-identifier",
! 2351: &d1);
! 2352: }
! 2353:
! 2354: data_string_forget(&d1, MDL);
! 2355: }
! 2356:
! 2357: /* If we got relay agent information options from the packet, then
! 2358: * cache them for renewal in case the relay agent can't supply them
! 2359: * when the client unicasts. The options may be from an addressed
! 2360: * "l3" relay, or from an unaddressed "l2" relay which does not set
! 2361: * giaddr.
! 2362: */
! 2363: if (!packet->agent_options_stashed &&
! 2364: (packet->options != NULL) &&
! 2365: packet->options->universe_count > agent_universe.index &&
! 2366: packet->options->universes[agent_universe.index] != NULL) {
! 2367: oc = lookup_option (&server_universe, state -> options,
! 2368: SV_STASH_AGENT_OPTIONS);
! 2369: if (!oc ||
! 2370: evaluate_boolean_option_cache (&ignorep, packet, lease,
! 2371: (struct client_state *)0,
! 2372: packet -> options,
! 2373: state -> options,
! 2374: &lease -> scope, oc, MDL)) {
! 2375: if (lt -> agent_options)
! 2376: option_chain_head_dereference (< -> agent_options, MDL);
! 2377: option_chain_head_reference
! 2378: (< -> agent_options,
! 2379: (struct option_chain_head *)
! 2380: packet -> options -> universes [agent_universe.index],
! 2381: MDL);
! 2382: }
! 2383: }
! 2384:
! 2385: /* Replace the old lease hostname with the new one, if it's changed. */
! 2386: oc = lookup_option (&dhcp_universe, packet -> options, DHO_HOST_NAME);
! 2387: if (oc)
! 2388: s1 = evaluate_option_cache (&d1, packet, (struct lease *)0,
! 2389: (struct client_state *)0,
! 2390: packet -> options,
! 2391: (struct option_state *)0,
! 2392: &global_scope, oc, MDL);
! 2393: else
! 2394: s1 = 0;
! 2395:
! 2396: if (oc && s1 &&
! 2397: lease -> client_hostname &&
! 2398: strlen (lease -> client_hostname) == d1.len &&
! 2399: !memcmp (lease -> client_hostname, d1.data, d1.len)) {
! 2400: /* Hasn't changed. */
! 2401: data_string_forget (&d1, MDL);
! 2402: lt -> client_hostname = lease -> client_hostname;
! 2403: lease -> client_hostname = (char *)0;
! 2404: } else if (oc && s1) {
! 2405: lt -> client_hostname = dmalloc (d1.len + 1, MDL);
! 2406: if (!lt -> client_hostname)
! 2407: log_error ("no memory for client hostname.");
! 2408: else {
! 2409: memcpy (lt -> client_hostname, d1.data, d1.len);
! 2410: lt -> client_hostname [d1.len] = 0;
! 2411: }
! 2412: data_string_forget (&d1, MDL);
! 2413: }
! 2414:
! 2415: /* Record the hardware address, if given... */
! 2416: lt -> hardware_addr.hlen = packet -> raw -> hlen + 1;
! 2417: lt -> hardware_addr.hbuf [0] = packet -> raw -> htype;
! 2418: memcpy (< -> hardware_addr.hbuf [1], packet -> raw -> chaddr,
! 2419: sizeof packet -> raw -> chaddr);
! 2420:
! 2421: lt -> flags = lease -> flags & ~PERSISTENT_FLAGS;
! 2422:
! 2423: /* If there are statements to execute when the lease is
! 2424: committed, execute them. */
! 2425: if (lease -> on_commit && (!offer || offer == DHCPACK)) {
! 2426: execute_statements ((struct binding_value **)0,
! 2427: packet, lt, (struct client_state *)0,
! 2428: packet -> options,
! 2429: state -> options, < -> scope,
! 2430: lease -> on_commit);
! 2431: if (lease -> on_commit)
! 2432: executable_statement_dereference (&lease -> on_commit,
! 2433: MDL);
! 2434: }
! 2435:
! 2436: #ifdef NSUPDATE
! 2437: /* Perform DDNS updates, if configured to. */
! 2438: if ((!offer || offer == DHCPACK) &&
! 2439: (!(oc = lookup_option (&server_universe, state -> options,
! 2440: SV_DDNS_UPDATES)) ||
! 2441: evaluate_boolean_option_cache (&ignorep, packet, lt,
! 2442: (struct client_state *)0,
! 2443: packet -> options,
! 2444: state -> options,
! 2445: < -> scope, oc, MDL))) {
! 2446: ddns_updates(packet, lt, lease, NULL, NULL, state->options);
! 2447: }
! 2448: #endif /* NSUPDATE */
! 2449:
! 2450: /* Don't call supersede_lease on a mocked-up lease. */
! 2451: if (lease -> flags & STATIC_LEASE) {
! 2452: /* Copy the hardware address into the static lease
! 2453: structure. */
! 2454: lease -> hardware_addr.hlen = packet -> raw -> hlen + 1;
! 2455: lease -> hardware_addr.hbuf [0] = packet -> raw -> htype;
! 2456: memcpy (&lease -> hardware_addr.hbuf [1],
! 2457: packet -> raw -> chaddr,
! 2458: sizeof packet -> raw -> chaddr); /* XXX */
! 2459: } else {
! 2460: #if !defined(DELAYED_ACK)
! 2461: /* Install the new information on 'lt' onto the lease at
! 2462: * 'lease'. If this is a DHCPOFFER, it is a 'soft' promise,
! 2463: * if it is a DHCPACK, it is a 'hard' binding, so it needs
! 2464: * to be recorded and propogated immediately. If the update
! 2465: * fails, don't ACK it (or BOOTREPLY) either; we may give
! 2466: * the same lease to another client later, and that would be
! 2467: * a conflict.
! 2468: */
! 2469: if (!supersede_lease(lease, lt, !offer || (offer == DHCPACK),
! 2470: offer == DHCPACK, offer == DHCPACK)) {
! 2471: #else /* defined(DELAYED_ACK) */
! 2472: /* Install the new information on 'lt' onto the lease at
! 2473: * 'lease'. Â We will not 'commit' this information to disk
! 2474: * yet (fsync()), we will 'propogate' the information if
! 2475: * this is BOOTP or a DHCPACK, but we will not 'pimmediate'ly
! 2476: * transmit failover binding updates (this is delayed until
! 2477: * after the fsync()). If the update fails, don't ACK it (or
! 2478: * BOOTREPLY either); we may give the same lease out to a
! 2479: * different client, and that would be a conflict.
! 2480: */
! 2481: if (!supersede_lease(lease, lt, 0, !offer || offer == DHCPACK,
! 2482: 0)) {
! 2483: #endif
! 2484: log_info ("%s: database update failed", msg);
! 2485: free_lease_state (state, MDL);
! 2486: lease_dereference (<, MDL);
! 2487: return;
! 2488: }
! 2489: }
! 2490: lease_dereference (<, MDL);
! 2491:
! 2492: /* Remember the interface on which the packet arrived. */
! 2493: state -> ip = packet -> interface;
! 2494:
! 2495: /* Remember the giaddr, xid, secs, flags and hops. */
! 2496: state -> giaddr = packet -> raw -> giaddr;
! 2497: state -> ciaddr = packet -> raw -> ciaddr;
! 2498: state -> xid = packet -> raw -> xid;
! 2499: state -> secs = packet -> raw -> secs;
! 2500: state -> bootp_flags = packet -> raw -> flags;
! 2501: state -> hops = packet -> raw -> hops;
! 2502: state -> offer = offer;
! 2503:
! 2504: /* If we're always supposed to broadcast to this client, set
! 2505: the broadcast bit in the bootp flags field. */
! 2506: if ((oc = lookup_option (&server_universe, state -> options,
! 2507: SV_ALWAYS_BROADCAST)) &&
! 2508: evaluate_boolean_option_cache (&ignorep, packet, lease,
! 2509: (struct client_state *)0,
! 2510: packet -> options, state -> options,
! 2511: &lease -> scope, oc, MDL))
! 2512: state -> bootp_flags |= htons (BOOTP_BROADCAST);
! 2513:
! 2514: /* Get the Maximum Message Size option from the packet, if one
! 2515: was sent. */
! 2516: oc = lookup_option (&dhcp_universe, packet -> options,
! 2517: DHO_DHCP_MAX_MESSAGE_SIZE);
! 2518: if (oc &&
! 2519: evaluate_option_cache (&d1, packet, lease,
! 2520: (struct client_state *)0,
! 2521: packet -> options, state -> options,
! 2522: &lease -> scope, oc, MDL)) {
! 2523: if (d1.len == sizeof (u_int16_t))
! 2524: state -> max_message_size = getUShort (d1.data);
! 2525: data_string_forget (&d1, MDL);
! 2526: } else {
! 2527: oc = lookup_option (&dhcp_universe, state -> options,
! 2528: DHO_DHCP_MAX_MESSAGE_SIZE);
! 2529: if (oc &&
! 2530: evaluate_option_cache (&d1, packet, lease,
! 2531: (struct client_state *)0,
! 2532: packet -> options, state -> options,
! 2533: &lease -> scope, oc, MDL)) {
! 2534: if (d1.len == sizeof (u_int16_t))
! 2535: state -> max_message_size =
! 2536: getUShort (d1.data);
! 2537: data_string_forget (&d1, MDL);
! 2538: }
! 2539: }
! 2540:
! 2541: /* Get the Subnet Selection option from the packet, if one
! 2542: was sent. */
! 2543: if ((oc = lookup_option (&dhcp_universe, packet -> options,
! 2544: DHO_SUBNET_SELECTION))) {
! 2545:
! 2546: /* Make a copy of the data. */
! 2547: struct option_cache *noc = (struct option_cache *)0;
! 2548: if (option_cache_allocate (&noc, MDL)) {
! 2549: if (oc -> data.len)
! 2550: data_string_copy (&noc -> data,
! 2551: &oc -> data, MDL);
! 2552: if (oc -> expression)
! 2553: expression_reference (&noc -> expression,
! 2554: oc -> expression, MDL);
! 2555: if (oc -> option)
! 2556: option_reference(&(noc->option), oc->option,
! 2557: MDL);
! 2558: }
! 2559:
! 2560: save_option (&dhcp_universe, state -> options, noc);
! 2561: option_cache_dereference (&noc, MDL);
! 2562: }
! 2563:
! 2564: /* Now, if appropriate, put in DHCP-specific options that
! 2565: override those. */
! 2566: if (state -> offer) {
! 2567: i = DHO_DHCP_MESSAGE_TYPE;
! 2568: oc = (struct option_cache *)0;
! 2569: if (option_cache_allocate (&oc, MDL)) {
! 2570: if (make_const_data (&oc -> expression,
! 2571: &state -> offer, 1, 0, 0, MDL)) {
! 2572: option_code_hash_lookup(&oc->option,
! 2573: dhcp_universe.code_hash,
! 2574: &i, 0, MDL);
! 2575: save_option (&dhcp_universe,
! 2576: state -> options, oc);
! 2577: }
! 2578: option_cache_dereference (&oc, MDL);
! 2579: }
! 2580:
! 2581: get_server_source_address(&from, state->options, packet);
! 2582: memcpy(state->from.iabuf, &from, sizeof(from));
! 2583: state->from.len = sizeof(from);
! 2584:
! 2585: offered_lease_time =
! 2586: state -> offered_expiry - cur_time;
! 2587:
! 2588: putULong(state->expiry, (u_int32_t)offered_lease_time);
! 2589: i = DHO_DHCP_LEASE_TIME;
! 2590: oc = (struct option_cache *)0;
! 2591: if (option_cache_allocate (&oc, MDL)) {
! 2592: if (make_const_data(&oc->expression, state->expiry,
! 2593: 4, 0, 0, MDL)) {
! 2594: option_code_hash_lookup(&oc->option,
! 2595: dhcp_universe.code_hash,
! 2596: &i, 0, MDL);
! 2597: save_option (&dhcp_universe,
! 2598: state -> options, oc);
! 2599: }
! 2600: option_cache_dereference (&oc, MDL);
! 2601: }
! 2602:
! 2603: /* Renewal time is lease time * 0.5. */
! 2604: offered_lease_time /= 2;
! 2605: putULong(state->renewal, (u_int32_t)offered_lease_time);
! 2606: i = DHO_DHCP_RENEWAL_TIME;
! 2607: oc = (struct option_cache *)0;
! 2608: if (option_cache_allocate (&oc, MDL)) {
! 2609: if (make_const_data(&oc->expression, state->renewal,
! 2610: 4, 0, 0, MDL)) {
! 2611: option_code_hash_lookup(&oc->option,
! 2612: dhcp_universe.code_hash,
! 2613: &i, 0, MDL);
! 2614: save_option (&dhcp_universe,
! 2615: state -> options, oc);
! 2616: }
! 2617: option_cache_dereference (&oc, MDL);
! 2618: }
! 2619:
! 2620: /* Rebinding time is lease time * 0.875. */
! 2621: offered_lease_time += (offered_lease_time / 2
! 2622: + offered_lease_time / 4);
! 2623: putULong(state->rebind, (u_int32_t)offered_lease_time);
! 2624: i = DHO_DHCP_REBINDING_TIME;
! 2625: oc = (struct option_cache *)0;
! 2626: if (option_cache_allocate (&oc, MDL)) {
! 2627: if (make_const_data(&oc->expression, state->rebind,
! 2628: 4, 0, 0, MDL)) {
! 2629: option_code_hash_lookup(&oc->option,
! 2630: dhcp_universe.code_hash,
! 2631: &i, 0, MDL);
! 2632: save_option (&dhcp_universe,
! 2633: state -> options, oc);
! 2634: }
! 2635: option_cache_dereference (&oc, MDL);
! 2636: }
! 2637: } else {
! 2638: /* XXXSK: should we use get_server_source_address() here? */
! 2639: if (state -> ip -> address_count) {
! 2640: state -> from.len =
! 2641: sizeof state -> ip -> addresses [0];
! 2642: memcpy (state -> from.iabuf,
! 2643: &state -> ip -> addresses [0],
! 2644: state -> from.len);
! 2645: }
! 2646: }
! 2647:
! 2648: /* Figure out the address of the boot file server. */
! 2649: memset (&state -> siaddr, 0, sizeof state -> siaddr);
! 2650: if ((oc =
! 2651: lookup_option (&server_universe,
! 2652: state -> options, SV_NEXT_SERVER))) {
! 2653: if (evaluate_option_cache (&d1, packet, lease,
! 2654: (struct client_state *)0,
! 2655: packet -> options, state -> options,
! 2656: &lease -> scope, oc, MDL)) {
! 2657: /* If there was more than one answer,
! 2658: take the first. */
! 2659: if (d1.len >= 4 && d1.data)
! 2660: memcpy (&state -> siaddr, d1.data, 4);
! 2661: data_string_forget (&d1, MDL);
! 2662: }
! 2663: }
! 2664:
! 2665: /* Use the subnet mask from the subnet declaration if no other
! 2666: mask has been provided. */
! 2667: i = DHO_SUBNET_MASK;
! 2668: if (!lookup_option (&dhcp_universe, state -> options, i)) {
! 2669: oc = (struct option_cache *)0;
! 2670: if (option_cache_allocate (&oc, MDL)) {
! 2671: if (make_const_data (&oc -> expression,
! 2672: lease -> subnet -> netmask.iabuf,
! 2673: lease -> subnet -> netmask.len,
! 2674: 0, 0, MDL)) {
! 2675: option_code_hash_lookup(&oc->option,
! 2676: dhcp_universe.code_hash,
! 2677: &i, 0, MDL);
! 2678: save_option (&dhcp_universe,
! 2679: state -> options, oc);
! 2680: }
! 2681: option_cache_dereference (&oc, MDL);
! 2682: }
! 2683: }
! 2684:
! 2685: /* Use the hostname from the host declaration if there is one
! 2686: and no hostname has otherwise been provided, and if the
! 2687: use-host-decl-name flag is set. */
! 2688: i = DHO_HOST_NAME;
! 2689: j = SV_USE_HOST_DECL_NAMES;
! 2690: if (!lookup_option (&dhcp_universe, state -> options, i) &&
! 2691: lease -> host && lease -> host -> name &&
! 2692: (evaluate_boolean_option_cache
! 2693: (&ignorep, packet, lease, (struct client_state *)0,
! 2694: packet -> options, state -> options, &lease -> scope,
! 2695: lookup_option (&server_universe, state -> options, j), MDL))) {
! 2696: oc = (struct option_cache *)0;
! 2697: if (option_cache_allocate (&oc, MDL)) {
! 2698: if (make_const_data (&oc -> expression,
! 2699: ((unsigned char *)
! 2700: lease -> host -> name),
! 2701: strlen (lease -> host -> name),
! 2702: 1, 0, MDL)) {
! 2703: option_code_hash_lookup(&oc->option,
! 2704: dhcp_universe.code_hash,
! 2705: &i, 0, MDL);
! 2706: save_option (&dhcp_universe,
! 2707: state -> options, oc);
! 2708: }
! 2709: option_cache_dereference (&oc, MDL);
! 2710: }
! 2711: }
! 2712:
! 2713: /* If we don't have a hostname yet, and we've been asked to do
! 2714: a reverse lookup to find the hostname, do it. */
! 2715: i = DHO_HOST_NAME;
! 2716: j = SV_GET_LEASE_HOSTNAMES;
! 2717: if (!lookup_option(&dhcp_universe, state->options, i) &&
! 2718: evaluate_boolean_option_cache
! 2719: (&ignorep, packet, lease, NULL,
! 2720: packet->options, state->options, &lease->scope,
! 2721: lookup_option (&server_universe, state->options, j), MDL)) {
! 2722: struct in_addr ia;
! 2723: struct hostent *h;
! 2724:
! 2725: memcpy (&ia, lease -> ip_addr.iabuf, 4);
! 2726:
! 2727: h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET);
! 2728: if (!h)
! 2729: log_error ("No hostname for %s", inet_ntoa (ia));
! 2730: else {
! 2731: oc = (struct option_cache *)0;
! 2732: if (option_cache_allocate (&oc, MDL)) {
! 2733: if (make_const_data (&oc -> expression,
! 2734: ((unsigned char *)
! 2735: h -> h_name),
! 2736: strlen (h -> h_name) + 1,
! 2737: 1, 1, MDL)) {
! 2738: option_code_hash_lookup(&oc->option,
! 2739: dhcp_universe.code_hash,
! 2740: &i, 0, MDL);
! 2741: save_option (&dhcp_universe,
! 2742: state -> options, oc);
! 2743: }
! 2744: option_cache_dereference (&oc, MDL);
! 2745: }
! 2746: }
! 2747: }
! 2748:
! 2749: /* If so directed, use the leased IP address as the router address.
! 2750: This supposedly makes Win95 machines ARP for all IP addresses,
! 2751: so if the local router does proxy arp, you win. */
! 2752:
! 2753: if (evaluate_boolean_option_cache
! 2754: (&ignorep, packet, lease, (struct client_state *)0,
! 2755: packet -> options, state -> options, &lease -> scope,
! 2756: lookup_option (&server_universe, state -> options,
! 2757: SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE), MDL)) {
! 2758: i = DHO_ROUTERS;
! 2759: oc = lookup_option (&dhcp_universe, state -> options, i);
! 2760: if (!oc) {
! 2761: oc = (struct option_cache *)0;
! 2762: if (option_cache_allocate (&oc, MDL)) {
! 2763: if (make_const_data (&oc -> expression,
! 2764: lease -> ip_addr.iabuf,
! 2765: lease -> ip_addr.len,
! 2766: 0, 0, MDL)) {
! 2767: option_code_hash_lookup(&oc->option,
! 2768: dhcp_universe.code_hash,
! 2769: &i, 0, MDL);
! 2770: save_option (&dhcp_universe,
! 2771: state -> options, oc);
! 2772: }
! 2773: option_cache_dereference (&oc, MDL);
! 2774: }
! 2775: }
! 2776: }
! 2777:
! 2778: /* If a site option space has been specified, use that for
! 2779: site option codes. */
! 2780: i = SV_SITE_OPTION_SPACE;
! 2781: if ((oc = lookup_option (&server_universe, state -> options, i)) &&
! 2782: evaluate_option_cache (&d1, packet, lease,
! 2783: (struct client_state *)0,
! 2784: packet -> options, state -> options,
! 2785: &lease -> scope, oc, MDL)) {
! 2786: struct universe *u = (struct universe *)0;
! 2787:
! 2788: if (!universe_hash_lookup (&u, universe_hash,
! 2789: (const char *)d1.data, d1.len,
! 2790: MDL)) {
! 2791: log_error ("unknown option space %s.", d1.data);
! 2792: return;
! 2793: }
! 2794:
! 2795: state -> options -> site_universe = u -> index;
! 2796: state->options->site_code_min = find_min_site_code(u);
! 2797: data_string_forget (&d1, MDL);
! 2798: } else {
! 2799: state -> options -> site_code_min = 0;
! 2800: state -> options -> site_universe = dhcp_universe.index;
! 2801: }
! 2802:
! 2803: /* If the client has provided a list of options that it wishes
! 2804: returned, use it to prioritize. If there's a parameter
! 2805: request list in scope, use that in preference. Otherwise
! 2806: use the default priority list. */
! 2807:
! 2808: oc = lookup_option (&dhcp_universe, state -> options,
! 2809: DHO_DHCP_PARAMETER_REQUEST_LIST);
! 2810:
! 2811: if (!oc)
! 2812: oc = lookup_option (&dhcp_universe, packet -> options,
! 2813: DHO_DHCP_PARAMETER_REQUEST_LIST);
! 2814: if (oc)
! 2815: evaluate_option_cache (&state -> parameter_request_list,
! 2816: packet, lease, (struct client_state *)0,
! 2817: packet -> options, state -> options,
! 2818: &lease -> scope, oc, MDL);
! 2819:
! 2820: #ifdef DEBUG_PACKET
! 2821: dump_packet (packet);
! 2822: dump_raw ((unsigned char *)packet -> raw, packet -> packet_length);
! 2823: #endif
! 2824:
! 2825: lease -> state = state;
! 2826:
! 2827: log_info ("%s", msg);
! 2828:
! 2829: /* Hang the packet off the lease state. */
! 2830: packet_reference (&lease -> state -> packet, packet, MDL);
! 2831:
! 2832: /* If this is a DHCPOFFER, ping the lease address before actually
! 2833: sending the offer. */
! 2834: if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE) &&
! 2835: ((cur_time - lease_cltt) > 60) &&
! 2836: (!(oc = lookup_option (&server_universe, state -> options,
! 2837: SV_PING_CHECKS)) ||
! 2838: evaluate_boolean_option_cache (&ignorep, packet, lease,
! 2839: (struct client_state *)0,
! 2840: packet -> options,
! 2841: state -> options,
! 2842: &lease -> scope, oc, MDL))) {
! 2843: icmp_echorequest (&lease -> ip_addr);
! 2844:
! 2845: /* Determine whether to use configured or default ping timeout.
! 2846: */
! 2847: if ((oc = lookup_option (&server_universe, state -> options,
! 2848: SV_PING_TIMEOUT)) &&
! 2849: evaluate_option_cache (&d1, packet, lease, NULL,
! 2850: packet -> options,
! 2851: state -> options,
! 2852: &lease -> scope, oc, MDL)) {
! 2853: if (d1.len == sizeof (u_int32_t))
! 2854: ping_timeout = getULong (d1.data);
! 2855: else
! 2856: ping_timeout = DEFAULT_PING_TIMEOUT;
! 2857:
! 2858: data_string_forget (&d1, MDL);
! 2859: } else
! 2860: ping_timeout = DEFAULT_PING_TIMEOUT;
! 2861:
! 2862: #ifdef DEBUG
! 2863: log_debug ("Ping timeout: %ld", (long)ping_timeout);
! 2864: #endif
! 2865:
! 2866: /*
! 2867: * Set a timeout for 'ping-timeout' seconds from NOW, including
! 2868: * current microseconds. As ping-timeout defaults to 1, the
! 2869: * exclusion of current microseconds causes a value somewhere
! 2870: * /between/ zero and one.
! 2871: */
! 2872: tv.tv_sec = cur_tv.tv_sec + ping_timeout;
! 2873: tv.tv_usec = cur_tv.tv_usec;
! 2874: add_timeout (&tv, lease_ping_timeout, lease,
! 2875: (tvref_t)lease_reference,
! 2876: (tvunref_t)lease_dereference);
! 2877: ++outstanding_pings;
! 2878: } else {
! 2879: lease->cltt = cur_time;
! 2880: #if defined(DELAYED_ACK)
! 2881: if (!(lease->flags & STATIC_LEASE) &&
! 2882: (!offer || (offer == DHCPACK)))
! 2883: delayed_ack_enqueue(lease);
! 2884: else
! 2885: #endif
! 2886: dhcp_reply(lease);
! 2887: }
! 2888: }
! 2889:
! 2890: /* CC: queue single ACK:
! 2891: - write the lease (but do not fsync it yet)
! 2892: - add to double linked list
! 2893: - commit if more than xx ACKs pending
! 2894: - Not yet: schedule a fsync at the next interval (1 second?)
! 2895: */
! 2896:
! 2897: void
! 2898: delayed_ack_enqueue(struct lease *lease)
! 2899: {
! 2900: struct leasequeue *q;
! 2901:
! 2902: if (!write_lease(lease))
! 2903: return;
! 2904: if (free_ackqueue) {
! 2905: q = free_ackqueue;
! 2906: free_ackqueue = q->next;
! 2907: } else {
! 2908: q = ((struct leasequeue *)
! 2909: dmalloc(sizeof(struct leasequeue), MDL));
! 2910: if (!q)
! 2911: log_fatal("delayed_ack_enqueue: no memory!");
! 2912: }
! 2913: memset(q, 0, sizeof *q);
! 2914: /* prepend to ackqueue*/
! 2915: lease_reference(&q->lease, lease, MDL);
! 2916: q->next = ackqueue_head;
! 2917: ackqueue_head = q;
! 2918: if (!ackqueue_tail)
! 2919: ackqueue_tail = q;
! 2920: else
! 2921: q->next->prev = q;
! 2922:
! 2923: outstanding_acks++;
! 2924: if (outstanding_acks > max_outstanding_acks)
! 2925: commit_leases();
! 2926:
! 2927: /* If next_fsync is not set, schedule an fsync. */
! 2928: if (next_fsync.tv_sec == 0 && next_fsync.tv_usec == 0) {
! 2929: next_fsync.tv_sec = cur_tv.tv_sec + max_ack_delay_secs;
! 2930: next_fsync.tv_usec = cur_tv.tv_usec + max_ack_delay_usecs;
! 2931:
! 2932: if (next_fsync.tv_usec >= 1000000) {
! 2933: next_fsync.tv_sec++;
! 2934: next_fsync.tv_usec -= 1000000;
! 2935: }
! 2936:
! 2937: add_timeout(&next_fsync, commit_leases_ackout, NULL,
! 2938: (tvref_t) NULL, (tvunref_t) NULL);
! 2939: }
! 2940: }
! 2941:
! 2942: void
! 2943: commit_leases_readerdry(void *foo)
! 2944: {
! 2945: if (outstanding_acks) {
! 2946: commit_leases();
! 2947:
! 2948: /* Reset next_fsync and cancel any pending timeout. */
! 2949: memset(&next_fsync, 0, sizeof(next_fsync));
! 2950: cancel_timeout(commit_leases_ackout, NULL);
! 2951: }
! 2952: }
! 2953:
! 2954: static void
! 2955: commit_leases_ackout(void *foo)
! 2956: {
! 2957: if (outstanding_acks) {
! 2958: commit_leases();
! 2959:
! 2960: memset(&next_fsync, 0, sizeof(next_fsync));
! 2961: }
! 2962: }
! 2963:
! 2964: /* CC: process the delayed ACK responses:
! 2965: - send out the ACK packets
! 2966: - move the queue slots to the free list
! 2967: */
! 2968: void
! 2969: flush_ackqueue(void *foo)
! 2970: {
! 2971: struct leasequeue *ack, *p;
! 2972: /* process from bottom to retain packet order */
! 2973: for (ack = ackqueue_tail ; ack ; ack = p) {
! 2974: p = ack->prev;
! 2975:
! 2976: /* dhcp_reply() requires that the reply state still be valid */
! 2977: if (ack->lease->state == NULL)
! 2978: log_error("delayed ack for %s has gone stale",
! 2979: piaddr(ack->lease->ip_addr));
! 2980: else
! 2981: dhcp_reply(ack->lease);
! 2982:
! 2983: lease_dereference(&ack->lease, MDL);
! 2984: ack->next = free_ackqueue;
! 2985: free_ackqueue = ack;
! 2986: }
! 2987: ackqueue_head = NULL;
! 2988: ackqueue_tail = NULL;
! 2989: outstanding_acks = 0;
! 2990: }
! 2991:
! 2992: #if defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)
! 2993: void
! 2994: relinquish_ackqueue(void)
! 2995: {
! 2996: struct leasequeue *q, *n;
! 2997:
! 2998: for (q = ackqueue_head ; q ; q = n) {
! 2999: n = q->next;
! 3000: dfree(q, MDL);
! 3001: }
! 3002: for (q = free_ackqueue ; q ; q = n) {
! 3003: n = q->next;
! 3004: dfree(q, MDL);
! 3005: }
! 3006: }
! 3007: #endif
! 3008:
! 3009: void dhcp_reply (lease)
! 3010: struct lease *lease;
! 3011: {
! 3012: int bufs = 0;
! 3013: unsigned packet_length;
! 3014: struct dhcp_packet raw;
! 3015: struct sockaddr_in to;
! 3016: struct in_addr from;
! 3017: struct hardware hto;
! 3018: int result;
! 3019: struct lease_state *state = lease -> state;
! 3020: int nulltp, bootpp, unicastp = 1;
! 3021: struct data_string d1;
! 3022: const char *s;
! 3023:
! 3024: if (!state)
! 3025: log_fatal ("dhcp_reply was supplied lease with no state!");
! 3026:
! 3027: /* Compose a response for the client... */
! 3028: memset (&raw, 0, sizeof raw);
! 3029: memset (&d1, 0, sizeof d1);
! 3030:
! 3031: /* Copy in the filename if given; otherwise, flag the filename
! 3032: buffer as available for options. */
! 3033: if (state -> filename.len && state -> filename.data) {
! 3034: memcpy (raw.file,
! 3035: state -> filename.data,
! 3036: state -> filename.len > sizeof raw.file
! 3037: ? sizeof raw.file : state -> filename.len);
! 3038: if (sizeof raw.file > state -> filename.len)
! 3039: memset (&raw.file [state -> filename.len], 0,
! 3040: (sizeof raw.file) - state -> filename.len);
! 3041: else
! 3042: log_info("file name longer than packet field "
! 3043: "truncated - field: %lu name: %d %.*s",
! 3044: (unsigned long)sizeof(raw.file),
! 3045: state->filename.len, state->filename.len,
! 3046: state->filename.data);
! 3047: } else
! 3048: bufs |= 1;
! 3049:
! 3050: /* Copy in the server name if given; otherwise, flag the
! 3051: server_name buffer as available for options. */
! 3052: if (state -> server_name.len && state -> server_name.data) {
! 3053: memcpy (raw.sname,
! 3054: state -> server_name.data,
! 3055: state -> server_name.len > sizeof raw.sname
! 3056: ? sizeof raw.sname : state -> server_name.len);
! 3057: if (sizeof raw.sname > state -> server_name.len)
! 3058: memset (&raw.sname [state -> server_name.len], 0,
! 3059: (sizeof raw.sname) - state -> server_name.len);
! 3060: else
! 3061: log_info("server name longer than packet field "
! 3062: "truncated - field: %lu name: %d %.*s",
! 3063: (unsigned long)sizeof(raw.sname),
! 3064: state->server_name.len,
! 3065: state->server_name.len,
! 3066: state->server_name.data);
! 3067: } else
! 3068: bufs |= 2; /* XXX */
! 3069:
! 3070: memcpy (raw.chaddr,
! 3071: &lease -> hardware_addr.hbuf [1], sizeof raw.chaddr);
! 3072: raw.hlen = lease -> hardware_addr.hlen - 1;
! 3073: raw.htype = lease -> hardware_addr.hbuf [0];
! 3074:
! 3075: /* See if this is a Microsoft client that NUL-terminates its
! 3076: strings and expects us to do likewise... */
! 3077: if (lease -> flags & MS_NULL_TERMINATION)
! 3078: nulltp = 1;
! 3079: else
! 3080: nulltp = 0;
! 3081:
! 3082: /* See if this is a bootp client... */
! 3083: if (state -> offer)
! 3084: bootpp = 0;
! 3085: else
! 3086: bootpp = 1;
! 3087:
! 3088: /* Insert such options as will fit into the buffer. */
! 3089: packet_length = cons_options (state -> packet, &raw, lease,
! 3090: (struct client_state *)0,
! 3091: state -> max_message_size,
! 3092: state -> packet -> options,
! 3093: state -> options, &global_scope,
! 3094: bufs, nulltp, bootpp,
! 3095: &state -> parameter_request_list,
! 3096: (char *)0);
! 3097:
! 3098: memcpy (&raw.ciaddr, &state -> ciaddr, sizeof raw.ciaddr);
! 3099: memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
! 3100: raw.siaddr = state -> siaddr;
! 3101: raw.giaddr = state -> giaddr;
! 3102:
! 3103: raw.xid = state -> xid;
! 3104: raw.secs = state -> secs;
! 3105: raw.flags = state -> bootp_flags;
! 3106: raw.hops = state -> hops;
! 3107: raw.op = BOOTREPLY;
! 3108:
! 3109: if (lease -> client_hostname) {
! 3110: if ((strlen (lease -> client_hostname) <= 64) &&
! 3111: db_printable((unsigned char *)lease->client_hostname))
! 3112: s = lease -> client_hostname;
! 3113: else
! 3114: s = "Hostname Unsuitable for Printing";
! 3115: } else
! 3116: s = (char *)0;
! 3117:
! 3118: /* Say what we're doing... */
! 3119: log_info ("%s on %s to %s %s%s%svia %s",
! 3120: (state -> offer
! 3121: ? (state -> offer == DHCPACK ? "DHCPACK" : "DHCPOFFER")
! 3122: : "BOOTREPLY"),
! 3123: piaddr (lease -> ip_addr),
! 3124: (lease -> hardware_addr.hlen
! 3125: ? print_hw_addr (lease -> hardware_addr.hbuf [0],
! 3126: lease -> hardware_addr.hlen - 1,
! 3127: &lease -> hardware_addr.hbuf [1])
! 3128: : print_hex_1(lease->uid_len, lease->uid, 60)),
! 3129: s ? "(" : "", s ? s : "", s ? ") " : "",
! 3130: (state -> giaddr.s_addr
! 3131: ? inet_ntoa (state -> giaddr)
! 3132: : state -> ip -> name));
! 3133:
! 3134: /* Set up the hardware address... */
! 3135: hto.hlen = lease -> hardware_addr.hlen;
! 3136: memcpy (hto.hbuf, lease -> hardware_addr.hbuf, hto.hlen);
! 3137:
! 3138: to.sin_family = AF_INET;
! 3139: #ifdef HAVE_SA_LEN
! 3140: to.sin_len = sizeof to;
! 3141: #endif
! 3142: memset (to.sin_zero, 0, sizeof to.sin_zero);
! 3143:
! 3144: #ifdef DEBUG_PACKET
! 3145: dump_raw ((unsigned char *)&raw, packet_length);
! 3146: #endif
! 3147:
! 3148: /* Make sure outgoing packets are at least as big
! 3149: as a BOOTP packet. */
! 3150: if (packet_length < BOOTP_MIN_LEN)
! 3151: packet_length = BOOTP_MIN_LEN;
! 3152:
! 3153: /* If this was gatewayed, send it back to the gateway... */
! 3154: if (raw.giaddr.s_addr) {
! 3155: to.sin_addr = raw.giaddr;
! 3156: if (raw.giaddr.s_addr != htonl (INADDR_LOOPBACK))
! 3157: to.sin_port = local_port;
! 3158: else
! 3159: to.sin_port = remote_port; /* For debugging. */
! 3160:
! 3161: if (fallback_interface) {
! 3162: result = send_packet (fallback_interface,
! 3163: (struct packet *)0,
! 3164: &raw, packet_length,
! 3165: raw.siaddr, &to,
! 3166: (struct hardware *)0);
! 3167:
! 3168: free_lease_state (state, MDL);
! 3169: lease -> state = (struct lease_state *)0;
! 3170: return;
! 3171: }
! 3172:
! 3173: /* If the client is RENEWING, unicast to the client using the
! 3174: regular IP stack. Some clients, particularly those that
! 3175: follow RFC1541, are buggy, and send both ciaddr and server
! 3176: identifier. We deal with this situation by assuming that
! 3177: if we got both dhcp-server-identifier and ciaddr, and
! 3178: giaddr was not set, then the client is on the local
! 3179: network, and we can therefore unicast or broadcast to it
! 3180: successfully. A client in REQUESTING state on another
! 3181: network that's making this mistake will have set giaddr,
! 3182: and will therefore get a relayed response from the above
! 3183: code. */
! 3184: } else if (raw.ciaddr.s_addr &&
! 3185: !((state -> got_server_identifier ||
! 3186: (raw.flags & htons (BOOTP_BROADCAST))) &&
! 3187: /* XXX This won't work if giaddr isn't zero, but it is: */
! 3188: (state -> shared_network ==
! 3189: lease -> subnet -> shared_network)) &&
! 3190: state -> offer == DHCPACK) {
! 3191: to.sin_addr = raw.ciaddr;
! 3192: to.sin_port = remote_port;
! 3193:
! 3194: if (fallback_interface) {
! 3195: result = send_packet (fallback_interface,
! 3196: (struct packet *)0,
! 3197: &raw, packet_length,
! 3198: raw.siaddr, &to,
! 3199: (struct hardware *)0);
! 3200: free_lease_state (state, MDL);
! 3201: lease -> state = (struct lease_state *)0;
! 3202: return;
! 3203: }
! 3204:
! 3205: /* If it comes from a client that already knows its address
! 3206: and is not requesting a broadcast response, and we can
! 3207: unicast to a client without using the ARP protocol, sent it
! 3208: directly to that client. */
! 3209: } else if (!(raw.flags & htons (BOOTP_BROADCAST)) &&
! 3210: can_unicast_without_arp (state -> ip)) {
! 3211: to.sin_addr = raw.yiaddr;
! 3212: to.sin_port = remote_port;
! 3213:
! 3214: /* Otherwise, broadcast it on the local network. */
! 3215: } else {
! 3216: to.sin_addr = limited_broadcast;
! 3217: to.sin_port = remote_port;
! 3218: if (!(lease -> flags & UNICAST_BROADCAST_HACK))
! 3219: unicastp = 0;
! 3220: }
! 3221:
! 3222: memcpy (&from, state -> from.iabuf, sizeof from);
! 3223:
! 3224: result = send_packet (state -> ip,
! 3225: (struct packet *)0, &raw, packet_length,
! 3226: from, &to,
! 3227: unicastp ? &hto : (struct hardware *)0);
! 3228:
! 3229: /* Free all of the entries in the option_state structure
! 3230: now that we're done with them. */
! 3231:
! 3232: free_lease_state (state, MDL);
! 3233: lease -> state = (struct lease_state *)0;
! 3234: }
! 3235:
! 3236: int find_lease (struct lease **lp,
! 3237: struct packet *packet, struct shared_network *share, int *ours,
! 3238: int *peer_has_leases, struct lease *ip_lease_in,
! 3239: const char *file, int line)
! 3240: {
! 3241: struct lease *uid_lease = (struct lease *)0;
! 3242: struct lease *ip_lease = (struct lease *)0;
! 3243: struct lease *hw_lease = (struct lease *)0;
! 3244: struct lease *lease = (struct lease *)0;
! 3245: struct iaddr cip;
! 3246: struct host_decl *hp = (struct host_decl *)0;
! 3247: struct host_decl *host = (struct host_decl *)0;
! 3248: struct lease *fixed_lease = (struct lease *)0;
! 3249: struct lease *next = (struct lease *)0;
! 3250: struct option_cache *oc;
! 3251: struct data_string d1;
! 3252: int have_client_identifier = 0;
! 3253: struct data_string client_identifier;
! 3254: struct hardware h;
! 3255:
! 3256: #if defined(FAILOVER_PROTOCOL)
! 3257: /* Quick check to see if the peer has leases. */
! 3258: if (peer_has_leases) {
! 3259: struct pool *pool;
! 3260:
! 3261: for (pool = share->pools ; pool ; pool = pool->next) {
! 3262: dhcp_failover_state_t *peer = pool->failover_peer;
! 3263:
! 3264: if (peer &&
! 3265: ((peer->i_am == primary && pool->backup_leases) ||
! 3266: (peer->i_am == secondary && pool->free_leases))) {
! 3267: *peer_has_leases = 1;
! 3268: break;
! 3269: }
! 3270: }
! 3271: }
! 3272: #endif /* FAILOVER_PROTOCOL */
! 3273:
! 3274: if (packet -> raw -> ciaddr.s_addr) {
! 3275: cip.len = 4;
! 3276: memcpy (cip.iabuf, &packet -> raw -> ciaddr, 4);
! 3277: } else {
! 3278: /* Look up the requested address. */
! 3279: oc = lookup_option (&dhcp_universe, packet -> options,
! 3280: DHO_DHCP_REQUESTED_ADDRESS);
! 3281: memset (&d1, 0, sizeof d1);
! 3282: if (oc &&
! 3283: evaluate_option_cache (&d1, packet, (struct lease *)0,
! 3284: (struct client_state *)0,
! 3285: packet -> options,
! 3286: (struct option_state *)0,
! 3287: &global_scope, oc, MDL)) {
! 3288: packet -> got_requested_address = 1;
! 3289: cip.len = 4;
! 3290: memcpy (cip.iabuf, d1.data, cip.len);
! 3291: data_string_forget (&d1, MDL);
! 3292: } else
! 3293: cip.len = 0;
! 3294: }
! 3295:
! 3296: /* Try to find a host or lease that's been assigned to the
! 3297: specified unique client identifier. */
! 3298: oc = lookup_option (&dhcp_universe, packet -> options,
! 3299: DHO_DHCP_CLIENT_IDENTIFIER);
! 3300: memset (&client_identifier, 0, sizeof client_identifier);
! 3301: if (oc &&
! 3302: evaluate_option_cache (&client_identifier,
! 3303: packet, (struct lease *)0,
! 3304: (struct client_state *)0,
! 3305: packet -> options, (struct option_state *)0,
! 3306: &global_scope, oc, MDL)) {
! 3307: /* Remember this for later. */
! 3308: have_client_identifier = 1;
! 3309:
! 3310: /* First, try to find a fixed host entry for the specified
! 3311: client identifier... */
! 3312: if (find_hosts_by_uid (&hp, client_identifier.data,
! 3313: client_identifier.len, MDL)) {
! 3314: /* Remember if we know of this client. */
! 3315: packet -> known = 1;
! 3316: mockup_lease (&fixed_lease, packet, share, hp);
! 3317: }
! 3318:
! 3319: #if defined (DEBUG_FIND_LEASE)
! 3320: if (fixed_lease) {
! 3321: log_info ("Found host for client identifier: %s.",
! 3322: piaddr (fixed_lease -> ip_addr));
! 3323: }
! 3324: #endif
! 3325: if (hp) {
! 3326: if (!fixed_lease) /* Save the host if we found one. */
! 3327: host_reference (&host, hp, MDL);
! 3328: host_dereference (&hp, MDL);
! 3329: }
! 3330:
! 3331: find_lease_by_uid (&uid_lease, client_identifier.data,
! 3332: client_identifier.len, MDL);
! 3333: }
! 3334:
! 3335: /* If we didn't find a fixed lease using the uid, try doing
! 3336: it with the hardware address... */
! 3337: if (!fixed_lease && !host) {
! 3338: if (find_hosts_by_haddr (&hp, packet -> raw -> htype,
! 3339: packet -> raw -> chaddr,
! 3340: packet -> raw -> hlen, MDL)) {
! 3341: /* Remember if we know of this client. */
! 3342: packet -> known = 1;
! 3343: if (host)
! 3344: host_dereference (&host, MDL);
! 3345: host_reference (&host, hp, MDL);
! 3346: host_dereference (&hp, MDL);
! 3347: mockup_lease (&fixed_lease, packet, share, host);
! 3348: #if defined (DEBUG_FIND_LEASE)
! 3349: if (fixed_lease) {
! 3350: log_info ("Found host for link address: %s.",
! 3351: piaddr (fixed_lease -> ip_addr));
! 3352: }
! 3353: #endif
! 3354: }
! 3355: }
! 3356:
! 3357: /* If fixed_lease is present but does not match the requested
! 3358: IP address, and this is a DHCPREQUEST, then we can't return
! 3359: any other lease, so we might as well return now. */
! 3360: if (packet -> packet_type == DHCPREQUEST && fixed_lease &&
! 3361: (fixed_lease -> ip_addr.len != cip.len ||
! 3362: memcmp (fixed_lease -> ip_addr.iabuf,
! 3363: cip.iabuf, cip.len))) {
! 3364: if (ours)
! 3365: *ours = 1;
! 3366: strcpy (dhcp_message, "requested address is incorrect");
! 3367: #if defined (DEBUG_FIND_LEASE)
! 3368: log_info ("Client's fixed-address %s doesn't match %s%s",
! 3369: piaddr (fixed_lease -> ip_addr), "request ",
! 3370: print_dotted_quads (cip.len, cip.iabuf));
! 3371: #endif
! 3372: goto out;
! 3373: }
! 3374:
! 3375: /* If we found leases matching the client identifier, loop through
! 3376: * the n_uid pointer looking for one that's actually valid. We
! 3377: * can't do this until we get here because we depend on
! 3378: * packet -> known, which may be set by either the uid host
! 3379: * lookup or the haddr host lookup.
! 3380: *
! 3381: * Note that the n_uid lease chain is sorted in order of
! 3382: * preference, so the first one is the best one.
! 3383: */
! 3384: while (uid_lease) {
! 3385: #if defined (DEBUG_FIND_LEASE)
! 3386: log_info ("trying next lease matching client id: %s",
! 3387: piaddr (uid_lease -> ip_addr));
! 3388: #endif
! 3389:
! 3390: #if defined (FAILOVER_PROTOCOL)
! 3391: /* When failover is active, it's possible that there could
! 3392: be two "free" leases for the same uid, but only one of
! 3393: them that's available for this failover peer to allocate. */
! 3394: if (uid_lease -> binding_state != FTS_ACTIVE &&
! 3395: !lease_mine_to_reallocate (uid_lease)) {
! 3396: #if defined (DEBUG_FIND_LEASE)
! 3397: log_info ("not mine to allocate: %s",
! 3398: piaddr (uid_lease -> ip_addr));
! 3399: #endif
! 3400: goto n_uid;
! 3401: }
! 3402: #endif
! 3403:
! 3404: if (uid_lease -> subnet -> shared_network != share) {
! 3405: #if defined (DEBUG_FIND_LEASE)
! 3406: log_info ("wrong network segment: %s",
! 3407: piaddr (uid_lease -> ip_addr));
! 3408: #endif
! 3409: goto n_uid;
! 3410: }
! 3411:
! 3412: if ((uid_lease -> pool -> prohibit_list &&
! 3413: permitted (packet, uid_lease -> pool -> prohibit_list)) ||
! 3414: (uid_lease -> pool -> permit_list &&
! 3415: !permitted (packet, uid_lease -> pool -> permit_list))) {
! 3416: #if defined (DEBUG_FIND_LEASE)
! 3417: log_info ("not permitted: %s",
! 3418: piaddr (uid_lease -> ip_addr));
! 3419: #endif
! 3420: n_uid:
! 3421: if (uid_lease -> n_uid)
! 3422: lease_reference (&next,
! 3423: uid_lease -> n_uid, MDL);
! 3424: if (!packet -> raw -> ciaddr.s_addr)
! 3425: release_lease (uid_lease, packet);
! 3426: lease_dereference (&uid_lease, MDL);
! 3427: if (next) {
! 3428: lease_reference (&uid_lease, next, MDL);
! 3429: lease_dereference (&next, MDL);
! 3430: }
! 3431: continue;
! 3432: }
! 3433: break;
! 3434: }
! 3435: #if defined (DEBUG_FIND_LEASE)
! 3436: if (uid_lease)
! 3437: log_info ("Found lease for client id: %s.",
! 3438: piaddr (uid_lease -> ip_addr));
! 3439: #endif
! 3440:
! 3441: /* Find a lease whose hardware address matches, whose client
! 3442: * identifier matches (or equally doesn't have one), that's
! 3443: * permitted, and that's on the correct subnet.
! 3444: *
! 3445: * Note that the n_hw chain is sorted in order of preference, so
! 3446: * the first one found is the best one.
! 3447: */
! 3448: h.hlen = packet -> raw -> hlen + 1;
! 3449: h.hbuf [0] = packet -> raw -> htype;
! 3450: memcpy (&h.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
! 3451: find_lease_by_hw_addr (&hw_lease, h.hbuf, h.hlen, MDL);
! 3452: while (hw_lease) {
! 3453: #if defined (DEBUG_FIND_LEASE)
! 3454: log_info ("trying next lease matching hw addr: %s",
! 3455: piaddr (hw_lease -> ip_addr));
! 3456: #endif
! 3457: #if defined (FAILOVER_PROTOCOL)
! 3458: /* When failover is active, it's possible that there could
! 3459: be two "free" leases for the same uid, but only one of
! 3460: them that's available for this failover peer to allocate. */
! 3461: if (hw_lease -> binding_state != FTS_ACTIVE &&
! 3462: !lease_mine_to_reallocate (hw_lease)) {
! 3463: #if defined (DEBUG_FIND_LEASE)
! 3464: log_info ("not mine to allocate: %s",
! 3465: piaddr (hw_lease -> ip_addr));
! 3466: #endif
! 3467: goto n_hw;
! 3468: }
! 3469: #endif
! 3470:
! 3471: if (hw_lease -> binding_state != FTS_FREE &&
! 3472: hw_lease -> binding_state != FTS_BACKUP &&
! 3473: hw_lease -> uid &&
! 3474: (!have_client_identifier ||
! 3475: hw_lease -> uid_len != client_identifier.len ||
! 3476: memcmp (hw_lease -> uid, client_identifier.data,
! 3477: hw_lease -> uid_len))) {
! 3478: #if defined (DEBUG_FIND_LEASE)
! 3479: log_info ("wrong client identifier: %s",
! 3480: piaddr (hw_lease -> ip_addr));
! 3481: #endif
! 3482: goto n_hw;
! 3483: }
! 3484: if (hw_lease -> subnet -> shared_network != share) {
! 3485: #if defined (DEBUG_FIND_LEASE)
! 3486: log_info ("wrong network segment: %s",
! 3487: piaddr (hw_lease -> ip_addr));
! 3488: #endif
! 3489: goto n_hw;
! 3490: }
! 3491: if ((hw_lease -> pool -> prohibit_list &&
! 3492: permitted (packet, hw_lease -> pool -> prohibit_list)) ||
! 3493: (hw_lease -> pool -> permit_list &&
! 3494: !permitted (packet, hw_lease -> pool -> permit_list))) {
! 3495: #if defined (DEBUG_FIND_LEASE)
! 3496: log_info ("not permitted: %s",
! 3497: piaddr (hw_lease -> ip_addr));
! 3498: #endif
! 3499: if (!packet -> raw -> ciaddr.s_addr)
! 3500: release_lease (hw_lease, packet);
! 3501: n_hw:
! 3502: if (hw_lease -> n_hw)
! 3503: lease_reference (&next, hw_lease -> n_hw, MDL);
! 3504: lease_dereference (&hw_lease, MDL);
! 3505: if (next) {
! 3506: lease_reference (&hw_lease, next, MDL);
! 3507: lease_dereference (&next, MDL);
! 3508: }
! 3509: continue;
! 3510: }
! 3511: break;
! 3512: }
! 3513: #if defined (DEBUG_FIND_LEASE)
! 3514: if (hw_lease)
! 3515: log_info ("Found lease for hardware address: %s.",
! 3516: piaddr (hw_lease -> ip_addr));
! 3517: #endif
! 3518:
! 3519: /* Try to find a lease that's been allocated to the client's
! 3520: IP address. */
! 3521: if (ip_lease_in)
! 3522: lease_reference (&ip_lease, ip_lease_in, MDL);
! 3523: else if (cip.len)
! 3524: find_lease_by_ip_addr (&ip_lease, cip, MDL);
! 3525:
! 3526: #if defined (DEBUG_FIND_LEASE)
! 3527: if (ip_lease)
! 3528: log_info ("Found lease for requested address: %s.",
! 3529: piaddr (ip_lease -> ip_addr));
! 3530: #endif
! 3531:
! 3532: /* If ip_lease is valid at this point, set ours to one, so that
! 3533: even if we choose a different lease, we know that the address
! 3534: the client was requesting was ours, and thus we can NAK it. */
! 3535: if (ip_lease && ours)
! 3536: *ours = 1;
! 3537:
! 3538: /* If the requested IP address isn't on the network the packet
! 3539: came from, don't use it. Allow abandoned leases to be matched
! 3540: here - if the client is requesting it, there's a decent chance
! 3541: that it's because the lease database got trashed and a client
! 3542: that thought it had this lease answered an ARP or PING, causing the
! 3543: lease to be abandoned. If so, this request probably came from
! 3544: that client. */
! 3545: if (ip_lease && (ip_lease -> subnet -> shared_network != share)) {
! 3546: if (ours)
! 3547: *ours = 1;
! 3548: #if defined (DEBUG_FIND_LEASE)
! 3549: log_info ("...but it was on the wrong shared network.");
! 3550: #endif
! 3551: strcpy (dhcp_message, "requested address on bad subnet");
! 3552: lease_dereference (&ip_lease, MDL);
! 3553: }
! 3554:
! 3555: /* Toss ip_lease if it hasn't yet expired and doesn't belong to the
! 3556: client. */
! 3557: if (ip_lease &&
! 3558: (ip_lease -> uid ?
! 3559: (!have_client_identifier ||
! 3560: ip_lease -> uid_len != client_identifier.len ||
! 3561: memcmp (ip_lease -> uid, client_identifier.data,
! 3562: ip_lease -> uid_len)) :
! 3563: (ip_lease -> hardware_addr.hbuf [0] != packet -> raw -> htype ||
! 3564: ip_lease -> hardware_addr.hlen != packet -> raw -> hlen + 1 ||
! 3565: memcmp (&ip_lease -> hardware_addr.hbuf [1],
! 3566: packet -> raw -> chaddr,
! 3567: (unsigned)(ip_lease -> hardware_addr.hlen - 1))))) {
! 3568: /* If we're not doing failover, the only state in which
! 3569: we can allocate this lease to the client is FTS_FREE.
! 3570: If we are doing failover, things are more complicated.
! 3571: If the lease is free or backup, we let the caller decide
! 3572: whether or not to give it out. */
! 3573: if (ip_lease -> binding_state != FTS_FREE &&
! 3574: ip_lease -> binding_state != FTS_BACKUP) {
! 3575: #if defined (DEBUG_FIND_LEASE)
! 3576: log_info ("rejecting lease for requested address.");
! 3577: #endif
! 3578: /* If we're rejecting it because the peer has
! 3579: it, don't set "ours", because we shouldn't NAK. */
! 3580: if (ours && ip_lease -> binding_state != FTS_ACTIVE)
! 3581: *ours = 0;
! 3582: lease_dereference (&ip_lease, MDL);
! 3583: }
! 3584: }
! 3585:
! 3586: /* If we got an ip_lease and a uid_lease or hw_lease, and ip_lease
! 3587: is not active, and is not ours to reallocate, forget about it. */
! 3588: if (ip_lease && (uid_lease || hw_lease) &&
! 3589: ip_lease -> binding_state != FTS_ACTIVE &&
! 3590: #if defined(FAILOVER_PROTOCOL)
! 3591: !lease_mine_to_reallocate (ip_lease) &&
! 3592: #endif
! 3593: packet -> packet_type == DHCPDISCOVER) {
! 3594: #if defined (DEBUG_FIND_LEASE)
! 3595: log_info ("ip lease not ours to offer.");
! 3596: #endif
! 3597: lease_dereference (&ip_lease, MDL);
! 3598: }
! 3599:
! 3600: /* If for some reason the client has more than one lease
! 3601: on the subnet that matches its uid, pick the one that
! 3602: it asked for and (if we can) free the other. */
! 3603: if (ip_lease && ip_lease->binding_state == FTS_ACTIVE &&
! 3604: ip_lease->uid && ip_lease != uid_lease) {
! 3605: if (have_client_identifier &&
! 3606: (ip_lease -> uid_len == client_identifier.len) &&
! 3607: !memcmp (client_identifier.data,
! 3608: ip_lease -> uid, ip_lease -> uid_len)) {
! 3609: if (uid_lease) {
! 3610: if (uid_lease->binding_state == FTS_ACTIVE) {
! 3611: log_error ("client %s has duplicate%s on %s",
! 3612: (print_hw_addr
! 3613: (packet -> raw -> htype,
! 3614: packet -> raw -> hlen,
! 3615: packet -> raw -> chaddr)),
! 3616: " leases",
! 3617: (ip_lease -> subnet ->
! 3618: shared_network -> name));
! 3619:
! 3620: /* If the client is REQUESTing the lease,
! 3621: it shouldn't still be using the old
! 3622: one, so we can free it for allocation. */
! 3623: if (uid_lease &&
! 3624: uid_lease->binding_state == FTS_ACTIVE &&
! 3625: !packet -> raw -> ciaddr.s_addr &&
! 3626: (share ==
! 3627: uid_lease -> subnet -> shared_network) &&
! 3628: packet -> packet_type == DHCPREQUEST)
! 3629: release_lease (uid_lease, packet);
! 3630: }
! 3631: lease_dereference (&uid_lease, MDL);
! 3632: lease_reference (&uid_lease, ip_lease, MDL);
! 3633: }
! 3634: }
! 3635:
! 3636: /* If we get to here and fixed_lease is not null, that means
! 3637: that there are both a dynamic lease and a fixed-address
! 3638: declaration for the same IP address. */
! 3639: if (packet -> packet_type == DHCPREQUEST && fixed_lease) {
! 3640: lease_dereference (&fixed_lease, MDL);
! 3641: db_conflict:
! 3642: log_error ("Dynamic and static leases present for %s.",
! 3643: piaddr (cip));
! 3644: log_error ("Remove host declaration %s or remove %s",
! 3645: (fixed_lease && fixed_lease -> host
! 3646: ? (fixed_lease -> host -> name
! 3647: ? fixed_lease -> host -> name
! 3648: : piaddr (cip))
! 3649: : piaddr (cip)),
! 3650: piaddr (cip));
! 3651: log_error ("from the dynamic address pool for %s",
! 3652: ip_lease -> subnet -> shared_network -> name
! 3653: );
! 3654: if (fixed_lease)
! 3655: lease_dereference (&ip_lease, MDL);
! 3656: strcpy (dhcp_message,
! 3657: "database conflict - call for help!");
! 3658: }
! 3659:
! 3660: if (ip_lease && ip_lease != uid_lease) {
! 3661: #if defined (DEBUG_FIND_LEASE)
! 3662: log_info ("requested address not available.");
! 3663: #endif
! 3664: lease_dereference (&ip_lease, MDL);
! 3665: }
! 3666: }
! 3667:
! 3668: /* If we get to here with both fixed_lease and ip_lease not
! 3669: null, then we have a configuration file bug. */
! 3670: if (packet -> packet_type == DHCPREQUEST && fixed_lease && ip_lease)
! 3671: goto db_conflict;
! 3672:
! 3673: /* Toss extra pointers to the same lease... */
! 3674: if (hw_lease && hw_lease == uid_lease) {
! 3675: #if defined (DEBUG_FIND_LEASE)
! 3676: log_info ("hardware lease and uid lease are identical.");
! 3677: #endif
! 3678: lease_dereference (&hw_lease, MDL);
! 3679: }
! 3680: if (ip_lease && ip_lease == hw_lease) {
! 3681: lease_dereference (&hw_lease, MDL);
! 3682: #if defined (DEBUG_FIND_LEASE)
! 3683: log_info ("hardware lease and ip lease are identical.");
! 3684: #endif
! 3685: }
! 3686: if (ip_lease && ip_lease == uid_lease) {
! 3687: lease_dereference (&uid_lease, MDL);
! 3688: #if defined (DEBUG_FIND_LEASE)
! 3689: log_info ("uid lease and ip lease are identical.");
! 3690: #endif
! 3691: }
! 3692:
! 3693: /* Make sure the client is permitted to use the requested lease. */
! 3694: if (ip_lease &&
! 3695: ((ip_lease -> pool -> prohibit_list &&
! 3696: permitted (packet, ip_lease -> pool -> prohibit_list)) ||
! 3697: (ip_lease -> pool -> permit_list &&
! 3698: !permitted (packet, ip_lease -> pool -> permit_list)))) {
! 3699: if (!packet->raw->ciaddr.s_addr &&
! 3700: (ip_lease->binding_state == FTS_ACTIVE))
! 3701: release_lease (ip_lease, packet);
! 3702:
! 3703: lease_dereference (&ip_lease, MDL);
! 3704: }
! 3705:
! 3706: if (uid_lease &&
! 3707: ((uid_lease -> pool -> prohibit_list &&
! 3708: permitted (packet, uid_lease -> pool -> prohibit_list)) ||
! 3709: (uid_lease -> pool -> permit_list &&
! 3710: !permitted (packet, uid_lease -> pool -> permit_list)))) {
! 3711: if (!packet -> raw -> ciaddr.s_addr)
! 3712: release_lease (uid_lease, packet);
! 3713: lease_dereference (&uid_lease, MDL);
! 3714: }
! 3715:
! 3716: if (hw_lease &&
! 3717: ((hw_lease -> pool -> prohibit_list &&
! 3718: permitted (packet, hw_lease -> pool -> prohibit_list)) ||
! 3719: (hw_lease -> pool -> permit_list &&
! 3720: !permitted (packet, hw_lease -> pool -> permit_list)))) {
! 3721: if (!packet -> raw -> ciaddr.s_addr)
! 3722: release_lease (hw_lease, packet);
! 3723: lease_dereference (&hw_lease, MDL);
! 3724: }
! 3725:
! 3726: /* If we've already eliminated the lease, it wasn't there to
! 3727: begin with. If we have come up with a matching lease,
! 3728: set the message to bad network in case we have to throw it out. */
! 3729: if (!ip_lease) {
! 3730: strcpy (dhcp_message, "requested address not available");
! 3731: }
! 3732:
! 3733: /* If this is a DHCPREQUEST, make sure the lease we're going to return
! 3734: matches the requested IP address. If it doesn't, don't return a
! 3735: lease at all. */
! 3736: if (packet -> packet_type == DHCPREQUEST &&
! 3737: !ip_lease && !fixed_lease) {
! 3738: #if defined (DEBUG_FIND_LEASE)
! 3739: log_info ("no applicable lease found for DHCPREQUEST.");
! 3740: #endif
! 3741: goto out;
! 3742: }
! 3743:
! 3744: /* At this point, if fixed_lease is nonzero, we can assign it to
! 3745: this client. */
! 3746: if (fixed_lease) {
! 3747: lease_reference (&lease, fixed_lease, MDL);
! 3748: lease_dereference (&fixed_lease, MDL);
! 3749: #if defined (DEBUG_FIND_LEASE)
! 3750: log_info ("choosing fixed address.");
! 3751: #endif
! 3752: }
! 3753:
! 3754: /* If we got a lease that matched the ip address and don't have
! 3755: a better offer, use that; otherwise, release it. */
! 3756: if (ip_lease) {
! 3757: if (lease) {
! 3758: if (!packet -> raw -> ciaddr.s_addr)
! 3759: release_lease (ip_lease, packet);
! 3760: #if defined (DEBUG_FIND_LEASE)
! 3761: log_info ("not choosing requested address (!).");
! 3762: #endif
! 3763: } else {
! 3764: #if defined (DEBUG_FIND_LEASE)
! 3765: log_info ("choosing lease on requested address.");
! 3766: #endif
! 3767: lease_reference (&lease, ip_lease, MDL);
! 3768: if (lease -> host)
! 3769: host_dereference (&lease -> host, MDL);
! 3770: }
! 3771: lease_dereference (&ip_lease, MDL);
! 3772: }
! 3773:
! 3774: /* If we got a lease that matched the client identifier, we may want
! 3775: to use it, but if we already have a lease we like, we must free
! 3776: the lease that matched the client identifier. */
! 3777: if (uid_lease) {
! 3778: if (lease) {
! 3779: log_error("uid lease %s for client %s is duplicate "
! 3780: "on %s",
! 3781: piaddr(uid_lease->ip_addr),
! 3782: print_hw_addr(packet->raw->htype,
! 3783: packet->raw->hlen,
! 3784: packet->raw->chaddr),
! 3785: uid_lease->subnet->shared_network->name);
! 3786:
! 3787: if (!packet -> raw -> ciaddr.s_addr &&
! 3788: packet -> packet_type == DHCPREQUEST &&
! 3789: uid_lease -> binding_state == FTS_ACTIVE)
! 3790: release_lease(uid_lease, packet);
! 3791: #if defined (DEBUG_FIND_LEASE)
! 3792: log_info ("not choosing uid lease.");
! 3793: #endif
! 3794: } else {
! 3795: lease_reference (&lease, uid_lease, MDL);
! 3796: if (lease -> host)
! 3797: host_dereference (&lease -> host, MDL);
! 3798: #if defined (DEBUG_FIND_LEASE)
! 3799: log_info ("choosing uid lease.");
! 3800: #endif
! 3801: }
! 3802: lease_dereference (&uid_lease, MDL);
! 3803: }
! 3804:
! 3805: /* The lease that matched the hardware address is treated likewise. */
! 3806: if (hw_lease) {
! 3807: if (lease) {
! 3808: #if defined (DEBUG_FIND_LEASE)
! 3809: log_info ("not choosing hardware lease.");
! 3810: #endif
! 3811: } else {
! 3812: /* We're a little lax here - if the client didn't
! 3813: send a client identifier and it's a bootp client,
! 3814: but the lease has a client identifier, we still
! 3815: let the client have a lease. */
! 3816: if (!hw_lease -> uid_len ||
! 3817: (have_client_identifier
! 3818: ? (hw_lease -> uid_len ==
! 3819: client_identifier.len &&
! 3820: !memcmp (hw_lease -> uid,
! 3821: client_identifier.data,
! 3822: client_identifier.len))
! 3823: : packet -> packet_type == 0)) {
! 3824: lease_reference (&lease, hw_lease, MDL);
! 3825: if (lease -> host)
! 3826: host_dereference (&lease -> host, MDL);
! 3827: #if defined (DEBUG_FIND_LEASE)
! 3828: log_info ("choosing hardware lease.");
! 3829: #endif
! 3830: } else {
! 3831: #if defined (DEBUG_FIND_LEASE)
! 3832: log_info ("not choosing hardware lease: %s.",
! 3833: "uid mismatch");
! 3834: #endif
! 3835: }
! 3836: }
! 3837: lease_dereference (&hw_lease, MDL);
! 3838: }
! 3839:
! 3840: /*
! 3841: * If we found a host_decl but no matching address, try to
! 3842: * find a host_decl that has no address, and if there is one,
! 3843: * hang it off the lease so that we can use the supplied
! 3844: * options.
! 3845: */
! 3846: if (lease && host && !lease->host) {
! 3847: struct host_decl *p = NULL;
! 3848: struct host_decl *n = NULL;
! 3849:
! 3850: host_reference(&p, host, MDL);
! 3851: while (p != NULL) {
! 3852: if (!p->fixed_addr) {
! 3853: /*
! 3854: * If the lease is currently active, then it
! 3855: * must be allocated to the present client.
! 3856: * We store a reference to the host record on
! 3857: * the lease to save a lookup later (in
! 3858: * ack_lease()). We mustn't refer to the host
! 3859: * record on non-active leases because the
! 3860: * client may be denied later.
! 3861: *
! 3862: * XXX: Not having this reference (such as in
! 3863: * DHCPDISCOVER/INIT) means ack_lease will have
! 3864: * to perform this lookup a second time. This
! 3865: * hopefully isn't a problem as DHCPREQUEST is
! 3866: * more common than DHCPDISCOVER.
! 3867: */
! 3868: if (lease->binding_state == FTS_ACTIVE)
! 3869: host_reference(&lease->host, p, MDL);
! 3870:
! 3871: host_dereference(&p, MDL);
! 3872: break;
! 3873: }
! 3874: if (p->n_ipaddr != NULL)
! 3875: host_reference(&n, p->n_ipaddr, MDL);
! 3876: host_dereference(&p, MDL);
! 3877: if (n != NULL) {
! 3878: host_reference(&p, n, MDL);
! 3879: host_dereference(&n, MDL);
! 3880: }
! 3881: }
! 3882: }
! 3883:
! 3884: /* If we find an abandoned lease, but it's the one the client
! 3885: requested, we assume that previous bugginess on the part
! 3886: of the client, or a server database loss, caused the lease to
! 3887: be abandoned, so we reclaim it and let the client have it. */
! 3888: if (lease &&
! 3889: (lease -> binding_state == FTS_ABANDONED) &&
! 3890: lease == ip_lease &&
! 3891: packet -> packet_type == DHCPREQUEST) {
! 3892: log_error ("Reclaiming REQUESTed abandoned IP address %s.",
! 3893: piaddr (lease -> ip_addr));
! 3894: } else if (lease && (lease -> binding_state == FTS_ABANDONED)) {
! 3895: /* Otherwise, if it's not the one the client requested, we do not
! 3896: return it - instead, we claim it's ours, causing a DHCPNAK to be
! 3897: sent if this lookup is for a DHCPREQUEST, and force the client
! 3898: to go back through the allocation process. */
! 3899: if (ours)
! 3900: *ours = 1;
! 3901: lease_dereference (&lease, MDL);
! 3902: }
! 3903:
! 3904: out:
! 3905: if (have_client_identifier)
! 3906: data_string_forget (&client_identifier, MDL);
! 3907:
! 3908: if (fixed_lease)
! 3909: lease_dereference (&fixed_lease, MDL);
! 3910: if (hw_lease)
! 3911: lease_dereference (&hw_lease, MDL);
! 3912: if (uid_lease)
! 3913: lease_dereference (&uid_lease, MDL);
! 3914: if (ip_lease)
! 3915: lease_dereference (&ip_lease, MDL);
! 3916: if (host)
! 3917: host_dereference (&host, MDL);
! 3918:
! 3919: if (lease) {
! 3920: #if defined (DEBUG_FIND_LEASE)
! 3921: log_info ("Returning lease: %s.",
! 3922: piaddr (lease -> ip_addr));
! 3923: #endif
! 3924: lease_reference (lp, lease, file, line);
! 3925: lease_dereference (&lease, MDL);
! 3926: return 1;
! 3927: }
! 3928: #if defined (DEBUG_FIND_LEASE)
! 3929: log_info ("Not returning a lease.");
! 3930: #endif
! 3931: return 0;
! 3932: }
! 3933:
! 3934: /* Search the provided host_decl structure list for an address that's on
! 3935: the specified shared network. If one is found, mock up and return a
! 3936: lease structure for it; otherwise return the null pointer. */
! 3937:
! 3938: int mockup_lease (struct lease **lp, struct packet *packet,
! 3939: struct shared_network *share, struct host_decl *hp)
! 3940: {
! 3941: struct lease *lease = (struct lease *)0;
! 3942: struct host_decl *rhp = (struct host_decl *)0;
! 3943:
! 3944: if (lease_allocate (&lease, MDL) != ISC_R_SUCCESS)
! 3945: return 0;
! 3946: if (host_reference (&rhp, hp, MDL) != ISC_R_SUCCESS) {
! 3947: lease_dereference (&lease, MDL);
! 3948: return 0;
! 3949: }
! 3950: if (!find_host_for_network (&lease -> subnet,
! 3951: &rhp, &lease -> ip_addr, share)) {
! 3952: lease_dereference (&lease, MDL);
! 3953: host_dereference (&rhp, MDL);
! 3954: return 0;
! 3955: }
! 3956: host_reference (&lease -> host, rhp, MDL);
! 3957: if (rhp -> client_identifier.len > sizeof lease -> uid_buf)
! 3958: lease -> uid = dmalloc (rhp -> client_identifier.len, MDL);
! 3959: else
! 3960: lease -> uid = lease -> uid_buf;
! 3961: if (!lease -> uid) {
! 3962: lease_dereference (&lease, MDL);
! 3963: host_dereference (&rhp, MDL);
! 3964: return 0;
! 3965: }
! 3966: memcpy (lease -> uid, rhp -> client_identifier.data,
! 3967: rhp -> client_identifier.len);
! 3968: lease -> uid_len = rhp -> client_identifier.len;
! 3969: lease -> hardware_addr = rhp -> interface;
! 3970: lease -> starts = lease -> cltt = lease -> ends = MIN_TIME;
! 3971: lease -> flags = STATIC_LEASE;
! 3972: lease -> binding_state = FTS_FREE;
! 3973:
! 3974: lease_reference (lp, lease, MDL);
! 3975:
! 3976: lease_dereference (&lease, MDL);
! 3977: host_dereference (&rhp, MDL);
! 3978: return 1;
! 3979: }
! 3980:
! 3981: /* Look through all the pools in a list starting with the specified pool
! 3982: for a free lease. We try to find a virgin lease if we can. If we
! 3983: don't find a virgin lease, we try to find a non-virgin lease that's
! 3984: free. If we can't find one of those, we try to reclaim an abandoned
! 3985: lease. If all of these possibilities fail to pan out, we don't return
! 3986: a lease at all. */
! 3987:
! 3988: int allocate_lease (struct lease **lp, struct packet *packet,
! 3989: struct pool *pool, int *peer_has_leases)
! 3990: {
! 3991: struct lease *lease = (struct lease *)0;
! 3992: struct lease *candl = (struct lease *)0;
! 3993:
! 3994: for (; pool ; pool = pool -> next) {
! 3995: if ((pool -> prohibit_list &&
! 3996: permitted (packet, pool -> prohibit_list)) ||
! 3997: (pool -> permit_list &&
! 3998: !permitted (packet, pool -> permit_list)))
! 3999: continue;
! 4000:
! 4001: #if defined (FAILOVER_PROTOCOL)
! 4002: /* Peer_has_leases just says that we found at least one
! 4003: free lease. If no free lease is returned, the caller
! 4004: can deduce that this means the peer is hogging all the
! 4005: free leases, so we can print a better error message. */
! 4006: /* XXX Do we need code here to ignore PEER_IS_OWNER and
! 4007: * XXX just check tstp if we're in, e.g., PARTNER_DOWN?
! 4008: * XXX Where do we deal with CONFLICT_DETECTED, et al? */
! 4009: /* XXX This should be handled by the lease binding "state
! 4010: * XXX machine" - that is, when we get here, if a lease
! 4011: * XXX could be allocated, it will have the correct
! 4012: * XXX binding state so that the following code will
! 4013: * XXX result in its being allocated. */
! 4014: /* Skip to the most expired lease in the pool that is not
! 4015: * owned by a failover peer. */
! 4016: if (pool->failover_peer != NULL) {
! 4017: if (pool->failover_peer->i_am == primary) {
! 4018: candl = pool->free;
! 4019:
! 4020: /*
! 4021: * In normal operation, we never want to touch
! 4022: * the peer's leases. In partner-down
! 4023: * operation, we need to be able to pick up
! 4024: * the peer's leases after STOS+MCLT.
! 4025: */
! 4026: if (pool->backup != NULL) {
! 4027: if (((candl == NULL) ||
! 4028: (candl->ends >
! 4029: pool->backup->ends)) &&
! 4030: lease_mine_to_reallocate(
! 4031: pool->backup)) {
! 4032: candl = pool->backup;
! 4033: } else {
! 4034: *peer_has_leases = 1;
! 4035: }
! 4036: }
! 4037: } else {
! 4038: candl = pool->backup;
! 4039:
! 4040: if (pool->free != NULL) {
! 4041: if (((candl == NULL) ||
! 4042: (candl->ends >
! 4043: pool->free->ends)) &&
! 4044: lease_mine_to_reallocate(
! 4045: pool->free)) {
! 4046: candl = pool->free;
! 4047: } else {
! 4048: *peer_has_leases = 1;
! 4049: }
! 4050: }
! 4051: }
! 4052:
! 4053: if ((candl == NULL) &&
! 4054: (pool->abandoned != NULL) &&
! 4055: lease_mine_to_reallocate(pool->abandoned))
! 4056: candl = pool->abandoned;
! 4057: } else
! 4058: #endif
! 4059: {
! 4060: if (pool -> free)
! 4061: candl = pool -> free;
! 4062: else
! 4063: candl = pool -> abandoned;
! 4064: }
! 4065:
! 4066: /*
! 4067: * XXX: This may not match with documented expectation.
! 4068: * It's expected that when we OFFER a lease, we set its
! 4069: * ends time forward 2 minutes so that it gets sorted to
! 4070: * the end of its free list (avoiding a similar allocation
! 4071: * to another client). It is not expected that we issue a
! 4072: * "no free leases" error when the last lease has been
! 4073: * offered, but it's not exactly broken either.
! 4074: */
! 4075: if (!candl || (candl -> ends > cur_time))
! 4076: continue;
! 4077:
! 4078: if (!lease) {
! 4079: lease = candl;
! 4080: continue;
! 4081: }
! 4082:
! 4083: if ((lease -> binding_state == FTS_ABANDONED) &&
! 4084: ((candl -> binding_state != FTS_ABANDONED) ||
! 4085: (candl -> ends < lease -> ends))) {
! 4086: lease = candl;
! 4087: continue;
! 4088: } else if (candl -> binding_state == FTS_ABANDONED)
! 4089: continue;
! 4090:
! 4091: if ((lease -> uid_len || lease -> hardware_addr.hlen) &&
! 4092: ((!candl -> uid_len && !candl -> hardware_addr.hlen) ||
! 4093: (candl -> ends < lease -> ends))) {
! 4094: lease = candl;
! 4095: continue;
! 4096: } else if (candl -> uid_len || candl -> hardware_addr.hlen)
! 4097: continue;
! 4098:
! 4099: if (candl -> ends < lease -> ends)
! 4100: lease = candl;
! 4101: }
! 4102:
! 4103: if (lease != NULL) {
! 4104: if (lease->binding_state == FTS_ABANDONED)
! 4105: log_error("Reclaiming abandoned lease %s.",
! 4106: piaddr(lease->ip_addr));
! 4107:
! 4108: /*
! 4109: * XXX: For reliability, we go ahead and remove the host
! 4110: * record and try to move on. For correctness, if there
! 4111: * are any other stale host vectors, we want to find them.
! 4112: */
! 4113: if (lease->host != NULL) {
! 4114: log_debug("soft impossible condition (%s:%d): stale "
! 4115: "host \"%s\" found on lease %s", MDL,
! 4116: lease->host->name,
! 4117: piaddr(lease->ip_addr));
! 4118: host_dereference(&lease->host, MDL);
! 4119: }
! 4120:
! 4121: lease_reference (lp, lease, MDL);
! 4122: return 1;
! 4123: }
! 4124:
! 4125: return 0;
! 4126: }
! 4127:
! 4128: /* Determine whether or not a permit exists on a particular permit list
! 4129: that matches the specified packet, returning nonzero if so, zero if
! 4130: not. */
! 4131:
! 4132: int permitted (packet, permit_list)
! 4133: struct packet *packet;
! 4134: struct permit *permit_list;
! 4135: {
! 4136: struct permit *p;
! 4137: int i;
! 4138:
! 4139: for (p = permit_list; p; p = p -> next) {
! 4140: switch (p -> type) {
! 4141: case permit_unknown_clients:
! 4142: if (!packet -> known)
! 4143: return 1;
! 4144: break;
! 4145:
! 4146: case permit_known_clients:
! 4147: if (packet -> known)
! 4148: return 1;
! 4149: break;
! 4150:
! 4151: case permit_authenticated_clients:
! 4152: if (packet -> authenticated)
! 4153: return 1;
! 4154: break;
! 4155:
! 4156: case permit_unauthenticated_clients:
! 4157: if (!packet -> authenticated)
! 4158: return 1;
! 4159: break;
! 4160:
! 4161: case permit_all_clients:
! 4162: return 1;
! 4163:
! 4164: case permit_dynamic_bootp_clients:
! 4165: if (!packet -> options_valid ||
! 4166: !packet -> packet_type)
! 4167: return 1;
! 4168: break;
! 4169:
! 4170: case permit_class:
! 4171: for (i = 0; i < packet -> class_count; i++) {
! 4172: if (p -> class == packet -> classes [i])
! 4173: return 1;
! 4174: if (packet -> classes [i] &&
! 4175: packet -> classes [i] -> superclass &&
! 4176: (packet -> classes [i] -> superclass ==
! 4177: p -> class))
! 4178: return 1;
! 4179: }
! 4180: break;
! 4181:
! 4182: case permit_after:
! 4183: if (cur_time > p->after)
! 4184: return 1;
! 4185: break;
! 4186: }
! 4187: }
! 4188: return 0;
! 4189: }
! 4190:
! 4191: int locate_network (packet)
! 4192: struct packet *packet;
! 4193: {
! 4194: struct iaddr ia;
! 4195: struct data_string data;
! 4196: struct subnet *subnet = (struct subnet *)0;
! 4197: struct option_cache *oc;
! 4198:
! 4199: /* See if there's a Relay Agent Link Selection Option, or a
! 4200: * Subnet Selection Option. The Link-Select and Subnet-Select
! 4201: * are formatted and used precisely the same, but we must prefer
! 4202: * the link-select over the subnet-select.
! 4203: */
! 4204: if ((oc = lookup_option(&agent_universe, packet->options,
! 4205: RAI_LINK_SELECT)) == NULL)
! 4206: oc = lookup_option(&dhcp_universe, packet->options,
! 4207: DHO_SUBNET_SELECTION);
! 4208:
! 4209: /* If there's no SSO and no giaddr, then use the shared_network
! 4210: from the interface, if there is one. If not, fail. */
! 4211: if (!oc && !packet -> raw -> giaddr.s_addr) {
! 4212: if (packet -> interface -> shared_network) {
! 4213: shared_network_reference
! 4214: (&packet -> shared_network,
! 4215: packet -> interface -> shared_network, MDL);
! 4216: return 1;
! 4217: }
! 4218: return 0;
! 4219: }
! 4220:
! 4221: /* If there's an option indicating link connection, and it's valid,
! 4222: * use it to figure out the subnet. If it's not valid, fail.
! 4223: */
! 4224: if (oc) {
! 4225: memset (&data, 0, sizeof data);
! 4226: if (!evaluate_option_cache (&data, packet, (struct lease *)0,
! 4227: (struct client_state *)0,
! 4228: packet -> options,
! 4229: (struct option_state *)0,
! 4230: &global_scope, oc, MDL)) {
! 4231: return 0;
! 4232: }
! 4233: if (data.len != 4) {
! 4234: return 0;
! 4235: }
! 4236: ia.len = 4;
! 4237: memcpy (ia.iabuf, data.data, 4);
! 4238: data_string_forget (&data, MDL);
! 4239: } else {
! 4240: ia.len = 4;
! 4241: memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);
! 4242: }
! 4243:
! 4244: /* If we know the subnet on which the IP address lives, use it. */
! 4245: if (find_subnet (&subnet, ia, MDL)) {
! 4246: shared_network_reference (&packet -> shared_network,
! 4247: subnet -> shared_network, MDL);
! 4248: subnet_dereference (&subnet, MDL);
! 4249: return 1;
! 4250: }
! 4251:
! 4252: /* Otherwise, fail. */
! 4253: return 0;
! 4254: }
! 4255:
! 4256: /*
! 4257: * Try to figure out the source address to send packets from.
! 4258: *
! 4259: * If the packet we received specified the server address, then we
! 4260: * will use that.
! 4261: *
! 4262: * Otherwise, use the first address from the interface. If we do
! 4263: * this, we also save this into the option cache as the server
! 4264: * address.
! 4265: */
! 4266: void
! 4267: get_server_source_address(struct in_addr *from,
! 4268: struct option_state *options,
! 4269: struct packet *packet) {
! 4270: unsigned option_num;
! 4271: struct option_cache *oc;
! 4272: struct data_string d;
! 4273: struct in_addr *a;
! 4274:
! 4275: memset(&d, 0, sizeof(d));
! 4276:
! 4277: option_num = DHO_DHCP_SERVER_IDENTIFIER;
! 4278: oc = lookup_option(&dhcp_universe, options, option_num);
! 4279: if ((oc != NULL) &&
! 4280: evaluate_option_cache(&d, packet, NULL, NULL, packet->options,
! 4281: options, &global_scope, oc, MDL)) {
! 4282: if (d.len == sizeof(*from)) {
! 4283: memcpy(from, d.data, sizeof(*from));
! 4284: data_string_forget(&d, MDL);
! 4285: return;
! 4286: }
! 4287: data_string_forget(&d, MDL);
! 4288: }
! 4289:
! 4290: if (packet->interface->address_count > 0) {
! 4291: if (option_cache_allocate(&oc, MDL)) {
! 4292: a = &packet->interface->addresses[0];
! 4293: if (make_const_data(&oc->expression,
! 4294: (unsigned char *)a, sizeof(*a),
! 4295: 0, 0, MDL)) {
! 4296: option_code_hash_lookup(&oc->option,
! 4297: dhcp_universe.code_hash,
! 4298: &option_num, 0, MDL);
! 4299: save_option(&dhcp_universe, options, oc);
! 4300: }
! 4301: option_cache_dereference(&oc, MDL);
! 4302: }
! 4303: *from = packet->interface->addresses[0];
! 4304: } else {
! 4305: memset(from, 0, sizeof(*from));
! 4306: }
! 4307: }
! 4308:
! 4309: /*
! 4310: * Look for the lowest numbered site code number and
! 4311: * apply a log warning if it is less than 224. Do not
! 4312: * permit site codes less than 128 (old code never did).
! 4313: *
! 4314: * Note that we could search option codes 224 down to 128
! 4315: * on the hash table, but the table is (probably) smaller
! 4316: * than that if it was declared as a standalone table with
! 4317: * defaults. So we traverse the option code hash.
! 4318: */
! 4319: static int
! 4320: find_min_site_code(struct universe *u)
! 4321: {
! 4322: if (u->site_code_min)
! 4323: return u->site_code_min;
! 4324:
! 4325: /*
! 4326: * Note that site_code_min has to be global as we can't pass an
! 4327: * argument through hash_foreach(). The value 224 is taken from
! 4328: * RFC 3942.
! 4329: */
! 4330: site_code_min = 224;
! 4331: option_code_hash_foreach(u->code_hash, lowest_site_code);
! 4332:
! 4333: if (site_code_min < 224) {
! 4334: log_error("WARNING: site-local option codes less than 224 have "
! 4335: "been deprecated by RFC3942. You have options "
! 4336: "listed in site local space %s that number as low as "
! 4337: "%d. Please investigate if these should be declared "
! 4338: "as regular options rather than site-local options, "
! 4339: "or migrated up past 224.",
! 4340: u->name, site_code_min);
! 4341: }
! 4342:
! 4343: /*
! 4344: * don't even bother logging, this is just silly, and never worked
! 4345: * on any old version of software.
! 4346: */
! 4347: if (site_code_min < 128)
! 4348: site_code_min = 128;
! 4349:
! 4350: /*
! 4351: * Cache the determined minimum site code on the universe structure.
! 4352: * Note that due to the < 128 check above, a value of zero is
! 4353: * impossible.
! 4354: */
! 4355: u->site_code_min = site_code_min;
! 4356:
! 4357: return site_code_min;
! 4358: }
! 4359:
! 4360: static isc_result_t
! 4361: lowest_site_code(const void *key, unsigned len, void *object)
! 4362: {
! 4363: struct option *option = object;
! 4364:
! 4365: if (option->code < site_code_min)
! 4366: site_code_min = option->code;
! 4367:
! 4368: return ISC_R_SUCCESS;
! 4369: }
! 4370:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>