summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShawn Routhier <sar@isc.org>2012-04-10 22:14:24 +0000
committerShawn Routhier <sar@isc.org>2012-04-10 22:14:24 +0000
commit057abb574878ff5b885db2e8f1b12513ff959d51 (patch)
tree4f6a4cbe2400ba16c304e499d3558a7ab701f30a
parent03b81d82fda80f5c7a58908ede344d16b60165a9 (diff)
downloadisc-dhcp-057abb574878ff5b885db2e8f1b12513ff959d51.tar.gz
Fix the NA and PD allocation code to handle the case where a client
provides a preference and the server doesn't have any addresses or prefixes available. Previoulsy the server ignored the request with this patch it replies with a NoAddrsAvail or NoPrefixAvai respone. By default the code performs according to the errata of August 2010 for RFC 3315 section 17.2.2, to enable the previous style see the seciton on RFC3315_PRE_ERRATA_2010_08 in includes/site.h. This option may be removed in the future. Thanks to Jiri Popelka at Red Hat for the patch. [ISC-Bugs #22676]
-rw-r--r--RELNOTES11
-rw-r--r--includes/site.h10
-rw-r--r--server/dhcpv6.c98
3 files changed, 64 insertions, 55 deletions
diff --git a/RELNOTES b/RELNOTES
index 5c23bba2..695875e7 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -95,6 +95,17 @@ work on other platforms. Please report any problems and suggested fixes to
an int as a boolean).
[ISC-Bugs #26203]
+- Fix the NA and PD allocation code to handle the case where a client
+ provides a preference and the server doesn't have any addresses or
+ prefixes available. Previoulsy the server ignored the request with
+ this patch it replies with a NoAddrsAvail or NoPrefixAvai respone.
+ By default the code performs according to the errata of August 2010
+ for RFC 3315 section 17.2.2, to enable the previous style see the
+ seciton on RFC3315_PRE_ERRATA_2010_08 in includes/site.h. This option
+ may be removed in the future.
+ Thanks to Jiri Popelka at Red Hat for the patch.
+ [ISC-Bugs #22676]
+
Changes since 4.1-ESV-R3
- Add AM_MAINTAINER_MODE to configure.ac to avoid rebuilding
diff --git a/includes/site.h b/includes/site.h
index 89ff82f3..7e0a29f7 100644
--- a/includes/site.h
+++ b/includes/site.h
@@ -207,3 +207,13 @@
future. */
#define ACCEPT_LIST_IN_DOMAIN_NAME
+
+/* In RFC3315 section 17.2.2 stated that if the server was not going
+ to be able to assign any addresses to any IAs in a subsequent Request
+ from a client that the server should not include any IAs. This
+ requirement was removed in an errata from August 2010. Define the
+ following if you want the pre-errata version.
+ You should only enable this option if you have clients that
+ require the original functionality. */
+
+/* #define RFC3315_PRE_ERRATA_2010_08 */
diff --git a/server/dhcpv6.c b/server/dhcpv6.c
index 1c65ca1c..26c73297 100644
--- a/server/dhcpv6.c
+++ b/server/dhcpv6.c
@@ -1091,7 +1091,8 @@ try_client_v6_prefix(struct iasubopt **pref,
return ISC_R_INVALIDARG;
}
tmp_plen = (int) requested_pref->data[0];
- if ((tmp_plen < 3) || (tmp_plen > 128)) {
+ if ((tmp_plen < 3) || (tmp_plen > 128) ||
+ ((int)tmp_plen != pool->units)) {
return ISC_R_FAILURE;
}
memcpy(&tmp_pref, requested_pref->data + 1, sizeof(tmp_pref));
@@ -1104,9 +1105,8 @@ try_client_v6_prefix(struct iasubopt **pref,
return ISC_R_FAILURE;
}
- if (((int)tmp_plen != pool->units) ||
- !ipv6_in_pool(&tmp_pref, pool)) {
- return ISC_R_FAILURE;
+ if (!ipv6_in_pool(&tmp_pref, pool)) {
+ return ISC_R_ADDRNOTAVAIL;
}
if (prefix6_exists(pool, &tmp_pref, tmp_plen)) {
@@ -1238,7 +1238,9 @@ lease_to_client(struct data_string *reply_ret,
static struct reply_state reply;
struct option_cache *oc;
struct data_string packet_oro;
- isc_boolean_t no_resources_avail;
+#if defined (RFC3315_PRE_ERRATA_2010_08)
+ isc_boolean_t no_resources_avail = ISC_FALSE;
+#endif
/* Locate the client. */
if (shared_network_from_packet6(&reply.shared,
@@ -1290,7 +1292,7 @@ lease_to_client(struct data_string *reply_ret,
/* Process the client supplied IA's onto the reply buffer. */
reply.ia_count = 0;
oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA);
- no_resources_avail = ISC_FALSE;
+
for (; oc != NULL ; oc = oc->next) {
isc_result_t status;
@@ -1308,12 +1310,14 @@ lease_to_client(struct data_string *reply_ret,
(status != ISC_R_NORESOURCES))
goto exit;
+#if defined (RFC3315_PRE_ERRATA_2010_08)
/*
* If any address cannot be given to any IA, then set the
* NoAddrsAvail status code.
*/
if (reply.client_resources == 0)
no_resources_avail = ISC_TRUE;
+#endif
}
oc = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_TA);
for (; oc != NULL ; oc = oc->next) {
@@ -1333,12 +1337,14 @@ lease_to_client(struct data_string *reply_ret,
(status != ISC_R_NORESOURCES))
goto exit;
+#if defined (RFC3315_PRE_ERRATA_2010_08)
/*
* If any address cannot be given to any IA, then set the
* NoAddrsAvail status code.
*/
if (reply.client_resources == 0)
no_resources_avail = ISC_TRUE;
+#endif
}
/* Same for IA_PD's. */
@@ -1360,13 +1366,6 @@ lease_to_client(struct data_string *reply_ret,
if ((status != ISC_R_SUCCESS) &&
(status != ISC_R_NORESOURCES))
goto exit;
-
- /*
- * If any prefix cannot be given to any IA_PD, then
- * set the NoPrefixAvail status code.
- */
- if (reply.client_resources == 0)
- no_resources_avail = ISC_TRUE;
}
/*
@@ -1422,6 +1421,7 @@ lease_to_client(struct data_string *reply_ret,
* the server.
* Sends a Renew/Rebind if the IA is not in the Reply message.
*/
+#if defined (RFC3315_PRE_ERRATA_2010_08)
if (no_resources_avail && (reply.ia_count != 0) &&
(reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
{
@@ -1452,36 +1452,6 @@ lease_to_client(struct data_string *reply_ret,
reply.opt_state, reply.packet,
required_opts_NAA,
NULL);
- } else if (no_resources_avail && (reply.ia_count == 0) &&
- (reply.packet->dhcpv6_msg_type == DHCPV6_SOLICIT))
- {
- /* Set the NoPrefixAvail status code. */
- if (!set_status_code(STATUS_NoPrefixAvail,
- "No prefixes available for this "
- "interface.", reply.opt_state)) {
- log_error("lease_to_client: Unable to set "
- "NoPrefixAvail status code.");
- goto exit;
- }
-
- /* Rewind the cursor to the start. */
- reply.cursor = REPLY_OPTIONS_INDEX;
-
- /*
- * Produce an advertise that includes only:
- *
- * Status code.
- * Server DUID.
- * Client DUID.
- */
- reply.buf.reply.msg_type = DHCPV6_ADVERTISE;
- reply.cursor += store_options6((char *)reply.buf.data +
- reply.cursor,
- sizeof(reply.buf) -
- reply.cursor,
- reply.opt_state, reply.packet,
- required_opts_NAA,
- NULL);
} else {
/*
* Having stored the client's IA's, store any options that
@@ -1495,6 +1465,17 @@ lease_to_client(struct data_string *reply_ret,
required_opts_solicit,
&packet_oro);
}
+#else /* defined (RFC3315_PRE_ERRATA_2010_08) */
+ /*
+ * Having stored the client's IA's, store any options that
+ * will fit in the remaining space.
+ */
+ reply.cursor += store_options6((char *)reply.buf.data + reply.cursor,
+ sizeof(reply.buf) - reply.cursor,
+ reply.opt_state, reply.packet,
+ required_opts_solicit,
+ &packet_oro);
+#endif /* defined (RFC3315_PRE_ERRATA_2010_08) */
/* Return our reply to the caller. */
reply_ret->len = reply.cursor;
@@ -2695,16 +2676,18 @@ find_client_temporaries(struct reply_state *reply) {
*/
static isc_result_t
reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
- isc_result_t status = ISC_R_NORESOURCES;
+ isc_result_t status = ISC_R_ADDRNOTAVAIL;
struct ipv6_pool *pool;
int i;
struct data_string data_addr;
if ((reply == NULL) || (reply->shared == NULL) ||
- (reply->shared->ipv6_pools == NULL) || (addr == NULL) ||
- (reply->lease != NULL))
+ (addr == NULL) || (reply->lease != NULL))
return ISC_R_INVALIDARG;
+ if (reply->shared->ipv6_pools == NULL)
+ return (ISC_R_ADDRNOTAVAIL);
+
memset(&data_addr, 0, sizeof(data_addr));
data_addr.len = addr->len;
data_addr.data = addr->iabuf;
@@ -2721,7 +2704,7 @@ reply_process_try_addr(struct reply_state *reply, struct iaddr *addr) {
/* Note that this is just pedantry. There is no allocation to free. */
data_string_forget(&data_addr, MDL);
/* Return just the most recent status... */
- return status;
+ return (status);
}
/* Look around for an address to give the client. First, look through the
@@ -3217,7 +3200,9 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) {
if (status == ISC_R_CANCELED)
break;
- if ((status != ISC_R_SUCCESS) && (status != ISC_R_ADDRINUSE))
+ if ((status != ISC_R_SUCCESS) &&
+ (status != ISC_R_ADDRINUSE) &&
+ (status != ISC_R_ADDRNOTAVAIL))
goto cleanup;
}
@@ -3496,8 +3481,9 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) {
status = reply_process_try_prefix(reply, &tmp_pref);
/* Either error out or skip this prefix. */
- if ((status != ISC_R_SUCCESS) &&
- (status != ISC_R_ADDRINUSE))
+ if ((status != ISC_R_SUCCESS) &&
+ (status != ISC_R_ADDRINUSE) &&
+ (status != ISC_R_ADDRNOTAVAIL))
goto cleanup;
if (reply->lease == NULL) {
@@ -3679,21 +3665,23 @@ prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) {
static isc_result_t
reply_process_try_prefix(struct reply_state *reply,
struct iaddrcidrnet *pref) {
- isc_result_t status = ISC_R_NORESOURCES;
+ isc_result_t status = ISC_R_ADDRNOTAVAIL;
struct ipv6_pool *pool;
int i;
struct data_string data_pref;
if ((reply == NULL) || (reply->shared == NULL) ||
- (reply->shared->ipv6_pools == NULL) || (pref == NULL) ||
- (reply->lease != NULL))
+ (pref == NULL) || (reply->lease != NULL))
return ISC_R_INVALIDARG;
+ if (reply->shared->ipv6_pools == NULL)
+ return (ISC_R_ADDRNOTAVAIL);
+
memset(&data_pref, 0, sizeof(data_pref));
data_pref.len = 17;
if (!buffer_allocate(&data_pref.buffer, data_pref.len, MDL)) {
log_error("reply_process_try_prefix: out of memory.");
- return ISC_R_NOMEMORY;
+ return (ISC_R_NOMEMORY);
}
data_pref.data = data_pref.buffer->data;
data_pref.buffer->data[0] = (u_int8_t) pref->bits;
@@ -3712,7 +3700,7 @@ reply_process_try_prefix(struct reply_state *reply,
data_string_forget(&data_pref, MDL);
/* Return just the most recent status... */
- return status;
+ return (status);
}
/* Look around for a prefix to give the client. First, look through the old