2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-09-01 06:45:27 +00:00

- 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.

  [ISC-Bugs #17638b]
This commit is contained in:
David Hankins
2008-08-19 17:55:57 +00:00
parent 0524508a91
commit 7d6180be3e
5 changed files with 135 additions and 57 deletions

View File

@@ -48,7 +48,7 @@ work on other platforms. Please report any problems and suggested fixes to
<dhcp-users@isc.org>. <dhcp-users@isc.org>.
Changes since 4.1.0a2 Changes since 4.1.0a1
- Corrected list of failover state values in dhcpd man page. - 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. - 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. - Fixed a coredump when adding a class via OMAPI.
- Check whether files are zero length before trying to parse them. - 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 - Fix handling of -A and -a flags in dhcrelay; it was failing to expand
packet size as needed to add relay agent options. 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) Changes since 4.0.0 (new features)
- Added DHCPv6 rapid commit support. - Added DHCPv6 rapid commit support.

View File

@@ -807,6 +807,10 @@ struct shared_network {
OMAPI_OBJECT_PREAMBLE; OMAPI_OBJECT_PREAMBLE;
struct shared_network *next; struct shared_network *next;
char *name; char *name;
#define SHARED_IMPLICIT 1 /* This network was synthesized. */
int flags;
struct subnet *subnets; struct subnet *subnets;
struct interface_info *interface; struct interface_info *interface;
struct pool *pools; struct pool *pools;
@@ -1395,6 +1399,7 @@ struct ipv6_pool {
released leases */ released leases */
struct shared_network *shared_network; /* shared_network for struct shared_network *shared_network; /* shared_network for
this pool */ this pool */
struct subnet *subnet; /* subnet for this pool */
}; };
extern struct ipv6_pool **pools; extern struct ipv6_pool **pools;

View File

