diff options
Diffstat (limited to 'server/dhcpv6.c')
-rw-r--r-- | server/dhcpv6.c | 152 |
1 files changed, 73 insertions, 79 deletions
diff --git a/server/dhcpv6.c b/server/dhcpv6.c index 4538882..70f3981 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2006-2012 by Internet Systems Consortium, Inc. ("ISC") * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -1092,7 +1092,8 @@ try_client_v6_prefix(struct iasubopt **pref, return DHCP_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)); @@ -1105,9 +1106,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)) { @@ -1239,7 +1239,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, @@ -1297,7 +1299,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; @@ -1315,12 +1317,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) { @@ -1340,12 +1344,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. */ @@ -1367,13 +1373,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; } /* @@ -1429,6 +1428,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)) { @@ -1459,36 +1459,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 @@ -1502,6 +1472,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; @@ -2228,13 +2209,13 @@ address_is_owned(struct reply_state *reply, struct iaddr *addr) { log_fatal("Impossible condition at %s:%d.", MDL); if (memcmp(addr->iabuf, reply->fixed.data, 16) == 0) - return ISC_TRUE; + return (ISC_TRUE); - return ISC_FALSE; + return (ISC_FALSE); } if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0)) - return ISC_FALSE; + return (ISC_FALSE); for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) { struct iasubopt *tmp; @@ -2242,12 +2223,15 @@ address_is_owned(struct reply_state *reply, struct iaddr *addr) { tmp = reply->old_ia->iasubopt[i]; if (memcmp(addr->iabuf, &tmp->addr, 16) == 0) { + if (lease6_usable(tmp) == ISC_FALSE) { + return (ISC_FALSE); + } iasubopt_reference(&reply->lease, tmp, MDL); - return ISC_TRUE; + return (ISC_TRUE); } } - return ISC_FALSE; + return (ISC_FALSE); } /* Process a client-supplied IA_TA. This may append options to the tail of @@ -2703,15 +2687,17 @@ 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)) - return DHCP_R_INVALIDARG; + (addr == NULL) || (reply->lease != NULL)) + return (DHCP_R_INVALIDARG); + + if (reply->shared->ipv6_pools == NULL) + return (ISC_R_ADDRNOTAVAIL); memset(&data_addr, 0, sizeof(data_addr)); data_addr.len = addr->len; @@ -2729,7 +2715,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 @@ -2769,7 +2755,8 @@ find_client_address(struct reply_state *reply) { * Look for the best lease on the client's shared * network. */ - if (candidate_shared == reply->shared) { + if ((candidate_shared == reply->shared) && + (lease6_usable(lease) == ISC_TRUE)) { best_lease = lease_compare(lease, best_lease); } } @@ -2780,7 +2767,7 @@ find_client_address(struct reply_state *reply) { */ if ((best_lease == NULL) || (best_lease->state == FTS_ABANDONED)) { status = pick_v6_address(&reply->lease, reply->shared, - &reply->client_id); + &reply->ia->iaid_duid); } else if (best_lease != NULL) { iasubopt_reference(&reply->lease, best_lease, MDL); status = ISC_R_SUCCESS; @@ -3224,7 +3211,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; } @@ -3503,8 +3492,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) { @@ -3652,14 +3642,14 @@ prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) { if ((pref->bits == l->cidrnet.bits) && (memcmp(pref->lo_addr.iabuf, l->cidrnet.lo_addr.iabuf, 16) == 0)) - return ISC_TRUE; + return (ISC_TRUE); } - return ISC_FALSE; + return (ISC_FALSE); } if ((reply->old_ia == NULL) || (reply->old_ia->num_iasubopt == 0)) - return ISC_FALSE; + return (ISC_FALSE); for (i = 0 ; i < reply->old_ia->num_iasubopt ; i++) { struct iasubopt *tmp; @@ -3667,13 +3657,16 @@ prefix_is_owned(struct reply_state *reply, struct iaddrcidrnet *pref) { tmp = reply->old_ia->iasubopt[i]; if ((pref->bits == (int) tmp->plen) && - memcmp(pref->lo_addr.iabuf, &tmp->addr, 16) == 0) { + (memcmp(pref->lo_addr.iabuf, &tmp->addr, 16) == 0)) { + if (lease6_usable(tmp) == ISC_FALSE) { + return (ISC_FALSE); + } iasubopt_reference(&reply->lease, tmp, MDL); - return ISC_TRUE; + return (ISC_TRUE); } } - return ISC_FALSE; + return (ISC_FALSE); } /* @@ -3683,21 +3676,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)) - return DHCP_R_INVALIDARG; + (pref == NULL) || (reply->lease != NULL)) + return (DHCP_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; @@ -3716,7 +3711,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 @@ -3767,8 +3762,9 @@ find_client_prefix(struct reply_state *reply) { * if it is scoped in a pool under the client's shared * network. */ - if (candidate_shared == NULL || - candidate_shared == reply->shared) { + if (((candidate_shared == NULL) || + (candidate_shared == reply->shared)) && + (lease6_usable(prefix) == ISC_TRUE)) { best_prefix = prefix_compare(reply, prefix, best_prefix); } @@ -4617,7 +4613,6 @@ iterate_over_ia_na(struct data_string *reply_ret, struct option_state *host_opt_state; struct data_string iaaddr; struct data_string fixed_addr; - int iaaddr_is_found; char reply_data[65536]; struct dhcpv6_packet *reply = (struct dhcpv6_packet *)reply_data; int reply_ofs = (int)(offsetof(struct dhcpv6_packet, options)); @@ -4724,7 +4719,6 @@ iterate_over_ia_na(struct data_string *reply_ret, */ for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_NA); ia != NULL; ia = ia->next) { - iaaddr_is_found = 0; if (!get_encapsulated_IA_state(&cli_enc_opt_state, &cli_enc_opt_data, @@ -5136,7 +5130,6 @@ iterate_over_ia_pd(struct data_string *reply_ret, struct host_decl *host; struct option_state *host_opt_state; struct data_string iaprefix; - int iaprefix_is_found; char reply_data[65536]; int reply_ofs; struct iasubopt *prefix; @@ -5203,7 +5196,6 @@ iterate_over_ia_pd(struct data_string *reply_ret, */ for (ia = lookup_option(&dhcpv6_universe, packet->options, D6O_IA_PD); ia != NULL; ia = ia->next) { - iaprefix_is_found = 0; if (!get_encapsulated_IA_state(&cli_enc_opt_state, &cli_enc_opt_data, @@ -5531,6 +5523,7 @@ dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) { msg_type = enc_opt_data.data[0]; if ((msg_type == DHCPV6_RELAY_FORW) || (msg_type == DHCPV6_RELAY_REPL)) { + int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options)); relay = (struct dhcpv6_relay_packet *)enc_opt_data.data; enc_packet->dhcpv6_msg_type = relay->msg_type; @@ -5543,13 +5536,14 @@ dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) { if (!parse_option_buffer(enc_packet->options, relay->options, - enc_opt_data.len-sizeof(*relay), + enc_opt_data.len - relaylen, &dhcpv6_universe)) { /* no logging here, as parse_option_buffer() logs all cases where it fails */ goto exit; } } else { + int msglen = (int)(offsetof(struct dhcpv6_packet, options)); msg = (struct dhcpv6_packet *)enc_opt_data.data; enc_packet->dhcpv6_msg_type = msg->msg_type; @@ -5560,7 +5554,7 @@ dhcpv6_relay_forw(struct data_string *reply_ret, struct packet *packet) { if (!parse_option_buffer(enc_packet->options, msg->options, - enc_opt_data.len-sizeof(*msg), + enc_opt_data.len - msglen, &dhcpv6_universe)) { /* no logging here, as parse_option_buffer() logs all cases where it fails */ |