diff --git a/lib/dns/include/dns/nametree.h b/lib/dns/include/dns/nametree.h index bae8dcefb3..3c5ac51893 100644 --- a/lib/dns/include/dns/nametree.h +++ b/lib/dns/include/dns/nametree.h @@ -147,7 +147,7 @@ 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, - uint32_t bit); + dns_name_t *found, uint32_t bit); /*%< * Indicates whether a 'name' (with optional 'bit' value) is covered by * 'nametree'. @@ -162,6 +162,9 @@ dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name, * If a name is not found, or if 'nametree' is NULL, the default return * value is false. * + * If 'found' is not NULL, the name or ancestor name that was found in + * the tree is copied into it. + * * Requires: * *\li 'nametree' is a valid nametree, or is NULL. diff --git a/lib/dns/nametree.c b/lib/dns/nametree.c index bbca177aea..af7cfbddf7 100644 --- a/lib/dns/nametree.c +++ b/lib/dns/nametree.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -281,7 +282,7 @@ 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, - uint32_t bit) { + dns_name_t *found, uint32_t bit) { isc_result_t result; dns_qpread_t qpr; dns_ntnode_t *node = NULL; @@ -296,6 +297,10 @@ 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, (void **)&node, NULL); if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) { + if (found != NULL) { + dns_name_copy(node->name, found); + } + switch (nametree->type) { case DNS_NAMETREE_BOOL: ret = node->set; diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 7984b3e4b5..02a578c261 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -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, 0)) { + if (dns_nametree_covered(view->answeracl_exclude, name, NULL, 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, 0)) { + if (dns_nametree_covered(view->answernames_exclude, qname, NULL, 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, 0)) { + if (dns_nametree_covered(view->denyanswernames, tname, NULL, 0)) { char qnamebuf[DNS_NAME_FORMATSIZE]; char tnamebuf[DNS_NAME_FORMATSIZE]; char classbuf[64]; @@ -10778,7 +10778,7 @@ dns_resolver_algorithm_supported(dns_resolver_t *resolver, return (false); } - if (dns_nametree_covered(resolver->algorithms, name, alg)) { + if (dns_nametree_covered(resolver->algorithms, name, NULL, alg)) { return (false); } @@ -10791,7 +10791,7 @@ dns_resolver_ds_digest_supported(dns_resolver_t *resolver, unsigned int digest_type) { REQUIRE(VALID_RESOLVER(resolver)); - if (dns_nametree_covered(resolver->digests, name, digest_type)) { + if (dns_nametree_covered(resolver->digests, name, NULL, digest_type)) { return (false); } @@ -10828,7 +10828,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, 0)); + return (dns_nametree_covered(resolver->mustbesecure, name, NULL, 0)); } void diff --git a/tests/dns/nametree_test.c b/tests/dns/nametree_test.c index 23df32f7e6..39ac4467c1 100644 --- a/tests/dns/nametree_test.c +++ b/tests/dns/nametree_test.c @@ -48,9 +48,9 @@ dns_nametree_t *counttree = NULL; * the test code concise. */ -/* Common setup: create a booltree to test with a few keys */ -static void -create_tables(void) { +/* Common setup: create trees of each type with a few keys */ +static int +setup(void **state ISC_ATTR_UNUSED) { dns_fixedname_t fn; dns_name_t *name = dns_fixedname_name(&fn); @@ -78,20 +78,17 @@ create_tables(void) { /* Add a bitfield node under a parent */ dns_test_namefromstring("sub.example.com.", &fn); assert_int_equal(dns_nametree_add(bitstree, name, 2), ISC_R_SUCCESS); + + return (0); } -static void -destroy_tables(void) { - if (booltree != NULL) { - dns_nametree_detach(&booltree); - } - if (bitstree != NULL) { - dns_nametree_detach(&bitstree); - } - if (counttree != NULL) { - dns_nametree_detach(&counttree); - } +static int +teardown(void **state ISC_ATTR_UNUSED) { + dns_nametree_detach(&booltree); + dns_nametree_detach(&bitstree); + dns_nametree_detach(&counttree); rcu_barrier(); + return (0); } ISC_RUN_TEST_IMPL(add_bool) { @@ -99,8 +96,6 @@ ISC_RUN_TEST_IMPL(add_bool) { dns_fixedname_t fn; dns_name_t *name = dns_fixedname_name(&fn); - create_tables(); - /* * Getting the node for example.com should succeed. */ @@ -125,8 +120,6 @@ ISC_RUN_TEST_IMPL(add_bool) { assert_int_equal(dns_nametree_find(booltree, name, &node), ISC_R_SUCCESS); dns_ntnode_detach(&node); - - destroy_tables(); } ISC_RUN_TEST_IMPL(add_bits) { @@ -134,8 +127,6 @@ ISC_RUN_TEST_IMPL(add_bits) { dns_fixedname_t fn; dns_name_t *name = dns_fixedname_name(&fn); - create_tables(); - /* * Getting the node for example.com should succeed. */ @@ -162,16 +153,12 @@ ISC_RUN_TEST_IMPL(add_bits) { assert_int_equal(dns_nametree_find(booltree, name, &node), ISC_R_SUCCESS); dns_ntnode_detach(&node); - - destroy_tables(); } ISC_RUN_TEST_IMPL(add_count) { dns_fixedname_t fn; dns_name_t *name = dns_fixedname_name(&fn); - create_tables(); - /* add a counter node five times */ dns_test_namefromstring("example.com.", &fn); assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS); @@ -181,115 +168,116 @@ ISC_RUN_TEST_IMPL(add_count) { assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS); /* delete it five times, checking coverage each time */ - assert_true(dns_nametree_covered(counttree, name, 0)); + assert_true(dns_nametree_covered(counttree, name, NULL, 0)); assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS); - assert_true(dns_nametree_covered(counttree, name, 0)); + assert_true(dns_nametree_covered(counttree, name, NULL, 0)); assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS); - assert_true(dns_nametree_covered(counttree, name, 0)); + assert_true(dns_nametree_covered(counttree, name, NULL, 0)); assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS); - assert_true(dns_nametree_covered(counttree, name, 0)); + assert_true(dns_nametree_covered(counttree, name, NULL, 0)); assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS); - assert_true(dns_nametree_covered(counttree, name, 0)); + assert_true(dns_nametree_covered(counttree, name, NULL, 0)); assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS); - assert_false(dns_nametree_covered(counttree, name, 0)); + assert_false(dns_nametree_covered(counttree, name, NULL, 0)); assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_NOTFOUND); - - destroy_tables(); } ISC_RUN_TEST_IMPL(covered_bool) { - dns_fixedname_t fn; - dns_name_t *name = dns_fixedname_name(&fn); + dns_fixedname_t fn, fn2; + dns_name_t *name = dns_fixedname_initname(&fn); + dns_name_t *found = dns_fixedname_initname(&fn2); + char buf[DNS_NAME_FORMATSIZE]; 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)); + assert_true(dns_nametree_covered(booltree, name, NULL, 0)); } for (const char **n = nonames; *n != NULL; n++) { dns_test_namefromstring(*n, &fn); - assert_false(dns_nametree_covered(booltree, name, 0)); + assert_false(dns_nametree_covered(booltree, name, NULL, 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)); + assert_false(dns_nametree_covered(NULL, name, NULL, 0)); - destroy_tables(); + /* Check that the found name is as expected */ + dns_test_namefromstring("other.example.com.", &fn); + assert_true(dns_nametree_covered(booltree, name, found, 0)); + dns_name_format(found, buf, sizeof(buf)); + assert_string_equal(buf, "example.com"); } 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)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 0)); + assert_true(dns_nametree_covered(bitstree, name, NULL, 1)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 2)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 3)); + assert_true(dns_nametree_covered(bitstree, name, NULL, 9)); + assert_true(dns_nametree_covered(bitstree, name, NULL, 53)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 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)); + assert_true(dns_nametree_covered(bitstree, name, NULL, 3)); /* add a large bit value, test again */ + assert_false(dns_nametree_covered(bitstree, name, NULL, 615)); assert_int_equal(dns_nametree_add(bitstree, name, 615), ISC_R_SUCCESS); - assert_true(dns_nametree_covered(bitstree, name, 615)); + assert_true(dns_nametree_covered(bitstree, name, NULL, 615)); + assert_int_equal(dns_nametree_add(bitstree, name, 999), ISC_R_SUCCESS); + assert_true(dns_nametree_covered(bitstree, name, NULL, 999)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 998)); /* 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)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 0)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 1)); + assert_true(dns_nametree_covered(bitstree, name, NULL, 2)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 3)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 9)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 53)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 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)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 0)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 1)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 2)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 3)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 9)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 53)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 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(); + assert_false(dns_nametree_covered(bitstree, name, NULL, 0)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 1)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 2)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 3)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 9)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 53)); + assert_false(dns_nametree_covered(bitstree, name, NULL, 288)); } ISC_RUN_TEST_IMPL(delete) { dns_fixedname_t fn; dns_name_t *name = dns_fixedname_name(&fn); - create_tables(); - /* name doesn't match */ dns_test_namefromstring("example.org.", &fn); assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND); @@ -310,8 +298,6 @@ ISC_RUN_TEST_IMPL(delete) { dns_test_namefromstring("negative.example.org.", &fn); assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_SUCCESS); assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND); - - destroy_tables(); } ISC_RUN_TEST_IMPL(find) { @@ -319,8 +305,6 @@ ISC_RUN_TEST_IMPL(find) { dns_fixedname_t fn; dns_name_t *name = dns_fixedname_name(&fn); - create_tables(); - /* * dns_nametree_find() requires exact name match. It matches node * that has a null key, too. @@ -335,18 +319,16 @@ ISC_RUN_TEST_IMPL(find) { assert_int_equal(dns_nametree_find(booltree, name, &node), ISC_R_SUCCESS); dns_ntnode_detach(&node); - - destroy_tables(); } ISC_TEST_LIST_START -ISC_TEST_ENTRY(add_bool) -ISC_TEST_ENTRY(add_bits) -ISC_TEST_ENTRY(add_count) -ISC_TEST_ENTRY(covered_bool) -ISC_TEST_ENTRY(covered_bits) -ISC_TEST_ENTRY(delete) -ISC_TEST_ENTRY(find) +ISC_TEST_ENTRY_CUSTOM(add_bool, setup, teardown) +ISC_TEST_ENTRY_CUSTOM(add_bits, setup, teardown) +ISC_TEST_ENTRY_CUSTOM(add_count, setup, teardown) +ISC_TEST_ENTRY_CUSTOM(covered_bool, setup, teardown) +ISC_TEST_ENTRY_CUSTOM(covered_bits, setup, teardown) +ISC_TEST_ENTRY_CUSTOM(delete, setup, teardown) +ISC_TEST_ENTRY_CUSTOM(find, setup, teardown) ISC_TEST_LIST_END ISC_TEST_MAIN