diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 721ac5e60a..5d78999941 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -144,6 +144,8 @@ struct dns_view { dns_rbt_t *denyanswernames; dns_rbt_t *answernames_exclude; dns_rrl_t *rrl; + dns_rbt_t *sfd; + isc_rwlock_t sfd_lock; bool provideixfr; bool requestnsid; bool sendcookie; @@ -1282,4 +1284,41 @@ dns_view_flushonshutdown(dns_view_t *view, bool flush); * Requires: *\li 'view' to be valid. */ + +void +dns_view_sfd_add(dns_view_t *view, const dns_name_t *name); +/*%< + * Add 'name' to the synth-from-dnssec namespace tree for the + * view. If the tree does not already exist create it. + * + * Requires: + *\li 'view' to be valid. + *\li 'name' to be valid. + */ + +void +dns_view_sfd_del(dns_view_t *view, const dns_name_t *name); +/*%< + * Delete 'name' to the synth-from-dnssec namespace tree for + * the view when the count of previous adds and deletes becomes + * zero. + * + * Requires: + *\li 'view' to be valid. + *\li 'name' to be valid. + */ + +void +dns_view_sfd_find(dns_view_t *view, const dns_name_t *name, + dns_name_t *foundname); +/*%< + * Find the enclosing name to the synth-from-dnssec namespace tree for 'name' + * in the specified view. + * + * Requires: + *\li 'view' to be valid. + *\li 'name' to be valid. + *\li 'foundname' to be valid with a buffer sufficient to hold the name. + */ + ISC_LANG_ENDDECLS diff --git a/lib/dns/view.c b/lib/dns/view.c index 1669cd18a8..4200eeb8c5 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -127,6 +127,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, const char *name, isc_mutex_init(&view->lock); + isc_rwlock_init(&view->sfd_lock, 0, 0); + view->zonetable = NULL; result = dns_zt_create(mctx, rdclass, &view->zonetable); if (result != ISC_R_SUCCESS) { @@ -215,6 +217,7 @@ cleanup_zt: } cleanup_mutex: + isc_rwlock_destroy(&view->sfd_lock); isc_mutex_destroy(&view->lock); if (view->nta_file != NULL) { @@ -381,6 +384,9 @@ destroy(dns_view_t *view) { if (view->answernames_exclude != NULL) { dns_rbt_destroy(&view->answernames_exclude); } + if (view->sfd != NULL) { + dns_rbt_destroy(&view->sfd); + } if (view->delonly != NULL) { dns_name_t *name; int i; @@ -464,6 +470,7 @@ 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); @@ -2334,3 +2341,77 @@ 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); +} + +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); +} + +void +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 { + dns_name_copy(dns_rootname, foundname); + } +}