]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master] Add use-host-decl-names support to BOOTP
authorThomas Markwalder <tmark@isc.org>
Mon, 27 Oct 2014 18:51:20 +0000 (14:51 -0400)
committerThomas Markwalder <tmark@isc.org>
Mon, 27 Oct 2014 18:51:20 +0000 (14:51 -0400)
    Merges in rt36233.

RELNOTES
common/options.c
common/tree.c
includes/dhcpd.h
server/bootp.c
server/dhcp.c

index b86316ab4308cb7338b17771b600ae8ec1219144..cf92bfcd05f044499ce2d9c0f0f241cc813e34f2 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -125,6 +125,10 @@ by Eric Young (eay@cryptsoft.com).
   [ISC-Bugs 35958]
   [ISC-Bugs 32545]
 
+- Added support of the configuration parameter, use-host-decl-names, to
+  BOOTP request handling.
+  [ISC-Bugs #36233]
+
                        Changes since 4.3.1b1
 
 - Modify the linux and openwrt dhclient scripts to process information
index 58610d7efd942ffab3d9236b31f654ee97c1fc75..315067197960cfa530c08e44b71fec1dd8ec44d3 100644 (file)
@@ -43,17 +43,11 @@ static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
                                 struct option_cache **opp);
 
 /* Parse all available options out of the specified packet. */
-
+/* Note, the caller is responsible for allocating packet->options. */
 int parse_options (packet)
        struct packet *packet;
 {
-       struct option_cache *op = (struct option_cache *)0;
-
-       /* Allocate a new option state. */
-       if (!option_state_allocate (&packet -> options, MDL)) {
-               packet -> options_valid = 0;
-               return 0;
-       }
+       struct option_cache *op = NULL;
 
        /* If we don't see the magic cookie, there's nothing to parse. */
        if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
@@ -3856,12 +3850,15 @@ void do_packet (interface, packet, len, from_port, from, hfrom)
                return;
        }
 
+       /* Allocate packet->options now so it is non-null for all packets */
+       decoded_packet->options_valid = 0;
+       if (!option_state_allocate (&decoded_packet->options, MDL)) {
+               return;
+       }
+
        /* If there's an option buffer, try to parse it. */
        if (decoded_packet->packet_length >= DHCP_FIXED_NON_UDP + 4) {
                if (!parse_options(decoded_packet)) {
-                       if (decoded_packet->options)
-                               option_state_dereference
-                                       (&decoded_packet->options, MDL);
                        packet_dereference (&decoded_packet, MDL);
                        return;
                }
index 102d80e63a91cf2a74ee3f264cd2b6b8a74b400d..bf5f0ec3b23a3ac4daa960ad984ae6273cf9b845 100644 (file)
@@ -2072,7 +2072,7 @@ int evaluate_data_expression (result, packet, lease, client_state,
                     ((packet == NULL) ||
                      (packet->dhcpv6_container_packet == NULL)))) {
 #if defined (DEBUG_EXPRESSIONS)
-                       log_debug("data: v6relay(%d) = NULL", len);
+                       log_debug("data: v6relay(%lu) = NULL", len);
 #endif
                        return (0);
                }
