commit a5252220fbb8cc144b3706d6a391a004ad7924d4
Author: Thomas Markwalder <tmark@isc.org>
Date:   Thu Jul 7 14:11:26 2016 -0400

    [master] Add abandon-lease-time parameter
    
        Merges in rt41815.

diff --git a/RELNOTES b/RELNOTES
index 3d05131..352dd7f 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -92,6 +92,12 @@ by Eric Young (eay@cryptsoft.com).
   are issues while cleaning up the A or AAAA records.
   [ISC-Bugs #23954]
 
+- Added global configuration parameter, abandon-lease-time, which determines
+  the amount of time a lease remains abandoned.  The default is 84600 seconds.
+  Additionaly, the server now conducts a ping check (if ping checks are
+  enabled) prior to offering an abandoned lease to client.
+  [ISC-Bugs #41815]
+
 			Changes since 4.3.4b1
 
 - None
diff --git a/includes/dhcpd.h b/includes/dhcpd.h
index d149792..261714d 100644
--- a/includes/dhcpd.h
+++ b/includes/dhcpd.h
@@ -798,6 +798,7 @@ struct lease_state {
 #define SV_SERVER_ID_CHECK		86
 #define SV_PREFIX_LEN_MODE		87
 #define SV_DHCPV6_SET_TEE_TIMES		88
+#define SV_ABANDON_LEASE_TIME		89
 
 #if !defined (DEFAULT_PING_TIMEOUT)
 # define DEFAULT_PING_TIMEOUT 1
@@ -846,6 +847,10 @@ struct lease_state {
 # define MIN_LEASE_WRITE 15
 #endif
 
+#if !defined (DEFAULT_ABANDON_LEASE_TIME)
+# define DEFAULT_ABANDON_LEASE_TIME 86400
+#endif
+
 #define PLM_IGNORE 0
 #define PLM_PREFER 1
 #define PLM_EXACT 2
@@ -2069,6 +2074,7 @@ extern int server_id_check;
 extern int prefix_length_mode;
 extern int authoring_byte_order;
 extern int lease_id_format;
+extern u_int32_t abandon_lease_time;
 
 extern const char *path_dhcpd_conf;
 extern const char *path_dhcpd_db;
diff --git a/server/dhcp.c b/server/dhcp.c
index a823a4e..55a67bf 100644
--- a/server/dhcp.c
+++ b/server/dhcp.c
@@ -3490,7 +3490,8 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
 	/* If this is a DHCPOFFER, ping the lease address before actually
 	   sending the offer. */
 	if (offer == DHCPOFFER && !(lease -> flags & STATIC_LEASE) &&
-	    ((cur_time - lease_cltt) > 60) &&
+	    (((cur_time - lease_cltt) > 60) ||
+             (lease->binding_state == FTS_ABANDONED)) &&
 	    (!(oc = lookup_option (&server_universe, state -> options,
 				   SV_PING_CHECKS)) ||
 	     evaluate_boolean_option_cache (&ignorep, packet, lease,
@@ -4871,8 +4872,11 @@ int allocate_lease (struct lease **lp, struct packet *packet,
 		 * "no free leases" error when the last lease has been
 		 * offered, but it's not exactly broken either.
 		 */
-		if (!candl || (candl -> ends > cur_time))
+		if (!candl ||
+	            (candl->binding_state != FTS_ABANDONED &&
+		     (candl->ends > cur_time))) {
 			continue;
+		}
 
 		if (!lease) {
 			lease = candl;
diff --git a/server/dhcpd.c b/server/dhcpd.c
index a42d759..4364282 100644
--- a/server/dhcpd.c
+++ b/server/dhcpd.c
@@ -78,6 +78,7 @@ int prefix_length_mode = PLM_EXACT;
 
 int authoring_byte_order = 0; /* 0 = not set */
 int lease_id_format = TOKEN_OCTAL; /* octal by default */
+u_int32_t abandon_lease_time = DEFAULT_ABANDON_LEASE_TIME;
 
 const char *path_dhcpd_conf = _PATH_DHCPD_CONF;
 const char *path_dhcpd_db = _PATH_DHCPD_DB;
@@ -1241,6 +1242,20 @@ void postconf_initialization (int quiet)
 		data_string_forget(&db, MDL);
 	}
 
+	// Set global abandon-lease-time option.
+	oc = lookup_option (&server_universe, options, SV_ABANDON_LEASE_TIME);
+	if ((oc != NULL) &&
+	    evaluate_option_cache(&db, NULL, NULL, NULL, options, NULL,
+				  &global_scope, oc, MDL)) {
+		if (db.len == sizeof (u_int32_t)) {
+			abandon_lease_time = getULong (db.data);
+		} else {
+			log_fatal("invalid abandon-lease-time");
+		}
+
+		data_string_forget (&db, MDL);
+        }
+
 #if defined (BINARY_LEASES)
 	if (local_family == AF_INET) {
 		log_info("Source compiled to use binary-leases");
diff --git a/server/dhcpd.conf.5 b/server/dhcpd.conf.5
index 9c99676..a053ef1 100644
--- a/server/dhcpd.conf.5
+++ b/server/dhcpd.conf.5
@@ -405,7 +405,8 @@ the lease as in use.
 If a response is received to an ICMP Echo request, the DHCP server
 assumes that there is a configuration error - the IP address is in use
 by some host on the network that is not a DHCP client.  It marks the
-address as abandoned, and will not assign it to clients.
+address as abandoned, and will not assign it to clients. The lease will
+remain abandoned for a minimum of abandon-lease-time seconds.
 .PP
 If a DHCP client tries to get an IP address, but none are available,
 but there are abandoned IP addresses, then the DHCP server will
@@ -1882,6 +1883,27 @@ min-lease-time allows for a gradual change.
 e.g. 4 2007/08/24 11:14:32 -7200
 .SH REFERENCE: PARAMETERS
 The
+.I abandon-lease-time
+statement
+.RS 0.25i
+.PP
+.B adandon-lease-time \fItime\fR\fB;\fR
+.PP
+.I Time
+should be the maximum amount of time (in seconds) that an abandoned IPv4 lease
+remains unavailable for assignment to a client.  Abandoned leases will only be
+offered to clients if there are no free leases.  If not defined, the default
+abandon lease time is 86400 seconds (24 hours).  Note the abandoned lease time
+for a given lease is preserved across server restarts.  The parameter may only
+be set at the global scope and is evaluated only once during server startup.
+.PP
+Values less than sixty seconds are not recommended as this is below the ping
+check threshold and can cause leases once abandoned but since returned to the
+free state to not be pinged before being offered.  If the requested time is
+larger than 0x7FFFFFFF - 1 or the sum of the current time plus the abandoned time isgreater than 0x7FFFFFFF it is treated as infinite.
+.RE
+.PP
+The
 .I adaptive-lease-time-threshold
 statement
 .RS 0.25i
@@ -2802,7 +2824,12 @@ address to a client, it first sends an ICMP Echo request (a \fIping\fR)
 to the address being assigned.  It waits for a second, and if no
 ICMP Echo response has been heard, it assigns the address.  If a
 response \fIis\fR heard, the lease is abandoned, and the server does
-not respond to the client.
+not respond to the client.  The lease will remain abandoned for a minimum
+of abandon-lease-time seconds.
+.PP
+If a there are no free addressses but there are abandoned IP addresses, the
+DHCP server will attempt to reclaim an abandoned IP address regardless of the
+value of abandon-lease-time.
 .PP
 This \fIping check\fR introduces a default one-second delay in responding
 to DHCPDISCOVER messages, which can be a problem for some clients.  The
diff --git a/server/mdb.c b/server/mdb.c
index 48947c5..6af6b63 100644
--- a/server/mdb.c
+++ b/server/mdb.c
@@ -1808,30 +1808,40 @@ void abandon_lease (lease, message)
 	struct lease *lease;
 	const char *message;
 {
-	struct lease *lt = (struct lease *)0;
+	struct lease *lt = NULL;
 #if defined (NSUPDATE)
 	(void) ddns_removals(lease, NULL, NULL, ISC_FALSE);
 #endif
 
-	if (!lease_copy (&lt, lease, MDL))
+	if (!lease_copy(&lt, lease, MDL)) {
 		return;
+	}
 
-	if (lt->scope)
+	if (lt->scope) {
 		binding_scope_dereference(&lt->scope, MDL);
+	}
 
-	lt -> ends = cur_time; /* XXX */
-	lt -> next_binding_state = FTS_ABANDONED;
+	/* Calculate the abandone expiry time.  If it wraps,
+ 	 * use the maximum expiry time. */
+	lt->ends = cur_time + abandon_lease_time;
+	if (lt->ends < cur_time || lt->ends > MAX_TIME) {
+		lt->ends = MAX_TIME;
+	}
 
-	log_error ("Abandoning IP address %s: %s",
-	      piaddr (lease -> ip_addr), message);
-	lt -> hardware_addr.hlen = 0;
-	if (lt -> uid && lt -> uid != lt -> uid_buf)
-		dfree (lt -> uid, MDL);
-	lt -> uid = (unsigned char *)0;
-	lt -> uid_len = 0;
-	lt -> uid_max = 0;
-	supersede_lease (lease, lt, 1, 1, 1, 0);
-	lease_dereference (&lt, MDL);
+	lt->next_binding_state = FTS_ABANDONED;
+
+	log_error ("Abandoning IP address %s: %s", piaddr(lease->ip_addr),
+                    message);
+	lt->hardware_addr.hlen = 0;
+	if (lt->uid && lt->uid != lt->uid_buf) {
+		dfree(lt->uid, MDL);
+	}
+
+	lt->uid = NULL;
+	lt->uid_len = 0;
+	lt->uid_max = 0;
+	supersede_lease(lease, lt, 1, 1, 1, 0);
+	lease_dereference(&lt, MDL);
 }
 
 #if 0
diff --git a/server/stables.c b/server/stables.c
index 3a83acb..445ef0f 100644
--- a/server/stables.c
+++ b/server/stables.c
@@ -276,6 +276,7 @@ static struct option server_options[] = {
 	{ "server-id-check", "f",		&server_universe,  SV_SERVER_ID_CHECK, 1 },
 	{ "prefix-length-mode", "Nprefix_length_modes.",	&server_universe,  SV_PREFIX_LEN_MODE, 1 },
 	{ "dhcpv6-set-tee-times", "f",		&server_universe,  SV_DHCPV6_SET_TEE_TIMES, 1 },
+	{ "abandon-lease-time", "T",		&server_universe,  SV_ABANDON_LEASE_TIME, 1 },
 	{ NULL, NULL, NULL, 0, 0 }
 };
 
