diff --git a/RELNOTES b/RELNOTES index 15d55f61..2d08edce 100644 --- a/RELNOTES +++ b/RELNOTES @@ -69,6 +69,8 @@ work on other platforms. Please report any problems and suggested fixes to - Shared network selection should be done from the innermost relay valid link-address field, rather than the outermost. +- Prefix pools are attached to shared network scopes. + Changes since 4.0.0 (new features) - Added DHCPv6 rapid commit support. diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 7b177093..eddeb081 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -813,6 +813,7 @@ struct shared_network { struct ipv6_pool **ipv6_pools; /* NULL-terminated array */ int last_ipv6_pool; /* offset of last IPv6 pool used to issue a lease */ + struct ipv6_ppool **ipv6_ppools; /* NULL-terminated array */ struct group *group; #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *failover_peer; @@ -1427,6 +1428,8 @@ struct ipv6_ppool { int num_inactive; /* count of inactive IAADDR */ isc_heap_t *inactive_timeouts; /* timeouts for expired or released leases */ + struct shared_network *shared_network; /* shared_network for + this pool */ }; extern struct ipv6_ppool **ppools; diff --git a/server/confpars.c b/server/confpars.c index 1aaaaed2..b0163884 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -627,7 +627,7 @@ int parse_statement (cfile, group, type, host_decl, declaration) case PREFIX6: next_token(NULL, NULL, cfile); - if (type != ROOT_GROUP) { + if ((type != SUBNET_DECL) || (group->subnet == NULL)) { parse_warn (cfile, "prefix6 definitions may not be scoped."); skip_to_semi(cfile); @@ -3817,11 +3817,14 @@ parse_address_range6(struct parse *cfile, struct group *group) { } static void -add_ipv6_ppool_to_global(struct iaddr *start_addr, - int pool_bits, - int alloc_bits) { +add_ipv6_ppool_to_shared_network(struct shared_network *share, + struct iaddr *start_addr, + int pool_bits, + int alloc_bits) { struct ipv6_ppool *ppool; struct in6_addr tmp_in6_addr; + int num_ppools; + struct ipv6_ppool **tmp; /* * Create our prefix pool. @@ -3843,6 +3846,43 @@ add_ipv6_ppool_to_global(struct iaddr *start_addr, if (add_ipv6_ppool(ppool) != ISC_R_SUCCESS) { log_fatal ("Out of memory"); } + + /* + * Link our prefix pool to our shared_network. + */ + ppool->shared_network = NULL; + shared_network_reference(&ppool->shared_network, share, MDL); + + /* + * Increase our array size for ipv6_ppools in the shared_network. + */ + if (share->ipv6_ppools == NULL) { + num_ppools = 0; + } else { + num_ppools = 0; + while (share->ipv6_ppools[num_ppools] != NULL) { + num_ppools++; + } + } + tmp = dmalloc(sizeof(struct ipv6_ppool *) * (num_ppools + 2), MDL); + if (tmp == NULL) { + log_fatal("Out of memory"); + } + if (num_ppools > 0) { + memcpy(tmp, share->ipv6_ppools, + sizeof(struct ipv6_ppool *) * num_ppools); + } + if (share->ipv6_ppools != NULL) { + dfree(share->ipv6_ppools, MDL); + } + share->ipv6_ppools = tmp; + + /* + * Record this prefix pool in our array of prefix pools + * for this shared network. + */ + ipv6_ppool_reference(&share->ipv6_ppools[num_ppools], ppool, MDL); + share->ipv6_ppools[num_ppools+1] = NULL; } /* prefix6-declaration :== ip-address6 ip-address6 SLASH number SEMI */ @@ -3853,9 +3893,25 @@ parse_prefix6(struct parse *cfile, struct group *group) { int bits; enum dhcp_token token; const char *val; + struct shared_network *share; struct iaddrcidrnetlist *nets; struct iaddrcidrnetlist *p; + if (local_family != AF_INET6) { + parse_warn(cfile, "prefix6 statement is only supported " + "in DHCPv6 mode."); + skip_to_semi(cfile); + return; + } + + /* + * We'll use the shared_network from our group. + */ + share = group->shared_network; + if (share == NULL) { + share = group->subnet->shared_network; + } + /* * Read starting and ending address. */ @@ -3900,7 +3956,6 @@ parse_prefix6(struct parse *cfile, struct group *group) { return; } - /* * Convert our range to a set of CIDR networks. */ @@ -3918,8 +3973,9 @@ parse_prefix6(struct parse *cfile, struct group *group) { parse_warn(cfile, "impossible mask length"); continue; } - add_ipv6_ppool_to_global(&p->cidrnet.lo_addr, - p->cidrnet.bits, bits); + add_ipv6_ppool_to_shared_network(share, + &p->cidrnet.lo_addr, + p->cidrnet.bits, bits); } free_iaddrcidrnetlist(&nets); diff --git a/server/dhcpv6.c b/server/dhcpv6.c index 7b20d36b..a0ecec03 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -103,8 +103,8 @@ static int get_encapsulated_IA_state(struct option_state **enc_opt_state, struct option_cache *oc, int offset); static void build_dhcpv6_reply(struct data_string *, struct packet *); -static void shared_network_from_packet6(struct shared_network **shared, - struct packet *packet); +static isc_result_t shared_network_from_packet6(struct shared_network **shared, + struct packet *packet); static void seek_shared_host(struct host_decl **hp, struct shared_network *shared); static isc_boolean_t fixed_matches_shared(struct host_decl *host, @@ -1143,6 +1143,7 @@ try_client_v6_prefix(struct iaprefix **pref, */ static isc_result_t pick_v6_prefix(struct iaprefix **pref, int plen, + struct shared_network *shared_network, const struct data_string *client_id) { struct ipv6_ppool *p; @@ -1153,19 +1154,19 @@ pick_v6_prefix(struct iaprefix **pref, int plen, /* * No prefix pools, we're done. */ - if (!num_ppools) { + if (shared_network->ipv6_ppools == NULL) { log_debug("Unable to pick client prefix: " - "no IPv6 prefix pools"); + "no IPv6 prefix pools on this shared network"); return ISC_R_NORESOURCES; } /* * Otherwise try to get a prefix. */ - for (i = 0; i < num_ppools; i++) { - p = ppools[i]; + for (i = 0;; i++) { + p = shared_network->ipv6_ppools[i]; if (p == NULL) { - continue; + break; } /* @@ -1229,7 +1230,9 @@ lease_to_client(struct data_string *reply_ret, isc_boolean_t no_resources_avail; /* Locate the client. */ - shared_network_from_packet6(&reply.shared, packet); + if (shared_network_from_packet6(&reply.shared, + packet) != ISC_R_SUCCESS) + goto exit; /* * Initialize the reply. @@ -1264,17 +1267,13 @@ lease_to_client(struct data_string *reply_ret, * valid for the shared network the client is on. */ if (find_hosts_by_option(&reply.host, packet, packet->options, MDL)) { - if (reply.shared != NULL) { - seek_shared_host(&reply.host, reply.shared); - } + seek_shared_host(&reply.host, reply.shared); } if ((reply.host == NULL) && find_hosts_by_uid(&reply.host, client_id->data, client_id->len, MDL)) { - if (reply.shared != NULL) { - seek_shared_host(&reply.host, reply.shared); - } + seek_shared_host(&reply.host, reply.shared); } /* Process the client supplied IA's onto the reply buffer. */ @@ -1284,10 +1283,6 @@ lease_to_client(struct data_string *reply_ret, for (; oc != NULL ; oc = oc->next) { isc_result_t status; - /* A shared network is required. */ - if (reply.shared == NULL) - goto exit; - /* Start counting resources (addresses) offered. */ reply.client_resources = 0; reply.ia_resources_included = ISC_FALSE; @@ -1313,10 +1308,6 @@ lease_to_client(struct data_string *reply_ret, for (; oc != NULL ; oc = oc->next) { isc_result_t status; - /* A shared network is required. */ - if (reply.shared == NULL) - goto exit; - /* Start counting resources (addresses) offered. */ reply.client_resources = 0; reply.ia_resources_included = ISC_FALSE; @@ -3373,7 +3364,7 @@ reply_process_prefix(struct reply_state *reply, struct option_cache *pref) { log_fatal("Impossible condition at %s:%d.", MDL); scope = &reply->prefix->scope; - group = root_group; + group = reply->shared->group; } /* @@ -3490,7 +3481,9 @@ reply_process_try_prefix(struct reply_state *reply, int i; struct data_string data_pref; - if ((reply == NULL) || (pref == NULL) || (reply->prefix != NULL)) + if ((reply == NULL) || (reply->shared == NULL) || + (reply->shared->ipv6_ppools == NULL) || (pref == NULL) || + (reply->prefix != NULL)) return ISC_R_INVALIDARG; memset(&data_pref, 0, sizeof(data_pref)); @@ -3503,10 +3496,10 @@ reply_process_try_prefix(struct reply_state *reply, data_pref.buffer->data[0] = (u_int8_t) pref->bits; memcpy(data_pref.buffer->data + 1, pref->lo_addr.iabuf, 16); - for (i = 0 ; i < num_ppools ; i++) { - ppool = ppools[i]; + for (i = 0 ;; i++) { + ppool = reply->shared->ipv6_ppools[i]; if (ppool == NULL) - continue; + break; status = try_client_v6_prefix(&reply->prefix, ppool, &data_pref); if (status == ISC_R_SUCCESS) @@ -3533,10 +3526,8 @@ find_client_prefix(struct reply_state *reply) { if (reply->host != NULL) group = reply->host->group; - else if (reply->shared != NULL) - group = reply->shared->group; else - group = root_group; + group = reply->shared->group; if (reply->static_prefixes > 0) { struct iaddrcidrnetlist *l; @@ -3576,7 +3567,7 @@ find_client_prefix(struct reply_state *reply) { */ if ((best_prefix == NULL) || (best_prefix->state == FTS_ABANDONED)) { status = pick_v6_prefix(&reply->prefix, reply->preflen, - &reply->client_id); + reply->shared, &reply->client_id); } else if (best_prefix != NULL) { iaprefix_reference(&reply->prefix, best_prefix, MDL); status = ISC_R_SUCCESS; @@ -3599,11 +3590,7 @@ find_client_prefix(struct reply_state *reply) { log_fatal("Impossible condition at %s:%d.", MDL); scope = &reply->prefix->scope; - if (reply->shared != NULL) { - group = reply->shared->group; - } else { - group = root_group; - } + group = reply->shared->group; send_pref.lo_addr.len = 16; memcpy(send_pref.lo_addr.iabuf, &reply->prefix->pref, 16); @@ -3929,7 +3916,7 @@ dhcpv6_request(struct data_string *reply_ret, struct packet *packet) { /* Find a DHCPv6 packet's shared network from hints in the packet. */ -static void +static isc_result_t shared_network_from_packet6(struct shared_network **shared, struct packet *packet) { @@ -3937,11 +3924,10 @@ shared_network_from_packet6(struct shared_network **shared, const struct in6_addr *link_addr, *first_link_addr; struct iaddr tmp_addr; struct subnet *subnet; + isc_result_t status; - if ((shared == NULL) || (*shared != NULL) || (packet == NULL)) { - log_error("shared_network_from_packet6: invalid arg."); - return; - } + if ((shared == NULL) || (*shared != NULL) || (packet == NULL)) + return ISC_R_INVALIDARG; /* * First, find the link address where the packet from the client @@ -3972,9 +3958,10 @@ shared_network_from_packet6(struct shared_network **shared, if (!find_subnet(&subnet, tmp_addr, MDL)) { log_debug("No subnet found for link-address %s.", piaddr(tmp_addr)); - return; + return ISC_R_NOTFOUND; } - shared_network_reference(shared, subnet->shared_network, MDL); + status = shared_network_reference(shared, + subnet->shared_network, MDL); subnet_dereference(&subnet, MDL); /* @@ -3982,10 +3969,12 @@ shared_network_from_packet6(struct shared_network **shared, * that this packet came in on to pick the shared_network. */ } else { - shared_network_reference(shared, + status = shared_network_reference(shared, packet->interface->shared_network, MDL); } + + return status; } /* @@ -4054,8 +4043,8 @@ dhcpv6_confirm(struct data_string *reply_ret, struct packet *packet) { * network the client is on. */ shared = NULL; - shared_network_from_packet6(&shared, packet); - if (shared == NULL) + if ((shared_network_from_packet6(&shared, packet) != ISC_R_SUCCESS) || + (shared == NULL)) goto exit; /* If there are no recorded subnets, then we have no @@ -5651,8 +5640,9 @@ seek_shared_host(struct host_decl **hp, struct shared_network *shared) { struct host_decl *seek, *hold = NULL; /* - * Seek forward through fixed addresses for the right broadcast - * domain. + * Seek forward through fixed addresses for the right link. + * + * Note: how to do this for fixed prefixes??? */ host_reference(&hold, *hp, MDL); host_dereference(hp, MDL);