diff options
-rw-r--r-- | RELNOTES | 7 | ||||
-rw-r--r-- | includes/dhcpd.h | 5 | ||||
-rw-r--r-- | server/dhcp.c | 55 | ||||
-rw-r--r-- | server/dhcpv6.c | 34 |
4 files changed, 76 insertions, 25 deletions
@@ -187,6 +187,13 @@ by Eric Young (eay@cryptsoft.com). Mritunjaykumar Dubey at Nokia for reporting the issue. [ISC-Bugs #41473] +- Altered DHCPv4 lease time calculation to avoid roll over errors on 64-bit + OS systems when using -1 or large values for default-lease-time. Rollover + values will be replaced with 0x7FFFFFFF - 1. This alleviates unintentionally + short expiration times being handed out when infinite lease times (-1) in + conjuction with failover. + [ISC-Bugs #41976] + Changes since 4.3.0 (bug fixes) - Tidy up several small tickets. diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 5a3888d5..5d5e1d0f 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -1588,8 +1588,9 @@ typedef unsigned char option_mask [16]; #define DHCPD_LOG_FACILITY LOG_DAEMON #endif -#define MAX_TIME 0x7fffffff -#define MIN_TIME 0 +#define INFINITE_TIME 0xffffffff +#define MAX_TIME 0x7fffffff +#define MIN_TIME 0 #ifdef USE_LOG_PID /* include the pid in the syslog messages */ diff --git a/server/dhcp.c b/server/dhcp.c index 1109e204..5b4e0b96 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -85,6 +85,8 @@ const int dhcp_type_name_max = ((sizeof dhcp_type_names) / sizeof (char *)); # define send_packet trace_packet_send #endif +static TIME leaseTimeCheck(TIME calculated, TIME alternate); + void dhcp (struct packet *packet) { int ms_nulltp = 0; @@ -2878,8 +2880,15 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) * the desired lease time upon renewal. */ if (offer == DHCPACK) { - lt->tstp = cur_time + lease_time + - (new_lease_time / 2); + if (lease_time == INFINITE_TIME) { + lt->tstp = MAX_TIME; + } else { + lt->tstp = + leaseTimeCheck( + (cur_time + lease_time + + (new_lease_time / 2)), + MAX_TIME - 1); + } /* If we reduced the potential expiry time, * make sure we don't offer an old-expiry-time @@ -2896,12 +2905,16 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) } #endif /* FAILOVER_PROTOCOL */ - /* If the lease duration causes the time value to wrap, - use the maximum expiry time. */ - if (cur_time + lease_time < cur_time) - state -> offered_expiry = MAX_TIME - 1; - else - state -> offered_expiry = cur_time + lease_time; + if (lease_time == INFINITE_TIME) { + state->offered_expiry = MAX_TIME; + } else { + /* If the lease duration causes the time value to wrap, + use the maximum expiry time. */ + state->offered_expiry + = leaseTimeCheck(cur_time + lease_time, + MAX_TIME - 1); + } + if (when) lt -> ends = when; else @@ -5670,3 +5683,29 @@ reuse_lease (struct packet* packet, lease->cannot_reuse = (!reusable && offer == DHCPOFFER); return (reusable); } + +/* \brief Validates a proposed value for use as a lease time + * + * Convenience function used for catching calculeated lease + * times that overflow 4-byte times used in v4 protocol. + * + * We use variables of type TIME in lots of places, which on + * 64-bit systems is 8 bytes while on 32-bit OSs it is int32_t, + * so we have all sorts of fun places to mess things up. + * This function checks a calculated lease time for and if it + * is unsuitable for use as a lease time, the given alternate + * value is returned. + * \param calculated + * \param alternate + * + * \returen either the calculated value if it is valid, or + * the alternate value supplied + */ +TIME leaseTimeCheck(TIME calculated, TIME alternate) { + if ((sizeof(TIME) > 4 && calculated >= INFINITE_TIME) || + (calculated < cur_time)) { + return (alternate); + } + + return (calculated); +} diff --git a/server/dhcpv6.c b/server/dhcpv6.c index d18758ba..a8bae63c 100644 --- a/server/dhcpv6.c +++ b/server/dhcpv6.c @@ -2090,7 +2090,7 @@ reply_process_ia_na(struct reply_state *reply, struct option_cache *ia) { * A not included IA ("cleanup" below) could give a Renew/Rebind. */ oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR); - reply->min_valid = reply->min_prefer = 0xffffffff; + reply->min_valid = reply->min_prefer = INFINITE_TIME; reply->client_valid = reply->client_prefer = 0; for (; oc != NULL ; oc = oc->next) { status = reply_process_addr(reply, oc); @@ -2845,7 +2845,7 @@ reply_process_ia_ta(struct reply_state *reply, struct option_cache *ia) { * Deal with an IAADDR for lifetimes. * For all or none, process IAADDRs as hints. */ - reply->min_valid = reply->min_prefer = 0xffffffff; + reply->min_valid = reply->min_prefer = INFINITE_TIME; reply->client_valid = reply->client_prefer = 0; oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAADDR); for (; oc != NULL; oc = oc->next) { @@ -3567,10 +3567,10 @@ reply_process_is_addressed(struct reply_state *reply, * The following doesn't work on at least some systems: * (cur_time + reply->send_valid < cur_time) */ - if (reply->send_valid != 0xFFFFFFFF) { + if (reply->send_valid != INFINITE_TIME) { time_t test_time = cur_time + reply->send_valid; if (test_time < cur_time) - reply->send_valid = 0xFFFFFFFF; + reply->send_valid = INFINITE_TIME; } if (reply->client_prefer == 0) @@ -3579,7 +3579,7 @@ reply_process_is_addressed(struct reply_state *reply, reply->send_prefer = reply->client_prefer; if ((reply->send_prefer >= reply->send_valid) && - (reply->send_valid != 0xFFFFFFFF)) + (reply->send_valid != INFINITE_TIME)) reply->send_prefer = (reply->send_valid / 2) + (reply->send_valid / 8); @@ -3634,7 +3634,7 @@ reply_process_is_addressed(struct reply_state *reply, * when connecting to the lease file MAX_TIME is */ if (reply->buf.reply.msg_type == DHCPV6_REPLY) { - if (reply->send_valid == 0xFFFFFFFF) { + if (reply->send_valid == INFINITE_TIME) { reply->lease->soft_lifetime_end_time = MAX_TIME; } else { reply->lease->soft_lifetime_end_time = @@ -3921,7 +3921,7 @@ reply_process_ia_pd(struct reply_state *reply, struct option_cache *ia) { * For each prefix in this IA_PD, decide what to do about it. */ oc = lookup_option(&dhcpv6_universe, packet_ia, D6O_IAPREFIX); - reply->min_valid = reply->min_prefer = 0xffffffff; + reply->min_valid = reply->min_prefer = INFINITE_TIME; reply->client_valid = reply->client_prefer = 0; reply->preflen = -1; for (; oc != NULL ; oc = oc->next) { @@ -4813,10 +4813,10 @@ reply_process_is_prefixed(struct reply_state *reply, * The following doesn't work on at least some systems: * (cur_time + reply->send_valid < cur_time) */ - if (reply->send_valid != 0xFFFFFFFF) { + if (reply->send_valid != INFINITE_TIME) { time_t test_time = cur_time + reply->send_valid; if (test_time < cur_time) - reply->send_valid = 0xFFFFFFFF; + reply->send_valid = INFINITE_TIME; } if (reply->client_prefer == 0) @@ -4825,7 +4825,7 @@ reply_process_is_prefixed(struct reply_state *reply, reply->send_prefer = reply->client_prefer; if ((reply->send_prefer >= reply->send_valid) && - (reply->send_valid != 0xFFFFFFFF)) + (reply->send_valid != INFINITE_TIME)) reply->send_prefer = (reply->send_valid / 2) + (reply->send_valid / 8); @@ -4865,7 +4865,7 @@ reply_process_is_prefixed(struct reply_state *reply, * when connecting to the lease file MAX_TIME is */ if (reply->buf.reply.msg_type == DHCPV6_REPLY) { - if (reply->send_valid == 0xFFFFFFFF) { + if (reply->send_valid == INFINITE_TIME) { reply->lease->soft_lifetime_end_time = MAX_TIME; } else { reply->lease->soft_lifetime_end_time = @@ -8089,8 +8089,10 @@ set_reply_tee_times(struct reply_state* reply, unsigned ia_cursor) } else if (set_tee_times) { /* Setting them is enabled so T1 is either infinite or * 0.5 * the shortest preferred lifetime in the IA_XX */ - reply->renew = (reply->min_prefer == 0xFFFFFFFF ? 0xFFFFFFFF - : reply->min_prefer / 2); + if (reply->min_prefer == INFINITE_TIME) + reply->renew = INFINITE_TIME; + else + reply->renew = reply->min_prefer / 2; } else { /* Default is to let the client choose */ reply->renew = 0; @@ -8122,8 +8124,10 @@ set_reply_tee_times(struct reply_state* reply, unsigned ia_cursor) } else if (set_tee_times) { /* Setting them is enabled so T2 is either infinite or * 0.8 * the shortest preferred lifetime in the reply */ - reply->rebind = (reply->min_prefer == 0xFFFFFFFF ? 0xFFFFFFFF - : (reply->min_prefer / 5) * 4); + if (reply->min_prefer == INFINITE_TIME) + reply->rebind = INFINITE_TIME; + else + reply->rebind = (reply->min_prefer / 5) * 4; } else { /* Default is to let the client choose */ reply->rebind = 0; |