update to 9.7.2rc1
[tridge/bind9.git] / lib / dns / tsig.c
index 265fc275b3fad9d4cb5ca0ce90623e96c7cc978a..6e1844e22ca3b43b243dbade51e278d282189815 100644 (file)
@@ -16,7 +16,7 @@
  */
 
 /*
- * $Id: tsig.c,v 1.138.136.2 2010/03/12 23:49:56 tbox Exp $
+ * $Id: tsig.c,v 1.138.136.3 2010/07/09 05:14:08 each Exp $
  */
 /*! \file */
 #include <config.h>
@@ -26,6 +26,7 @@
 #include <isc/mem.h>
 #include <isc/print.h>
 #include <isc/refcount.h>
+#include <isc/serial.h>
 #include <isc/string.h>                /* Required for HP/UX (and others?) */
 #include <isc/util.h>
 #include <isc/time.h>
 #define TSIG_MAGIC             ISC_MAGIC('T', 'S', 'I', 'G')
 #define VALID_TSIG_KEY(x)      ISC_MAGIC_VALID(x, TSIG_MAGIC)
 
+#ifndef DNS_TSIG_MAXGENERATEDKEYS
+#define DNS_TSIG_MAXGENERATEDKEYS 4096
+#endif
+
 #define is_response(msg) (msg->flags & DNS_MESSAGEFLAG_QR)
 #define algname_is_allocated(algname) \
        ((algname) != dns_tsig_hmacmd5_name && \
@@ -215,6 +220,31 @@ tsig_log(dns_tsigkey_t *key, int level, const char *fmt, ...) {
                              level, "tsig key '%s': %s", namestr, message);
 }
 
+static void
+remove_fromring(dns_tsigkey_t *tkey) {
+       if (tkey->generated) {
+               ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
+               tkey->ring->generated--;
+       }
+       (void)dns_rbt_deletename(tkey->ring->keys, &tkey->name, ISC_FALSE);
+}
+
+static void
+adjust_lru(dns_tsigkey_t *tkey) {
+       if (tkey->generated) {
+               RWLOCK(&tkey->ring->lock, isc_rwlocktype_write);
+               /*
+                * We may have been removed from the LRU list between
+                * removing the read lock and aquiring the write lock.
+                */
+               if (ISC_LINK_LINKED(tkey, link)) {
+                       ISC_LIST_UNLINK(tkey->ring->lru, tkey, link);
+                       ISC_LIST_APPEND(tkey->ring->lru, tkey, link);
+               }
+               RWUNLOCK(&tkey->ring->lock, isc_rwlocktype_write);
+       }
+}
+
 /*
  * A supplemental routine just to add a key to ring.  Note that reference
  * counter should be counted separately because we may be adding the key
@@ -241,6 +271,15 @@ keyring_add(dns_tsig_keyring_t *ring, dns_name_t *name,
        }
 
        result = dns_rbt_addname(ring->keys, name, tkey);
+       if (tkey->generated) {
+               /*
+                * Add the new key to the LRU list and remove the least
+                * recently used key if there are too many keys on the list.
+                */
+               ISC_LIST_INITANDAPPEND(ring->lru, tkey, link);
+               if (ring->generated++ > ring->maxgenerated)
+                       remove_fromring(ISC_LIST_HEAD(ring->lru));
+       }
        RWUNLOCK(&ring->lock, isc_rwlocktype_write);
 
        return (result);
@@ -470,9 +509,7 @@ cleanup_ring(dns_tsig_keyring_t *ring)
                                tsig_log(tkey, 2, "tsig expire: deleting");
                                /* delete the key */
                                dns_rbtnodechain_invalidate(&chain);
-                               (void)dns_rbt_deletename(ring->keys,
-                                                        &tkey->name,
-                                                        ISC_FALSE);
+                               remove_fromring(tkey);
                                goto again;
                        }
                }
@@ -482,7 +519,6 @@ cleanup_ring(dns_tsig_keyring_t *ring)
                        dns_rbtnodechain_invalidate(&chain);
                        return;
                }
-
        }
 }
 
@@ -647,7 +683,7 @@ dns_tsigkey_setdeleted(dns_tsigkey_t *key) {
        REQUIRE(key->ring != NULL);
 
        RWLOCK(&key->ring->lock, isc_rwlocktype_write);
-       (void)dns_rbt_deletename(key->ring->keys, &key->name, ISC_FALSE);
+       remove_fromring(key);
        RWUNLOCK(&key->ring->lock, isc_rwlocktype_write);
 }
 
@@ -1490,19 +1526,30 @@ dns_tsigkey_find(dns_tsigkey_t **tsigkey, dns_name_t *name,
                RWUNLOCK(&ring->lock, isc_rwlocktype_read);
                return (ISC_R_NOTFOUND);
        }
-       if (key->inception != key->expire && key->expire < now) {
+       if (key->inception != key->expire && isc_serial_lt(key->expire, now)) {
                /*
                 * The key has expired.
                 */
                RWUNLOCK(&ring->lock, isc_rwlocktype_read);
                RWLOCK(&ring->lock, isc_rwlocktype_write);
-               (void)dns_rbt_deletename(ring->keys, name, ISC_FALSE);
+               remove_fromring(key);
                RWUNLOCK(&ring->lock, isc_rwlocktype_write);
                return (ISC_R_NOTFOUND);
        }
-
+#if 0
+       /*
+        * MPAXXX We really should look at the inception time.
+        */
+       if (key->inception != key->expire &&
+           isc_serial_lt(key->inception, now)) {
+               RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+               adjust_lru(key);
+               return (ISC_R_NOTFOUND);
+       }
+#endif
        isc_refcount_increment(&key->refs, NULL);
        RWUNLOCK(&ring->lock, isc_rwlocktype_read);
+       adjust_lru(key);
        *tsigkey = key;
        return (ISC_R_SUCCESS);
 }
@@ -1548,6 +1595,9 @@ dns_tsigkeyring_create(isc_mem_t *mctx, dns_tsig_keyring_t **ringp) {
 
        ring->writecount = 0;
        ring->mctx = NULL;
+       ring->generated = 0;
+       ring->maxgenerated = DNS_TSIG_MAXGENERATEDKEYS;
+       ISC_LIST_INIT(ring->lru);
        isc_mem_attach(mctx, &ring->mctx);
 
        *ringp = ring;