mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-10 17:50:00 -04:00
Merge branch 'each-cleanup-rbt' into 'main'
replace RBT usage throughout named See merge request isc-projects/bind9!8213
This commit is contained in:
commit
00a6268c8f
13 changed files with 978 additions and 378 deletions
4
CHANGES
4
CHANGES
|
|
@ -1,3 +1,7 @@
|
|||
6238. [cleanup] Refactor several objects relying on dns_rbt trees
|
||||
to instead of dns_nametree, a wrapper around dns_qp.
|
||||
[GL !8213]
|
||||
|
||||
6237. [bug] Address memory leaks due to not clearing OpenSSL error
|
||||
stack. [GL #4159]
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@
|
|||
#include <dns/keyvalues.h>
|
||||
#include <dns/master.h>
|
||||
#include <dns/masterdump.h>
|
||||
#include <dns/nametree.h>
|
||||
#include <dns/nsec3.h>
|
||||
#include <dns/nta.h>
|
||||
#include <dns/order.h>
|
||||
|
|
@ -602,21 +603,23 @@ configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||
static isc_result_t
|
||||
configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
||||
const char *confname, const char *conftuplename,
|
||||
isc_mem_t *mctx, dns_rbt_t **rbtp) {
|
||||
isc_result_t result;
|
||||
isc_mem_t *mctx, dns_nametree_t **ntp) {
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
const cfg_obj_t *maps[3];
|
||||
const cfg_obj_t *obj = NULL;
|
||||
const cfg_listelt_t *element;
|
||||
const cfg_listelt_t *element = NULL;
|
||||
int i = 0;
|
||||
dns_fixedname_t fixed;
|
||||
dns_name_t *name;
|
||||
dns_name_t *name = NULL;
|
||||
isc_buffer_t b;
|
||||
const char *str;
|
||||
const cfg_obj_t *nameobj;
|
||||
const char *str = NULL;
|
||||
const cfg_obj_t *nameobj = NULL;
|
||||
|
||||
if (*rbtp != NULL) {
|
||||
dns_rbt_destroy(rbtp);
|
||||
if (*ntp != NULL) {
|
||||
dns_nametree_detach(ntp);
|
||||
}
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_BOOL, confname, ntp);
|
||||
|
||||
if (vconfig != NULL) {
|
||||
maps[i++] = cfg_tuple_get(vconfig, "options");
|
||||
}
|
||||
|
|
@ -632,7 +635,7 @@ configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||
(void)named_config_get(maps, confname, &obj);
|
||||
if (obj == NULL) {
|
||||
/*
|
||||
* No value available. *rbtp == NULL.
|
||||
* No value available. *ntp == NULL.
|
||||
*/
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
|
@ -644,11 +647,6 @@ configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||
}
|
||||
}
|
||||
|
||||
result = dns_rbt_create(mctx, NULL, NULL, rbtp);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
name = dns_fixedname_initname(&fixed);
|
||||
for (element = cfg_list_first(obj); element != NULL;
|
||||
element = cfg_list_next(element))
|
||||
|
|
@ -658,14 +656,7 @@ configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||
isc_buffer_constinit(&b, str, strlen(str));
|
||||
isc_buffer_add(&b, strlen(str));
|
||||
CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
|
||||
/*
|
||||
* We don't need the node data, but need to set dummy data to
|
||||
* avoid a partial match with an empty node. For example, if
|
||||
* we have foo.example.com and bar.example.com, we'd get a match
|
||||
* for baz.example.com, which is not the expected result.
|
||||
* We simply use (void *)1 as the dummy data.
|
||||
*/
|
||||
result = dns_rbt_addname(*rbtp, name, (void *)1);
|
||||
result = dns_nametree_add(*ntp, name, true);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
|
||||
"failed to add %s for %s: %s", str,
|
||||
|
|
@ -674,10 +665,10 @@ configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
|
|||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
dns_rbt_destroy(rbtp);
|
||||
dns_nametree_detach(ntp);
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
|
@ -4915,7 +4906,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
/*
|
||||
* Set supported DNSSEC algorithms.
|
||||
*/
|
||||
dns_resolver_reset_algorithms(view->resolver);
|
||||
disabled = NULL;
|
||||
(void)named_config_get(maps, "disable-algorithms", &disabled);
|
||||
if (disabled != NULL) {
|
||||
|
|
@ -4930,7 +4920,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
/*
|
||||
* Set supported DS digest types.
|
||||
*/
|
||||
dns_resolver_reset_ds_digests(view->resolver);
|
||||
disabled = NULL;
|
||||
(void)named_config_get(maps, "disable-ds-digests", &disabled);
|
||||
if (disabled != NULL) {
|
||||
|
|
@ -5530,7 +5519,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config,
|
|||
*/
|
||||
CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
|
||||
auto_root));
|
||||
dns_resolver_resetmustbesecure(view->resolver);
|
||||
|
||||
obj = NULL;
|
||||
result = named_config_get(maps, "dnssec-must-be-secure", &obj);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
|
|
|
|||
|
|
@ -91,6 +91,7 @@ libdns_la_HEADERS = \
|
|||
include/dns/masterdump.h \
|
||||
include/dns/message.h \
|
||||
include/dns/name.h \
|
||||
include/dns/nametree.h \
|
||||
include/dns/ncache.h \
|
||||
include/dns/nsec.h \
|
||||
include/dns/nsec3.h \
|
||||
|
|
@ -196,6 +197,7 @@ libdns_la_SOURCES = \
|
|||
masterdump.c \
|
||||
message.c \
|
||||
name.c \
|
||||
nametree.c \
|
||||
ncache.c \
|
||||
nsec.c \
|
||||
nsec3.c \
|
||||
|
|
|
|||
194
lib/dns/include/dns/nametree.h
Normal file
194
lib/dns/include/dns/nametree.h
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* 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 https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/*****
|
||||
***** Module Info
|
||||
*****/
|
||||
|
||||
/*! \file
|
||||
* \brief
|
||||
* A nametree module is a tree of DNS names containing boolean values
|
||||
* or bitfields, allowing a quick lookup to see whether a name is included
|
||||
* in or excluded from some policy.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/lang.h>
|
||||
#include <isc/magic.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/rwlock.h>
|
||||
#include <isc/stdtime.h>
|
||||
|
||||
#include <dns/rdatastruct.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
/* Define to 1 for detailed reference tracing */
|
||||
#undef DNS_NAMETREE_TRACE
|
||||
|
||||
typedef enum {
|
||||
DNS_NAMETREE_BOOL,
|
||||
DNS_NAMETREE_BITS,
|
||||
DNS_NAMETREE_COUNT
|
||||
} dns_nametree_type_t;
|
||||
|
||||
ISC_LANG_BEGINDECLS
|
||||
|
||||
void
|
||||
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), bitfields (DNS_NAMETREE_BITS), or counters
|
||||
* (DNS_NAMETREE_COUNT).
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'mctx' is a valid memory context.
|
||||
*\li ntp != NULL && *ntp == NULL
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
uint32_t value);
|
||||
/*%<
|
||||
* Add a node to 'nametree'.
|
||||
*
|
||||
* 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_COUNT, then 'value'
|
||||
* can only be true. Each time the same name is added to the tree,
|
||||
* ISC_R_SUCCESS is returned and a counter is incremented.
|
||||
* dns_nametree_delete() must be deleted the same number of times
|
||||
* as dns_nametree_add() before the name is removed from the tree.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li ISC_R_SUCCESS
|
||||
*\li ISC_R_EXISTS
|
||||
*
|
||||
*\li Any other result indicates failure.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_nametree_delete(dns_nametree_t *nametree, const dns_name_t *name);
|
||||
/*%<
|
||||
* Delete 'name' from 'nametree'.
|
||||
*
|
||||
* If the nametree type was set to DNS_NAMETREE_COUNT, then this must
|
||||
* be called for each name the same number of times as dns_nametree_add()
|
||||
* was called before the name is removed.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'nametree' points to a valid nametree.
|
||||
*\li 'name' is not NULL
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li ISC_R_SUCCESS
|
||||
*
|
||||
*\li Any other result indicates failure.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_nametree_find(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
dns_ntnode_t **ntp);
|
||||
/*%<
|
||||
* Retrieve the node that exactly matches 'name' from 'nametree'.
|
||||
*
|
||||
* Requires:
|
||||
*
|
||||
*\li 'nametree' is a valid nametree.
|
||||
*
|
||||
*\li 'name' is a valid name.
|
||||
*
|
||||
*\li ntp != NULL && *ntp == NULL
|
||||
*
|
||||
* Returns:
|
||||
*
|
||||
*\li ISC_R_SUCCESS
|
||||
*\li ISC_R_NOTFOUND
|
||||
*
|
||||
*\li Any other result indicates an error.
|
||||
*/
|
||||
|
||||
bool
|
||||
dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
dns_name_t *found, uint32_t bit);
|
||||
/*%<
|
||||
* 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.
|
||||
*
|
||||
* If a name is not found, 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.
|
||||
*/
|
||||
|
||||
#if DNS_NAMETREE_TRACE
|
||||
#define dns_nametree_ref(ptr) \
|
||||
dns_nametree__ref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_nametree_unref(ptr) \
|
||||
dns_nametree__unref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_nametree_attach(ptr, ptrp) \
|
||||
dns_nametree__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
|
||||
#define dns_nametree_detach(ptrp) \
|
||||
dns_nametree__detach(ptrp, __func__, __FILE__, __LINE__)
|
||||
#define dns_ntnode_ref(ptr) dns_ntnode__ref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_ntnode_unref(ptr) \
|
||||
dns_ntnode__unref(ptr, __func__, __FILE__, __LINE__)
|
||||
#define dns_ntnode_attach(ptr, ptrp) \
|
||||
dns_ntnode__attach(ptr, ptrp, __func__, __FILE__, __LINE__)
|
||||
#define dns_ntnode_detach(ptrp) \
|
||||
dns_ntnode__detach(ptrp, __func__, __FILE__, __LINE__)
|
||||
ISC_REFCOUNT_TRACE_DECL(dns_nametree);
|
||||
ISC_REFCOUNT_TRACE_DECL(dns_ntnode);
|
||||
#else
|
||||
ISC_REFCOUNT_DECL(dns_nametree);
|
||||
ISC_REFCOUNT_DECL(dns_ntnode);
|
||||
#endif
|
||||
ISC_LANG_ENDDECLS
|
||||
|
|
@ -423,18 +423,6 @@ dns_resolver_addalternate(dns_resolver_t *resolver, const isc_sockaddr_t *alt,
|
|||
* \li only one of 'name' or 'alt' to be valid.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_resolver_reset_algorithms(dns_resolver_t *resolver);
|
||||
/*%<
|
||||
* Clear the disabled DNSSEC algorithms.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_resolver_reset_ds_digests(dns_resolver_t *resolver);
|
||||
/*%<
|
||||
* Clear the disabled DS digest types.
|
||||
*/
|
||||
|
||||
isc_result_t
|
||||
dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name,
|
||||
unsigned int alg);
|
||||
|
|
@ -482,9 +470,6 @@ dns_resolver_ds_digest_supported(dns_resolver_t *resolver,
|
|||
* crypto libraries if it was not specifically disabled.
|
||||
*/
|
||||
|
||||
void
|
||||
dns_resolver_resetmustbesecure(dns_resolver_t *resolver);
|
||||
|
||||
isc_result_t
|
||||
dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name,
|
||||
bool value);
|
||||
|
|
|
|||
|
|
@ -116,8 +116,10 @@ typedef struct dns_message dns_message_t;
|
|||
typedef uint16_t dns_messageid_t;
|
||||
typedef isc_region_t dns_label_t;
|
||||
typedef struct dns_name dns_name_t;
|
||||
typedef struct dns_nametree dns_nametree_t;
|
||||
typedef ISC_LIST(dns_name_t) dns_namelist_t;
|
||||
typedef struct dns_ntatable dns_ntatable_t;
|
||||
typedef struct dns_ntnode dns_ntnode_t;
|
||||
typedef uint16_t dns_opcode_t;
|
||||
typedef struct dns_order dns_order_t;
|
||||
typedef struct dns_peer dns_peer_t;
|
||||
|
|
|
|||
|
|
@ -140,12 +140,11 @@ struct dns_view {
|
|||
dns_acl_t *denyansweracl;
|
||||
dns_acl_t *nocasecompress;
|
||||
bool msgcompression;
|
||||
dns_rbt_t *answeracl_exclude;
|
||||
dns_rbt_t *denyanswernames;
|
||||
dns_rbt_t *answernames_exclude;
|
||||
dns_nametree_t *answeracl_exclude;
|
||||
dns_nametree_t *denyanswernames;
|
||||
dns_nametree_t *answernames_exclude;
|
||||
dns_nametree_t *sfd;
|
||||
dns_rrl_t *rrl;
|
||||
dns_rbt_t *sfd;
|
||||
isc_rwlock_t sfd_lock;
|
||||
bool provideixfr;
|
||||
bool requestnsid;
|
||||
bool sendcookie;
|
||||
|
|
|
|||
342
lib/dns/nametree.c
Normal file
342
lib/dns/nametree.c
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* 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 https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <isc/mem.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/urcu.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/nametree.h>
|
||||
#include <dns/qp.h>
|
||||
|
||||
#define NAMETREE_MAGIC ISC_MAGIC('N', 'T', 'r', 'e')
|
||||
#define VALID_NAMETREE(kt) ISC_MAGIC_VALID(kt, NAMETREE_MAGIC)
|
||||
|
||||
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];
|
||||
};
|
||||
|
||||
struct dns_ntnode {
|
||||
isc_mem_t *mctx;
|
||||
isc_refcount_t references;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name;
|
||||
bool set;
|
||||
uint8_t *bits;
|
||||
};
|
||||
|
||||
/* QP trie methods */
|
||||
static void
|
||||
qp_attach(void *uctx, void *pval, uint32_t ival);
|
||||
static void
|
||||
qp_detach(void *uctx, void *pval, uint32_t ival);
|
||||
static size_t
|
||||
qp_makekey(dns_qpkey_t key, void *uctx, void *pval, uint32_t ival);
|
||||
static void
|
||||
qp_triename(void *uctx, char *buf, size_t size);
|
||||
|
||||
static dns_qpmethods_t qpmethods = {
|
||||
qp_attach,
|
||||
qp_detach,
|
||||
qp_makekey,
|
||||
qp_triename,
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_ntnode(dns_ntnode_t *node) {
|
||||
isc_refcount_destroy(&node->references);
|
||||
if (node->bits != NULL) {
|
||||
isc_mem_cput(node->mctx, node->bits, node->bits[0],
|
||||
sizeof(char));
|
||||
}
|
||||
isc_mem_putanddetach(&node->mctx, node, sizeof(dns_ntnode_t));
|
||||
}
|
||||
|
||||
#if DNS_NAMETREE_TRACE
|
||||
ISC_REFCOUNT_TRACE_IMPL(dns_ntnode, destroy_ntnode);
|
||||
#else
|
||||
ISC_REFCOUNT_IMPL(dns_ntnode, destroy_ntnode);
|
||||
#endif
|
||||
|
||||
void
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if (name != NULL) {
|
||||
strlcpy(nametree->name, name, sizeof(nametree->name));
|
||||
}
|
||||
|
||||
dns_qpmulti_create(mctx, &qpmethods, nametree, &nametree->table);
|
||||
*ntp = nametree;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_nametree(dns_nametree_t *nametree) {
|
||||
/* dns_qpread_t qpr; */
|
||||
/* dns_qpiter_t iter; */
|
||||
/* void *pval = NULL; */
|
||||
|
||||
nametree->magic = 0;
|
||||
|
||||
/* dns_qpmulti_query(nametree->table, &qpr); */
|
||||
/* dns_qpiter_init(&qpr, &iter); */
|
||||
/* while (dns_qpiter_next(&iter, &pval, NULL) == ISC_R_SUCCESS) { */
|
||||
/* dns_ntnode_t *n = pval; */
|
||||
/* dns_ntnode_detach(&n); */
|
||||
/* } */
|
||||
/* dns_qpread_destroy(nametree->table, &qpr); */
|
||||
|
||||
dns_qpmulti_destroy(&nametree->table);
|
||||
isc_refcount_destroy(&nametree->references);
|
||||
|
||||
isc_mem_putanddetach(&nametree->mctx, nametree, sizeof(*nametree));
|
||||
}
|
||||
|
||||
#if DNS_NAMETREE_TRACE
|
||||
ISC_REFCOUNT_TRACE_IMPL(dns_nametree, destroy_nametree);
|
||||
#else
|
||||
ISC_REFCOUNT_IMPL(dns_nametree, destroy_nametree);
|
||||
#endif
|
||||
|
||||
static dns_ntnode_t *
|
||||
newnode(isc_mem_t *mctx, const dns_name_t *name) {
|
||||
dns_ntnode_t *node = isc_mem_get(mctx, sizeof(*node));
|
||||
*node = (dns_ntnode_t){ 0 };
|
||||
isc_mem_attach(mctx, &node->mctx);
|
||||
isc_refcount_init(&node->references, 1);
|
||||
|
||||
node->name = dns_fixedname_initname(&node->fn);
|
||||
dns_name_copy(name, node->name);
|
||||
|
||||
return (node);
|
||||
}
|
||||
|
||||
static bool
|
||||
matchbit(unsigned char *bits, uint32_t val) {
|
||||
unsigned int len = val / 8 + 2;
|
||||
unsigned int mask = 1 << (val % 8);
|
||||
|
||||
if (len <= bits[0] && (bits[len - 1] & mask) != 0) {
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_nametree_add(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
uint32_t value) {
|
||||
isc_result_t result;
|
||||
dns_qp_t *qp = NULL;
|
||||
uint32_t size, pos, mask, count = 0;
|
||||
dns_ntnode_t *old = NULL, *new = NULL;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
REQUIRE(name != NULL);
|
||||
|
||||
dns_qpmulti_write(nametree->table, &qp);
|
||||
|
||||
switch (nametree->type) {
|
||||
case DNS_NAMETREE_BOOL:
|
||||
new = newnode(nametree->mctx, name);
|
||||
new->set = value;
|
||||
break;
|
||||
|
||||
case DNS_NAMETREE_COUNT:
|
||||
new = newnode(nametree->mctx, name);
|
||||
new->set = true;
|
||||
result = dns_qp_deletename(qp, name, (void **)&old, &count);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
count += 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
size = pos = value / 8 + 2;
|
||||
mask = 1 << (value % 8);
|
||||
|
||||
if (old != NULL && old->bits[0] > pos) {
|
||||
size = old->bits[0];
|
||||
}
|
||||
|
||||
new = newnode(nametree->mctx, name);
|
||||
new->bits = isc_mem_cget(nametree->mctx, size, sizeof(char));
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
memmove(new->bits, old->bits, old->bits[0]);
|
||||
result = dns_qp_deletename(qp, name, NULL, NULL);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
new->bits[pos - 1] |= mask;
|
||||
new->bits[0] = size;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
result = dns_qp_insert(qp, new, count);
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_nametree_delete(dns_nametree_t *nametree, const dns_name_t *name) {
|
||||
isc_result_t result;
|
||||
dns_qp_t *qp = NULL;
|
||||
dns_ntnode_t *old = NULL;
|
||||
uint32_t count;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
REQUIRE(name != NULL);
|
||||
|
||||
dns_qpmulti_write(nametree->table, &qp);
|
||||
result = dns_qp_deletename(qp, name, (void **)&old, &count);
|
||||
switch (nametree->type) {
|
||||
case DNS_NAMETREE_BOOL:
|
||||
case DNS_NAMETREE_BITS:
|
||||
break;
|
||||
|
||||
case DNS_NAMETREE_COUNT:
|
||||
if (result == ISC_R_SUCCESS && count-- != 0) {
|
||||
dns_ntnode_t *new = newnode(nametree->mctx, name);
|
||||
new->set = true;
|
||||
result = dns_qp_insert(qp, new, count);
|
||||
INSIST(result == ISC_R_SUCCESS);
|
||||
dns_ntnode_detach(&new);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
dns_qp_compact(qp, DNS_QPGC_MAYBE);
|
||||
dns_qpmulti_commit(nametree->table, &qp);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_nametree_find(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
dns_ntnode_t **ntnodep) {
|
||||
isc_result_t result;
|
||||
dns_ntnode_t *node = NULL;
|
||||
dns_qpread_t qpr;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
REQUIRE(name != NULL);
|
||||
REQUIRE(ntnodep != NULL && *ntnodep == NULL);
|
||||
|
||||
dns_qpmulti_query(nametree->table, &qpr);
|
||||
result = dns_qp_getname(&qpr, name, (void **)&node, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
dns_ntnode_attach(node, ntnodep);
|
||||
}
|
||||
dns_qpread_destroy(nametree->table, &qpr);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
bool
|
||||
dns_nametree_covered(dns_nametree_t *nametree, const dns_name_t *name,
|
||||
dns_name_t *found, uint32_t bit) {
|
||||
isc_result_t result;
|
||||
dns_qpread_t qpr;
|
||||
dns_ntnode_t *node = NULL;
|
||||
bool ret = false;
|
||||
|
||||
REQUIRE(VALID_NAMETREE(nametree));
|
||||
|
||||
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;
|
||||
break;
|
||||
case DNS_NAMETREE_COUNT:
|
||||
ret = true;
|
||||
break;
|
||||
case DNS_NAMETREE_BITS:
|
||||
ret = matchbit(node->bits, bit);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dns_qpread_destroy(nametree->table, &qpr);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
qp_attach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
||||
uint32_t ival ISC_ATTR_UNUSED) {
|
||||
dns_ntnode_t *ntnode = pval;
|
||||
dns_ntnode_ref(ntnode);
|
||||
}
|
||||
|
||||
static void
|
||||
qp_detach(void *uctx ISC_ATTR_UNUSED, void *pval,
|
||||
uint32_t ival ISC_ATTR_UNUSED) {
|
||||
dns_ntnode_t *ntnode = pval;
|
||||
dns_ntnode_detach(&ntnode);
|
||||
}
|
||||
|
||||
static size_t
|
||||
qp_makekey(dns_qpkey_t key, void *uctx ISC_ATTR_UNUSED, void *pval,
|
||||
uint32_t ival ISC_ATTR_UNUSED) {
|
||||
dns_ntnode_t *ntnode = pval;
|
||||
return (dns_qpkey_fromname(key, ntnode->name));
|
||||
}
|
||||
|
||||
static void
|
||||
qp_triename(void *uctx, char *buf, size_t size) {
|
||||
dns_nametree_t *nametree = uctx;
|
||||
snprintf(buf, size, "%s nametree", nametree->name);
|
||||
}
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
#include <dns/log.h>
|
||||
#include <dns/message.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/nametree.h>
|
||||
#include <dns/ncache.h>
|
||||
#include <dns/nsec.h>
|
||||
#include <dns/nsec3.h>
|
||||
|
|
@ -561,9 +562,9 @@ struct dns_resolver {
|
|||
|
||||
uint32_t lame_ttl;
|
||||
ISC_LIST(alternate_t) alternates;
|
||||
dns_rbt_t *algorithms;
|
||||
dns_rbt_t *digests;
|
||||
dns_rbt_t *mustbesecure;
|
||||
dns_nametree_t *algorithms;
|
||||
dns_nametree_t *digests;
|
||||
dns_nametree_t *mustbesecure;
|
||||
unsigned int spillatmax;
|
||||
unsigned int spillatmin;
|
||||
isc_timer_t *spillattimer;
|
||||
|
|
@ -6751,15 +6752,8 @@ 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 (view->answeracl_exclude != NULL) {
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
||||
result = dns_rbt_findnode(view->answeracl_exclude, name, NULL,
|
||||
&node, NULL, 0, NULL, NULL);
|
||||
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
return (true);
|
||||
}
|
||||
if (dns_nametree_covered(view->answeracl_exclude, name, NULL, 0)) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -6806,7 +6800,6 @@ static bool
|
|||
is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname,
|
||||
dns_rdataset_t *rdataset, bool *chainingp) {
|
||||
isc_result_t result;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
dns_name_t *tname = NULL;
|
||||
dns_rdata_cname_t cname;
|
||||
dns_rdata_dname_t dname;
|
||||
|
|
@ -6872,12 +6865,8 @@ 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 (view->answernames_exclude != NULL) {
|
||||
result = dns_rbt_findnode(view->answernames_exclude, qname,
|
||||
NULL, &node, NULL, 0, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
return (true);
|
||||
}
|
||||
if (dns_nametree_covered(view->answernames_exclude, qname, NULL, 0)) {
|
||||
return (true);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -6896,9 +6885,7 @@ is_answertarget_allowed(fetchctx_t *fctx, dns_name_t *qname, dns_name_t *rname,
|
|||
/*
|
||||
* Otherwise, apply filters.
|
||||
*/
|
||||
result = dns_rbt_findnode(view->denyanswernames, tname, NULL, &node,
|
||||
NULL, 0, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
if (dns_nametree_covered(view->denyanswernames, tname, NULL, 0)) {
|
||||
char qnamebuf[DNS_NAME_FORMATSIZE];
|
||||
char tnamebuf[DNS_NAME_FORMATSIZE];
|
||||
char classbuf[64];
|
||||
|
|
@ -9822,13 +9809,12 @@ dns_resolver__destroy(dns_resolver_t *res) {
|
|||
|
||||
REQUIRE(atomic_load_acquire(&res->nfctx) == 0);
|
||||
|
||||
/* These must be run before zeroing the magic number */
|
||||
dns_resolver_reset_algorithms(res);
|
||||
dns_resolver_reset_ds_digests(res);
|
||||
dns_resolver_resetmustbesecure(res);
|
||||
|
||||
res->magic = 0;
|
||||
|
||||
dns_nametree_detach(&res->algorithms);
|
||||
dns_nametree_detach(&res->digests);
|
||||
dns_nametree_detach(&res->mustbesecure);
|
||||
|
||||
if (res->querystats != NULL) {
|
||||
dns_stats_detach(&res->querystats);
|
||||
}
|
||||
|
|
@ -9968,6 +9954,13 @@ dns_resolver_create(dns_view_t *view, isc_loopmgr_t *loopmgr,
|
|||
isc_mutex_init(&res->lock);
|
||||
isc_mutex_init(&res->primelock);
|
||||
|
||||
dns_nametree_create(res->mctx, DNS_NAMETREE_BITS, "algorithms",
|
||||
&res->algorithms);
|
||||
dns_nametree_create(res->mctx, DNS_NAMETREE_BITS, "ds-digests",
|
||||
&res->digests);
|
||||
dns_nametree_create(res->mctx, DNS_NAMETREE_BOOL,
|
||||
"dnssec-must-be-secure", &res->mustbesecure);
|
||||
|
||||
res->magic = RES_MAGIC;
|
||||
|
||||
*resp = res;
|
||||
|
|
@ -10730,239 +10723,59 @@ dns_resolver_printbadcache(dns_resolver_t *resolver, FILE *fp) {
|
|||
(void)dns_badcache_print(resolver->badcache, "Bad cache", fp);
|
||||
}
|
||||
|
||||
static void
|
||||
free_algorithm(void *node, void *arg) {
|
||||
unsigned char *algorithms = node;
|
||||
isc_mem_t *mctx = arg;
|
||||
|
||||
isc_mem_put(mctx, algorithms, *algorithms);
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_reset_algorithms(dns_resolver_t *resolver) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (resolver->algorithms != NULL) {
|
||||
dns_rbt_destroy(&resolver->algorithms);
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_resolver_disable_algorithm(dns_resolver_t *resolver, const dns_name_t *name,
|
||||
unsigned int alg) {
|
||||
unsigned int len, mask;
|
||||
isc_result_t result;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
unsigned char *algorithms = NULL;
|
||||
unsigned int algorithms_len;
|
||||
|
||||
/*
|
||||
* Whether an algorithm is disabled (or not) is stored in a
|
||||
* per-name bitfield that is stored as the node data of an
|
||||
* RBT.
|
||||
*/
|
||||
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (alg > 255) {
|
||||
return (ISC_R_RANGE);
|
||||
}
|
||||
|
||||
if (resolver->algorithms == NULL) {
|
||||
result = dns_rbt_create(resolver->mctx, free_algorithm,
|
||||
resolver->mctx, &resolver->algorithms);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
return (result);
|
||||
}
|
||||
return (dns_nametree_add(resolver->algorithms, name, alg));
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name,
|
||||
unsigned int digest_type) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (digest_type > 255) {
|
||||
return (ISC_R_RANGE);
|
||||
}
|
||||
|
||||
len = alg / 8 + 2;
|
||||
mask = 1 << (alg % 8);
|
||||
|
||||
result = dns_rbt_addnode(resolver->algorithms, name, &node);
|
||||
|
||||
if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* If algorithms is set, algorithms[0] contains its length. */
|
||||
algorithms = node->data;
|
||||
algorithms_len = (algorithms) ? algorithms[0] : 0;
|
||||
|
||||
if (algorithms == NULL || len > algorithms_len) {
|
||||
INSIST(len > 0);
|
||||
/*
|
||||
* If no bitfield exists in the node data, or if
|
||||
* it is not long enough, allocate a new
|
||||
* bitfield and copy the old (smaller) bitfield
|
||||
* into it if one exists.
|
||||
*/
|
||||
node->data = algorithms =
|
||||
isc_mem_creget(resolver->mctx, algorithms,
|
||||
algorithms_len, len, sizeof(char));
|
||||
/* store the new length */
|
||||
algorithms[0] = len;
|
||||
}
|
||||
|
||||
algorithms[len - 1] |= mask;
|
||||
return (ISC_R_SUCCESS);
|
||||
return (dns_nametree_add(resolver->digests, name, digest_type));
|
||||
}
|
||||
|
||||
bool
|
||||
dns_resolver_algorithm_supported(dns_resolver_t *resolver,
|
||||
const dns_name_t *name, unsigned int alg) {
|
||||
unsigned int len, mask;
|
||||
unsigned char *algorithms;
|
||||
void *data = NULL;
|
||||
isc_result_t result;
|
||||
bool found = false;
|
||||
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if ((alg == DST_ALG_DH) || (alg == DST_ALG_INDIRECT)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (resolver->algorithms == NULL) {
|
||||
goto unlock;
|
||||
}
|
||||
result = dns_rbt_findname(resolver->algorithms, name, 0, NULL, &data);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
len = alg / 8 + 2;
|
||||
mask = 1 << (alg % 8);
|
||||
algorithms = data;
|
||||
if (len <= *algorithms && (algorithms[len - 1] & mask) != 0) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
if (found) {
|
||||
if (dns_nametree_covered(resolver->algorithms, name, NULL, alg)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (dst_algorithm_supported(alg));
|
||||
}
|
||||
|
||||
static void
|
||||
free_digest(void *node, void *arg) {
|
||||
unsigned char *digests = node;
|
||||
isc_mem_t *mctx = arg;
|
||||
|
||||
isc_mem_put(mctx, digests, *digests);
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_reset_ds_digests(dns_resolver_t *resolver) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (resolver->digests != NULL) {
|
||||
dns_rbt_destroy(&resolver->digests);
|
||||
}
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
dns_resolver_disable_ds_digest(dns_resolver_t *resolver, const dns_name_t *name,
|
||||
unsigned int digest_type) {
|
||||
unsigned int len, mask;
|
||||
isc_result_t result;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
||||
/*
|
||||
* Whether a digest is disabled (or not) is stored in a per-name
|
||||
* bitfield that is stored as the node data of an RBT.
|
||||
*/
|
||||
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
if (digest_type > 255) {
|
||||
return (ISC_R_RANGE);
|
||||
}
|
||||
|
||||
if (resolver->digests == NULL) {
|
||||
result = dns_rbt_create(resolver->mctx, free_digest,
|
||||
resolver->mctx, &resolver->digests);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
len = digest_type / 8 + 2;
|
||||
mask = 1 << (digest_type % 8);
|
||||
|
||||
result = dns_rbt_addnode(resolver->digests, name, &node);
|
||||
|
||||
if (result == ISC_R_SUCCESS || result == ISC_R_EXISTS) {
|
||||
unsigned char *digests = node->data;
|
||||
/* If digests is set, digests[0] contains its length. */
|
||||
if (digests == NULL || len > *digests) {
|
||||
/*
|
||||
* If no bitfield exists in the node data, or if
|
||||
* it is not long enough, allocate a new
|
||||
* bitfield and copy the old (smaller) bitfield
|
||||
* into it if one exists.
|
||||
*/
|
||||
unsigned char *tmp = isc_mem_cget(resolver->mctx, 1,
|
||||
len);
|
||||
if (digests != NULL) {
|
||||
memmove(tmp, digests, *digests);
|
||||
}
|
||||
tmp[len - 1] |= mask;
|
||||
/* tmp[0] should contain the length of 'tmp'. */
|
||||
*tmp = len;
|
||||
node->data = tmp;
|
||||
/* Free the older bitfield. */
|
||||
if (digests != NULL) {
|
||||
isc_mem_put(resolver->mctx, digests, *digests);
|
||||
}
|
||||
} else {
|
||||
digests[len - 1] |= mask;
|
||||
}
|
||||
}
|
||||
result = ISC_R_SUCCESS;
|
||||
cleanup:
|
||||
return (result);
|
||||
}
|
||||
|
||||
bool
|
||||
dns_resolver_ds_digest_supported(dns_resolver_t *resolver,
|
||||
const dns_name_t *name,
|
||||
unsigned int digest_type) {
|
||||
unsigned int len, mask;
|
||||
unsigned char *digests;
|
||||
void *data = NULL;
|
||||
isc_result_t result;
|
||||
bool found = false;
|
||||
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (resolver->digests == NULL) {
|
||||
goto unlock;
|
||||
}
|
||||
result = dns_rbt_findname(resolver->digests, name, 0, NULL, &data);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
len = digest_type / 8 + 2;
|
||||
mask = 1 << (digest_type % 8);
|
||||
digests = data;
|
||||
if (len <= *digests && (digests[len - 1] & mask) != 0) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
if (found) {
|
||||
if (dns_nametree_covered(resolver->digests, name, NULL, digest_type)) {
|
||||
return (false);
|
||||
}
|
||||
|
||||
return (dst_ds_digest_supported(digest_type));
|
||||
}
|
||||
|
||||
void
|
||||
dns_resolver_resetmustbesecure(dns_resolver_t *resolver) {
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (resolver->mustbesecure != NULL) {
|
||||
dns_rbt_destroy(&resolver->mustbesecure);
|
||||
}
|
||||
}
|
||||
|
||||
static bool yes = true, no = false;
|
||||
|
||||
isc_result_t
|
||||
dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name,
|
||||
bool value) {
|
||||
|
|
@ -10970,36 +10783,15 @@ dns_resolver_setmustbesecure(dns_resolver_t *resolver, const dns_name_t *name,
|
|||
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (resolver->mustbesecure == NULL) {
|
||||
result = dns_rbt_create(resolver->mctx, NULL, NULL,
|
||||
&resolver->mustbesecure);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
result = dns_rbt_addname(resolver->mustbesecure, name,
|
||||
value ? &yes : &no);
|
||||
cleanup:
|
||||
result = dns_nametree_add(resolver->mustbesecure, name, value);
|
||||
return (result);
|
||||
}
|
||||
|
||||
bool
|
||||
dns_resolver_getmustbesecure(dns_resolver_t *resolver, const dns_name_t *name) {
|
||||
void *data = NULL;
|
||||
bool value = false;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(VALID_RESOLVER(resolver));
|
||||
|
||||
if (resolver->mustbesecure == NULL) {
|
||||
goto unlock;
|
||||
}
|
||||
result = dns_rbt_findname(resolver->mustbesecure, name, 0, NULL, &data);
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_PARTIALMATCH) {
|
||||
value = *(bool *)data;
|
||||
}
|
||||
unlock:
|
||||
return (value);
|
||||
return (dns_nametree_covered(resolver->mustbesecure, name, NULL, 0));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <isc/hashmap.h>
|
||||
#include <isc/list.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/netaddr.h>
|
||||
|
|
@ -22,8 +23,8 @@
|
|||
#include <isc/sockaddr.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/rbt.h>
|
||||
#include <dns/transport.h>
|
||||
|
||||
#define TRANSPORT_MAGIC ISC_MAGIC('T', 'r', 'n', 's')
|
||||
|
|
@ -37,7 +38,7 @@ struct dns_transport_list {
|
|||
isc_refcount_t references;
|
||||
isc_mem_t *mctx;
|
||||
isc_rwlock_t lock;
|
||||
dns_rbt_t *transports[DNS_TRANSPORT_COUNT];
|
||||
isc_hashmap_t *transports[DNS_TRANSPORT_COUNT];
|
||||
};
|
||||
|
||||
typedef enum ternary { ter_none = 0, ter_true = 1, ter_false = 2 } ternary_t;
|
||||
|
|
@ -47,6 +48,8 @@ struct dns_transport {
|
|||
isc_refcount_t references;
|
||||
isc_mem_t *mctx;
|
||||
dns_transport_type_t type;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name;
|
||||
struct {
|
||||
char *tlsname;
|
||||
char *certfile;
|
||||
|
|
@ -64,29 +67,20 @@ struct dns_transport {
|
|||
} doh;
|
||||
};
|
||||
|
||||
static void
|
||||
free_dns_transport(void *node, void *arg) {
|
||||
dns_transport_t *transport = node;
|
||||
|
||||
REQUIRE(node != NULL);
|
||||
|
||||
UNUSED(arg);
|
||||
|
||||
dns_transport_detach(&transport);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
list_add(dns_transport_list_t *list, const dns_name_t *name,
|
||||
const dns_transport_type_t type, dns_transport_t *transport) {
|
||||
isc_result_t result;
|
||||
dns_rbt_t *rbt = NULL;
|
||||
isc_hashmap_t *hm = NULL;
|
||||
|
||||
RWLOCK(&list->lock, isc_rwlocktype_write);
|
||||
rbt = list->transports[type];
|
||||
INSIST(rbt != NULL);
|
||||
|
||||
result = dns_rbt_addname(rbt, name, transport);
|
||||
hm = list->transports[type];
|
||||
INSIST(hm != NULL);
|
||||
|
||||
transport->name = dns_fixedname_initname(&transport->fn);
|
||||
dns_name_copy(name, transport->name);
|
||||
result = isc_hashmap_add(hm, NULL, transport->name->ndata,
|
||||
transport->name->length, transport);
|
||||
RWUNLOCK(&list->lock, isc_rwlocktype_write);
|
||||
|
||||
return (result);
|
||||
|
|
@ -629,15 +623,16 @@ dns_transport_find(const dns_transport_type_t type, const dns_name_t *name,
|
|||
dns_transport_list_t *list) {
|
||||
isc_result_t result;
|
||||
dns_transport_t *transport = NULL;
|
||||
dns_rbt_t *rbt = NULL;
|
||||
isc_hashmap_t *hm = NULL;
|
||||
|
||||
REQUIRE(VALID_TRANSPORT_LIST(list));
|
||||
REQUIRE(list->transports[type] != NULL);
|
||||
|
||||
rbt = list->transports[type];
|
||||
hm = list->transports[type];
|
||||
|
||||
RWLOCK(&list->lock, isc_rwlocktype_read);
|
||||
result = dns_rbt_findname(rbt, name, 0, NULL, (void *)&transport);
|
||||
result = isc_hashmap_find(hm, NULL, name->ndata, name->length,
|
||||
(void **)&transport);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
isc_refcount_increment(&transport->references);
|
||||
}
|
||||
|
|
@ -660,10 +655,8 @@ dns_transport_list_new(isc_mem_t *mctx) {
|
|||
list->magic = TRANSPORT_LIST_MAGIC;
|
||||
|
||||
for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) {
|
||||
isc_result_t result;
|
||||
result = dns_rbt_create(list->mctx, free_dns_transport, NULL,
|
||||
&list->transports[type]);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
isc_hashmap_create(list->mctx, 10, ISC_HASHMAP_CASE_INSENSITIVE,
|
||||
&list->transports[type]);
|
||||
}
|
||||
|
||||
return (list);
|
||||
|
|
@ -686,9 +679,24 @@ transport_list_destroy(dns_transport_list_t *list) {
|
|||
list->magic = 0;
|
||||
|
||||
for (size_t type = 0; type < DNS_TRANSPORT_COUNT; type++) {
|
||||
if (list->transports[type] != NULL) {
|
||||
dns_rbt_destroy(&list->transports[type]);
|
||||
isc_result_t result;
|
||||
isc_hashmap_iter_t *it = NULL;
|
||||
|
||||
if (list->transports[type] == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isc_hashmap_iter_create(list->transports[type], &it);
|
||||
for (result = isc_hashmap_iter_first(it);
|
||||
result == ISC_R_SUCCESS;
|
||||
result = isc_hashmap_iter_delcurrent_next(it))
|
||||
{
|
||||
dns_transport_t *transport = NULL;
|
||||
isc_hashmap_iter_current(it, (void **)&transport);
|
||||
dns_transport_detach(&transport);
|
||||
}
|
||||
isc_hashmap_iter_destroy(&it);
|
||||
isc_hashmap_destroy(&list->transports[type]);
|
||||
}
|
||||
isc_rwlock_destroy(&list->lock);
|
||||
isc_mem_putanddetach(&list->mctx, list, sizeof(*list));
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <dns/keyvalues.h>
|
||||
#include <dns/master.h>
|
||||
#include <dns/masterdump.h>
|
||||
#include <dns/nametree.h>
|
||||
#include <dns/nta.h>
|
||||
#include <dns/order.h>
|
||||
#include <dns/peer.h>
|
||||
|
|
@ -136,8 +137,6 @@ dns_view_create(isc_mem_t *mctx, dns_dispatchmgr_t *dispatchmgr,
|
|||
|
||||
isc_mutex_init(&view->lock);
|
||||
|
||||
isc_rwlock_init(&view->sfd_lock);
|
||||
|
||||
dns_zt_create(mctx, view, &view->zonetable);
|
||||
|
||||
dns_fwdtable_create(mctx, view, &view->fwdtable);
|
||||
|
|
@ -163,6 +162,8 @@ dns_view_create(isc_mem_t *mctx, dns_dispatchmgr_t *dispatchmgr,
|
|||
goto cleanup_peerlist;
|
||||
}
|
||||
|
||||
dns_nametree_create(view->mctx, DNS_NAMETREE_COUNT, "sfd", &view->sfd);
|
||||
|
||||
view->magic = DNS_VIEW_MAGIC;
|
||||
*viewp = view;
|
||||
|
||||
|
|
@ -195,7 +196,6 @@ cleanup_new_zone_lock:
|
|||
dns_fwdtable_destroy(&view->fwdtable);
|
||||
dns_zt_detach(&view->zonetable);
|
||||
|
||||
isc_rwlock_destroy(&view->sfd_lock);
|
||||
isc_mutex_destroy(&view->lock);
|
||||
|
||||
if (view->nta_file != NULL) {
|
||||
|
|
@ -348,16 +348,16 @@ destroy(dns_view_t *view) {
|
|||
dns_acl_detach(&view->pad_acl);
|
||||
}
|
||||
if (view->answeracl_exclude != NULL) {
|
||||
dns_rbt_destroy(&view->answeracl_exclude);
|
||||
dns_nametree_detach(&view->answeracl_exclude);
|
||||
}
|
||||
if (view->denyanswernames != NULL) {
|
||||
dns_rbt_destroy(&view->denyanswernames);
|
||||
dns_nametree_detach(&view->denyanswernames);
|
||||
}
|
||||
if (view->answernames_exclude != NULL) {
|
||||
dns_rbt_destroy(&view->answernames_exclude);
|
||||
dns_nametree_detach(&view->answernames_exclude);
|
||||
}
|
||||
if (view->sfd != NULL) {
|
||||
dns_rbt_destroy(&view->sfd);
|
||||
dns_nametree_detach(&view->sfd);
|
||||
}
|
||||
if (view->secroots_priv != NULL) {
|
||||
dns_keytable_detach(&view->secroots_priv);
|
||||
|
|
@ -407,7 +407,6 @@ destroy(dns_view_t *view) {
|
|||
dns_badcache_destroy(&view->failcache);
|
||||
}
|
||||
isc_mutex_destroy(&view->new_zone_lock);
|
||||
isc_rwlock_destroy(&view->sfd_lock);
|
||||
isc_mutex_destroy(&view->lock);
|
||||
isc_refcount_destroy(&view->references);
|
||||
isc_refcount_destroy(&view->weakrefs);
|
||||
|
|
@ -2317,58 +2316,21 @@ dns_view_flushonshutdown(dns_view_t *view, bool flush) {
|
|||
view->flush = flush;
|
||||
}
|
||||
|
||||
static void
|
||||
free_sfd(void *data, void *arg) {
|
||||
isc_mem_put(arg, data, sizeof(unsigned int));
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_sfd_add(dns_view_t *view, const dns_name_t *name) {
|
||||
isc_result_t result;
|
||||
dns_rbtnode_t *node = NULL;
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
RWLOCK(&view->sfd_lock, isc_rwlocktype_write);
|
||||
if (view->sfd == NULL) {
|
||||
result = dns_rbt_create(view->mctx, free_sfd, view->mctx,
|
||||
&view->sfd);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
result = dns_rbt_addnode(view->sfd, name, &node);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS || result == ISC_R_EXISTS);
|
||||
if (node->data != NULL) {
|
||||
unsigned int *count = node->data;
|
||||
(*count)++;
|
||||
} else {
|
||||
unsigned int *count = isc_mem_get(view->mctx,
|
||||
sizeof(unsigned int));
|
||||
*count = 1;
|
||||
node->data = count;
|
||||
}
|
||||
RWUNLOCK(&view->sfd_lock, isc_rwlocktype_write);
|
||||
result = dns_nametree_add(view->sfd, name, 0);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
dns_view_sfd_del(dns_view_t *view, const dns_name_t *name) {
|
||||
isc_result_t result;
|
||||
void *data = NULL;
|
||||
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
RWLOCK(&view->sfd_lock, isc_rwlocktype_write);
|
||||
INSIST(view->sfd != NULL);
|
||||
result = dns_rbt_findname(view->sfd, name, 0, NULL, &data);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
unsigned int *count = data;
|
||||
INSIST(count != NULL);
|
||||
if (--(*count) == 0U) {
|
||||
result = dns_rbt_deletename(view->sfd, name, false);
|
||||
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
||||
}
|
||||
}
|
||||
RWUNLOCK(&view->sfd_lock, isc_rwlocktype_write);
|
||||
dns_nametree_delete(view->sfd, name);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -2376,17 +2338,7 @@ dns_view_sfd_find(dns_view_t *view, const dns_name_t *name,
|
|||
dns_name_t *foundname) {
|
||||
REQUIRE(DNS_VIEW_VALID(view));
|
||||
|
||||
if (view->sfd != NULL) {
|
||||
isc_result_t result;
|
||||
void *data = NULL;
|
||||
|
||||
RWLOCK(&view->sfd_lock, isc_rwlocktype_read);
|
||||
result = dns_rbt_findname(view->sfd, name, 0, foundname, &data);
|
||||
RWUNLOCK(&view->sfd_lock, isc_rwlocktype_read);
|
||||
if (result != ISC_R_SUCCESS && result != DNS_R_PARTIALMATCH) {
|
||||
dns_name_copy(dns_rootname, foundname);
|
||||
}
|
||||
} else {
|
||||
if (!dns_nametree_covered(view->sfd, name, foundname, 0)) {
|
||||
dns_name_copy(dns_rootname, foundname);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ check_PROGRAMS = \
|
|||
dst_test \
|
||||
keytable_test \
|
||||
name_test \
|
||||
nametree_test \
|
||||
nsec3_test \
|
||||
nsec3param_test \
|
||||
private_test \
|
||||
|
|
|
|||
330
tests/dns/nametree_test.c
Normal file
330
tests/dns/nametree_test.c
Normal file
|
|
@ -0,0 +1,330 @@
|
|||
/*
|
||||
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
*
|
||||
* SPDX-License-Identifier: MPL-2.0
|
||||
*
|
||||
* 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 https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See the COPYRIGHT file distributed with this work for additional
|
||||
* information regarding copyright ownership.
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sched.h> /* IWYU pragma: keep */
|
||||
#include <setjmp.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define UNIT_TESTING
|
||||
#include <cmocka.h>
|
||||
|
||||
#include <isc/base64.h>
|
||||
#include <isc/buffer.h>
|
||||
#include <isc/md.h>
|
||||
#include <isc/util.h>
|
||||
|
||||
#include <dns/fixedname.h>
|
||||
#include <dns/name.h>
|
||||
#include <dns/nametree.h>
|
||||
|
||||
#include <dst/dst.h>
|
||||
|
||||
#include <tests/dns.h>
|
||||
|
||||
dns_nametree_t *booltree = NULL;
|
||||
dns_nametree_t *bitstree = NULL;
|
||||
dns_nametree_t *counttree = NULL;
|
||||
|
||||
/*
|
||||
* Test utilities. In general, these assume input parameters are valid
|
||||
* (checking with assert_int_equal, thus aborting if not) and unlikely run time
|
||||
* errors (such as memory allocation failure) won't happen. This helps keep
|
||||
* the test code concise.
|
||||
*/
|
||||
|
||||
/* 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);
|
||||
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_BOOL, "bool test", &booltree);
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_BITS, "bits test", &bitstree);
|
||||
dns_nametree_create(mctx, DNS_NAMETREE_COUNT, "count test", &counttree);
|
||||
|
||||
/* Add a positive boolean node */
|
||||
dns_test_namefromstring("example.com.", &fn);
|
||||
assert_int_equal(dns_nametree_add(booltree, name, true), ISC_R_SUCCESS);
|
||||
|
||||
/* 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(booltree, name, false),
|
||||
ISC_R_SUCCESS);
|
||||
dns_test_namefromstring("negative.example.org.", &fn);
|
||||
assert_int_equal(dns_nametree_add(booltree, name, false),
|
||||
ISC_R_SUCCESS);
|
||||
|
||||
/* 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 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) {
|
||||
dns_ntnode_t *node = NULL;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_name(&fn);
|
||||
|
||||
/*
|
||||
* 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 fail.
|
||||
*/
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(add_bits) {
|
||||
dns_ntnode_t *node = NULL;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_name(&fn);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(add_count) {
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_name(&fn);
|
||||
|
||||
/* add a counter node five times */
|
||||
dns_test_namefromstring("example.com.", &fn);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_add(counttree, name, 0), ISC_R_SUCCESS);
|
||||
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, NULL, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
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, NULL, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
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, NULL, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_SUCCESS);
|
||||
|
||||
assert_false(dns_nametree_covered(counttree, name, NULL, 0));
|
||||
assert_int_equal(dns_nametree_delete(counttree, name), ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(covered_bool) {
|
||||
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 };
|
||||
|
||||
for (const char **n = yesnames; *n != NULL; n++) {
|
||||
dns_test_namefromstring(*n, &fn);
|
||||
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, NULL, 0));
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
||||
/* check existing bit values */
|
||||
dns_test_namefromstring("example.com.", &fn);
|
||||
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, 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, 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, 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, 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, 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);
|
||||
|
||||
/* name doesn't match */
|
||||
dns_test_namefromstring("example.org.", &fn);
|
||||
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(booltree, name), ISC_R_NOTFOUND);
|
||||
|
||||
/*
|
||||
* delete requires exact match: this should return SUCCESS on
|
||||
* the first try, then NOTFOUND on the second even though an
|
||||
* ancestor does exist.
|
||||
*/
|
||||
dns_test_namefromstring("negative.example.com.", &fn);
|
||||
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(booltree, name), ISC_R_SUCCESS);
|
||||
assert_int_equal(dns_nametree_delete(booltree, name), ISC_R_NOTFOUND);
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(find) {
|
||||
dns_ntnode_t *node = NULL;
|
||||
dns_fixedname_t fn;
|
||||
dns_name_t *name = dns_fixedname_name(&fn);
|
||||
|
||||
/*
|
||||
* dns_nametree_find() requires exact name match. It matches node
|
||||
* that has a null key, too.
|
||||
*/
|
||||
dns_test_namefromstring("example.org.", &fn);
|
||||
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(booltree, name, &node),
|
||||
ISC_R_NOTFOUND);
|
||||
dns_test_namefromstring("example.com.", &fn);
|
||||
assert_int_equal(dns_nametree_find(booltree, name, &node),
|
||||
ISC_R_SUCCESS);
|
||||
dns_ntnode_detach(&node);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
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
|
||||
Loading…
Reference in a new issue