@@ -35,6 +35,7 @@
#include "dhcpd.h" #include "dhcpd.h"
static unsigned char global_host_once = 1; static unsigned char global_host_once = 1;
static unsigned char dhcpv6_class_once = 1;
static int parse_binding_value(struct parse *cfile, static int parse_binding_value(struct parse *cfile,
struct binding_value *value); 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 we're in a subnet declaration, just do the parse. */
if (group->shared_network) { if (group->shared_network != NULL) {
if (token == SUBNET) { if (token == SUBNET) {
parse_subnet_declaration(cfile, parse_subnet_declaration(cfile,
group->shared_network); group->shared_network);
@@ -443,10 +444,15 @@ int parse_statement (cfile, group, type, host_decl, declaration)
break; 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); status = shared_network_allocate (&share, MDL);
if (status != ISC_R_SUCCESS) if (status != ISC_R_SUCCESS)
log_fatal ("Can't allocate shared subnet: %s", 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, shared_network_reference (&share -> group -> shared_network,
share, MDL); share, MDL);
/*
* This is an implicit shared network, not explicit in
* the config.
*/
share->flags |= SHARED_IMPLICIT;
if (token == SUBNET) { if (token == SUBNET) {
parse_subnet_declaration(cfile, share); parse_subnet_declaration(cfile, share);
} else { } else {
@@ -2022,6 +2034,12 @@ int parse_class_declaration (cp, cfile, group, type)
int submatchedonce = 0; int submatchedonce = 0;
unsigned code; 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); token = next_token (&val, (unsigned *)0, cfile);
if (token != STRING) { if (token != STRING) {
parse_warn (cfile, "Expecting class name"); parse_warn (cfile, "Expecting class name");
@@ -2547,8 +2565,22 @@ void parse_subnet_declaration (cfile, share)
log_fatal ("Allocation of new subnet failed: %s", log_fatal ("Allocation of new subnet failed: %s",
isc_result_totext (status)); isc_result_totext (status));
shared_network_reference (&subnet -> shared_network, share, MDL); 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); subnet_reference (&subnet -> group -> subnet, subnet, MDL);
/* Get the network number... */ /* Get the network number... */
@@ -2626,8 +2658,21 @@ parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) {
isc_result_totext(status)); isc_result_totext(status));
} }
shared_network_reference(&subnet->shared_network, share, MDL); 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); subnet_reference(&subnet->group->subnet, subnet, MDL);
@@ -3636,16 +3681,16 @@ void parse_address_range (cfile, group, type, inpool, lpchain)
#ifdef DHCPv6 #ifdef DHCPv6
static void static void
add_ipv6_pool_to_shared_network(struct shared_network *share, add_ipv6_pool_to_subnet(struct subnet *subnet, u_int16_t type,
u_int16_t type, struct iaddr *lo_addr, int bits, int units) {
struct iaddr *lo_addr,
int bits,
int units) {
struct ipv6_pool *pool; struct ipv6_pool *pool;
struct shared_network *share;
struct in6_addr tmp_in6_addr; struct in6_addr tmp_in6_addr;
int num_pools; int num_pools;
struct ipv6_pool **tmp; struct ipv6_pool **tmp;
share = subnet->shared_network;
/* /*
* Create our pool. * 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; pool->shared_network = NULL;
shared_network_reference(&pool->shared_network, share, MDL); shared_network_reference(&pool->shared_network, share, MDL);
@@ -3714,7 +3761,6 @@ parse_address_range6(struct parse *cfile, struct group *group) {
int bits; int bits;
enum dhcp_token token; enum dhcp_token token;
const char *val; const char *val;
struct shared_network *share;
struct iaddrcidrnetlist *nets; struct iaddrcidrnetlist *nets;
struct iaddrcidrnetlist *p; struct iaddrcidrnetlist *p;
@@ -3725,13 +3771,9 @@ parse_address_range6(struct parse *cfile, struct group *group) {
return; return;
} }
/* /* This is enforced by the caller, this is just a sanity check. */
* We'll use the shared_network from our group. if (group->subnet == NULL)
*/ log_fatal("Impossible condition at %s:%d.", MDL);
share = group->shared_network;
if (share == NULL) {
share = group->subnet->shared_network;
}
/* /*
* Read starting address. * Read starting address.
@@ -3767,8 +3809,8 @@ parse_address_range6(struct parse *cfile, struct group *group) {
return; return;
} }
add_ipv6_pool_to_shared_network(share, D6O_IA_NA, &lo, add_ipv6_pool_to_subnet(group->subnet, D6O_IA_NA, &lo, bits,
bits, 128); 128);
} else if (token == TEMPORARY) { } else if (token == TEMPORARY) {
/* /*
@@ -3782,8 +3824,8 @@ parse_address_range6(struct parse *cfile, struct group *group) {
return; return;
} }
add_ipv6_pool_to_shared_network(share, D6O_IA_TA, &lo, add_ipv6_pool_to_subnet(group->subnet, D6O_IA_TA, &lo, bits,
bits, 128); 128);
} else { } else {
/* /*
* No '/', so we are looking for the end address of * 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) { for (p=nets; p != NULL; p=p->next) {
add_ipv6_pool_to_shared_network(share, D6O_IA_NA, add_ipv6_pool_to_subnet(group->subnet, D6O_IA_NA,
&p->cidrnet.lo_addr, &p->cidrnet.lo_addr,
p->cidrnet.bits, 128); p->cidrnet.bits, 128);
} }
free_iaddrcidrnetlist(&nets); free_iaddrcidrnetlist(&nets);
} }
token = next_token(NULL, NULL, cfile); token = next_token(NULL, NULL, cfile);
@@ -3827,7 +3868,6 @@ parse_prefix6(struct parse *cfile, struct group *group) {
int bits; int bits;
enum dhcp_token token; enum dhcp_token token;
const char *val; const char *val;
struct shared_network *share;
struct iaddrcidrnetlist *nets; struct iaddrcidrnetlist *nets;
struct iaddrcidrnetlist *p; struct iaddrcidrnetlist *p;
@@ -3838,14 +3878,10 @@ parse_prefix6(struct parse *cfile, struct group *group) {
return; return;
} }
/* /* This is enforced by the caller, so it's just a sanity check. */
* We'll use the shared_network from our group. if (group->subnet == NULL)
*/ log_fatal("Impossible condition at %s:%d.", MDL);
share = group->shared_network;
if (share == NULL) {
share = group->subnet->shared_network;
}
/* /*
* Read starting and ending address. * Read starting and ending address.
*/ */
@@ -3907,9 +3943,9 @@ parse_prefix6(struct parse *cfile, struct group *group) {
parse_warn(cfile, "impossible mask length"); parse_warn(cfile, "impossible mask length");
continue; continue;
} }
add_ipv6_pool_to_shared_network(share, D6O_IA_PD, add_ipv6_pool_to_subnet(group->subnet, D6O_IA_PD,
&p->cidrnet.lo_addr, &p->cidrnet.lo_addr,
p->cidrnet.bits, bits); p->cidrnet.bits, bits);
} }
free_iaddrcidrnetlist(&nets); free_iaddrcidrnetlist(&nets);

