From 703873ab371c5861c977a8be8d64a85ee3e8e74e Mon Sep 17 00:00:00 2001 From: David Hankins Date: Tue, 20 Nov 2007 18:33:07 +0000 Subject: [PATCH] - If the client had multiple addresses, and one expired (was not renewed by the server), the client would continue to attempt to renew the same old address over and over. Now, the client will omit any expired addresses from future Confirm, Renew, or Rebind messages. [ISC-Bugs #17266] - dhclient -6 will now select renew/rebind timers based upon the longest address expiration time rather than the shortest expiration time, in order to avoid cascading renewals in the event a server elects not to extend one of multiple IAADDR leases. [ISC-Bugs #17266] --- RELNOTES | 12 +++++++++ client/dhc6.c | 67 +++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/RELNOTES b/RELNOTES index fa32799c4..7c131c59c 100644 --- a/RELNOTES +++ b/RELNOTES @@ -53,6 +53,18 @@ may not work on other platforms. Please report any problems and suggested fixes to . + Changes since 4.0.0b3 + +- If the client had multiple addresses, and one expired (was not renewed + by the server), the client would continue to attempt to renew the same + old address over and over. Now, the client will omit any expired + addresses from future Confirm, Renew, or Rebind messages. + +- dhclient -6 will now select renew/rebind timers based upon the longest + address expiration time rather than the shortest expiration time, in + order to avoid cascading renewals in the event a server elects not to + extend one of multiple IAADDR leases. + Changes since 4.0.0b2 - Clarified error message when lease limit exceeded diff --git a/client/dhc6.c b/client/dhc6.c index 2731ba6b4..33a5101e8 100644 --- a/client/dhc6.c +++ b/client/dhc6.c @@ -2186,6 +2186,14 @@ dhc6_add_ia(struct client_state *client, struct data_string *packet, } for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { + /* + * Do not confirm expired addresses, do not request + * expired addresses (but we keep them around for + * solicit). + */ + if (addr->flags & DHC6_ADDR_EXPIRED) + continue; + if (addr->address.len != 16) { log_error("Illegal IPv6 address length (%d), " "ignoring. (%s:%d)", @@ -2455,6 +2463,11 @@ dhc6_check_times(struct client_state *client) cancel_timeout(do_expire, client); for(ia = lease->bindings ; ia != NULL ; ia = ia->next) { + TIME this_ia_lo_expire, this_ia_hi_expire, use_expire; + + this_ia_lo_expire = MAX_TIME; + this_ia_hi_expire = 0; + for (addr = ia->addrs ; addr != NULL ; addr = addr->next) { if(!(addr->flags & DHC6_ADDR_DEPREFFED)) { if (addr->preferred_life == 0xffffffff) @@ -2468,27 +2481,41 @@ dhc6_check_times(struct client_state *client) } if (!(addr->flags & DHC6_ADDR_EXPIRED)) { + /* Find EPOCH-relative expiration. */ if (addr->max_life == 0xffffffff) tmp = MAX_TIME; else tmp = addr->starts + addr->max_life; - if (tmp > hi_expire) - hi_expire = tmp; - if (tmp < lo_expire) - lo_expire = tmp; + /* Make the times ia->starts relative. */ + tmp -= ia->starts; + + if (tmp > this_ia_hi_expire) + this_ia_hi_expire = tmp; + if (tmp < this_ia_lo_expire) + this_ia_lo_expire = tmp; has_addrs = ISC_TRUE; } } - if (ia->renew == 0) { - if (lo_expire != MAX_TIME) - tmp = (lo_expire - ia->starts) / 2; - else - tmp = client->config->requested_lease / 2; + /* These times are ia->starts relative. */ + if (this_ia_lo_expire <= (this_ia_hi_expire / 2)) + use_expire = this_ia_hi_expire; + else + use_expire = this_ia_lo_expire; - tmp += ia->starts; + /* + * If the auto-selected expiration time is "infinite", or + * zero, assert a reasonable default. + */ + if ((use_expire == MAX_TIME) || (use_expire <= 1)) + use_expire = client->config->requested_lease / 2; + else + use_expire /= 2; + + if (ia->renew == 0) { + tmp = ia->starts + use_expire; } else if(ia->renew == 0xffffffff) tmp = MAX_TIME; else @@ -2498,12 +2525,8 @@ dhc6_check_times(struct client_state *client) renew = tmp; if (ia->rebind == 0) { - if (lo_expire != MAX_TIME) - tmp = (lo_expire - ia->starts) / 2; - else - tmp = client->config->requested_lease / 2; - - tmp += ia->starts + (tmp / 2); + /* Set rebind to 3/4 expiration interval. */ + tmp = ia->starts + use_expire + (use_expire / 2); } else if (ia->renew == 0xffffffff) tmp = MAX_TIME; else @@ -2511,6 +2534,18 @@ dhc6_check_times(struct client_state *client) if (tmp < rebind) rebind = tmp; + + /* + * Return expiration ranges to EPOCH relative for event + * scheduling (add_timeout()). + */ + this_ia_hi_expire += ia->starts; + this_ia_lo_expire += ia->starts; + + if (this_ia_hi_expire > hi_expire) + hi_expire = this_ia_hi_expire; + if (this_ia_lo_expire < lo_expire) + lo_expire = this_ia_lo_expire; } /* If there are no addresses, give up, go to INIT. -- 2.39.5