]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
add semantics to dns_nametree to support bitfields
authorEvan Hunt <each@isc.org>
Thu, 17 Aug 2023 02:59:50 +0000 (19:59 -0700)
committerOndřej Surý <ondrej@isc.org>
Mon, 4 Sep 2023 08:19:48 +0000 (10:19 +0200)
name trees can now hold either boolean values or bit fields. the
type is selected when the name tree is created.

the behavior of dns_nametree_add() differs slightly beteween the types:
in a boolean tree adding an existing name will return ISC_R_EXISTS,
but in a bitfield tree it simply sets the specified bit in the bitfield
and returns ISC_R_SUCCESS.

bin/named/server.c
lib/dns/include/dns/nametree.h
lib/dns/nametree.c
lib/dns/resolver.c
tests/dns/nametree_test.c

index e0e12c860de9331669f534cd3260741601341f21..03483fd2b8b1e5da337177715aa72002c12a4a40 100644 (file)
@@ -645,7 +645,7 @@ configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
                }
        }
 
-       dns_nametree_create(mctx, confname, ntp);
+       dns_nametree_create(mctx, DNS_NAMETREE_BOOL, confname, ntp);
 
        name = dns_fixedname_initname(&fixed);
        for (element = cfg_list_first(obj); element != NULL;
index be549dab01614b542b701d694c9461f6b7ac0ea2..acd8bbd21f9a9e20cec9a08e930a609c74151d1c 100644 (file)
 /* Define to 1 for detailed reference tracing */
 #undef DNS_NAMETREE_TRACE
 
+typedef enum { DNS_NAMETREE_BOOL, DNS_NAMETREE_BITS } dns_nametree_type_t;
+
 ISC_LANG_BEGINDECLS
 
 void
-dns_nametree_create(isc_mem_t *mctx, const char *name, dns_nametree_t **ntp);
+dns_nametree_create(isc_mem_t *mctx, dns_nametree_type_t type, const char *name,
+                   dns_nametree_t **ntp);
 /*%<
  * Create a nametree.
  *
  * If 'name' is not NULL, it will be saved as the name of the QP trie
  * for debugging purposes.
  *
+ * 'type' indicates whether the tree will be used for storing boolean
+ * values (DNS_NAMETREE_BOOL) or bitfields (DNS_NAMETREE_BITS).
+ *
  * Requires:
  *
  *\li  'mctx' is a valid memory context.
@@ -57,13 +63,22 @@ dns_nametree_create(isc_mem_t *mctx, const char *name, dns_nametree_t **ntp);
  */
 
 isc_result_t
-dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name, bool value);
+dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
+                uint32_t value);
 /*%<
  * Add a node to 'nametree'.
  *
- * 'value' is a single boolean value, true or false. If the name already
+ * If the nametree type was set to DNS_NAMETREE_BOOL, then 'value'
+ * represents a single boolean value, true or false. If the name already
  * exists within the tree, then return ISC_R_EXISTS.
  *
+ * If the nametree type was set to DNS_NAMETREE_BITS, then 'value' is
+ * a bit number within a bit field, which is sized to accomodate at least
+ * 'value' bits. If the name already exists, then that bit will be set
+ * in the bitfield, other bits will be retained, and ISC_R_SUCCESS will be
+ * returned. If 'value' excees the number of bits in the existing bit
+ * field, the field will be expanded.
+ *
  * Requires:
  *
  *\li  'nametree' points to a valid nametree.
@@ -116,13 +131,21 @@ dns_nametree_find(dns_nametree_t *nametree, const dns_name_t *name,
  */
 
 bool
-dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name);
+dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
+                    uint32_t bit);
 /*%<
- * Indicates whether a 'name' is covered by 'nametree'.
+ * Indicates whether a 'name' (with optional 'bit' value) is covered by
+ * 'nametree'.
+ *
+ * In DNS_NAMETREE_BOOL nametrees, this returns true if 'name' has a match
+ * or a closest ancestor in 'nametree' with its value set to 'true'.
+ * 'bit' is ignored.
+ *
+ * In DNS_NAMETREE_BITS trees, this returns true if 'name' has a match or
+ * a closest ancestor in 'nametree' with the 'bit' set in its bitfield.
  *
- * This returns true if 'name' has a match or a closest ancestor in
- * 'nametree' with its value set to 'true'.  If a name is not found, or if
- * 'nametree' is NULL, the default return value is false.
+ * If a name is not found, or if 'nametree' is NULL, the default return
+ * value is false.
  *
  * Requires:
  *
index 464690d6c8abda651fd888b5013bf7b1d79821bc..b148dd756505a124e9beb7852e451890c6f2fb77 100644 (file)
@@ -32,6 +32,7 @@ struct dns_nametree {
        unsigned int magic;
        isc_mem_t *mctx;
        isc_refcount_t references;
+       dns_nametree_type_t type;
        dns_qpmulti_t *table;
        char name[64];
 };
@@ -41,10 +42,8 @@ struct dns_ntnode {
        isc_refcount_t references;
        dns_fixedname_t fn;
        dns_name_t *name;
-       union {
-               bool value;
-               unsigned char *bits;
-       };
+       bool set;
+       uint8_t *bits;
 };
 
 /* QP trie methods */