@@ -2090,7 +2090,7 @@ int evaluate_data_expression (result, packet, lease, client_state,
                /* We wanted a specific relay but were unable to find it */
                if ((len <= MAX_V6RELAY_HOPS) && (i != 0)) {
 #if defined (DEBUG_EXPRESSIONS)
-                       log_debug("data: v6relay(%d) = NULL", len);
+                       log_debug("data: v6relay(%lu) = NULL", len);
 #endif
                        return (0);
                }
@@ -2107,7 +2107,7 @@ int evaluate_data_expression (result, packet, lease, client_state,
                }
 
 #if defined (DEBUG_EXPRESSIONS)
-               log_debug("data: v6relay(%d) = %s", len, 
+               log_debug("data: v6relay(%lu) = %s", len,
                          s1 ? print_hex_3(result->len, result->data, 30)
                          : "NULL");
 #endif
@@ -2664,9 +2664,16 @@ int evaluate_option_cache (result, packet, lease, client_state,
                                         oc -> expression, file, line);
 }
 
-/* Evaluate an option cache and extract a boolean from the result,
-   returning the boolean.   Return false if there is no data. */
-
+/* Evaluate an option cache and extract a boolean from the result.
+ * The boolean option cache is actually a trinary value where:
+ *
+ *     0 = return 0, ignore parameter 0 (also the case for no data)
+ *     1 = return 1, ignore parameter 0
+ *     2 = return 0, ignore parameter 1
+ *
+ * This supports both classic boolean flags on/off as well as the
+ * allow/deny/ignore keywords
+*/
 int evaluate_boolean_option_cache (ignorep, packet,
                                   lease, client_state, in_options,
                                   cfg_options, scope, oc, file, line)
@@ -2681,36 +2688,35 @@ int evaluate_boolean_option_cache (ignorep, packet,
        const char *file;
        int line;
 {
-       struct data_string ds;
-       int result;
+       int result = 0;
+       if (ignorep)
+               *ignorep = 0;
 
-       /* So that we can be called with option_lookup as an argument. */
-       if (!oc || !in_options)
-               return 0;
-       
-       memset (&ds, 0, sizeof ds);
-       if (!evaluate_option_cache (&ds, packet,
-                                   lease, client_state, in_options,
-                                   cfg_options, scope, oc, file, line))
-               return 0;
+       /* Only attempt to evaluate if option_cache is not null. This permits
+        * us to be called with option_lookup() as an argument. */
+       if (oc && in_options) {
+               struct data_string ds;
+
+               memset(&ds, 0, sizeof ds);
+               if (evaluate_option_cache(&ds, packet,
+                                         lease, client_state, in_options,
+                                         cfg_options, scope, oc, file,
+                                         line)) {
+                       /* We have a value for the option set result and
+                        * ignore parameter accordingly. */
+                       if (ds.len) {
+                               if (ds.data[0] == 1)
+                                       result = 1;
+                               else if ((ds.data[0] == 2) && (ignorep != NULL))
+                                       *ignorep = 1;
+                       }
 
-       /* The boolean option cache is actually a trinary value.  Zero is
-        * off, one is on, and 2 is 'ignore'.
-        */
-       if (ds.len) {
-               result = ds.data [0];
-               if (result == 2) {
-                       result = 0;
-                       if (ignorep != NULL)
-                               *ignorep = 1;
-               } else if (ignorep != NULL)
-                       *ignorep = 0;
-       } else
-               result = 0;
-       data_string_forget (&ds, MDL);
-       return result;
+                       data_string_forget(&ds, MDL);
+               }
+       }
+
+       return (result);
 }
-               
 
 /* Evaluate a boolean expression and return the result of the evaluation,
    or FALSE if it failed. */
index 86773ecb83049b59216c5f9473ee3619a75bfbd6..2043708f53d716b204aad1e26e21315f147a44aa 100644 (file)
@@ -2277,7 +2277,8 @@ isc_result_t get_client_id(struct packet *, struct data_string *);
 void dhcpv6(struct packet *);
 
 /* bootp.c */
-void bootp (struct packet *);
+void bootp(struct packet *);
+void use_host_decl_name(struct packet *, struct lease* , struct option_state *);
 
 /* memory.c */
 extern int (*group_write_hook) (struct group_object *);
index 41528204b6918e3dbed6cba73ab30757589d05b8..ca54be6465bcc30df9beb8e32623123ce9008172 100644 (file)
@@ -170,29 +170,29 @@ void bootp (packet)
 
        /* Execute the host statements. */
        if (hp != NULL) {
-               execute_statements_in_scope (NULL, packet, lease, NULL,
-                                            packet->options, options,
-                                            &lease->scope, hp->group,
-                                            lease->subnet->group, 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;
@@ -205,20 +205,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_MAX_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)) {
@@ -238,6 +244,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. */
index 492487a15de52a0db4d5d23303482ae85f13ad5b..f055c4738b9f624a978c4d430fd51d689906a28b 100644 (file)
@@ -3216,33 +3216,10 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
                }
        }
 
-       /* Use the hostname from the host declaration if there is one
+       /* Use the name of the host declaration if there is one
           and no hostname has otherwise been provided, and if the 
           use-host-decl-name flag is set. */
-       i = DHO_HOST_NAME;
-       j = SV_USE_HOST_DECL_NAMES;
-       if (!lookup_option (&dhcp_universe, state -> options, i) &&
-           lease -> host && lease -> host -> name &&
-           (evaluate_boolean_option_cache
-            (&ignorep, packet, lease, (struct client_state *)0,
-             packet -> options, state -> options, &lease -> scope,
-             lookup_option (&server_universe, state -> options, j), MDL))) {
-               oc = (struct option_cache *)0;
-               if (option_cache_allocate (&oc, MDL)) {
-                       if (make_const_data (&oc -> expression,
-                                            ((unsigned char *)
-                                             lease -> host -> name),
-                                            strlen (lease -> host -> name),
-                                            1, 0, MDL)) {
-                               option_code_hash_lookup(&oc->option,
-                                                       dhcp_universe.code_hash,
-                                                       &i, 0, MDL);
-                               save_option (&dhcp_universe,
-                                            state -> options, oc);
-                       }
-                       option_cache_dereference (&oc, MDL);
-               }
-       }
+       use_host_decl_name(packet, lease, state->options);
 
        /* Send client_id back if we received it and echo-client-id is on. */
        echo_client_id(packet, lease, state->options, state->options);
@@ -5144,3 +5121,44 @@ maybe_return_agent_options(struct packet *packet, struct option_state *options)
                        options->universe_count = agent_universe.index + 1;
        }
 }
+
+/*!
+ * \brief Adds hostname option when use-host-decl-names is enabled.
+ *
+ * Constructs a hostname option from the name of the host declaration if
+ * there is one and no hostname has otherwise been provided and the
+ * use-host-decl-names flag is set, then adds the new option to the given
+ * option_state.  This funciton is used for both bootp and dhcp.
+ *
+ * \param packet inbound packet received from the client
+ * \param lease lease associated with the client
+ * \param options option state to search and update
+ */
+void use_host_decl_name(struct packet* packet,
+                       struct lease *lease,
+                       struct option_state *options) {
+       unsigned int ocode = SV_USE_HOST_DECL_NAMES;
+        if ((lease->host && lease->host->name) &&
+           !lookup_option(&dhcp_universe, options, DHO_HOST_NAME) &&
+            (evaluate_boolean_option_cache(NULL, packet, lease, NULL,
+                                          packet->options, options,
+                                          &lease->scope,
+                                          lookup_option(&server_universe,
+                                                        options, ocode),
+                                          MDL))) {
+               struct option_cache *oc = NULL;
+                if (option_cache_allocate (&oc, MDL)) {
+                        if (make_const_data(&oc -> expression,
+                                            ((unsigned char*)lease->host->name),
+                                            strlen(lease->host->name),
+                                           1, 0, MDL)) {
+                               ocode = DHO_HOST_NAME;
+                                option_code_hash_lookup(&oc->option,
+                                                        dhcp_universe.code_hash,
+                                                        &ocode, 0, MDL);
+                                save_option(&dhcp_universe, options, oc);
+                        }
+                        option_cache_dereference(&oc, MDL);
+                }
+        }
+}