]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3169. [func] Catch db/version mis-matches when call dns_db_*().
authorMark Andrews <marka@isc.org>
Thu, 13 Oct 2011 00:37:34 +0000 (00:37 +0000)
committerMark Andrews <marka@isc.org>
Thu, 13 Oct 2011 00:37:34 +0000 (00:37 +0000)
                        [RT #26017]

CHANGES
lib/dns/rbtdb.c
lib/dns/tests/Makefile.in
lib/dns/tests/dbversion_test.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index 3df0fdde8ccf04214029ead30d7e22d2f96d6c94..a1652d8bae20f61ac62433196af8d68dc9106982 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,6 @@
+3169.  [func]          Catch db/version mis-matches when call dns_db_*().
+                       [RT #26017]
+
 3167.  [bug]           Negative answers from forwarders were not being
                        correctly tagged making them appear to not be cached.
                        [RT #25380]
index d81fe4c10fbac3fcd08fa58ad90fc35904c18d77..93a2a32ac7d77e5e696c7572487164313691bf88 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.270.12.33 2011/08/23 00:57:11 each Exp $ */
+/* $Id: rbtdb.c,v 1.270.12.34 2011/10/13 00:37:34 marka Exp $ */
 
 /*! \file */
 
@@ -364,9 +364,12 @@ typedef enum {
        dns_db_secure
 } dns_db_secure_t;
 
+typedef struct dns_rbtdb dns_rbtdb_t;
+
 typedef struct rbtdb_version {
        /* Not locked */
        rbtdb_serial_t                  serial;
+       dns_rbtdb_t *                   rbtdb;
        /*
         * Protected in the refcount routines.
         * XXXJT: should we change the lock policy based on the refcount
@@ -391,7 +394,7 @@ typedef struct rbtdb_version {
 
 typedef ISC_LIST(rbtdb_version_t)       rbtdb_versionlist_t;
 
-typedef struct {
+struct dns_rbtdb {
        /* Unlocked. */
        dns_db_t                        common;
        /* Locks the data in this struct */
@@ -449,7 +452,7 @@ typedef struct {
 
        /* Unlocked */
        unsigned int                    quantum;
-} dns_rbtdb_t;
+};
 
 #define RBTDB_ATTR_LOADED               0x01
 #define RBTDB_ATTR_LOADING              0x02
@@ -1102,6 +1105,7 @@ newversion(dns_db_t *db, dns_dbversion_t **versionp) {
        version = allocate_version(rbtdb->common.mctx, rbtdb->next_serial, 1,
                                   ISC_TRUE);
        if (version != NULL) {
+               version->rbtdb = rbtdb;
                version->commit_ok = ISC_TRUE;
                version->secure = rbtdb->current_version->secure;
                version->havensec3 = rbtdb->current_version->havensec3;
@@ -1143,6 +1147,7 @@ attachversion(dns_db_t *db, dns_dbversion_t *source,
        unsigned int refs;
 
        REQUIRE(VALID_RBTDB(rbtdb));
+       INSIST(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
 
        isc_refcount_increment(&rbtversion->references, &refs);
        INSIST(refs > 1);
@@ -2145,6 +2150,7 @@ closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
 
        REQUIRE(VALID_RBTDB(rbtdb));
        version = (rbtdb_version_t *)*versionp;
+       INSIST(version->rbtdb == rbtdb);
 
        cleanup_version = NULL;
        ISC_LIST_INIT(cleanup_list);
@@ -3472,6 +3478,8 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
        search.rbtdb = (dns_rbtdb_t *)db;
 
        REQUIRE(VALID_RBTDB(search.rbtdb));
+       INSIST(version == NULL ||
+              ((rbtdb_version_t *)version)->rbtdb == (dns_rbtdb_t *)db);
 
        /*
         * We don't care about 'now'.
@@ -5172,6 +5180,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
 
        REQUIRE(VALID_RBTDB(rbtdb));
        REQUIRE(type != dns_rdatatype_any);
+       INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
 
        if (rbtversion == NULL) {
                currentversion(db, (dns_dbversion_t **) (void *)(&rbtversion));
@@ -5360,6 +5369,8 @@ allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                else {
                        unsigned int refs;
 
+                       INSIST(rbtversion->rbtdb == rbtdb);
+
                        isc_refcount_increment(&rbtversion->references,
                                               &refs);
                        INSIST(refs > 1);
@@ -6027,6 +6038,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        isc_boolean_t cache_is_overmem = ISC_FALSE;
 
        REQUIRE(VALID_RBTDB(rbtdb));
+       INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
 
        if (rbtdb->common.methods == &zone_methods)
                REQUIRE(((rbtnode->nsec3 &&
@@ -6043,8 +6055,7 @@ addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                now = 0;
 
        result = dns_rdataslab_fromrdataset(rdataset, rbtdb->common.mctx,
-                                           &region,
-                                           sizeof(rdatasetheader_t));
+                                           &region, sizeof(rdatasetheader_t));
        if (result != ISC_R_SUCCESS)
                return (result);
 
@@ -6187,6 +6198,7 @@ subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        rbtdb_changed_t *changed;
 
        REQUIRE(VALID_RBTDB(rbtdb));
+       REQUIRE(rbtversion != NULL && rbtversion->rbtdb == rbtdb);
 
        if (rbtdb->common.methods == &zone_methods)
                REQUIRE(((rbtnode->nsec3 &&
@@ -6367,6 +6379,7 @@ deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        rdatasetheader_t *newheader;
 
        REQUIRE(VALID_RBTDB(rbtdb));
+       INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
 
        if (type == dns_rdatatype_any)
                return (ISC_R_NOTIMPLEMENTED);
@@ -6722,6 +6735,7 @@ getnsec3parameters(dns_db_t *db, dns_dbversion_t *version, dns_hash_t *hash,
        rbtdb = (dns_rbtdb_t *)db;
 
        REQUIRE(VALID_RBTDB(rbtdb));
+       INSIST(rbtversion == NULL || rbtversion->rbtdb == rbtdb);
 
        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
 
@@ -6851,11 +6865,16 @@ resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
 
        REQUIRE(VALID_RBTDB(rbtdb));
        REQUIRE(rdataset != NULL);
+       REQUIRE(rdataset->methods == &rdataset_methods);
        REQUIRE(rbtdb->future_version == rbtversion);
+       REQUIRE(rbtversion != NULL);
        REQUIRE(rbtversion->writer);
+       REQUIRE(rbtversion->rbtdb == rbtdb);
 
        node = rdataset->private2;
+       INSIST(node != NULL);
        header = rdataset->private3;
+       INSIST(header != NULL);
        header--;
 
        RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_write);
@@ -7233,6 +7252,7 @@ dns_rbtdb_create
                free_rbtdb(rbtdb, ISC_FALSE, NULL);
                return (ISC_R_NOMEMORY);
        }
+       rbtdb->current_version->rbtdb = rbtdb;
        rbtdb->current_version->secure = dns_db_insecure;
        rbtdb->current_version->havensec3 = ISC_FALSE;
        rbtdb->current_version->flags = 0;
index 88e829f3bccf7b2cae48e2ad7f731c6850d87303..d7148a1beb9c44fd95dc88a08003c35d866d3c45 100644 (file)
@@ -12,7 +12,7 @@
 # OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 # PERFORMANCE OF THIS SOFTWARE.
 
-# $Id: Makefile.in,v 1.2.6.6 2011/09/05 07:19:26 each Exp $
+# $Id: Makefile.in,v 1.2.6.7 2011/10/13 00:37:34 marka Exp $
 
 srcdir =       @srcdir@
 VPATH =                @srcdir@
@@ -38,11 +38,11 @@ LIBS =              @LIBS@ @ATFLIBS@
 
 OBJS =         dnstest.@O@
 SRCS =         dnstest.c master_test.c time_test.c dbiterator_test.c \
-               zonemgr_test.c
+               dbversion_test.c zonemgr_test.c
 
 SUBDIRS =
 TARGETS =      master_test@EXEEXT@ time_test@EXEEXT@ dbiterator_test@EXEEXT@ \
-               zonemgr_test@EXEEXT@
+               dbversion_test@EXEEXT@ zonemgr_test@EXEEXT@
 
 @BIND9_MAKE_RULES@
 
@@ -55,11 +55,17 @@ time_test@EXEEXT@: time_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
                        time_test.@O@ dnstest.@O@ ${DNSLIBS} \
                                ${ISCLIBS} ${LIBS}
+
 dbiterator_test@EXEEXT@: dbiterator_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
                        dbiterator_test.@O@ dnstest.@O@ ${DNSLIBS} \
                                ${ISCLIBS} ${LIBS}
 
+dbversion_test@EXEEXT@: dbversion_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+       ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+                       dbversion_test.@O@ dnstest.@O@ ${DNSLIBS} \
+                               ${ISCLIBS} ${LIBS}
+
 zonemgr_test@EXEEXT@: zonemgr_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
        ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
                        zonemgr_test.@O@ dnstest.@O@ ${DNSLIBS} \
diff --git a/lib/dns/tests/dbversion_test.c b/lib/dns/tests/dbversion_test.c
new file mode 100644 (file)
index 0000000..be86225
--- /dev/null
@@ -0,0 +1,747 @@
+/*
+ * Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: dbversion_test.c,v 1.2.6.2 2011/10/13 00:37:34 marka Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+#include <time.h>
+
+#include <isc/file.h>
+#include <isc/result.h>
+#include <isc/serial.h>
+#include <isc/stdtime.h>
+#include <isc/msgcat.h>
+
+#include <dns/db.h>
+#include <dns/fixedname.h>
+#include <dns/nsec3.h>
+#include <dns/rdatalist.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+
+#include "dnstest.h"
+
+static char tempname[11] = "dtXXXXXXXX";
+
+static void
+callback(const char *file, int line, isc_assertiontype_t type,
+         const char *cond)
+{
+       UNUSED(file); UNUSED(line); UNUSED(type); UNUSED(cond);
+       if (strcmp(tempname, "dtXXXXXXXX"))
+               unlink(tempname);
+       atf_tc_pass();
+       exit(0);
+}
+
+static dns_db_t *db1 = NULL, *db2 = NULL;
+static dns_dbversion_t *v1 = NULL, *v2 = NULL;
+
+static void
+setup_db() {
+       isc_result_t result;
+       result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+                               dns_rdataclass_in, 0, NULL, &db1);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       dns_db_newversion(db1, &v1);
+
+       result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,
+                               dns_rdataclass_in, 0, NULL, &db2);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       dns_db_newversion(db2, &v2);
+}
+
+static void
+close_db() {
+       if (v1 != NULL) {
+               dns_db_closeversion(db1, &v1, ISC_FALSE);
+               ATF_REQUIRE_EQ(v1, NULL);
+       }
+       if (db1 != NULL) {
+               dns_db_detach(&db1);
+               ATF_REQUIRE_EQ(db1, NULL);
+       }
+
+       if (v2 != NULL) {
+               dns_db_closeversion(db2, &v2, ISC_FALSE);
+               ATF_REQUIRE_EQ(v2, NULL);
+       }
+       if (db2 != NULL) {
+               dns_db_detach(&db2);
+               ATF_REQUIRE_EQ(db2, NULL);
+       }
+}
+
+#define VERSION(callback) ((callback == NULL) ? v1 : v2)
+#define VERSIONP(callback) ((callback == NULL) ? &v1 : &v2)
+/*
+ * Individual unit tests
+ */
+static void
+attachversion(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_dbversion_t *v = NULL;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       
+       setup_db();
+
+       isc_assertion_setcallback(callback);
+       dns_db_attachversion(db1, VERSION(callback), &v);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_attachversion did not assert");
+
+       ATF_REQUIRE_EQ(v, v1);
+       dns_db_closeversion(db1, &v, ISC_FALSE);
+       ATF_REQUIRE_EQ(v, NULL);
+
+       close_db();
+       dns_test_end();
+}
+
+ATF_TC(attachversion);
+ATF_TC_HEAD(attachversion, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_attachversion passes with matching db/verison");
+}
+ATF_TC_BODY(attachversion, tc) {
+
+       UNUSED(tc);
+       
+       attachversion(NULL);
+}
+
+ATF_TC(attachversion_bad);
+ATF_TC_HEAD(attachversion_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_attachversion aborts with mis-matching db/verison");
+}
+ATF_TC_BODY(attachversion_bad, tc) {
+
+       UNUSED(tc);
+
+       attachversion(callback);
+}
+
+static void
+closeversion(isc_assertioncallback_t callback) {
+       isc_result_t result;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+       
+       setup_db();
+
+       isc_assertion_setcallback(callback);
+       dns_db_closeversion(db1, VERSIONP(callback), ISC_FALSE);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_closeversion did not assert");
+       ATF_REQUIRE_EQ(v1, NULL);
+
+       close_db();
+       dns_test_end();
+}
+
+ATF_TC(closeversion);
+ATF_TC_HEAD(closeversion, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_closeversion passes with matching db/verison");
+}
+ATF_TC_BODY(closeversion, tc) {
+
+       UNUSED(tc);
+
+       closeversion(NULL);
+}
+
+ATF_TC(closeversion_bad);
+ATF_TC_HEAD(closeversion_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_closeversion asserts with mis-matching db/verison");
+}
+ATF_TC_BODY(closeversion_bad, tc) {
+
+       UNUSED(tc);
+
+       closeversion(callback);
+}
+
+static void
+find(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_rdataset_t rdataset;
+       dns_fixedname_t fixed;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       dns_rdataset_init(&rdataset);
+       dns_fixedname_init(&fixed);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_find(db1, dns_rootname, VERSION(callback),
+                            dns_rdatatype_soa, 0, 0, NULL,
+                            dns_fixedname_name(&fixed), &rdataset, NULL);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_find did not assert");
+       ATF_REQUIRE_EQ(result, DNS_R_NXDOMAIN);
+       
+       close_db();
+
+       dns_test_end();
+}
+ATF_TC(find);
+ATF_TC_HEAD(find, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_find passes with matching db/version");
+}
+ATF_TC_BODY(find, tc) {
+
+       UNUSED(tc);
+
+       find(NULL);
+}
+
+ATF_TC(find_bad);
+ATF_TC_HEAD(find_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_find asserts with mis-matching db/version");
+}
+ATF_TC_BODY(find_bad, tc) {
+
+       UNUSED(tc);
+
+       find(callback);
+}
+
+static void
+allrdatasets(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_dbnode_t *node = NULL;
+       dns_rdatasetiter_t *iterator = NULL;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_allrdatasets(db1, node, VERSION(callback), 0,
+                                    &iterator);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_allrdatasets did not assert");
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       dns_rdatasetiter_destroy(&iterator);
+       ATF_REQUIRE_EQ(iterator, NULL);
+
+       dns_db_detachnode(db1, &node);
+       ATF_REQUIRE_EQ(node, NULL);
+       
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(allrdatasets);
+ATF_TC_HEAD(allrdatasets, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_allrdatasets passes with matching db/version");
+}
+ATF_TC_BODY(allrdatasets, tc) {
+
+       UNUSED(tc);
+
+       allrdatasets(NULL);
+}
+
+ATF_TC(allrdatasets_bad);
+ATF_TC_HEAD(allrdatasets_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_allrdatasets aborts with mis-matching db/version");
+}
+ATF_TC_BODY(allrdatasets_bad, tc) {
+
+       UNUSED(tc);
+
+       allrdatasets(callback);
+}
+
+static void
+findrdataset(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_rdataset_t rdataset;
+       dns_fixedname_t fixed;
+       dns_dbnode_t *node = NULL;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       dns_rdataset_init(&rdataset);
+       dns_fixedname_init(&fixed);
+
+       result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_findrdataset(db1, node, VERSION(callback),
+                                    dns_rdatatype_soa, 0, 0, &rdataset, NULL);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_findrdataset did not assert");
+       ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
+
+       dns_db_detachnode(db1, &node);
+       ATF_REQUIRE_EQ(node, NULL);
+       
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(findrdataset);
+ATF_TC_HEAD(findrdataset, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_findrdataset passes with matching db/version");
+}
+ATF_TC_BODY(findrdataset, tc) {
+
+       UNUSED(tc);
+
+       findrdataset(NULL);
+}
+
+ATF_TC(findrdataset_bad);
+ATF_TC_HEAD(findrdataset_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_findrdataset aborts with mis-matching db/version");
+}
+ATF_TC_BODY(findrdataset_bad, tc) {
+
+       UNUSED(tc);
+
+       findrdataset(callback);
+}
+
+static void
+deleterdataset(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_rdataset_t rdataset;
+       dns_fixedname_t fixed;
+       dns_dbnode_t *node = NULL;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       dns_rdataset_init(&rdataset);
+       dns_fixedname_init(&fixed);
+
+       result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_deleterdataset(db1, node, VERSION(callback),
+                                      dns_rdatatype_soa, 0);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_deleterdataset did not assert");
+       ATF_REQUIRE_EQ(result, DNS_R_UNCHANGED);
+
+       dns_db_detachnode(db1, &node);
+       ATF_REQUIRE_EQ(node, NULL);
+       
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(deleterdataset);
+ATF_TC_HEAD(deleterdataset, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_deleterdataset passes with matching db/version");
+}
+ATF_TC_BODY(deleterdataset, tc) {
+
+       UNUSED(tc);
+
+       deleterdataset(NULL);
+}
+
+ATF_TC(deleterdataset_bad);
+ATF_TC_HEAD(deleterdataset_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_deleterdataset aborts with mis-matching db/version");
+}
+ATF_TC_BODY(deleterdataset_bad, tc) {
+
+       UNUSED(tc);
+
+       deleterdataset(callback);
+}
+
+static void
+subtract(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_rdataset_t rdataset;
+       dns_fixedname_t fixed;
+       dns_dbnode_t *node = NULL;
+       dns_rdatalist_t rdatalist;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       dns_rdataset_init(&rdataset);
+       dns_rdatalist_init(&rdatalist);
+       dns_fixedname_init(&fixed);
+
+       rdatalist.rdclass = dns_rdataclass_in;
+
+       result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_subtractrdataset(db1, node, VERSION(callback),
+                                        &rdataset, 0, NULL);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_dns_db_subtractrdataset did not assert");
+       /*
+        * 9.6 does support caching of a rdataset with no records so we get
+        * ISC_R_FAILURE rather then DNS_R_UNCHANGED.
+        */
+       ATF_REQUIRE_EQ(result, ISC_R_FAILURE);
+
+       dns_db_detachnode(db1, &node);
+       ATF_REQUIRE_EQ(node, NULL);
+       
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(subtractrdataset);
+ATF_TC_HEAD(subtractrdataset, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_subtractrdataset passes with matching db/version");
+}
+ATF_TC_BODY(subtractrdataset, tc) {
+
+       UNUSED(tc);
+       
+       subtract(NULL);
+}
+
+ATF_TC(subtractrdataset_bad);
+ATF_TC_HEAD(subtractrdataset_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_subtractrdataset aborts with mis-matching db/version");
+}
+ATF_TC_BODY(subtractrdataset_bad, tc) {
+
+       UNUSED(tc);
+
+       subtract(callback);
+}
+
+static void
+dump(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       FILE *f = NULL;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       result = isc_file_openunique(tempname, &f);
+       fclose(f);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_dump(db1, VERSION(callback), tempname);
+       (void)unlink(tempname);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_dump did not assert");
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(dump);
+ATF_TC_HEAD(dump, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_dump passes with matching db/version");
+}
+ATF_TC_BODY(dump, tc) {
+
+       UNUSED(tc);
+
+       dump(NULL);
+}
+
+ATF_TC(dump_bad);
+ATF_TC_HEAD(dump_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_dump aborts with mis-matching db/version");
+}
+ATF_TC_BODY(dump_bad, tc) {
+
+       UNUSED(tc);
+
+       dump(callback);
+}
+
+static void
+addrdataset(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_rdataset_t rdataset;
+       dns_fixedname_t fixed;
+       dns_dbnode_t *node = NULL;
+       dns_rdatalist_t rdatalist;
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       dns_rdataset_init(&rdataset);
+       dns_rdatalist_init(&rdatalist);
+       dns_fixedname_init(&fixed);
+
+       rdatalist.rdclass = dns_rdataclass_in;
+
+       result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_addrdataset(db1, node, VERSION(callback), 0, &rdataset,
+                                   0, NULL);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_adddataset did not assert");
+       /*
+        * 9.6 does support caching of a rdataset with no record so we get
+        * ISC_R_FAILURE rather then ISC_R_SUCCESS.
+        */
+       ATF_REQUIRE_EQ(result, ISC_R_FAILURE);
+
+       dns_db_detachnode(db1, &node);
+       ATF_REQUIRE_EQ(node, NULL);
+       
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(addrdataset);
+ATF_TC_HEAD(addrdataset, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_addrdataset passes with matching db/version");
+}
+ATF_TC_BODY(addrdataset, tc) {
+
+       UNUSED(tc);
+
+       addrdataset(NULL);
+}
+
+ATF_TC(addrdataset_bad);
+ATF_TC_HEAD(addrdataset_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_addrdataset aborts with mis-matching db/version");
+}
+ATF_TC_BODY(addrdataset_bad, tc) {
+
+       UNUSED(tc);
+
+       addrdataset(callback);
+}
+
+static void
+getnsec3parameters(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_hash_t hash;
+       isc_uint8_t flags;
+       isc_uint16_t iterations;
+       unsigned char salt[DNS_NSEC3_SALTSIZE];
+       size_t salt_length = sizeof(salt);
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       isc_assertion_setcallback(callback);
+       result = dns_db_getnsec3parameters(db1, VERSION(callback), &hash,
+                                          &flags, &iterations, salt,
+                                          &salt_length);
+       if (callback != NULL)
+               atf_tc_fail("dns_db_dump did not assert");
+       ATF_REQUIRE_EQ(result, ISC_R_NOTFOUND);
+
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(getnsec3parameters);
+ATF_TC_HEAD(getnsec3parameters, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_getnsec3parameters passes with matching db/version");
+}
+ATF_TC_BODY(getnsec3parameters, tc) {
+
+       UNUSED(tc);
+
+       getnsec3parameters(NULL);
+}
+
+ATF_TC(getnsec3parameters_bad);
+ATF_TC_HEAD(getnsec3parameters_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_db_getnsec3parameters aborts with mis-matching db/version");
+}
+ATF_TC_BODY(getnsec3parameters_bad, tc) {
+
+       UNUSED(tc);
+
+       getnsec3parameters(callback);
+}
+
+static void
+resigned(isc_assertioncallback_t callback) {
+       isc_result_t result;
+       dns_rdataset_t rdataset, added;
+       dns_dbnode_t *node = NULL;
+       dns_rdatalist_t rdatalist;
+       dns_rdata_rrsig_t rrsig;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       isc_buffer_t b;
+       unsigned char buf[1024];
+
+       result = dns_test_begin(NULL, ISC_FALSE);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       setup_db();
+
+       /*
+        * Create a dummy RRSIG record and set a resigning time.
+        */
+       dns_rdataset_init(&added);
+       dns_rdataset_init(&rdataset);
+       dns_rdatalist_init(&rdatalist);
+       isc_buffer_init(&b, buf, sizeof(buf));
+
+       DNS_RDATACOMMON_INIT(&rrsig, dns_rdatatype_rrsig, dns_rdataclass_in);
+       rrsig.covered = dns_rdatatype_a;
+       rrsig.algorithm = 100;
+       rrsig.labels = 0;
+       rrsig.originalttl = 0;
+       rrsig.timeexpire = 3600;
+       rrsig.timesigned = 0;
+       rrsig.keyid = 0;
+       dns_name_init(&rrsig.signer, NULL);
+       dns_name_clone(dns_rootname, &rrsig.signer);
+       rrsig.siglen = 0;
+       rrsig.signature = NULL;
+
+       result = dns_rdata_fromstruct(&rdata, dns_rdataclass_in,
+                                     dns_rdatatype_rrsig, &rrsig, &b);
+
+       rdatalist.rdclass = dns_rdataclass_in;
+       rdatalist.type = dns_rdatatype_rrsig;
+       ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
+
+       result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       rdataset.attributes |= DNS_RDATASETATTR_RESIGN;
+       rdataset.resign = 7200;
+
+       result = dns_db_findnode(db1, dns_rootname, ISC_FALSE, &node);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       result = dns_db_addrdataset(db1, node, v1, 0, &rdataset, 0, &added);
+       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+       dns_db_detachnode(db1, &node);
+       ATF_REQUIRE_EQ(node, NULL);
+
+       isc_assertion_setcallback(callback);
+       dns_db_resigned(db1, &added, VERSION(callback));
+       if (callback != NULL)
+               atf_tc_fail("dns_db_resigned did not assert");
+
+       dns_rdataset_disassociate(&added);
+
+       close_db();
+
+       dns_test_end();
+}
+
+ATF_TC(resigned);
+ATF_TC_HEAD(resigned, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_rdataset_resigned passes with matching db/version");
+}
+ATF_TC_BODY(resigned, tc) {
+
+       UNUSED(tc);
+
+       resigned(NULL);
+}
+
+ATF_TC(resigned_bad);
+ATF_TC_HEAD(resigned_bad, tc) {
+  atf_tc_set_md_var(tc, "descr", "check dns_rdataset_resigned aborts with mis-matching db/version");
+}
+ATF_TC_BODY(resigned_bad, tc) {
+
+       UNUSED(tc);
+
+       resigned(callback);
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+       ATF_TP_ADD_TC(tp, dump);
+       ATF_TP_ADD_TC(tp, dump_bad);
+       ATF_TP_ADD_TC(tp, find);
+       ATF_TP_ADD_TC(tp, find_bad);
+       ATF_TP_ADD_TC(tp, allrdatasets);
+       ATF_TP_ADD_TC(tp, allrdatasets_bad);
+       ATF_TP_ADD_TC(tp, findrdataset);
+       ATF_TP_ADD_TC(tp, findrdataset_bad);
+       ATF_TP_ADD_TC(tp, addrdataset);
+       ATF_TP_ADD_TC(tp, addrdataset_bad);
+       ATF_TP_ADD_TC(tp, deleterdataset);
+       ATF_TP_ADD_TC(tp, deleterdataset_bad);
+       ATF_TP_ADD_TC(tp, subtractrdataset);
+       ATF_TP_ADD_TC(tp, subtractrdataset_bad);
+       ATF_TP_ADD_TC(tp, attachversion);
+       ATF_TP_ADD_TC(tp, attachversion_bad);
+       ATF_TP_ADD_TC(tp, closeversion);
+       ATF_TP_ADD_TC(tp, closeversion_bad);
+       ATF_TP_ADD_TC(tp, getnsec3parameters);
+       ATF_TP_ADD_TC(tp, getnsec3parameters_bad);
+       ATF_TP_ADD_TC(tp, resigned);
+       ATF_TP_ADD_TC(tp, resigned_bad);
+
+       return (atf_no_error());
+}