]> git.ipfire.org Git - thirdparty/dhcp.git/blobdiff - server/mdb.c
Update RELNOTES
[thirdparty/dhcp.git] / server / mdb.c
index ef54bedd59cf145a585eaa0d274b6634d269958d..b982cc16e51b6207b5277531be707c7630ab0be3 100644 (file)
@@ -3,13 +3,12 @@
    Server-specific in-memory database support. */
 
 /*
- * Copyright (c) 2011-2015 by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 2004-2009 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 2004-2019 by Internet Systems Consortium, Inc. ("ISC")
  * Copyright (c) 1996-2003 by Internet Software Consortium
  *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  *
  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -20,8 +19,8 @@
  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
  *   Internet Systems Consortium, Inc.
- *   950 Charter Street
- *   Redwood City, CA 94063
+ *   PO Box 360
+ *   Newmarket, NH 03857 USA
  *   <info@isc.org>
  *   https://www.isc.org/
  *
@@ -42,12 +41,12 @@ lease_id_hash_t *lease_hw_addr_hash;
 /*
  * We allow users to specify any option as a host identifier.
  *
- * Any host is uniquely identified by the combination of 
+ * Any host is uniquely identified by the combination of
  * option type & option data.
  *
- * We expect people will only use a few types of options as host 
+ * We expect people will only use a few types of options as host
  * identifier. Because of this, we store a list with an entry for
- * each option type. Each of these has a hash table, which contains 
+ * each option type. Each of these has a hash table, which contains
  * hash of the option data.
  *
  * For v6 we also include a relay count - this specifies which
@@ -68,7 +67,7 @@ static host_id_info_t *host_id_info = NULL;
 
 int numclasseswritten;
 
-omapi_object_type_t *dhcp_type_host;
+extern omapi_object_type_t *dhcp_type_host;
 
 isc_result_t enter_class(cd, dynamicp, commit)
        struct class *cd;
@@ -88,7 +87,7 @@ isc_result_t enter_class(cd, dynamicp, commit)
                        class_dereference(&c, MDL);
                        return ISC_R_EXISTS;
                }
-               
+
                /* Find the tail. */
                for (c = collections -> classes;
                     c -> nic; c = c -> nic)
@@ -189,7 +188,7 @@ change_host_uid(struct host_decl *host, const char *uid, int len) {
                }
        }
 
