]> git.ipfire.org Git - thirdparty/dhcp.git/commitdiff
- A bug in subnet6 parsing where options contained in subnet6 clauses would
authorDavid Hankins <dhankins@isc.org>
Tue, 19 Aug 2008 17:55:57 +0000 (17:55 +0000)
committerDavid Hankins <dhankins@isc.org>
Tue, 19 Aug 2008 17:55:57 +0000 (17:55 +0000)
  not be applied to clients addressed within that network was repaired.

- When configuring a "subnet {}" or "subnet6 {}" without an explicit
  shared-network enclosing it, the DHCP software would synthesize a
  shared-network to contain the subnet.  However, all configuration
  parameters within the subnet more intuitively belong "to any client
  on that interface", or rather the synthesized shared-network.  So,
  when a shared-network is synthesized, it is used to contain the
  configuration present inside the subnet {} clause.  This means that
  the configuration will be valid for all clients on that network, not
  just those addressed out of the stated subnet.  If you intended the
  opposite, the workaround is to explicitly configure an empty
  shared-network.

- A bug was fixed where Information-Request processing was not sourcing
  configured option values.

- A warning was added since the DHCPv6 processing software does not yet
  support class statements.

  [ISC-Bugs #17638b]

RELNOTES
includes/dhcpd.h
server/confpars.c
server/dhcpd.conf.5
server/dhcpv6.c

index 049287828d5ba10b6f9909fab8555739db95e1da..d9f71f7a9f6913fb067f1cddb4331d912a8c608a 100644 (file)
--- a/RELNOTES
+++ b/RELNOTES
@@ -48,7 +48,7 @@ work on other platforms. Please report any problems and suggested fixes to
 <dhcp-users@isc.org>.
 
 
-                       Changes since 4.1.0a2
+                       Changes since 4.1.0a1
 
 - Corrected list of failover state values in dhcpd man page.
 
@@ -60,8 +60,6 @@ work on other platforms. Please report any problems and suggested fixes to
 
 - The server wasn't always sending the FQDN option when it should.
 
-                       Changes since 4.1.0a1
-
 - Fixed a coredump when adding a class via OMAPI.
 
 - Check whether files are zero length before trying to parse them.
@@ -111,6 +109,27 @@ work on other platforms. Please report any problems and suggested fixes to
 - Fix handling of -A and -a flags in dhcrelay; it was failing to expand
   packet size as needed to add relay agent options.
 
+- A bug in subnet6 parsing where options contained in subnet6 clauses would
+  not be applied to clients addressed within that network was repaired.
+
+- When configuring a "subnet {}" or "subnet6 {}" without an explicit
+  shared-network enclosing it, the DHCP software would synthesize a
+  shared-network to contain the subnet.  However, all configuration
+  parameters within the subnet more intuitively belong "to any client
+  on that interface", or rather the synthesized shared-network.  So,
+  when a shared-network is synthesized, it is used to contain the
+  configuration present inside the subnet {} clause.  This means that
+  the configuration will be valid for all clients on that network, not
+  just those addressed out of the stated subnet.  If you intended the
+  opposite, the workaround is to explicitly configure an empty
+  shared-network.
+
+- A bug was fixed where Information-Request processing was not sourcing
+  configured option values.
+
+- A warning was added since the DHCPv6 processing software does not yet
+  support class statements.
+
                        Changes since 4.0.0 (new features)
 
 - Added DHCPv6 rapid commit support.
index 98ee91ef5556155c4b8eac6a76793219c7ce4970..41b0b01bbc669ee04ba822c524c7e8abe1ba8e2f 100644 (file)
@@ -807,6 +807,10 @@ struct shared_network {
        OMAPI_OBJECT_PREAMBLE;
        struct shared_network *next;
        char *name;
+
+#define SHARED_IMPLICIT          1 /* This network was synthesized. */
+       int flags;
+
        struct subnet *subnets;
        struct interface_info *interface;
        struct pool *pools;
@@ -1395,6 +1399,7 @@ struct ipv6_pool {
                                                   released leases */
        struct shared_network *shared_network;  /* shared_network for 
                                                   this pool */
+       struct subnet *subnet;                  /* subnet for this pool */
 };
 
 extern struct ipv6_pool **pools;
index 747779a9f83537e3b04b6dec14231f6f19f8ad1f..0a25cc44645bd33a6966fd47d922937ddf03a2f4 100644 (file)
@@ -35,6 +35,7 @@
 #include "dhcpd.h"
 
 static unsigned char global_host_once = 1;
+static unsigned char dhcpv6_class_once = 1;
 
 static int parse_binding_value(struct parse *cfile,
                                struct binding_value *value);
@@ -432,7 +433,7 @@ int parse_statement (cfile, group, type, host_decl, declaration)
                }
 
                /* If we're in a subnet declaration, just do the parse. */
-               if (group->shared_network) {
+               if (group->shared_network != NULL) {
                        if (token == SUBNET) {
                                parse_subnet_declaration(cfile,
                                                         group->shared_network);
@@ -443,10 +444,15 @@ int parse_statement (cfile, group, type, host_decl, declaration)
                        break;
                }
 
-               /* Otherwise, cons up a fake shared network structure
-                  and populate it with the lone subnet... */
+               /*
+                * Otherwise, cons up a fake shared network structure
+                * and populate it with the lone subnet...because the
+                * intention most likely is to refer to the entire link
+                * by shorthand, any configuration inside the subnet is
+                * actually placed in the shared-network's group.
+                */
 
-               share = (struct shared_network *)0;
+               share = NULL;
                status = shared_network_allocate (&share, MDL);
                if (status != ISC_R_SUCCESS)
                        log_fatal ("Can't allocate shared subnet: %s",
@@ -456,6 +462,12 @@ int parse_statement (cfile, group, type, host_decl, declaration)
                shared_network_reference (&share -> group -> shared_network,
                                          share, MDL);
 
+               /*
+                * This is an implicit shared network, not explicit in
+                * the config.
+                */
+               share->flags |= SHARED_IMPLICIT;
+
                if (token == SUBNET) {
                        parse_subnet_declaration(cfile, share);
                } else {
@@ -2022,6 +2034,12 @@ int parse_class_declaration (cp, cfile, group, type)
        int submatchedonce = 0;
        unsigned code;
 
+       if (dhcpv6_class_once && local_family == AF_INET6) {
+               dhcpv6_class_once = 0;
+               log_error("WARNING: class declarations are not supported "
+                         "for DHCPv6.");
+       }
+
        token = next_token (&val, (unsigned *)0, cfile);
        if (token != STRING) {
                parse_warn (cfile, "Expecting class name");
@@ -2547,8 +2565,22 @@ void parse_subnet_declaration (cfile, share)
                log_fatal ("Allocation of new subnet failed: %s",
                           isc_result_totext (status));
        shared_network_reference (&subnet -> shared_network, share, MDL);
-       if (!clone_group (&subnet -> group, share -> group, MDL))
-               log_fatal ("allocation of group for new subnet failed.");
+
+       /*
+        * If our parent shared network was implicitly created by the software,
+        * and not explicitly configured by the user, then we actually put all
+        * configuration scope in the parent (the shared network and subnet
+        * share the same {}-level scope).
+        *
+        * Otherwise, we clone the parent group and continue as normal.
+        */
+       if (share->flags & SHARED_IMPLICIT) {
+               group_reference(&subnet->group, share->group, MDL);
+       } else {
+               if (!clone_group(&subnet->group, share->group, MDL)) {
+                       log_fatal("Allocation of group for new subnet failed.");
+               }
+       }
        subnet_reference (&subnet -> group -> subnet, subnet, MDL);
 
        /* Get the network number... */
@@ -2626,8 +2658,21 @@ parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
                          isc_result_totext(status));
        }
        shared_network_reference(&subnet->shared_network, share, MDL);
-       if (!clone_group(&subnet->group, share->group, MDL)) {
-               log_fatal("Allocation of group for new subnet failed.");
+
+       /*
+        * If our parent shared network was implicitly created by the software,
+        * and not explicitly configured by the user, then we actually put all
+        * configuration scope in the parent (the shared network and subnet
+        * share the same {}-level scope).
+        *
+        * Otherwise, we clone the parent group and continue as normal.
+        */
+       if (share->flags & SHARED_IMPLICIT) {
+               group_reference(&subnet->group, share->group, MDL);
+       } else {
+               if (!clone_group(&subnet->group, share->group, MDL)) {
+                       log_fatal("Allocation of group for new subnet failed.");
+               }
        }
        subnet_reference(&subnet->group->subnet, subnet, MDL);
 
@@ -3636,16 +3681,16 @@ void parse_address_range (cfile, group, type, inpool, lpchain)
 
 #ifdef DHCPv6
 static void
-add_ipv6_pool_to_shared_network(struct shared_network *share,
-                               u_int16_t type,
-                               struct iaddr *lo_addr,
-                               int bits,
-                               int units) {
+add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
+                       struct iaddr *lo_addr, int bits, int units) {
        struct ipv6_pool *pool;
+       struct shared_network *share;
        struct in6_addr tmp_in6_addr;
        int num_pools;
        struct ipv6_pool **tmp;
 
+       share = subnet->shared_network;
+
        /*
         * Create our pool.
         */
@@ -3668,8 +3713,10 @@ add_ipv6_pool_to_shared_network(struct shared_network *share,
        }
 
        /*
-        * Link our pool to our shared_network.
+        * Link the pool to its network.
         */
+       pool->subnet = NULL;
+       subnet_reference(&pool->subnet, subnet, MDL);
        pool->shared_network = NULL;
        shared_network_reference(&pool->shared_network, share, MDL);
 
@@ -3714,7 +3761,6 @@ parse_address_range6(struct parse *cfile, struct group *group) {
        int bits;
        enum dhcp_token token;
        const char *val;
-       struct shared_network *share;
        struct iaddrcidrnetlist *nets;
        struct iaddrcidrnetlist *p;
 
@@ -3725,13 +3771,9 @@ parse_address_range6(struct parse *cfile, struct group *group) {
                 return;
         }
 
-       /*
-        * We'll use the shared_network from our group.
-        */
-       share = group->shared_network;
-       if (share == NULL) {
-               share = group->subnet->shared_network;
-       }
+       /* This is enforced by the caller, this is just a sanity check. */
+       if (group->subnet == NULL)
+               log_fatal("Impossible condition at %s:%d.", MDL);
 
        /*
         * Read starting address.
@@ -3767,8 +3809,8 @@ parse_address_range6(struct parse *cfile, struct group *group) {
                        return;
                }
 
-               add_ipv6_pool_to_shared_network(share, D6O_IA_NA, &lo,
-                                               bits, 128);
+               add_ipv6_pool_to_subnet(group->subnet, D6O_IA_NA, &lo, bits,
+                                       128);
 
        } else if (token == TEMPORARY) {
                /*
@@ -3782,8 +3824,8 @@ parse_address_range6(struct parse *cfile, struct group *group) {
                        return;
                }
 
-               add_ipv6_pool_to_shared_network(share, D6O_IA_TA, &lo,
-                                               bits, 128);
+               add_ipv6_pool_to_subnet(group->subnet, D6O_IA_TA, &lo, bits,
+                                       128);
        } else {
                /*
                 * No '/', so we are looking for the end address of 
@@ -3802,13 +3844,12 @@ parse_address_range6(struct parse *cfile, struct group *group) {
                }
 
                for (p=nets; p != NULL; p=p->next) {
-                       add_ipv6_pool_to_shared_network(share, D6O_IA_NA,
-                                                       &p->cidrnet.lo_addr, 
-                                                       p->cidrnet.bits, 128);
+                       add_ipv6_pool_to_subnet(group->subnet, D6O_IA_NA,
+                                               &p->cidrnet.lo_addr, 
+                                               p->cidrnet.bits, 128);
                }
 
                free_iaddrcidrnetlist(&nets);
-
        }
 
        token = next_token(NULL, NULL, cfile);
@@ -3827,7 +3868,6 @@ parse_prefix6(struct parse *cfile, struct group *group) {
        int bits;
        enum dhcp_token token;
        const char *val;
-       struct shared_network *share;
        struct iaddrcidrnetlist *nets;
        struct iaddrcidrnetlist *p;
 
@@ -3838,14 +3878,10 @@ parse_prefix6(struct parse *cfile, struct group *group) {
                return;
        }
 
-       /*
-        * We'll use the shared_network from our group.
-        */
-       share = group->shared_network;
-       if (share == NULL) {
-               share = group->subnet->shared_network;
-       }
-        
+       /* This is enforced by the caller, so it's just a sanity check. */
+       if (group->subnet == NULL)
+               log_fatal("Impossible condition at %s:%d.", MDL);
+
        /*
         * Read starting and ending address.
         */
@@ -3907,9 +3943,9 @@ parse_prefix6(struct parse *cfile, struct group *group) {
                        parse_warn(cfile, "impossible mask length");
                        continue;
                }
-               add_ipv6_pool_to_shared_network(share, D6O_IA_PD,
-                                               &p->cidrnet.lo_addr,
-                                               p->cidrnet.bits, bits);
+               add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
+                                       &p->cidrnet.lo_addr,
+                                       p->cidrnet.bits, bits);
        }
 
        free_iaddrcidrnetlist(&nets);
index dd71b78b3e7c24f0e88ecc83f7d764bef087e5f0..47ef2571ea7f2a61d174ed70c22153e21919e448 100644 (file)
@@ -28,7 +28,7 @@
 .\" see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
 .\" ``http://www.nominum.com''.
 .\"
-.\" $Id: dhcpd.conf.5,v 1.96 2008/06/30 17:37:47 jreed Exp $
+.\" $Id: dhcpd.conf.5,v 1.97 2008/08/19 17:55:57 dhankins Exp $
 .\"
 .TH dhcpd.conf 5
 .SH NAME
@@ -86,6 +86,12 @@ ethernet until such time as a new physical network can be added.   In
 this case, the \fIsubnet\fR declarations for these two networks must be
 enclosed in a \fIshared-network\fR declaration.
 .PP
+Note that even when the \fIshared-network\fR declaration is absent, an
+empty one is created by the server to contain the \fIsubnet\fR (and any scoped
+parameters included in the \fIsubnet\fR).  For practical purposes, this means
+that "stateless" DHCP clients, which are not tied to addresses (and therefore
+subnets) will receive the same configuration as stateful ones.
+.PP
 Some sites may have departments which have clients on more than one
 subnet, but it may be desirable to offer those clients a uniform set
 of parameters which are different than what would be offered to
index a2e6ac75bde3863aff6826c6b60715b0f8ddce23..3aa6610e8c7b2e6f823a1da2c8f738c75add168b 100644 (file)
@@ -1366,9 +1366,21 @@ lease_to_client(struct data_string *reply_ret,
         * Make no reply if we gave no resources and is not
         * for Information-Request.
         */
-       if ((reply.ia_count == 0) && (reply.pd_count == 0) &&
-           (reply.packet->dhcpv6_msg_type != DHCPV6_INFORMATION_REQUEST))
-               goto exit;
+       if ((reply.ia_count == 0) && (reply.pd_count == 0)) {
+               if (reply.packet->dhcpv6_msg_type !=
+                                           DHCPV6_INFORMATION_REQUEST)
+                       goto exit;
+
+               /*
+                * Because we only execute statements on a per-IA basis,
+                * we need to execute statements in any non-IA reply to
+                * source configuration.
+                */
+               execute_statements_in_scope(NULL, reply.packet, NULL, NULL,
+                                           reply.packet->options,
+                                           reply.opt_state, &global_scope,
+                                           reply.shared->group, root_group);
+       }
 
        /*
         * RFC3315 section 17.2.2 (Solicit):
@@ -2087,7 +2099,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) {
                        log_fatal("Impossible condition at %s:%d.", MDL);
 
                scope = &reply->lease->scope;
-               group = reply->shared->group;
+               group = reply->lease->ipv6_pool->subnet->group;
        }
 
        /*
@@ -2518,7 +2530,7 @@ find_client_temporaries(struct reply_state *reply) {
 
                status = reply_process_is_addressed(reply,
                                                    &reply->lease->scope,
-                                                   reply->shared->group);
+                                     reply->lease->ipv6_pool->subnet->group);
                if (status != ISC_R_SUCCESS) {
                        goto cleanup;
                }
@@ -2588,11 +2600,6 @@ find_client_address(struct reply_state *reply) {
        struct group *group;
        int i;
 
-       if (reply->host != NULL)
-               group = reply->host->group;
-       else
-               group = reply->shared->group;
-
        if (reply->static_lease) {
                if (reply->host == NULL)
                        return ISC_R_INVALIDARG;
@@ -2602,6 +2609,7 @@ find_client_address(struct reply_state *reply) {
 
                status = ISC_R_SUCCESS;
                scope = &global_scope;
+               group = reply->host->group;
                goto send_addr;
        }
 
@@ -2640,8 +2648,12 @@ find_client_address(struct reply_state *reply) {
        if (reply->lease == NULL)
                log_fatal("Impossible condition at %s:%d.", MDL);
 
+       /* Draw binding scopes from the lease's binding scope, and config
+        * from the lease's containing subnet and higher.  Note that it may
+        * be desirable to place the group attachment directly in the pool.
+        */
        scope = &reply->lease->scope;
-       group = reply->shared->group;
+       group = reply->lease->ipv6_pool->subnet->group;
 
        send_addr.len = 16;
        memcpy(send_addr.iabuf, &reply->lease->addr, 16);