diff --git a/RELNOTES b/RELNOTES index 7c131c59..28a531bc 100644 --- a/RELNOTES +++ b/RELNOTES @@ -65,6 +65,10 @@ suggested fixes to . order to avoid cascading renewals in the event a server elects not to extend one of multiple IAADDR leases. +- The server now limits clients that request multiple addresses to one + address per IA by default, which can be adjusted through the + "limit-addrs-per-ia" configuration option. + Changes since 4.0.0b2 - Clarified error message when lease limit exceeded diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 0d5de798..1b86b337 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -620,6 +620,7 @@ struct lease_state { #define SV_PREFER_LIFETIME 53 #define SV_DHCPV6_LEASE_FILE_NAME 54 #define SV_DHCPV6_PID_FILE_NAME 55 +#define SV_LIMIT_ADDRS_PER_IA 56 #if !defined (DEFAULT_PING_TIMEOUT) # define DEFAULT_PING_TIMEOUT 1 diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index 1ed8b65a..15e4e010 100644 --- a/server/dhcpd.conf.5 +++ b/server/dhcpd.conf.5 @@ -28,7 +28,7 @@ .\" see ``http://www.vix.com''. To learn more about Nominum, Inc., see .\" ``http://www.nominum.com''. .\" -.\" $Id: dhcpd.conf.5,v 1.90 2007/10/31 19:13:33 dhankins Exp $ +.\" $Id: dhcpd.conf.5,v 1.91 2007/11/20 18:34:37 dhankins Exp $ .\" .TH dhcpd.conf 5 .SH NAME @@ -2251,6 +2251,22 @@ environment variable. .RE .PP The +.I limit-addrs-per-ia +statement +.RS 0.25i +.PP +.B limit-addrs-per-ia \fInumber\fB;\fR +.PP +By default, the DHCPv6 server will limit clients to one IAADDR per IA +option, meaning one address. If you wish to permit clients to hang onto +multiple addresses at a time, configure a larger \fInumber\fR here. +.PP +Note that there is no present method to configure the server to forcibly +configure the client with one IP address per each subnet on a shared network. +This is left to future work. +.RE +.PP +The .I dhcpv6-lease-file-name statement .RS 0.25i diff --git a/server/dhcpv6.c b/server/dhcpv6.c index c501e622..f8e2797f 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -49,7 +49,8 @@ struct reply_state { /* IA level persistent state */ unsigned ia_count; - isc_boolean_t client_addressed, static_lease; + unsigned client_addresses; + isc_boolean_t static_lease; struct ia_na *ia_na; struct ia_na *old_ia; struct option_state *reply_ia; @@ -1244,7 +1245,7 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) { oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR); reply->valid = reply->prefer = 0xffffffff; reply->client_valid = reply->client_prefer = 0; - reply->client_addressed = ISC_FALSE; + reply->client_addresses = 0; for (; oc != NULL ; oc = oc->next) { status = reply_process_addr(reply, oc); @@ -1267,7 +1268,7 @@ reply_process_ia(struct reply_state *reply, struct option_cache *ia) { * If we fell through the above and never gave the client * an address, give it one now. */ - if ((status != ISC_R_CANCELED) && !reply->client_addressed) { + if ((status != ISC_R_CANCELED) && (reply->client_addresses == 0)) { status = find_client_address(reply); /* @@ -1482,6 +1483,7 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) { struct group *group; struct subnet *subnet; struct iaddr tmp_addr; + struct option_cache *oc; struct data_string iaaddr, data; isc_result_t status = ISC_R_SUCCESS; @@ -1689,6 +1691,47 @@ reply_process_addr(struct reply_state *reply, struct option_cache *addr) { group = reply->shared->group; } + /* + * If client_addresses is nonzero, then the reply_process_is_addressed + * function has executed configuration state into the reply option + * cache. We will use that valid cache to derive configuration for + * whether or not to engage in additional addresses, and similar. + */ + if (reply->client_addresses != 0) { + unsigned limit = 1; + + /* + * Does this client have "enough" addresses already? Default + * to one. Everybody gets one, and one should be enough for + * anybody. + */ + oc = lookup_option(&server_universe, reply->opt_state, + SV_LIMIT_ADDRS_PER_IA); + if (oc != NULL) { + if (!evaluate_option_cache(&data, reply->packet, + NULL, NULL, + reply->packet->options, + reply->opt_state, + scope, oc, MDL) || + (data.len != 4)) { + log_error("reply_process_ia: unable to " + "evaluate addrs-per-ia value."); + status = ISC_R_FAILURE; + goto cleanup; + } + + limit = getULong(data.data); + data_string_forget(&data, MDL); + } + + /* + * If we wish to limit the client to a certain number of + * addresses, then omit the address from the reply. + */ + if (reply->client_addresses >= limit) + goto cleanup; + } + status = reply_process_is_addressed(reply, scope, group); if (status != ISC_R_SUCCESS) goto cleanup; @@ -1889,12 +1932,10 @@ reply_process_is_addressed(struct reply_state *reply, oc = lookup_option(&server_universe, reply->opt_state, SV_DEFAULT_LEASE_TIME); if (oc != NULL) { - if (!evaluate_option_cache(&data, reply->packet, NULL, - NULL, + if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, - &reply->lease->scope, - oc, MDL) || + scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_ia: uanble to " "evaluate default lease time"); @@ -1918,12 +1959,10 @@ reply_process_is_addressed(struct reply_state *reply, oc = lookup_option(&server_universe, reply->opt_state, SV_PREFER_LIFETIME); if (oc != NULL) { - if (!evaluate_option_cache(&data, reply->packet, NULL, - NULL, + if (!evaluate_option_cache(&data, reply->packet, NULL, NULL, reply->packet->options, reply->opt_state, - &reply->lease->scope, - oc, MDL) || + scope, oc, MDL) || (data.len != 4)) { log_error("reply_process_ia: unable to " "evaluate preferred lease time"); @@ -1989,7 +2028,7 @@ reply_process_is_addressed(struct reply_state *reply, data_string_forget(&data, MDL); if (status == ISC_R_SUCCESS) - reply->client_addressed = ISC_TRUE; + reply->client_addresses++; return status; } diff --git a/server/stables.c b/server/stables.c index ef50efb6..3e1dffdc 100644 --- a/server/stables.c +++ b/server/stables.c @@ -237,6 +237,7 @@ static struct option server_options[] = { { "preferred-lifetime", "T", &server_universe, 53, 1 }, { "dhcpv6-lease-file-name", "t", &server_universe, 54, 1 }, { "dhcpv6-pid-file-name", "t", &server_universe, 55, 1 }, + { "limit-addrs-per-ia", "L", &server_universe, 56, 1 }, { NULL, NULL, NULL, 0, 0 } };