<dhcp-users@isc.org>.
- Changes since 4.1.0a2
+ Changes since 4.1.0a1
- Corrected list of failover state values in dhcpd man page.
- 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.
- 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.
#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);
}
/* 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);
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",
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 {
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");
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... */
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);
#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.
*/
}
/*
- * 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);
int bits;
enum dhcp_token token;
const char *val;
- struct shared_network *share;
struct iaddrcidrnetlist *nets;
struct iaddrcidrnetlist *p;
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.
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) {
/*
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
}
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);
int bits;
enum dhcp_token token;
const char *val;
- struct shared_network *share;
struct iaddrcidrnetlist *nets;
struct iaddrcidrnetlist *p;
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.
*/
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);
* 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):
log_fatal("Impossible condition at %s:%d.", MDL);
scope = &reply->lease->scope;
- group = reply->shared->group;
+ group = reply->lease->ipv6_pool->subnet->group;
}
/*
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;
}
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;
status = ISC_R_SUCCESS;
scope = &global_scope;
+ group = reply->host->group;
goto send_addr;
}
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);