BOOTP Protocol support. */
/*
- * Copyright (c) 2004,2005,2007 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-2003 by Internet Software Consortium
*
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Internet Systems Consortium, Inc.
- * 950 Charter Street
- * Redwood City, CA 94063
+ * PO Box 360
+ * Newmarket, NH 03857 USA
* <info@isc.org>
- * http://www.isc.org/
+ * https://www.isc.org/
*
- * This software has been written for Internet Systems Consortium
- * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
- * To learn more about Internet Systems Consortium, see
- * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
- * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
- * ``http://www.nominum.com''.
*/
#include "dhcpd.h"
if (!lease || ((lease->flags & STATIC_LEASE) == 0)) {
struct host_decl *h;
+
/* We didn't find an applicable fixed-address host
declaration. Just in case we may be able to dynamically
assign an address, see if there's a host declaration
packet -> shared_network -> pools,
&peer_has_leases);
- if (lease)
- ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
- else
- log_info ("%s: BOOTP from dynamic client and no "
- "dynamic leases", msgbuf);
+ if (lease == NULL) {
+ log_info("%s: BOOTP from dynamic client and no "
+ "dynamic leases", msgbuf);
+ goto out;
+ }
+
+#if defined(FAILOVER_PROTOCOL)
+ if ((lease->pool != NULL) &&
+ (lease->pool->failover_peer != NULL)) {
+ dhcp_failover_state_t *peer;
+
+ peer = lease->pool->failover_peer;
+
+ /* If we are in a failover state that bars us from
+ * answering, do not do so.
+ * If we are in a cooperative state, load balance
+ * (all) responses.
+ */
+ if ((peer->service_state == not_responding) ||
+ (peer->service_state == service_startup)) {
+ log_info("%s: not responding%s",
+ msgbuf, peer->nrr);
+ goto out;
+ } else if((peer->service_state == cooperating) &&
+ !load_balance_mine(packet, peer)) {
+ log_info("%s: load balance to peer %s",
+ msgbuf, peer->name);
+ goto out;
+ }
+ }
+#endif
+ ack_lease (packet, lease, 0, 0, msgbuf, 0, hp);
goto out;
}
option_state_allocate (&options, MDL);
/* Execute the subnet statements. */
- execute_statements_in_scope ((struct binding_value **)0,
- packet, lease, (struct client_state *)0,
- packet -> options, options,
- &lease -> scope, lease -> subnet -> group,
- (struct group *)0);
+ execute_statements_in_scope (NULL, packet, lease, NULL,
+ packet->options, options,
+ &lease->scope, lease->subnet->group,
+ NULL, NULL);
/* Execute statements from class scopes. */
for (i = packet -> class_count; i > 0; i--) {
- execute_statements_in_scope
- ((struct binding_value **)0,
- packet, lease, (struct client_state *)0,
- packet -> options, options,
- &lease -> scope, packet -> classes [i - 1] -> group,
- lease -> subnet -> group);
+ execute_statements_in_scope(NULL, packet, lease, NULL,
+ packet->options, options,
+ &lease->scope,
+ packet->classes[i - 1]->group,
+ lease->subnet->group, NULL);
}
/* Execute the host statements. */
- execute_statements_in_scope ((struct binding_value **)0,
- packet, lease, (struct client_state *)0,
- packet -> options, options,
- &lease -> scope,
- hp -> group, lease -> subnet -> group);
-
+ if (hp != NULL) {
+ execute_statements_in_scope(NULL, packet, lease, NULL,
+ packet->options, options,
+ &lease->scope, hp->group,
+ lease->subnet->group, NULL);
+ }
+
/* Drop the request if it's not allowed for this client. */
if ((oc = lookup_option (&server_universe, options, SV_ALLOW_BOOTP)) &&
- !evaluate_boolean_option_cache (&ignorep, packet, lease,
- (struct client_state *)0,
- packet -> options, options,
- &lease -> scope, oc, MDL)) {
+ !evaluate_boolean_option_cache(&ignorep, packet, lease,
+ NULL,
+ packet->options, options,
+ &lease->scope, oc, MDL)) {
if (!ignorep)
log_info ("%s: bootp disallowed", msgbuf);
goto out;
- }
+ }
- if ((oc = lookup_option (&server_universe,
+ if ((oc = lookup_option(&server_universe,
options, SV_ALLOW_BOOTING)) &&
- !evaluate_boolean_option_cache (&ignorep, packet, lease,
- (struct client_state *)0,
- packet -> options, options,
- &lease -> scope, oc, MDL)) {
+ !evaluate_boolean_option_cache(&ignorep, packet, lease,
+ NULL,
+ packet->options, options,
+ &lease->scope, oc, MDL)) {
if (!ignorep)
log_info ("%s: booting disallowed", msgbuf);
goto out;
/* If we didn't get a known vendor magic number on the way in,
just copy the input options to the output. */
- if (!packet -> options_valid &&
- !(evaluate_boolean_option_cache
- (&ignorep, packet, lease, (struct client_state *)0,
- packet -> options, options, &lease -> scope,
- lookup_option (&server_universe, options,
- SV_ALWAYS_REPLY_RFC1048), MDL))) {
- memcpy (outgoing.raw -> options,
- packet -> raw -> options, DHCP_OPTION_LEN);
- outgoing.packet_length = BOOTP_MIN_LEN;
+ i = SV_ALWAYS_REPLY_RFC1048;
+ if (!packet->options_valid &&
+ !(evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
+ packet->options, options,
+ &lease->scope,
+ lookup_option (&server_universe,
+ options, i), MDL))) {
+ if (packet->packet_length > DHCP_FIXED_NON_UDP) {
+ memcpy(outgoing.raw->options, packet->raw->options,
+ packet->packet_length - DHCP_FIXED_NON_UDP);
+ }
+
+ outgoing.packet_length =
+ (packet->packet_length < BOOTP_MIN_LEN)
+ ? BOOTP_MIN_LEN
+ : packet->packet_length;
} else {
/* Use the subnet mask from the subnet declaration if no other
mask has been provided. */
-
oc = (struct option_cache *)0;
i = DHO_SUBNET_MASK;
if (!lookup_option (&dhcp_universe, options, i)) {
}
}
+ /* If use-host-decl-names is enabled and there is a hostname
+ * defined in the host delcartion, send it back in hostname
+ * option */
+ use_host_decl_name(packet, lease, options);
+
/* Pack the options into the buffer. Unlike DHCP, we
can't pack options into the filename and server
name buffers. */
}
/* Execute the commit statements, if there are any. */
- execute_statements ((struct binding_value **)0,
- packet, lease, (struct client_state *)0,
- packet -> options,
- options, &lease -> scope, lease -> on_commit);
+ execute_statements (NULL, packet, lease, NULL, packet->options,
+ options, &lease->scope, lease->on_star.on_commit,
+ NULL);
/* We're done with the option state. */
option_state_dereference (&options, MDL);
+#if defined(DHCPv6) && defined(DHCP4o6)
+ if (dhcpv4_over_dhcpv6 && (packet->dhcp4o6_response != NULL)) {
+ /* Report what we're doing... */
+ log_info("%s", msgbuf);
+ log_info("DHCP4o6 BOOTREPLY for %s to %s (%s) via %s",
+ piaddr(lease->ip_addr),
+ ((hp != NULL) && (hp->name != NULL)) ?
+ hp -> name : "unknown",
+ print_hw_addr (packet->raw->htype,
+ packet->raw->hlen,
+ packet->raw->chaddr),
+ piaddr(packet->client_addr));
+
+ /* fill dhcp4o6_response */
+ packet->dhcp4o6_response->len = outgoing.packet_length;
+ packet->dhcp4o6_response->buffer = NULL;
+ if (!buffer_allocate(&packet->dhcp4o6_response->buffer,
+ outgoing.packet_length, MDL)) {
+ log_fatal("No memory to store DHCP4o6 reply.");
+ }
+ packet->dhcp4o6_response->data =
+ packet->dhcp4o6_response->buffer->data;
+ memcpy(packet->dhcp4o6_response->buffer->data,
+ outgoing.raw, outgoing.packet_length);
+ goto out;
+ }
+#endif
+
/* Set up the hardware destination address... */
hto.hbuf [0] = packet -> raw -> htype;
hto.hlen = packet -> raw -> hlen + 1;
memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen);
- if (packet->interface->address_count)
+ if (packet->interface->address_count) {
from = packet->interface->addresses[0];
+ } else {
+ log_error("%s: Interface %s appears to have no IPv4 "
+ "addresses, and so dhcpd cannot select a source "
+ "address.", msgbuf, packet->interface->name);
+ goto out;
+ }
/* Report what we're doing... */
- log_info ("%s", msgbuf);
- log_info ("BOOTREPLY for %s to %s (%s) via %s",
- piaddr (lease->ip_addr), hp -> name,
- print_hw_addr (packet -> raw -> htype,
- packet -> raw -> hlen,
- packet -> raw -> chaddr),
- packet -> raw -> giaddr.s_addr
- ? inet_ntoa (packet -> raw -> giaddr)
- : packet -> interface -> name);
+ log_info("%s", msgbuf);
+ log_info("BOOTREPLY for %s to %s (%s) via %s",
+ piaddr(lease->ip_addr),
+ ((hp != NULL) && (hp->name != NULL)) ? hp -> name : "unknown",
+ print_hw_addr (packet->raw->htype,
+ packet->raw->hlen,
+ packet->raw->chaddr),
+ packet->raw->giaddr.s_addr
+ ? inet_ntoa (packet->raw->giaddr)
+ : packet->interface->name);
/* Set up the parts of the address that are in common. */
to.sin_family = AF_INET;
to.sin_port = local_port;
if (fallback_interface) {
- result = send_packet (fallback_interface,
- (struct packet *)0,
- &raw, outgoing.packet_length,
- from, &to, &hto);
+ result = send_packet (fallback_interface, NULL, &raw,
+ outgoing.packet_length, from,
+ &to, &hto);
+ if (result < 0) {
+ log_error ("%s:%d: Failed to send %d byte long "
+ "packet over %s interface.", MDL,
+ outgoing.packet_length,
+ fallback_interface->name);
+ }
+
goto out;
}
}
errno = 0;
- result = send_packet (packet -> interface,
- packet, &raw, outgoing.packet_length,
- from, &to, &hto);
+ result = send_packet(packet->interface, packet, &raw,
+ outgoing.packet_length, from, &to, &hto);
+ if (result < 0) {
+ log_error ("%s:%d: Failed to send %d byte long packet over %s"
+ " interface.", MDL, outgoing.packet_length,
+ packet->interface->name);
+ }
+
out:
+
if (options)
option_state_dereference (&options, MDL);
if (lease)