View File

@@ -28,7 +28,7 @@
.\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see
.\" ``http://www.nominum.com''. .\" ``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 .TH dhcpd.conf 5
.SH NAME .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 this case, the \fIsubnet\fR declarations for these two networks must be
enclosed in a \fIshared-network\fR declaration. enclosed in a \fIshared-network\fR declaration.
.PP .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 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 subnet, but it may be desirable to offer those clients a uniform set
of parameters which are different than what would be offered to of parameters which are different than what would be offered to

View File

@@ -1366,9 +1366,21 @@ lease_to_client(struct data_string *reply_ret,
* Make no reply if we gave no resources and is not * Make no reply if we gave no resources and is not
* for Information-Request. * for Information-Request.
*/ */
if ((reply.ia_count == 0) && (reply.pd_count == 0) && if ((reply.ia_count == 0) && (reply.pd_count == 0)) {
(reply.packet->dhcpv6_msg_type != DHCPV6_INFORMATION_REQUEST)) if (reply.packet->dhcpv6_msg_type !=
goto exit; 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): * 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); log_fatal("Impossible condition at %s:%d.", MDL);
scope = &reply->lease->scope; 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, status = reply_process_is_addressed(reply,
&reply->lease->scope, &reply->lease->scope,
reply->shared->group); reply->lease->ipv6_pool->subnet->group);
if (status != ISC_R_SUCCESS) { if (status != ISC_R_SUCCESS) {
goto cleanup; goto cleanup;
} }
@@ -2588,11 +2600,6 @@ find_client_address(struct reply_state *reply) {
struct group *group; struct group *group;
int i; int i;
if (reply->host != NULL)
group = reply->host->group;
else
group = reply->shared->group;
if (reply->static_lease) { if (reply->static_lease) {
if (reply->host == NULL) if (reply->host == NULL)
return ISC_R_INVALIDARG; return ISC_R_INVALIDARG;
@@ -2602,6 +2609,7 @@ find_client_address(struct reply_state *reply) {
status = ISC_R_SUCCESS; status = ISC_R_SUCCESS;
scope = &global_scope; scope = &global_scope;
group = reply->host->group;
goto send_addr; goto send_addr;
} }
@@ -2640,8 +2648,12 @@ find_client_address(struct reply_state *reply) {
if (reply->lease == NULL) if (reply->lease == NULL)
log_fatal("Impossible condition at %s:%d.", MDL); 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; scope = &reply->lease->scope;
group = reply->shared->group; group = reply->lease->ipv6_pool->subnet->group;
send_addr.len = 16; send_addr.len = 16;
memcpy(send_addr.iabuf, &reply->lease->addr, 16); memcpy(send_addr.iabuf, &reply->lease->addr, 16);