]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
[master]
authorShawn Routhier <sar@isc.org>
Fri, 2 Nov 2012 23:37:03 +0000 (16:37 -0700)
committerShawn Routhier <sar@isc.org>
Fri, 2 Nov 2012 23:37:03 +0000 (16:37 -0700)
Modify the nak_lease function to make some attempts to find a
server-identifier option to use for the NAK.

RELNOTES
includes/site.h
server/dhcp.c

index 4bcacdf6fdbea4f7e3d1f775f01bc04c3a4011c8..80e129294ffdd99306a873d1100404fe0591a823 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -150,6 +150,10 @@ work on other platforms. Please report any problems and suggested fixes to
 - Parsing unquoted base64 strings improved. Parser now properly handles 
   strings that contain reserved names. [ISC-Bugs #23048]
 
+- Modify the nak_lease function to make some attempts to find a
+  server-identifier option to use for the NAK.
+  [ISC-Bugs #25689]
+
                        Changes since 4.2.3
 
 ! Add a check for a null pointer before calling the regexec function.
index 89c77a9eaf24de3461fdadb4f047061fec5b5a38..f424129dfac45affa1a6c313eed3f9b9e769fae9 100644 (file)
    require the original functionality. */
 
 /* #define RFC3315_PRE_ERRATA_2010_08 */
+
+/* In previous versions of the code when the server generates a NAK
+   it doesn't attempt to determine if the configuration included a
+   server ID for that client.  Defining this option causes the server
+   to make a modest effort to determine the server id when building
+   a NAK as a response.  This effort will only check the first subnet
+   and pool associated with a shared subnet and will not check for
+   host declarations.  With some configurations the server id
+   computed for a NAK may not match that computed for an ACK. */
+
+#define SERVER_ID_FOR_NAK
index 58072c93c3a40ceac07203b54a49036c07c5778f..6eb71febb1207489a8da6a7c4095e60ef81ab841 100644 (file)
@@ -1336,6 +1336,7 @@ void nak_lease (packet, cip)
        struct sockaddr_in to;
        struct in_addr from;
        int result;
+       int got_source = 0;
        struct dhcp_packet raw;
        unsigned char nak = DHCPNAK;
        struct packet outgoing;
@@ -1386,8 +1387,96 @@ void nak_lease (packet, cip)
                                &i, 0, MDL);
        save_option (&dhcp_universe, options, oc);
        option_cache_dereference (&oc, MDL);
-                    
-       get_server_source_address(&from, options, packet);
+
+#if defined(SERVER_ID_FOR_NAK)
+       /*
+        * Check to see if there is a server id we should use for the NAK.
+        * In order to minimize the effort involved we only check the
+        * global, shared_network and first subnet and pool on the
+        * shared_network (if they exist).  We skip the other subnets
+        * and pools and don't check on the host declarations.
+        *
+        * We get the shared subnet from the packet and execute the statements
+        * then check for a server id.  As we only want the server ID we
+        * execute the statements into a separate options area and then
+        * free that area when we finish
+        */
+       if (packet->shared_network != NULL) {
+               struct option_state *sid_options = NULL;
+               struct data_string d;
+               struct option_cache *soc = NULL;
+
+               option_state_allocate (&sid_options, MDL);
+               /*
+                * If we have a subnet and group start with that else start
+                * with the shared network group.  The first will recurse and
+                * include the second.
+                */
+               if ((packet->shared_network->subnets != NULL) &&
+                   (packet->shared_network->subnets->group != NULL)) {
+                       execute_statements_in_scope(NULL, packet, NULL, NULL,
+                                       packet->options, sid_options,
+                                       &global_scope,
+                                       packet->shared_network->subnets->group,
+                                       NULL);
+               } else {
+                       execute_statements_in_scope(NULL, packet, NULL, NULL,
+                                       packet->options, sid_options,
+                                       &global_scope,
+                                       packet->shared_network->group,
+                                       NULL);
+               }
+
+               /* do the pool if there is one */
+               if (packet->shared_network->pools != NULL) {
+                       execute_statements_in_scope(NULL, packet, NULL, NULL,
+                                       packet->options, sid_options,
+                                       &global_scope,
+                                       packet->shared_network->pools->group,
+                                       packet->shared_network->group);
+               }
+
+               memset(&d, 0, sizeof(d));
+
+               i = DHO_DHCP_SERVER_IDENTIFIER;
+               oc = lookup_option(&dhcp_universe, sid_options, i);
+               if ((oc != NULL) &&
+                   (evaluate_option_cache(&d, packet, NULL, NULL,
+                                          packet->options, sid_options, 
+                                          &global_scope, oc, MDL))) {
+                       if (d.len == sizeof(from)) {
+                               /* We have a server id and it's the proper length
+                                * for an address save the address and try to add
+                                * it to the options list we are building for the
+                                * response packet.
+                                */
+                               memcpy(&from, d.data, sizeof(from));
+                               got_source = 1;
+
+                               if (option_cache_allocate(&soc, MDL) &&
+                                   (make_const_data(&soc->expression,
+                                                    (unsigned char *)&from,
+                                                    sizeof(from),
+                                                    0, 1, MDL))) {
+                                       option_code_hash_lookup(&soc->option,
+                                                       dhcp_universe.code_hash,
+                                                       &i, 0, MDL);
+                                       save_option(&dhcp_universe, options,
+                                                   soc);
+                               }
+                               if (soc != NULL)
+                                       option_cache_dereference(&soc, MDL);
+                       }
+                       data_string_forget(&d, MDL);
+               }
+               oc = NULL;
+               option_state_dereference (&sid_options, MDL);
+       }
+#endif /* if defined(SERVER_ID_FOR_NAK) */
+
+       if (got_source == 0) {
+               get_server_source_address(&from, options, packet);
+       }
 
        /* If there were agent options in the incoming packet, return
         * them.  We do not check giaddr to detect the presence of a
@@ -2630,10 +2719,10 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
                        if (oc -> option)
                                option_reference(&(noc->option), oc->option,
                                                 MDL);
-               }
 
-               save_option (&dhcp_universe, state -> options, noc);
-               option_cache_dereference (&noc, MDL);
+                       save_option (&dhcp_universe, state -> options, noc);
+                       option_cache_dereference (&noc, MDL);
+               }
        }
 
        /* Now, if appropriate, put in DHCP-specific options that