From: David Hankins Date: Wed, 31 Oct 2007 19:13:33 +0000 (+0000) Subject: - Relative time may now be used as a qualifier for 'allow' and 'deny' access X-Git-Tag: v4_0_0b3~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b1d3778ce8f2e983e037354df377ac906df6f9fb;p=thirdparty%2Fdhcp.git - Relative time may now be used as a qualifier for 'allow' and 'deny' access control lists. These directives may be used to assist in re-addressing address pools without having to constantly reconfigure the server. Please see 'man dhcpd.conf' for more information on allow/deny 'after time' syntax. Thanks to a patch from Christof Chen. [ISC-Bugs #17110] --- diff --git a/RELNOTES b/RELNOTES index a8e0b47cd..55c7d9868 100644 --- a/RELNOTES +++ b/RELNOTES @@ -59,6 +59,12 @@ suggested fixes to . them, if advertised by the client. It still only seeks to allocate one new address. +- Relative time may now be used as a qualifier for 'allow' and 'deny' access + control lists. These directives may be used to assist in re-addressing + address pools without having to constantly reconfigure the server. Please + see 'man dhcpd.conf' for more information on allow/deny 'after time' syntax. + Thanks to a patch from Christof Chen. + Changes since 4.0.0b1 - Use different paths for PID and lease files when running in DHCPv4 diff --git a/common/conflex.c b/common/conflex.c index fc32a15a4..18a840d14 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -732,6 +732,8 @@ intern(char *atom, enum dhcp_token dfv) { return TOKEN_ACTIVE; if (!strcasecmp (atom + 1, "tsfp")) return ATSFP; + if (!strcasecmp (atom + 1, "fter")) + return AFTER; break; case 'b': if (!strcasecmp (atom + 1, "ackup")) diff --git a/common/parse.c b/common/parse.c index 01eced4ee..6171cd380 100644 --- a/common/parse.c +++ b/common/parse.c @@ -843,13 +843,15 @@ void convert_num (cfile, buf, str, base, size) * NUMBER COLON NUMBER COLON NUMBER NUMBER SEMI | * NEVER * - * Dates are stored in GMT or with a timezone offset; first number is day + * Dates are stored in UTC or with a timezone offset; first number is day * of week; next is year/month/day; next is hours:minutes:seconds on a * 24-hour clock, followed by the timezone offset in seconds, which is * optional. */ -TIME parse_date (cfile) +/* just parse the date */ +TIME +parse_date_core(cfile) struct parse *cfile; { int guess; @@ -1008,10 +1010,6 @@ TIME parse_date (cfile) } else tzoff = 0; - /* Make sure the date ends in a semicolon... */ - if (!parse_semi (cfile)) - return 0; - /* Guess the time value... */ guess = ((((((365 * (year - 70) + /* Days in years since '70 */ (year - 69) / 4 + /* Leap days since '70 */ @@ -1036,6 +1034,22 @@ TIME parse_date (cfile) return guess; } +/* Wrapper to consume the semicolon after the date */ +TIME +parse_date(cfile) + struct parse *cfile; +{ + int guess; + guess = parse_date_core(cfile); + + /* Make sure the date ends in a semicolon... */ + if (!parse_semi(cfile)) + return 0; + return guess; +} + + + /* * option-name :== IDENTIFIER | IDENTIFIER . IDENTIFIER diff --git a/includes/dhcpd.h b/includes/dhcpd.h index ab1675659..0d5de7989 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -752,9 +752,11 @@ struct permit { permit_unauthenticated_clients, permit_all_clients, permit_dynamic_bootp_clients, - permit_class + permit_class, + permit_after } type; struct class *class; + TIME after; /* date after which this clause applies */ }; struct pool { @@ -775,6 +777,9 @@ struct pool { int free_leases; int backup_leases; int index; + TIME valid_from; /* deny pool use before this date */ + TIME valid_until; /* deny pool use after this date */ + #if defined (FAILOVER_PROTOCOL) dhcp_failover_state_t *failover_peer; #endif @@ -1691,6 +1696,7 @@ unsigned char *parse_numeric_aggregate PROTO ((struct parse *, void convert_num PROTO ((struct parse *, unsigned char *, const char *, int, unsigned)); TIME parse_date PROTO ((struct parse *)); +TIME parse_date_core(struct parse *); isc_result_t parse_option_name PROTO ((struct parse *, int, int *, struct option **)); void parse_option_space_decl PROTO ((struct parse *)); diff --git a/includes/dhctoken.h b/includes/dhctoken.h index 5baea1c49..80ad0b3d5 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -344,7 +344,8 @@ enum dhcp_token { LL = 647, RANGE6 = 648, WHITESPACE = 649, - TOKEN_ALSO = 650 + TOKEN_ALSO = 650, + AFTER = 651 }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ diff --git a/server/confpars.c b/server/confpars.c index 5b850ade6..f6101b3b1 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -1344,6 +1344,8 @@ void parse_pool_statement (cfile, group, type) int declaration = 0; isc_result_t status; struct lease *lpchain = (struct lease *)0, *lp; + TIME t; + int is_allow = 0; pool = (struct pool *)0; status = pool_allocate (&pool, MDL); @@ -1440,6 +1442,8 @@ void parse_pool_statement (cfile, group, type) break; case ALLOW: permit_head = &pool -> permit_list; + /* remember the clause which leads to get_permit */ + is_allow = 1; get_permit: permit = new_permit (MDL); if (!permit) @@ -1522,6 +1526,24 @@ void parse_pool_statement (cfile, group, type) "no such class: %s", val); break; + case AFTER: + if (pool->valid_from || pool->valid_until) { + parse_warn(cfile, + "duplicate \"after\" clause."); + skip_to_semi(cfile); + free_permit(permit, MDL); + continue; + } + t = parse_date_core(cfile); + permit->type = permit_after; + permit->after = t; + if (is_allow) { + pool->valid_from = t; + } else { + pool->valid_until = t; + } + break; + default: parse_warn (cfile, "expecting permit type."); skip_to_semi (cfile); @@ -1535,6 +1557,8 @@ void parse_pool_statement (cfile, group, type) case DENY: permit_head = &pool -> prohibit_list; + /* remember the clause which leads to get_permit */ + is_allow = 0; goto get_permit; case RBRACE: diff --git a/server/dhcp.c b/server/dhcp.c index a27000b99..b1ec39266 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -1451,6 +1451,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) TIME ping_timeout; TIME lease_cltt; struct in_addr from; + TIME remaining_time; + struct iaddr cip; unsigned i, j; int s1; @@ -2072,6 +2074,54 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) data_string_forget(&d1, MDL); } + /* a client requests an address which is not yet active*/ + if (lease->pool && lease->pool->valid_from && + cur_time < lease->pool->valid_from) { + /* NAK leases before pool activation date */ + cip.len = 4; + memcpy (cip.iabuf, <->ip_addr.iabuf, 4); + nak_lease(packet, &cip); + free_lease_state (state, MDL); + lease_dereference (<, MDL); + if (host) + host_dereference (&host, MDL); + return; + + } + + /* CC: + a) NAK current lease if past the expiration date + b) extend lease only up to the expiration date, but not + below min-lease-time + Setting min-lease-time is essential for this to work! + The value of min-lease-time determines the lenght + of the transition window: + A client renewing a second before the deadline will + get a min-lease-time lease. Since the current ip might not + be routable after the deadline, the client will + be offline until it DISCOVERS again. Otherwise it will + receive a NAK at T/2. + A min-lease-time of 6 seconds effectively switches over + all clients in this pool very quickly. + */ + + if (lease->pool && lease->pool->valid_until) { + if (cur_time >= lease->pool->valid_until) { + /* NAK leases after pool expiration date */ + cip.len = 4; + memcpy (cip.iabuf, <->ip_addr.iabuf, 4); + nak_lease(packet, &cip); + free_lease_state (state, MDL); + lease_dereference (<, MDL); + if (host) + host_dereference (&host, MDL); + return; + } + remaining_time = lease->pool->valid_until - cur_time; + if (lease_time > remaining_time) + lease_time = remaining_time; + } + if (lease_time < min_lease_time) { if (min_lease_time) lease_time = min_lease_time; @@ -2079,6 +2129,7 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) lease_time = default_lease_time; } + #if defined (FAILOVER_PROTOCOL) /* Okay, we know the lease duration. Now check the failover state, if any. */ @@ -3839,6 +3890,11 @@ int permitted (packet, permit_list) return 1; } break; + + case permit_after: + if (cur_time > p->after) + return 1; + break; } } return 0; diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5 index f34eef551..1ed8b65ac 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.89 2007/10/27 19:15:36 each Exp $ +.\" $Id: dhcpd.conf.5,v 1.90 2007/10/31 19:13:33 dhankins Exp $ .\" .TH dhcpd.conf 5 .SH NAME @@ -1831,6 +1831,18 @@ pool declaration for some reason, but hold it in reserve, or when you want to renumber your network quickly, and thus want the server to force all clients that have been allocated addresses from this pool to obtain new addresses immediately when they next renew. +.PP + \fBafter \fItime\fR\fB;\fR +.PP +If specified, this statement either allows or prevents allocation from +this pool after a given date. This can be used when you want to move +clients from one pool to another. The server adjusts the regular lease +time so that the latest expiry time is at the given time+min-lease-time. +A short min-lease-time enforces a step change, whereas a longer +min-lease-time allows for a gradual change. +\fItime\fR is either second since epoch, or a UTC time string e.g. +4 2007/08/24 09:14:32 or a string with time zone offset in seconds +e.g. 4 2007/08/24 11:14:32 -7200 .SH REFERENCE: PARAMETERS The .I adaptive-lease-time-threshold