-       /* 
+       /*
         * Remove the old entry, if one exists.
         */
        if (host->client_identifier.data != NULL) {
@@ -200,7 +199,7 @@ change_host_uid(struct host_decl *host, const char *uid, int len) {
                data_string_forget(&host->client_identifier, MDL);
        }
 
-       /* 
+       /*
         * Set our new value.
         */
        memset(&host->client_identifier, 0, sizeof(host->client_identifier));
@@ -214,7 +213,7 @@ change_host_uid(struct host_decl *host, const char *uid, int len) {
        /*
         * And add to hash.
         */
-       host_hash_add(host_uid_hash, host->client_identifier.data, 
+       host_hash_add(host_uid_hash, host->client_identifier.data,
                      host->client_identifier.len, host, MDL);
 }
 
@@ -314,10 +313,32 @@ isc_result_t enter_host (hd, dynamicp, commit)
        esp = NULL;
        if (executable_statement_foreach (hd->group->statements,
                                          find_uid_statement, &esp, 0)) {
-               (void) evaluate_option_cache (&hd->client_identifier,
-                                             NULL, NULL, NULL, NULL, NULL, 
+               struct data_string cid;
+               memset(&cid, 0, sizeof(cid));
+               (void) evaluate_option_cache (&cid,
+                                             NULL, NULL, NULL, NULL, NULL,
                                              &global_scope,
                                              esp->data.option, MDL);
+
+               if (hd->client_identifier.len > 0 && cid.len > 0) {
+                       char uid_buf[256];
+                       char cid_buf[256];
+                       print_hex_or_string(hd->client_identifier.len,
+                                           hd->client_identifier.data,
+                                           sizeof(uid_buf) - 1, uid_buf);
+
+                       print_hex_or_string(cid.len, cid.data,
+                                           sizeof(cid_buf) - 1, cid_buf);
+
+                       log_error ("Warning, host declaration '%s'"
+                                  " already has uid '%s',"
+                                  " ignoring dhcp-client-identifier '%s'",
+                                  hd->name, uid_buf, cid_buf);
+
+                       data_string_forget(&cid, MDL);
+               } else {
+                       memcpy(&hd->client_identifier, &cid, sizeof(cid));
+               }
        }
 
        /* If we got a client identifier, hash this entry by
@@ -380,9 +401,9 @@ isc_result_t enter_host (hd, dynamicp, commit)
                                log_fatal("No memory for host-identifier "
                                          "option information.");
                        }
-                       option_reference(&h_id_info->option, 
+                       option_reference(&h_id_info->option,
                                         hd->host_id_option, MDL);
-                       if (!host_new_hash(&h_id_info->values_hash, 
+                       if (!host_new_hash(&h_id_info->values_hash,
                                           HOST_HASH_SIZE, MDL)) {
                                log_fatal("No memory for host-identifier "
                                          "option hash.");
@@ -392,16 +413,16 @@ isc_result_t enter_host (hd, dynamicp, commit)
                        host_id_info = h_id_info;
                }
 
-               if (host_hash_lookup(&hp, h_id_info->values_hash, 
+               if (host_hash_lookup(&hp, h_id_info->values_hash,
                                     hd->host_id.data, hd->host_id.len, MDL)) {
-                       /* 
-                        * If this option is already present, then add 
+                       /*
+                        * If this option is already present, then add
                         * this host to the list in n_ipaddr, unless
                         * we have already done so previously.
                         *
                         * XXXSK: This seems scary to me, but I don't
-                        *        fully understand how these are used. 
-                        *        Shouldn't there be multiple lists, or 
+                        *        fully understand how these are used.
+                        *        Shouldn't there be multiple lists, or
                         *        maybe we should just forbid duplicates?
                         */
                        if (np == NULL) {
@@ -415,7 +436,7 @@ isc_result_t enter_host (hd, dynamicp, commit)
                        }
                        host_dereference(&hp, MDL);
                } else {
-                       host_hash_add(h_id_info->values_hash, 
+                       host_hash_add(h_id_info->values_hash,
                                      hd->host_id.data,
                                      hd->host_id.len,
                                      hd, MDL);
@@ -441,18 +462,18 @@ isc_result_t delete_class (cp, commit)
 
        /* do the write first as we won't be leaving it in any data
           structures, unlike the host objects */
-       
+
        if (commit) {
                write_named_billing_class ((unsigned char *)cp->name, 0, cp);
                if (!commit_leases ())
                        return ISC_R_IOERROR;
        }
-       
+
        /*
         * If this is a subclass remove it from the class's hash table
         */
        if (cp->superclass) {
-               class_hash_delete(cp->superclass->hash, 
+               class_hash_delete(cp->superclass->hash,
                                  (const char *)cp->hash_string.data,
                                  cp->hash_string.len,
                                  MDL);
@@ -635,7 +656,7 @@ int find_hosts_by_uid (struct host_decl **hp,
 }
 
 int
-find_hosts_by_option(struct host_decl **hp, 
+find_hosts_by_option(struct host_decl **hp,
                     struct packet *packet,
                     struct option_state *opt_state,
                     const char *file, int line) {
@@ -645,9 +666,14 @@ find_hosts_by_option(struct host_decl **hp,
        int found;
        struct packet *relay_packet;
        struct option_state *relay_state;
-       
+
+#if defined(LDAP_CONFIGURATION)
+       if ((found = find_client_in_ldap (hp, packet, opt_state, file, line)))
+               return found;
+#endif
+
        for (p = host_id_info; p != NULL; p = p->next) {
-               relay_packet = packet;  
+               relay_packet = packet;
                relay_state = opt_state;
 
                /* If this option block is for a relay (relays != 0)
@@ -671,20 +697,20 @@ find_hosts_by_option(struct host_decl **hp,
                        relay_state = relay_packet->options;
                }
 
-               oc = lookup_option(p->option->universe, 
+               oc = lookup_option(p->option->universe,
                                   relay_state, p->option->code);
                if (oc != NULL) {
                        memset(&data, 0, sizeof(data));
 
                        if (!evaluate_option_cache(&data, relay_packet, NULL,
                                                   NULL, relay_state, NULL,
-                                                  &global_scope, oc, 
+                                                  &global_scope, oc,
                                                   MDL)) {
                                log_error("Error evaluating option cache");
                                return 0;
                        }
-                       
-                       found = host_hash_lookup(hp, p->values_hash, 
+
+                       found = host_hash_lookup(hp, p->values_hash,
                                                 data.data, data.len,
                                                 file, line);
 
@@ -761,9 +787,9 @@ void new_address_range (cfile, low, high, subnet, pool, lpchain)
 {
 #if defined(COMPACT_LEASES)
        struct lease *address_range;
-       unsigned n, s;
+       unsigned s;
 #endif
-       unsigned min, max, i;
+       unsigned min, max, i, num_addrs;
        char lowbuf [16], highbuf [16], netbuf [16];
        struct shared_network *share = subnet -> shared_network;
        struct lease *lt = (struct lease *)0;
@@ -819,22 +845,30 @@ void new_address_range (cfile, low, high, subnet, pool, lpchain)
                min = host_addr (high, subnet -> netmask);
        }
 
+       /* get the number of addresses we want, and add it to the pool info
+        * this value is only for use when setting up lease chains and will
+        * be overwritten when expire_all_pools is run
+        */
+       num_addrs = max - min + 1;
+#if defined (BINARY_LEASES)
+       pool->lease_count += num_addrs;
+#endif
+
        /* Get a lease structure for each address in the range. */
 #if defined (COMPACT_LEASES)
-       n = max - min + 1;
-       s = (n + 1) * sizeof (struct lease);
+       s = (num_addrs + 1) * sizeof (struct lease);
        /* Check unsigned overflow in new_leases().
           With 304 byte lease structure (x64_86), this happens at
           range 10.0.0.0 10.215.148.52; */
        if (((s % sizeof (struct lease)) != 0) ||
-           ((s / sizeof (struct lease)) != (n + 1))) {
+           ((s / sizeof (struct lease)) != (num_addrs + 1))) {
                strcpy (lowbuf, piaddr (low));
                strcpy (highbuf, piaddr (high));
-               parse_warn (cfile, "%s-%s is a far too large address range.",
+               parse_warn (cfile, "%s-%s is an overly large address range.",
                           lowbuf, highbuf);
                log_fatal ("Memory overflow.");
        }
-       address_range = new_leases (n, MDL);
+       address_range = new_leases (num_addrs, MDL);
        if (!address_range) {
                strcpy (lowbuf, piaddr (low));
                strcpy (highbuf, piaddr (high));
@@ -844,7 +878,7 @@ void new_address_range (cfile, low, high, subnet, pool, lpchain)
 #endif
 
        /* Fill out the lease structures with some minimal information. */
-       for (i = 0; i < max - min + 1; i++) {
+       for (i = 0; i < num_addrs; i++) {
                struct lease *lp = (struct lease *)0;
 #if defined (COMPACT_LEASES)
                omapi_object_initialize ((omapi_object_t *)&address_range [i],
@@ -901,6 +935,10 @@ int find_subnet (struct subnet **sp,
        struct subnet *rv;
 
        for (rv = subnets; rv; rv = rv -> next_subnet) {
+#if defined(DHCP4o6)
+               if (addr.len != rv->netmask.len)
+                       continue;
+#endif
                if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
                        if (subnet_reference (sp, rv,
                                              file, line) != ISC_R_SUCCESS)
@@ -918,6 +956,10 @@ int find_grouped_subnet (struct subnet **sp,
        struct subnet *rv;
 
        for (rv = share -> subnets; rv; rv = rv -> next_sibling) {
+#if defined(DHCP4o6)
+               if (addr.len != rv->netmask.len)
+                       continue;
+#endif
                if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) {
                        if (subnet_reference (sp, rv,
                                              file, line) != ISC_R_SUCCESS)
@@ -929,10 +971,14 @@ int find_grouped_subnet (struct subnet **sp,
 }
 
 /* XXX: could speed up if everyone had a prefix length */
-int 
-subnet_inner_than(const struct subnet *subnet, 
+int
+subnet_inner_than(const struct subnet *subnet,
                  const struct subnet *scan,
                  int warnp) {
+#if defined(DHCP4o6)
+       if (subnet->net.len != scan->net.len)
+               return 0;
+#endif
        if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) ||
            addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) {
                char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")];
@@ -1002,7 +1048,7 @@ void enter_subnet (subnet)
        }
        subnet_reference (&subnets, subnet, MDL);
 }
-       
+
 /* Enter a new shared network into the shared network list. */
 
 void enter_shared_network (share)
@@ -1015,7 +1061,7 @@ void enter_shared_network (share)
        }
        shared_network_reference (&shared_networks, share, MDL);
 }
-       
+
 void new_shared_network_interface (cfile, share, name)
        struct parse *cfile;
        struct shared_network *share;
@@ -1025,12 +1071,12 @@ void new_shared_network_interface (cfile, share, name)
        isc_result_t status;
 
        if (share -> interface) {
-               parse_warn (cfile, 
+               parse_warn (cfile,
                            "A subnet or shared network can't be connected %s",
                            "to two interfaces.");
                return;
        }
-       
+
        for (ip = interfaces; ip; ip = ip -> next)
                if (!strcmp (ip -> name, name))
                        break;
@@ -1112,7 +1158,7 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
        int pimmediate;
        int from_pool;
 {
-       struct lease *lp, **lq, *prev;
+       LEASE_STRUCT_PTR lq;
        struct timeval tv;
 #if defined (FAILOVER_PROTOCOL)
        int do_pool_check = 0;
@@ -1123,7 +1169,6 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
        if (pimmediate && !commit)
                return 0;
 #endif
-
        /* If there is no sample lease, just do the move. */
        if (!lease)
                goto just_move_it;
@@ -1177,8 +1222,8 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
 
        /* If the lease has been billed to a class, remove the billing. */
        if (comp -> billing_class != lease -> billing_class) {
-               if (comp -> billing_class)
-                       unbill_class (comp, comp -> billing_class);
+               if (comp->billing_class)
+                       unbill_class(comp);
                if (lease -> billing_class)
                        bill_class (comp, lease -> billing_class);
        }
@@ -1210,8 +1255,6 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
                host_dereference (&comp -> host, MDL);
        host_reference (&comp -> host, lease -> host, MDL);
        comp -> hardware_addr = lease -> hardware_addr;
-       comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) |
-                        (comp -> flags & ~EPHEMERAL_FLAGS));
        if (comp -> scope)
                binding_scope_dereference (&comp -> scope, MDL);
        if (lease -> scope) {
@@ -1360,34 +1403,14 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
 
        /* Remove the lease from its current place in its current
           timer sequence. */
-       /* XXX this is horrid. */
-       prev = (struct lease *)0;
-       for (lp = *lq; lp; lp = lp -> next) {
-               if (lp == comp)
-                       break;
-               prev = lp;
-       }
+       LEASE_REMOVEP(lq, comp);
 
-       if (!lp) {
-               log_fatal("Lease with binding state %s not on its queue.",
-                         (comp->binding_state < 1 ||
-                          comp->binding_state > FTS_LAST)
-                         ? "unknown"
-                         : binding_state_names[comp->binding_state - 1]);
-       }
-
-       if (prev) {
-               lease_dereference (&prev -> next, MDL);
-               if (comp -> next) {
-                       lease_reference (&prev -> next, comp -> next, MDL);
-                       lease_dereference (&comp -> next, MDL);
-               }
-       } else {
-               lease_dereference (lq, MDL);
-               if (comp -> next) {
-                       lease_reference (lq, comp -> next, MDL);
-                       lease_dereference (&comp -> next, MDL);
-               }
+       /* Now that we've done the flag-affected queue removal
+        * we can update the new lease's flags, if there's an
+        * existing lease */
+       if (lease) {
+               comp->flags = ((lease->flags & ~PERSISTENT_FLAGS) |
+                               (comp->flags & ~EPHEMERAL_FLAGS));
        }
 
        /* Make the state transition. */
@@ -1402,7 +1425,7 @@ int supersede_lease (comp, lease, commit, propogate, pimmediate, from_pool)
        /* If this is the next lease that will timeout on the pool,
           zap the old timeout and set the timeout on this pool to the
           time that the lease's next event will happen.
-                  
+
           We do not actually set the timeout unless commit is true -
           we don't want to thrash the timer queue when reading the
           lease database.  Instead, the database code calls the
@@ -1515,15 +1538,15 @@ void make_binding_state_transition (struct lease *lease)
                                executable_statement_dereference
                                        (&lease->on_star.on_expiry, MDL);
                }
-               
+
                /* No sense releasing a lease after it's expired. */
                if (lease->on_star.on_release)
                        executable_statement_dereference
                                (&lease->on_star.on_release, MDL);
                /* Get rid of client-specific bindings that are only
                   correct when the lease is active. */
-               if (lease -> billing_class)
-                       unbill_class (lease, lease -> billing_class);
+               if (lease->billing_class)
+                       unbill_class(lease);
                if (lease -> agent_options)
                        option_chain_head_dereference (&lease -> agent_options,
                                                       MDL);
@@ -1578,7 +1601,7 @@ void make_binding_state_transition (struct lease *lease)
                        executable_statement_dereference
                                (&lease->on_star.on_release, MDL);
                }
-               
+
                /* A released lease can't expire. */
                if (lease->on_star.on_expiry)
                        executable_statement_dereference
@@ -1586,8 +1609,8 @@ void make_binding_state_transition (struct lease *lease)
 
                /* Get rid of client-specific bindings that are only
                   correct when the lease is active. */
-               if (lease -> billing_class)
-                       unbill_class (lease, lease -> billing_class);
+               if (lease->billing_class)
+                       unbill_class(lease);
                if (lease -> agent_options)
                        option_chain_head_dereference (&lease -> agent_options,
                                                       MDL);
@@ -1807,30 +1830,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
@@ -1883,13 +1916,14 @@ void pool_timer (vpool)
        struct pool *pool;
        struct lease *next = NULL;
        struct lease *lease = NULL;
+       struct lease *ltemp = NULL;
 #define FREE_LEASES 0
 #define ACTIVE_LEASES 1
 #define EXPIRED_LEASES 2
 #define ABANDONED_LEASES 3
 #define BACKUP_LEASES 4
 #define RESERVED_LEASES 5
-       struct lease **lptr[RESERVED_LEASES+1];
+       LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
        TIME next_expiry = MAX_TIME;
        int i;
        struct timeval tv;
@@ -1905,7 +1939,7 @@ void pool_timer (vpool)
 
        for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
                /* If there's nothing on the queue, skip it. */
-               if (!*(lptr [i]))
+               if (!(LEASE_NOT_EMPTYP(lptr[i])))
                        continue;
 
 #if defined (FAILOVER_PROTOCOL)
@@ -1935,15 +1969,16 @@ void pool_timer (vpool)
                        if (i == EXPIRED_LEASES)
                                continue;
                }
-#endif         
-               lease_reference(&lease, *(lptr [i]), MDL);
+#endif
+               lease_reference(&lease, LEASE_GET_FIRSTP(lptr[i]), MDL);
 
                while (lease) {
                        /* Remember the next lease in the list. */
                        if (next)
                                lease_dereference(&next, MDL);
-                       if (lease -> next)
-                               lease_reference(&next, lease->next, MDL);
+                       ltemp = LEASE_GET_NEXTP(lptr[i], lease);
+                       if (ltemp)
+                               lease_reference(&next, ltemp, MDL);
 
                        /* If we've run out of things to expire on this list,
                           stop. */
@@ -2226,7 +2261,7 @@ hw_hash_add(struct lease *lease)
        if ((lease->hardware_addr.hlen == 1) &&
            (lease->hardware_addr.hbuf[0] == HTYPE_INFINIBAND))
                return;
-          
+
        /* If it's not in the hash, just add it. */
        if (!find_lease_by_hw_addr (&head, lease -> hardware_addr.hbuf,
                                    lease -> hardware_addr.hlen, MDL))
@@ -2358,7 +2393,7 @@ int write_leases4(void) {
        struct lease *l;
        struct shared_network *s;
        struct pool *p;
-       struct lease **lptr[RESERVED_LEASES+1];
+       LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
        int num_written = 0, i;
 
        /* Write all the leases. */
@@ -2372,7 +2407,9 @@ int write_leases4(void) {
                lptr[RESERVED_LEASES] = &p->reserved;
 
                for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
-                   for (l = *(lptr[i]); l; l = l->next) {
+                   for (l = LEASE_GET_FIRSTP(lptr[i]);
+                        l != NULL;
+                        l = LEASE_GET_NEXTP(lptr[i], l)) {
 #if !defined (DEBUG_DUMP_ALL_LEASES)
                        if (l->hardware_addr.hlen != 0 || l->uid_len != 0 ||
                            l->tsfp != 0 || l->binding_state != FTS_FREE)
@@ -2414,12 +2451,12 @@ int write_leases ()
                        }
                }
 
-               /* XXXJAB this number doesn't include subclasses... */ 
+               /* XXXJAB this number doesn't include subclasses... */
                log_info ("Wrote %d class decls to leases file.",
                          numclasseswritten);
        }
-       
-                       
+
+
        /* Write all the dynamically-created group declarations. */
        if (group_name_hash) {
            num_written = 0;
@@ -2499,6 +2536,133 @@ int write_leases ()
        return (1);
 }
 
+#if !defined (BINARY_LEASES)
+/* Unlink all the leases in the queue. */
+void lease_remove_all(struct lease **lq) {
+       struct lease *lp, *ln = NULL;
+
+       /* nothing to do */
+       if (*lq == NULL)
+               return;
+
+       /* We simply derefernce the first item in the list.  When
+        * it's reference counter goes to zero it will be cleaned
+        * and the reference counter
+        *
+        * Get a pointer to the first item in the list and then
+        * drop the reference from the queue pointer
+        */
+       lease_reference(&lp, *lq, MDL);
+       lease_dereference(lq, MDL);
+
+       do {
+               /* if we have a next save a pointer to it and unlink it */
+               if (lp->next) {
+                       lease_reference(&ln, lp->next, MDL);
+                       lease_dereference(&lp->next, MDL);
+               }
+
+               /* get rid of what we currently have */
+               lease_dereference(&lp, MDL);
+
+               /* move the next to the current and loop */
+               lp = ln;
+               ln = NULL;
+       } while (lp != NULL);
+}
+
+/*
+ * This routine walks through a given lease queue (lq) looking
+ * for comp.  If it doesn't find the lease it is a fatal error
+ * as it should be on the given queue.  Once we find the lease
+ * we can remove it from this list.
+ */
+void lease_remove(struct lease **lq, struct lease *comp)
+{
+       struct lease *prev, *lp;
+
+       prev = NULL;
+       for (lp = *lq; lp != NULL; lp = lp->next) {
+               if (lp == comp)
+                       break;
+               prev = lp;
+       }
+
+       if (!lp) {
+               log_fatal("Lease with binding state %s not on its queue.",
+                         (comp->binding_state < 1 ||
+                          comp->binding_state > FTS_LAST)
+                         ? "unknown"
+                         : binding_state_names[comp->binding_state - 1]);
+       }
+
+       if (prev) {
+               lease_dereference(&prev->next, MDL);
+               if (comp->next) {
+                       lease_reference(&prev->next, comp->next, MDL);
+                       lease_dereference (&comp->next, MDL);
+               }
+       } else {
+               lease_dereference(lq, MDL);
+               if (comp->next) {
+                       lease_reference(lq, comp->next, MDL);
+                       lease_dereference(&comp->next, MDL);
+               }
+       }
+}
+
+/* This routine inserts comp into lq in a sorted fashion.
+ * The sort key is comp->sort_time, smaller values are
+ * placed earlier in the list.
+ */
+void lease_insert(struct lease **lq, struct lease *comp)
+{
+       struct lease *prev, *lp;
+       static struct lease **last_lq = NULL;
+       static struct lease *last_insert_point = NULL;
+
+       /* This only works during server startup: during runtime, the last
+        * lease may be dequeued in between calls.  If the queue is the same
+        * as was used previously, and the lease structure isn't (this is not
+        * a re-queue), use that as a starting point for the insertion-sort.
+        */
+       if ((server_starting & SS_QFOLLOW) && (lq == last_lq) &&
+           (comp != last_insert_point) &&
+           (last_insert_point->sort_time <= comp->sort_time)) {
+               prev = last_insert_point;
+               lp = prev->next;
+       } else {
+               prev = NULL;
+               lp = *lq;
+       }
+
+       /* Insertion sort the lease onto the appropriate queue. */
+       for (; lp != NULL ; lp = lp->next) {
+               if (lp->sort_time >= comp->sort_time)
+                       break;
+               prev = lp;
+       }
+
+       if (prev) {
+               if (prev->next) {
+                       lease_reference(&comp->next, prev->next, MDL);
+                       lease_dereference(&prev->next, MDL);
+               }
+               lease_reference(&prev->next, comp, MDL);
+       } else {
+               if (*lq) {
+                       lease_reference (&comp->next, *lq, MDL);
+                       lease_dereference(lq, MDL);
+               }
+               lease_reference(lq, comp, MDL);
+       }
+       last_insert_point = comp;
+       last_lq = lq;
+
+       return;
+}
+#endif
+
 /* In addition to placing this lease upon a lease queue depending on its
  * state, it also keeps track of the number of FREE and BACKUP leases in
  * existence, and sets the sort_time on the lease.
@@ -2513,9 +2677,7 @@ int write_leases ()
  */
 int lease_enqueue (struct lease *comp)
 {
-       struct lease **lq, *prev, *lp;
-       static struct lease **last_lq = NULL;
-       static struct lease *last_insert_point = NULL;
+       LEASE_STRUCT_PTR lq;
 
        /* No queue to put it on? */
        if (!comp -> pool)
@@ -2589,43 +2751,8 @@ int lease_enqueue (struct lease *comp)
                return 0;
        }
 
-       /* This only works during server startup: during runtime, the last
-        * lease may be dequeued in between calls.  If the queue is the same
-        * as was used previously, and the lease structure isn't (this is not
-        * a re-queue), use that as a starting point for the insertion-sort.
-        */
-       if ((server_starting & SS_QFOLLOW) && (lq == last_lq) &&
-           (comp != last_insert_point) && 
-           (last_insert_point->sort_time <= comp->sort_time)) {
-               prev = last_insert_point;
-               lp = prev->next;
-       } else {
-               prev = NULL;
-               lp = *lq;
-       }
+       LEASE_INSERTP(lq, comp);
 
-       /* Insertion sort the lease onto the appropriate queue. */
-       for (; lp ; lp = lp->next) {
-               if (lp -> sort_time >= comp -> sort_time)
-                       break;
-               prev = lp;
-       }
-
-       if (prev) {
-               if (prev -> next) {
-                       lease_reference (&comp -> next, prev -> next, MDL);
-                       lease_dereference (&prev -> next, MDL);
-               }
-               lease_reference (&prev -> next, comp, MDL);
-       } else {
-               if (*lq) {
-                       lease_reference (&comp -> next, *lq, MDL);
-                       lease_dereference (lq, MDL);
-               }
-               lease_reference (lq, comp, MDL);
-       }
-       last_insert_point = comp;
-       last_lq = lq;
        return 1;
 }
 
@@ -2652,17 +2779,17 @@ lease_instantiate(const void *key, unsigned len, void *object)
         * pool must have been formerly configured for failover and
         * is now configured as standalone. This means we need to
         * move the lease to FTS_FREE to make it available. */
-       if ((lease->binding_state == FTS_BACKUP) && 
+       if ((lease->binding_state == FTS_BACKUP) &&
            (lease->pool->failover_peer == NULL)) {
 #else
        /* We aren't compiled for failover, so just move to FTS_FREE */
-       if (lease->binding_state == FTS_BACKUP) { 
+       if (lease->binding_state == FTS_BACKUP) {
 #endif
                lease->binding_state = FTS_FREE;
                lease->next_binding_state = FTS_FREE;
                lease->rewind_binding_state = FTS_FREE;
        }
-               
+
        /* Put the lease on the right queue.  Failure to queue is probably
         * due to a bogus binding state.  In such a case, we claim success,
         * so that later leases in a hash_foreach are processed, but we
@@ -2710,11 +2837,35 @@ void expire_all_pools ()
        struct pool *p;
        int i;
        struct lease *l;
-       struct lease **lptr[RESERVED_LEASES+1];
+       LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
 
        /* Indicate that we are in the startup phase */
        server_starting = SS_NOSYNC | SS_QFOLLOW;
 
+#if defined (BINARY_LEASES)
+       /* set up the growth factors for the binary leases.
+        * We use 100% for free, 50% for active and backup
+        * 20% for expired, abandoned and reserved
+        * but no less than 100, 50, and 20.
+        */
+       for (s = shared_networks; s; s = s -> next) {
+           for (p = s -> pools; p != NULL; p = p -> next) {
+               size_t num_f = 100, num_a = 50, num_e = 20;
+               if (p->lease_count > 100) {
+                   num_f = p->lease_count;
+                   num_a = num_f / 2;
+                   num_e = num_f / 5;
+               }
+               lc_init_growth(&p->free, num_f);
+               lc_init_growth(&p->active, num_a);
+               lc_init_growth(&p->expired, num_a);
+               lc_init_growth(&p->abandoned, num_e);
+               lc_init_growth(&p->backup, num_e);
+               lc_init_growth(&p->reserved, num_e);
+           }
+       }
+#endif
+
        /* First, go over the hash list and actually put all the leases
           on the appropriate lists. */
        lease_ip_hash_foreach(lease_ip_addr_hash, lease_instantiate);
@@ -2742,7 +2893,9 @@ void expire_all_pools ()
                lptr [RESERVED_LEASES] = &p->reserved;
 
                for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
-                   for (l = *(lptr [i]); l; l = l -> next) {
+                   for (l = LEASE_GET_FIRSTP(lptr[i]);
+                        l != NULL;
+                        l = LEASE_GET_NEXTP(lptr[i], l)) {
                        p -> lease_count++;
                        if (l -> ends <= cur_time) {
                                if (l->binding_state == FTS_FREE) {
@@ -2782,7 +2935,7 @@ void dump_subnets ()
        struct shared_network *s;
        struct subnet *n;
        struct pool *p;
-       struct lease **lptr[RESERVED_LEASES+1];
+       LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
        int i;
 
        log_info ("Subnets:");
@@ -2803,7 +2956,9 @@ void dump_subnets ()
                lptr [RESERVED_LEASES] = &p->reserved;
 
                for (i = FREE_LEASES; i <= RESERVED_LEASES; i++) {
-                   for (l = *(lptr [i]); l; l = l -> next) {
+                   for (l = LEASE_GET_FIRSTP(lptr[i]);
+                        l != NULL;
+                        l = LEASE_GET_NEXTP(lptr[i], l)) {
                            print_lease (l);
                    }
                }
@@ -2844,7 +2999,7 @@ void free_everything(void)
        struct shared_network *nc = (struct shared_network *)0,
                *nn = (struct shared_network *)0;
        struct pool *pc = (struct pool *)0, *pn = (struct pool *)0;
-       struct lease *lc = (struct lease *)0, *ln = (struct lease *)0;
+       struct lease *lc = NULL, *ln = NULL,  *ltemp = NULL;
        struct interface_info *ic = (struct interface_info *)0,
                *in = (struct interface_info *)0;
        struct class *cc = (struct class *)0, *cn = (struct class *)0;
@@ -2995,7 +3150,7 @@ void free_everything(void)
                if (nc -> pools) {
                    pool_reference (&pn, nc -> pools, MDL);
                    do {
-                       struct lease **lptr[RESERVED_LEASES+1];
+                       LEASE_STRUCT_PTR lptr[RESERVED_LEASES+1];
 
                        if (pn) {
                            pool_reference (&pc, pn, MDL);
@@ -3015,17 +3170,22 @@ void free_everything(void)
 
                        /* As (sigh) are leases. */
                        for (i = FREE_LEASES ; i <= RESERVED_LEASES ; i++) {
-                           if (*lptr [i]) {
-                               lease_reference (&ln, *lptr [i], MDL);
+                           if (LEASE_NOT_EMPTYP(lptr[i])) {
+                               lease_reference(&ln, LEASE_GET_FIRSTP(lptr[i]), MDL);
                                do {
-                                   if (ln) {
-                                       lease_reference (&lc, ln, MDL);
-                                       lease_dereference (&ln, MDL);
-                                   }
-                                   if (lc -> next) {
-                                       lease_reference (&ln, lc -> next, MDL);
-                                       lease_dereference (&lc -> next, MDL);
+                                   /* save a pointer to the current lease */
+                                   lease_reference (&lc, ln, MDL);
+                                   lease_dereference (&ln, MDL);
+
+                                   /* get the next lease if there is one */
+                                   ltemp = LEASE_GET_NEXTP(lptr[i], lc);
+                                   if (ltemp != NULL) {
+                                       lease_reference(&ln, ltemp, MDL);
                                    }
+
+                                   /* remove the current lease from the queue */
+                                   LEASE_REMOVEP(lptr[i], lc);
+
                                    if (lc -> billing_class)
                                       class_dereference (&lc -> billing_class,
                                                          MDL);
@@ -3038,7 +3198,6 @@ void free_everything(void)
                                        lease_dereference (&lc -> n_uid, MDL);
                                    lease_dereference (&lc, MDL);
                                } while (ln);
-                               lease_dereference (lptr [i], MDL);
                            }
                        }
                        if (pc -> group)
@@ -3060,7 +3219,9 @@ void free_everything(void)
 
        cancel_all_timeouts ();
        relinquish_timeouts ();
+#if defined(DELAYED_ACK)
        relinquish_ackqueue();
+#endif
        trace_free_all ();
        group_dereference (&root_group, MDL);
        executable_statement_dereference (&default_classification_rules, MDL);