]> git.ipfire.org Git - thirdparty/dhcp.git/blobdiff - server/bootp.c
Update RELNOTES
[thirdparty/dhcp.git] / server / bootp.c
index 3a48cb4d1637ec7176390d330d01add467bc989d..d81f4f3680d07a3887684ccacfdd129bf1837eb3 100644 (file)
@@ -3,12 +3,12 @@
    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"
@@ -86,6 +80,7 @@ void bootp (packet)
 
        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
@@ -117,12 +112,39 @@ void bootp (packet)
                                        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;
        }
 
@@ -131,46 +153,45 @@ void bootp (packet)
        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;
@@ -183,20 +204,26 @@ void bootp (packet)
 
        /* 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)) {
@@ -216,6 +243,11 @@ void bootp (packet)
                        }
                }
 
+               /* 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. */
@@ -310,32 +342,66 @@ void bootp (packet)
        }
 
        /* 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;
@@ -350,10 +416,16 @@ void bootp (packet)
                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;
                }
 
@@ -373,10 +445,16 @@ void bootp (packet)
        }
 
        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)