@@ -67,6 +66,9 @@ static dns_qpmethods_t qpmethods = {
 static void
 destroy_ntnode(dns_ntnode_t *node) {
        isc_refcount_destroy(&node->references);
+       if (node->bits != NULL) {
+               isc_mem_cput(node->mctx, node->bits, 8, sizeof(uint32_t));
+       }
        isc_mem_putanddetach(&node->mctx, node, sizeof(dns_ntnode_t));
 }
 
@@ -77,7 +79,8 @@ ISC_REFCOUNT_IMPL(dns_ntnode, destroy_ntnode);
 #endif
 
 void
-dns_nametree_create(isc_mem_t *mctx, const char *name, dns_nametree_t **ntp) {
+dns_nametree_create(isc_mem_t *mctx, dns_nametree_type_t type, const char *name,
+                   dns_nametree_t **ntp) {
        dns_nametree_t *nametree = NULL;
 
        REQUIRE(ntp != NULL && *ntp == NULL);
@@ -85,6 +88,7 @@ dns_nametree_create(isc_mem_t *mctx, const char *name, dns_nametree_t **ntp) {
        nametree = isc_mem_get(mctx, sizeof(*nametree));
        *nametree = (dns_nametree_t){
                .magic = NAMETREE_MAGIC,
+               .type = type,
        };
        isc_mem_attach(mctx, &nametree->mctx);
        isc_refcount_init(&nametree->references, 1);
@@ -126,31 +130,69 @@ newnode(isc_mem_t *mctx, const dns_name_t *name) {
        return (node);
 }
 
+static bool
+matchbit(unsigned char *bits, uint32_t val) {
+       unsigned int len = val / 8;
+       unsigned int mask = 1 << (val % 8);
+
+       if ((bits[len] & mask) != 0) {
+               return (true);
+       }
+       return (false);
+}
+
 isc_result_t
-dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name, bool value) {
+dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
+                uint32_t value) {
        isc_result_t result;
        dns_qp_t *qp = NULL;
+       unsigned int len, mask;
+       dns_ntnode_t *old = NULL, *new = NULL;
 
        REQUIRE(VALID_NAMETREE(nametree));
        REQUIRE(name != NULL);
 
        dns_qpmulti_write(nametree->table, &qp);
 
-       result = dns_qp_getname(qp, name, NULL, NULL);
-       if (result == ISC_R_SUCCESS) {
-               result = ISC_R_EXISTS;
-       } else {
-               dns_ntnode_t *node = newnode(nametree->mctx, name);
-               node->value = value;
-               result = dns_qp_insert(qp, node, 0);
-
-               /*
-                * We detach the node here, so any dns_qp_deletename() will
-                * destroy the node directly.
-                */
-               dns_ntnode_detach(&node);
+       switch (nametree->type) {
+       case DNS_NAMETREE_BOOL:
+               new = newnode(nametree->mctx, name);
+               new->set = value;
+               break;
+
+       case DNS_NAMETREE_BITS:
+               result = dns_qp_getname(qp, name, (void **)&old, NULL);
+               if (result == ISC_R_SUCCESS && matchbit(old->bits, value)) {
+                       goto out;
+               }
+
+               len = value / 8;
+               mask = 1 << (value % 8);
+
+               new = newnode(nametree->mctx, name);
+               new->bits = isc_mem_cget(nametree->mctx, 8, sizeof(value));
+               if (result == ISC_R_SUCCESS) {
+                       INSIST(old != NULL);
+                       memmove(new->bits, old->bits, old->bits[0]);
+                       result = dns_qp_deletename(qp, name, NULL, NULL);
+                       INSIST(result == ISC_R_SUCCESS);
+               }
+
+               new->bits[len] |= mask;
+               break;
+       default:
+               UNREACHABLE();
        }
 
+       result = dns_qp_insert(qp, new, 0);
+
+       /*
+        * We detach the node here, so any dns_qp_deletename() will
+        * destroy the node directly.
+        */
+       dns_ntnode_detach(&new);
+
+out:
        dns_qp_compact(qp, DNS_QPGC_MAYBE);
        dns_qpmulti_commit(nametree->table, &qp);
        return (result);
@@ -200,12 +242,12 @@ dns_nametree_find(dns_nametree_t *nametree, const dns_name_t *name,
 }
 
 bool
-dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name) {
+dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
+                    uint32_t bit) {
        isc_result_t result;
        dns_qpread_t qpr;
-       dns_ntnode_t *ntnode = NULL;
-       void *pval = NULL;
-       bool value = false;
+       dns_ntnode_t *node = NULL;
+       bool ret = false;
 
        REQUIRE(nametree == NULL || VALID_NAMETREE(nametree));
 
@@ -214,14 +256,17 @@ dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name) {
        }
 
        dns_qpmulti_query(nametree->table, &qpr);
-       result = dns_qp_findname_ancestor(&qpr, name, 0, &pval, NULL);
+       result = dns_qp_findname_ancestor(&qpr, name, 0, (void **)&node, NULL);
        if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
-               ntnode = pval;
-               value = ntnode->value;
+               if (nametree->type == DNS_NAMETREE_BOOL) {
+                       ret = node->set;
+               } else {
+                       ret = matchbit(node->bits, bit);
+               }
        }
 
        dns_qpread_destroy(nametree->table, &qpr);
-       return (value);
+       return (ret);
 }
 
 static void
index 4238a6d0080a0b839a6497b35f74ab64255d5c83..4b351ce20bca3ca20a195354c77b695309e41298 100644 (file)
@@ -6752,7 +6752,7 @@ is_answeraddress_allowed(dns_view_t *view, dns_name_t *name,
         * If the owner name matches one in the exclusion list, either
         * exactly or partially, allow it.
         */
-       if (dns_nametree_covered(view->answeracl_exclude, name)) {
+       if (dns_nametree_covered(view->answeracl_exclude, name, 0)) {
                return (true);
        }
 
@@ -6865,7 +6865,7 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname,
         * If the owner name matches one in the exclusion list, either
         * exactly or partially, allow it.
         */
-       if (dns_nametree_covered(view->answernames_exclude, qname)) {
+       if (dns_nametree_covered(view->answernames_exclude, qname, 0)) {
                return (true);
        }
 
@@ -6885,7 +6885,7 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname,
        /*
         * Otherwise, apply filters.
         */
-       if (dns_nametree_covered(view->denyanswernames, tname)) {
+       if (dns_nametree_covered(view->denyanswernames, tname, 0)) {
                char qnamebuf[DNS_NAME_FORMATSIZE];
                char tnamebuf[DNS_NAME_FORMATSIZE];
                char classbuf[64];
@@ -10887,7 +10887,8 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name,
        REQUIRE(VALID_RESOLVER(resolver));
 
        if (resolver->mustbesecure == NULL) {
-               dns_nametree_create(resolver->mctx, "dnssec-must-be-secure",
+               dns_nametree_create(resolver->mctx, DNS_NAMETREE_BOOL,
+                                   "dnssec-must-be-secure",
                                    &resolver->mustbesecure);
        }
 
@@ -10899,7 +10900,7 @@ bool
 dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name) {
        REQUIRE(VALID_RESOLVER(resolver));
 
-       return (dns_nametree_covered(resolver->mustbesecure, name));
+       return (dns_nametree_covered(resolver->mustbesecure, name, 0));
 }
 
 void
index 1557d2184f42397362020ebfe6965f7a79cb3486..840d3656e1687713855e837a5b2083b1f321c143 100644 (file)
@@ -37,7 +37,8 @@
 
 #include <tests/dns.h>
 
-dns_nametree_t *nametree = NULL;
+dns_nametree_t *booltree = NULL;
+dns_nametree_t *bitstree = NULL;
 
 /*
  * Test utilities.  In general, these assume input parameters are valid
@@ -46,38 +47,49 @@ dns_nametree_t *nametree = NULL;
  * the test code concise.
  */
 
-/* Common setup: create a nametree to test with a few keys */
+/* Common setup: create a booltree to test with a few keys */
 static void
 create_tables(void) {
        dns_fixedname_t fn;
        dns_name_t *name = dns_fixedname_name(&fn);
 
-       dns_nametree_create(mctx, "test", &nametree);
+       dns_nametree_create(mctx, DNS_NAMETREE_BOOL, "bool test", &booltree);
+       dns_nametree_create(mctx, DNS_NAMETREE_BITS, "bits test", &bitstree);
 
-       /* Add a positive node */
+       /* Add a positive boolean node */
        dns_test_namefromstring("example.com.", &fn);
-       assert_int_equal(dns_nametree_add(nametree, name, true), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_add(booltree, name, true), ISC_R_SUCCESS);
 
-       /* Add a negative node below it */
+       /* Add assorted bits to a bitfield node */
+       assert_int_equal(dns_nametree_add(bitstree, name, 1), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_add(bitstree, name, 9), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_add(bitstree, name, 53), ISC_R_SUCCESS);
+
+       /* Add negative boolean nodes with and without parents */
        dns_test_namefromstring("negative.example.com.", &fn);
-       assert_int_equal(dns_nametree_add(nametree, name, false),
+       assert_int_equal(dns_nametree_add(booltree, name, false),
                         ISC_R_SUCCESS);
-
-       /* Add a negative node with no parent */
        dns_test_namefromstring("negative.example.org.", &fn);
-       assert_int_equal(dns_nametree_add(nametree, name, false),
+       assert_int_equal(dns_nametree_add(booltree, name, false),
                         ISC_R_SUCCESS);
+
+       /* Add a bitfield nodes under a parent */
+       dns_test_namefromstring("sub.example.com.", &fn);
+       assert_int_equal(dns_nametree_add(bitstree, name, 2), ISC_R_SUCCESS);
 }
 
 static void
 destroy_tables(void) {
-       if (nametree != NULL) {
-               dns_nametree_detach(&nametree);
+       if (booltree != NULL) {
+               dns_nametree_detach(&booltree);
+       }
+       if (bitstree != NULL) {
+               dns_nametree_detach(&bitstree);
        }
        rcu_barrier();
 }
 
-ISC_RUN_TEST_IMPL(add) {
+ISC_RUN_TEST_IMPL(add_bool) {
        dns_ntnode_t *node = NULL;
        dns_fixedname_t fn;
        dns_name_t *name = dns_fixedname_name(&fn);
@@ -88,15 +100,15 @@ ISC_RUN_TEST_IMPL(add) {
         * Getting the node for example.com should succeed.
         */
        dns_test_namefromstring("example.com.", &fn);
-       assert_int_equal(dns_nametree_find(nametree, name, &node),
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
                         ISC_R_SUCCESS);
        dns_ntnode_detach(&node);
 
        /*
         * Try to add the same name.  This should fail.
         */
-       assert_int_equal(dns_nametree_add(nametree, name, false), ISC_R_EXISTS);
-       assert_int_equal(dns_nametree_find(nametree, name, &node),
+       assert_int_equal(dns_nametree_add(booltree, name, false), ISC_R_EXISTS);
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
                         ISC_R_SUCCESS);
        dns_ntnode_detach(&node);
 
@@ -104,11 +116,130 @@ ISC_RUN_TEST_IMPL(add) {
         * Try to add a new name.
         */
        dns_test_namefromstring("newname.com.", &fn);
-       assert_int_equal(dns_nametree_add(nametree, name, true), ISC_R_SUCCESS);
-       assert_int_equal(dns_nametree_find(nametree, name, &node),
+       assert_int_equal(dns_nametree_add(booltree, name, true), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
+                        ISC_R_SUCCESS);
+       dns_ntnode_detach(&node);
+
+       destroy_tables();
+}
+
+ISC_RUN_TEST_IMPL(add_bits) {
+       dns_ntnode_t *node = NULL;
+       dns_fixedname_t fn;
+       dns_name_t *name = dns_fixedname_name(&fn);
+
+       create_tables();
+
+       /*
+        * Getting the node for example.com should succeed.
+        */
+       dns_test_namefromstring("example.com.", &fn);
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
                         ISC_R_SUCCESS);
        dns_ntnode_detach(&node);
 
+       /*
+        * Try to add the same name. This should succeed.
+        */
+       assert_int_equal(dns_nametree_add(bitstree, name, 1), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_add(bitstree, name, 2), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_add(bitstree, name, 3), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
+                        ISC_R_SUCCESS);
+       dns_ntnode_detach(&node);
+
+       /*
+        * Try to add a new name.
+        */
+       dns_test_namefromstring("newname.com.", &fn);
+       assert_int_equal(dns_nametree_add(booltree, name, true), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
+                        ISC_R_SUCCESS);
+       dns_ntnode_detach(&node);
+
+       destroy_tables();
+}
+
+ISC_RUN_TEST_IMPL(covered_bool) {
+       dns_fixedname_t fn;
+       dns_name_t *name = dns_fixedname_name(&fn);
+       const char *yesnames[] = { "example.com.", "sub.example.com.", NULL };
+       const char *nonames[] = { "whatever.com.", "negative.example.com.",
+                                 "example.org.", "negative.example.org.",
+                                 NULL };
+       create_tables();
+
+       for (const char **n = yesnames; *n != NULL; n++) {
+               dns_test_namefromstring(*n, &fn);
+               assert_true(dns_nametree_covered(booltree, name, 0));
+       }
+       for (const char **n = nonames; *n != NULL; n++) {
+               dns_test_namefromstring(*n, &fn);
+               assert_false(dns_nametree_covered(booltree, name, 0));
+       }
+
+       /* If the nametree is NULL, dns_nametree_covered() returns false. */
+       dns_test_namefromstring("anyname.example.", &fn);
+       assert_false(dns_nametree_covered(NULL, name, 0));
+
+       destroy_tables();
+}
+
+ISC_RUN_TEST_IMPL(covered_bits) {
+       dns_fixedname_t fn;
+       dns_name_t *name = dns_fixedname_name(&fn);
+
+       create_tables();
+
+       /* check existing bit values */
+       dns_test_namefromstring("example.com.", &fn);
+       assert_false(dns_nametree_covered(bitstree, name, 0));
+       assert_true(dns_nametree_covered(bitstree, name, 1));
+       assert_false(dns_nametree_covered(bitstree, name, 2));
+       assert_false(dns_nametree_covered(bitstree, name, 3));
+       assert_true(dns_nametree_covered(bitstree, name, 9));
+       assert_true(dns_nametree_covered(bitstree, name, 53));
+       assert_false(dns_nametree_covered(bitstree, name, 288));
+
+       /* add a small bit value, test again */
+       assert_int_equal(dns_nametree_add(bitstree, name, 3), ISC_R_SUCCESS);
+       assert_true(dns_nametree_covered(bitstree, name, 3));
+
+       /* add a large bit value, test again */
+       assert_int_equal(dns_nametree_add(bitstree, name, 615), ISC_R_SUCCESS);
+       assert_true(dns_nametree_covered(bitstree, name, 615));
+
+       /* check existing bit values for subdomain */
+       dns_test_namefromstring("sub.example.com.", &fn);
+       assert_false(dns_nametree_covered(bitstree, name, 0));
+       assert_false(dns_nametree_covered(bitstree, name, 1));
+       assert_true(dns_nametree_covered(bitstree, name, 2));
+       assert_false(dns_nametree_covered(bitstree, name, 3));
+       assert_false(dns_nametree_covered(bitstree, name, 9));
+       assert_false(dns_nametree_covered(bitstree, name, 53));
+       assert_false(dns_nametree_covered(bitstree, name, 288));
+
+       /* check nonexistent subdomain is all false */
+       dns_test_namefromstring("other.example.com", &fn);
+       assert_false(dns_nametree_covered(bitstree, name, 0));
+       assert_false(dns_nametree_covered(bitstree, name, 1));
+       assert_false(dns_nametree_covered(bitstree, name, 2));
+       assert_false(dns_nametree_covered(bitstree, name, 3));
+       assert_false(dns_nametree_covered(bitstree, name, 9));
+       assert_false(dns_nametree_covered(bitstree, name, 53));
+       assert_false(dns_nametree_covered(bitstree, name, 288));
+
+       /* check nonexistent domain is all false */
+       dns_test_namefromstring("anyname.", &fn);
+       assert_false(dns_nametree_covered(bitstree, name, 0));
+       assert_false(dns_nametree_covered(bitstree, name, 1));
+       assert_false(dns_nametree_covered(bitstree, name, 2));
+       assert_false(dns_nametree_covered(bitstree, name, 3));
+       assert_false(dns_nametree_covered(bitstree, name, 9));
+       assert_false(dns_nametree_covered(bitstree, name, 53));
+       assert_false(dns_nametree_covered(bitstree, name, 288));
+
        destroy_tables();
 }
 
@@ -120,11 +251,11 @@ ISC_RUN_TEST_IMPL(delete) {
 
        /* name doesn't match */
        dns_test_namefromstring("example.org.", &fn);
-       assert_int_equal(dns_nametree_delete(nametree, name), ISC_R_NOTFOUND);
+       assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND);
 
        /* subdomain match is the same as no match */
        dns_test_namefromstring("sub.example.org.", &fn);
-       assert_int_equal(dns_nametree_delete(nametree, name), ISC_R_NOTFOUND);
+       assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND);
 
        /*
         * delete requires exact match: this should return SUCCESS on
@@ -132,12 +263,12 @@ ISC_RUN_TEST_IMPL(delete) {
         * ancestor does exist.
         */
        dns_test_namefromstring("negative.example.com.", &fn);
-       assert_int_equal(dns_nametree_delete(nametree, name), ISC_R_SUCCESS);
-       assert_int_equal(dns_nametree_delete(nametree, name), ISC_R_NOTFOUND);
+       assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND);
 
        dns_test_namefromstring("negative.example.org.", &fn);
-       assert_int_equal(dns_nametree_delete(nametree, name), ISC_R_SUCCESS);
-       assert_int_equal(dns_nametree_delete(nametree, name), ISC_R_NOTFOUND);
+       assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_SUCCESS);
+       assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND);
 
        destroy_tables();
 }
@@ -154,49 +285,26 @@ ISC_RUN_TEST_IMPL(find) {
         * that has a null key, too.
         */
        dns_test_namefromstring("example.org.", &fn);
-       assert_int_equal(dns_nametree_find(nametree, name, &node),
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
                         ISC_R_NOTFOUND);
        dns_test_namefromstring("sub.example.com.", &fn);
-       assert_int_equal(dns_nametree_find(nametree, name, &node),
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
                         ISC_R_NOTFOUND);
        dns_test_namefromstring("example.com.", &fn);
-       assert_int_equal(dns_nametree_find(nametree, name, &node),
+       assert_int_equal(dns_nametree_find(booltree, name, &node),
                         ISC_R_SUCCESS);
        dns_ntnode_detach(&node);
 
        destroy_tables();
 }
 
-ISC_RUN_TEST_IMPL(covered) {
-       dns_fixedname_t fn;
-       dns_name_t *name = dns_fixedname_name(&fn);
-       const char *yesnames[] = { "example.com.", "sub.example.com.", NULL };
-       const char *nonames[] = { "whatever.com.", "negative.example.com.",
-                                 "example.org.", "negative.example.org.",
-                                 NULL };
-       create_tables();
-
-       for (const char **n = yesnames; *n != NULL; n++) {
-               dns_test_namefromstring(*n, &fn);
-               assert_true(dns_nametree_covered(nametree, name));
-       }
-       for (const char **n = nonames; *n != NULL; n++) {
-               dns_test_namefromstring(*n, &fn);
-               assert_false(dns_nametree_covered(nametree, name));
-       }
-
-       /* If nametree is NULL, dns_nametree_covered() returns false. */
-       dns_test_namefromstring("anyname.example.", &fn);
-       assert_false(dns_nametree_covered(NULL, name));
-
-       destroy_tables();
-}
-
 ISC_TEST_LIST_START
-ISC_TEST_ENTRY(add)
-ISC_TEST_ENTRY(covered)
-ISC_TEST_ENTRY(find)
+ISC_TEST_ENTRY(add_bool)
+ISC_TEST_ENTRY(add_bits)
+ISC_TEST_ENTRY(covered_bool)
+ISC_TEST_ENTRY(covered_bits)
 ISC_TEST_ENTRY(delete)
+ISC_TEST_ENTRY(find)
 ISC_TEST_LIST_END
 
 ISC_TEST_MAIN