with the next entry in the lease file.
[ISC-Bugs #39314]
+- Be more liberal in finding a subnet group associated with a static
+ prefix. When we added the class matching code for v6 we also added
+ a requirement that the static prefix must be within a subnet the
+ client was in, in order to find the proper statements. We now
+ look for a subnet based on the prefix, failing that on the static
+ address for the client and failing that on the shared network
+ itself.
+ [ISC-Bugs #38329]
+
Changes since 4.3.2rc2
- None
.PP
The
.B host
-declaration provides a scope in which to provide configuration information about
-a specific client, and also provides a way to assign a client a fixed address.
-The host declaration provides a way for the DHCP server to identify a DHCP or
-BOOTP client, and also a way to assign the client a static IP address.
+declaration provides a way for the DHCP server to identify a DHCP or
+BOOTP client. This allows the server to provide configuration
+information including fixed addresses or, in DHCPv6, fixed prefixes
+for a specific client.
.PP
If it is desirable to be able to boot a DHCP or BOOTP client on more than one
-subnet with fixed addresses, more than one address may be specified in the
+subnet with fixed v4 addresses, more than one address may be specified in the
.I fixed-address
declaration, or more than one
.B host
statement may be specified matching the same client.
.PP
+The
+.I fixed-address6
+delcaration is used for v6 addresses. At this time it only works with a single
+address. For multiple addresses specify multiple
+.B host
+statements.
+.PP
If client-specific boot parameters must change based on the network
to which the client is attached, then multiple
.B host
.PP
Currently, abandoned IPv6 addresses are reclaimed in one of two ways:
a) Client renews a specific address:
- If a client using a given DUID submits a DHCP REQUEST containing the
- last address abandoned by that DUID, the address will be reassigned to
- that client.
+ If a client using a given DUID submits a DHCP REQUEST containing
+ the last address abandoned by that DUID, the address will be
+ reassigned to that client.
- b) Upon the second restart following an address abandonment. When an
- address is abandoned it is both recorded as such in the lease file and
- retained as abandoned in server memory until the server is restarted. Upon
- restart, the server will process the lease file and all addresses whose
- last known state is abandoned will be retained as such in memory but not
- rewritten to the lease file. This means that a subsequent restart of the
- server will not see the abandoned addresses in the lease file and
- therefore have no record of them as abandoned in memory and as such
- perceive them as free for assignment.
+ b) Upon the second restart following an address abandonment. When
+ an address is abandoned it is both recorded as such in the lease
+ file and retained as abandoned in server memory until the server
+ is restarted. Upon restart, the server will process the lease file
+ and all addresses whose last known state is abandoned will be
+ retained as such in memory but not rewritten to the lease file.
+ This means that a subsequent restart of the server will not see the
+ abandoned addresses in the lease file and therefore have no record
+ of them as abandoned in memory and as such perceive them as free
+ for assignment.
.PP
The total number addresses in a pool, available for a given DUID value,
is internally limited by the server's address generation mechanism. If
The appearance of the following error log, can be an indication of this
condition:
- "Best match for DUID <XX> is an abandoned address, This may be a result of
- multiple clients attempting to use this DUID"
+ "Best match for DUID <XX> is an abandoned address, This may be a
+ result of multiple clients attempting to use this DUID"
- where <XX> is an actual DUID value depicted as colon separated string of
- bytes in hexadecimal values.
+ where <XX> is an actual DUID value depicted as colon separated
+ string of bytes in hexadecimal values.
.PP
The \fBdeclines\fR flag tells the DHCP server whether or not to honor
DHCPDECLINE messages. If it is set to \fBdeny\fR or \fBignore\fR in
.RE
.PP
The
+.I fixed-prefix6
+declaration
+.RS 0.25i
+.PP
+.B fixed-prefix6\fR \fIlow-address\fR \fB/\fR \fIbits\fR\fB;\fR
+.PP
+The \fIfixed-prefix6\fR declaration is used to assign a fixed
+IPv6 prefix to a client. It should only appear in a \fIhost\fR
+declaration, but multiple \fIfixed-prefix6\fR statements may appear
+in a single \fIhost\fR declaration.
+.PP
+The \fIlow-address\fR specifies the start of the prefix and the \fIbits\fR
+specifies the size of the prefix in bits.
+.PP
+If there are multiple prefixes for a given host entry the server will
+choose one that matches the requested prefix size or, if none match,
+the first one.
+.PP
+If there are multiple \fIhost\fR delcarations the server will try to
+choose a declaration where the \fIfixed-address6\fR matches the client's
+subnet. If none match it will choose one that doesn't have a \fIfixed-address6\fR
+statement.
+.PP
+Note Well: Unlike the fixed address the fixed prefix does not need to match
+a subnet in order to be served. This allows you to provide a prefix to
+a client that is outside of the subnet on which the client makes the request
+to the the server.
+.RE
+.PP
+The
.I get-lease-hostnames
statement
.RS 0.25i
struct iasubopt *beta);
static isc_result_t reply_process_ia_pd(struct reply_state *reply,
struct option_cache *ia_pd);
+static struct group *find_group_by_prefix(struct reply_state *reply);
static isc_result_t reply_process_prefix(struct reply_state *reply,
struct option_cache *pref);
static isc_boolean_t prefix_is_owned(struct reply_state *reply,
return((status == ISC_R_CANCELED) ? ISC_R_SUCCESS : status);
}
+/*!
+ *
+ * \brief Find the proper scoping group for use with a v6 static prefix.
+ *
+ * We start by trying to find a subnet based on the given prefix and
+ * the shared network. If we don't find one then the prefix has been
+ * declared outside of any subnets. If there is a static address
+ * associated with the host we use it to try and find a subnet (this
+ * should succeed). If there isn't a static address we fall back
+ * to the shared subnet itself.
+ * Once we have a subnet we extract the group from it and return it.
+ *
+ * \param reply - the reply structure we use to collect information
+ * we will use the fields shared, fixed_pref and host
+ * from the structure
+ *
+ * \return a pointer to the group structure to use for scoping
+ */
+
+static struct group *
+find_group_by_prefix(struct reply_state *reply) {
+ /* default group if we don't find anything better */
+ struct group *group = reply->shared->group;
+ struct subnet *subnet = NULL;
+ struct iaddr tmp_addr;
+ struct data_string fixed_addr;
+
+ /* Try with the prefix first */
+ if (find_grouped_subnet(&subnet, reply->shared,
+ reply->fixed_pref.lo_addr, MDL) != 0) {
+ group = subnet->group;
+ subnet_dereference(&subnet, MDL);
+ return (group);
+ }
+
+ /* Didn't find a subnet via prefix, what about fixed address */
+ /* The caller has already tested reply->host != NULL */
+
+ memset(&fixed_addr, 0, sizeof(fixed_addr));
+
+ if ((reply->host->fixed_addr != NULL) &&
+ (evaluate_option_cache(&fixed_addr, NULL, NULL, NULL,
+ NULL, NULL, &global_scope,
+ reply->host->fixed_addr, MDL))) {
+ if (fixed_addr.len >= 16) {
+ tmp_addr.len = 16;
+ memcpy(tmp_addr.iabuf, fixed_addr.data, 16);
+ if (find_grouped_subnet(&subnet, reply->shared,
+ tmp_addr, MDL) != 0) {
+ group = subnet->group;
+ subnet_dereference(&subnet, MDL);
+ }
+ }
+ data_string_forget(&fixed_addr, MDL);
+ }
+
+ /* return whatever we got */
+ return (group);
+}
+
/*
* Process an IAPREFIX within a given IA_PD, storing any IAPREFIX reply
* contents into the reply's current ia_pd-scoped option cache. Returns
scope = &global_scope;
- /* Find the static prefixe's subnet. */
- if (find_grouped_subnet(&reply->subnet, reply->shared,
- tmp_pref.lo_addr, MDL) == 0)
- log_fatal("Impossible condition at %s:%d.", MDL);
- group = reply->subnet->group;
- subnet_dereference(&reply->subnet, MDL);
-
- /* Copy the static prefix for logging purposes */
+ /* Copy the static prefix for logging and finding the group */
memcpy(&reply->fixed_pref, &tmp_pref, sizeof(tmp_pref));
+
+ /* Try to find a group for the static prefix */
+ group = find_group_by_prefix(reply);
} else {
if (reply->lease == NULL)
log_fatal("Impossible condition at %s:%d.", MDL);
scope = &global_scope;
- /* Find the static prefixe's subnet. */
- if (find_grouped_subnet(&reply->subnet, reply->shared,
- send_pref.lo_addr, MDL) == 0)
- log_fatal("Impossible condition at %s:%d.", MDL);
- group = reply->subnet->group;
- subnet_dereference(&reply->subnet, MDL);
-
/* Copy the prefix for logging purposes */
memcpy(&reply->fixed_pref, &l->cidrnet, sizeof(send_pref));
+ /* Try to find a group for the static prefix */
+ group = find_group_by_prefix(reply);
+
goto send_pref;
}