From: Evan Hunt Date: Sat, 11 Aug 2018 02:32:12 +0000 (-0700) Subject: initial implementation of filter-aaaa.so as a shared object X-Git-Tag: v9.13.5~7^2~20 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d3f0f71b6b6fbe60753a67e245cfa9238a265859;p=thirdparty%2Fbind9.git initial implementation of filter-aaaa.so as a shared object - temporary kluge! in this version, for testing purposes, named always searches for a filter-aaaa module at /tmp/filter-aaaa.so. this enables the filter-aaaa system test to run even though the code to configure hooks in named.conf hasn't been written yet. - filter-aaaa-on-v4, filter-aaaa-on-v6 and the filter-aaaa ACL are still configured in the view as they were before, not in the hook. --- diff --git a/bin/named/server.c b/bin/named/server.c index c453396dd07..37282e9e09a 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -3716,6 +3716,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, bool old_rpz_ok = false; isc_dscp_t dscp4 = -1, dscp6 = -1; dns_dyndbctx_t *dctx = NULL; + ns_hookctx_t *hctx = NULL; unsigned int resolver_param; dns_ntatable_t *ntatable = NULL; const char *qminmode = NULL; @@ -5293,6 +5294,21 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, CHECK(configure_dyndb(dyndb, mctx, dctx)); } + + /* + * XXX: + * temporary! this forces loading of filter-aaaa.so from the + * current working directory, if present. later this will + * happen via configuration as dyndb does above. we don't + * bother checking whether it succeeded; if it doesn't, + * filter-aaaa simply won't work. + */ + if (hctx == NULL) { + CHECK(ns_hook_createctx(mctx, &hctx)); + } + ns_hooktable_init(NULL); + (void) ns_hookmodule_load("/tmp/filter-aaaa.so", "", "", 0, + hctx, NULL); #endif /* @@ -5546,6 +5562,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, if (dctx != NULL) { dns_dyndb_destroyctx(&dctx); } + if (hctx != NULL) { + ns_hook_destroyctx(&hctx); + } return (result); } @@ -8028,7 +8047,7 @@ load_configuration(const char *filename, named_server_t *server, CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx)); /* - * Shut down all dyndb instances. + * Shut down all dyndb and hook module instances. */ dns_dyndb_cleanup(false); ns_hookmodule_cleanup(); @@ -9512,6 +9531,9 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { dns_view_detach(&view); } + /* + * Shut down all dyndb and hook module instances. + */ dns_dyndb_cleanup(true); ns_hookmodule_cleanup(); diff --git a/configure b/configure index 5031db85a3e..bbca641c1b6 100755 --- a/configure +++ b/configure @@ -20240,8 +20240,8 @@ if test "$with_dlopen" = "yes"; then : case $host in #( *-linux*|*-gnu*) : + LDFLAGS="${LDFLAGS} -Wl,--export-dynamic" SO_CFLAGS="-fPIC" - LDFLAGS="${LDFLAGS} -Wl,--export-dynamic" SO_LDFLAGS="" if test "$use_libtool" = "yes"; then : diff --git a/configure.ac b/configure.ac index d831bae619e..af7f90cead8 100644 --- a/configure.ac +++ b/configure.ac @@ -2638,8 +2638,8 @@ AS_CASE([$with_dlopen], AS_IF([test "$with_dlopen" = "yes"], [AS_CASE([$host], [*-linux*|*-gnu*],[ + LDFLAGS="${LDFLAGS} -Wl,--export-dynamic" SO_CFLAGS="-fPIC" - LDFLAGS="${LDFLAGS} -Wl,--export-dynamic" SO_LDFLAGS="" AS_IF([test "$use_libtool" = "yes"],[ SO_LDFLAGS="-Xcompiler -shared" diff --git a/lib/ns/Makefile.in b/lib/ns/Makefile.in index 2e6c0183da7..ede65f8674d 100644 --- a/lib/ns/Makefile.in +++ b/lib/ns/Makefile.in @@ -53,8 +53,12 @@ SRCS = client.c hooks.c interfacemgr.c lib.c listenlist.c \ update.c version.c xfrout.c SUBDIRS = include -TARGETS = timestamp TESTDIRS = @UNITTESTS@ +SO_TARGETS = filter-aaaa.@SO@ +TARGETS = timestamp @SO_TARGETS@ + +SO_CFLAGS = @CFLAGS@ @SO_CFLAGS@ +SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ @BIND9_MAKE_RULES@ @@ -80,6 +84,14 @@ libns.la: ${OBJS} timestamp: libns.@A@ touch timestamp +filter-aaaa.@O@: filter-aaaa.c + ${LIBTOOL_MODE_COMPILE} ${CC} ${ALL_CFLAGS} ${SO_CFLAGS} \ + -c ${srcdir}/filter-aaaa.c + +filter-aaaa.@SO@: filter-aaaa.o libns.@A@ + ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ filter-aaaa.o \ + ${ISCLIBS} ${DNSLIBS} libns.@A@ ${ISCLIBS} @DNS_CRYPTO_LIBS@ ${DNSLIBS} ${LIBS} + installdirs: $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} @@ -91,4 +103,4 @@ uninstall:: ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/libns.@A@ clean distclean:: - rm -f libns.@A@ timestamp + rm -f libns.@A@ timestamp filter-aaaa.@O@ filter-aaaa.@SO@ diff --git a/lib/ns/filter-aaaa.c b/lib/ns/filter-aaaa.c new file mode 100644 index 00000000000..a0e8141fcf0 --- /dev/null +++ b/lib/ns/filter-aaaa.c @@ -0,0 +1,447 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * 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 http://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +/*! \file */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +ns_hook_destroy_t hook_destroy; +ns_hook_register_t hook_register; +ns_hook_version_t hook_version; + +/* + * Per-client flags set by this module + */ +#define FILTER_AAAA_RECURSING 0x0001 /* Recursing for A */ +#define FILTER_AAAA_FILTERED 0x0002 /* AAAA was removed from answer */ + + +/*% Want DNSSEC? */ +#define WANTDNSSEC(c) (((c)->attributes & \ + NS_CLIENTATTR_WANTDNSSEC) != 0) +/*% Recursion OK? */ +#define RECURSIONOK(c) (((c)->query.attributes & \ + NS_QUERYATTR_RECURSIONOK) != 0) + +static bool +filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp); + +static bool +filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp); + +static bool +filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp); + +static bool +filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp); + +ns_hook_t filter_respbegin = { + .callback = filter_respond_begin, +}; +ns_hook_t filter_respanyfound = { + .callback = filter_respond_any_found, +}; +ns_hook_t filter_prepresp = { + .callback = filter_prep_response_begin, +}; +ns_hook_t filter_donesend = { + .callback = filter_query_done_send, +}; + +isc_result_t +hook_register(const char *parameters, const char *file, unsigned long line, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp) +{ + UNUSED(parameters); + UNUSED(instp); + + isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "loading params for 'filter-aaaa' module from %s:%lu", + file, line); + + /* + * TODO: + * configure with parameters here + */ + + ns_hook_add(hooktable, NS_QUERY_RESPOND_BEGIN, + &filter_respbegin); + ns_hook_add(hooktable, NS_QUERY_RESPOND_ANY_FOUND, + &filter_respanyfound); + ns_hook_add(hooktable, NS_QUERY_PREP_RESPONSE_BEGIN, + &filter_prepresp); + ns_hook_add(hooktable, NS_QUERY_DONE_SEND, + &filter_donesend); + + /* + * TODO: + * Set up a serial number that can be used for accessing + * data blobs in qctx, client, view; + * return an instance pointer for later destruction + */ + return (ISC_R_SUCCESS); +} + +void +hook_destroy(void **instp) { + UNUSED(instp); + + return; +} + +int +hook_version(unsigned int *flags) { + UNUSED(flags); + + return (NS_HOOK_VERSION); +} + +/* + * Check whether this is a V4 client. + */ +static bool +is_v4_client(ns_client_t *client) { + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET) { + return (true); + } + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) + { + return (true); + } + return (false); +} + +/* + * Check whether this is a V6 client. + */ +static bool +is_v6_client(ns_client_t *client) { + if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && + !IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) + { + return (true); + } + return (false); +} + +/* + * The filter-aaaa-on-v4 option suppresses AAAAs for IPv4 + * clients if there is an A; filter-aaaa-on-v6 option does + * the same for IPv6 clients. + */ +static bool +filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) hookdata; + isc_result_t result; + + UNUSED(cbdata); + + qctx->filter_aaaa = dns_aaaa_ok; + if (qctx->client->view->v4_aaaa != dns_aaaa_ok || + qctx->client->view->v6_aaaa != dns_aaaa_ok) + { + result = ns_client_checkaclsilent(qctx->client, NULL, + qctx->client->view->aaaa_acl, + true); + if (result == ISC_R_SUCCESS && + qctx->client->view->v4_aaaa != dns_aaaa_ok && + is_v4_client(qctx->client)) + { + qctx->filter_aaaa = qctx->client->view->v4_aaaa; + } else if (result == ISC_R_SUCCESS && + qctx->client->view->v6_aaaa != dns_aaaa_ok && + is_v6_client(qctx->client)) + { + qctx->filter_aaaa = qctx->client->view->v6_aaaa; + } + } + + *resp = ISC_R_UNSET; + return (false); +} + +/* + * Optionally hide AAAA rrsets if there is a matching A. + * (This version is for processing answers to explicit AAAA + * queries; ANY queries are handled in query_filter_aaaa_any().) + */ +static bool +filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) hookdata; + isc_result_t result = ISC_R_UNSET; + + UNUSED(cbdata); + + if (qctx->filter_aaaa != dns_aaaa_break_dnssec && + (qctx->filter_aaaa != dns_aaaa_filter || + (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && + dns_rdataset_isassociated(qctx->sigrdataset)))) + { + *resp = result; + return (false); + } + + if (qctx->qtype == dns_rdatatype_aaaa) { + dns_rdataset_t *trdataset; + trdataset = ns_client_newrdataset(qctx->client); + result = dns_db_findrdataset(qctx->db, qctx->node, + qctx->version, + dns_rdatatype_a, 0, + qctx->client->now, + trdataset, NULL); + if (dns_rdataset_isassociated(trdataset)) { + dns_rdataset_disassociate(trdataset); + } + ns_client_putrdataset(qctx->client, &trdataset); + + /* + * We found an AAAA. If we also found an A, then the AAAA + * must not be rendered. + * + * If the A is not in our cache, then any result other than + * DNS_R_DELEGATION or ISC_R_NOTFOUND means there is no A, + * and so AAAAs are okay. + * + * We assume there is no A if we can't recurse for this + * client. That might be the wrong answer, but what else + * can we do? Besides, the fact that we have the AAAA and + * are using this mechanism in the first place suggests + * that we care more about As than AAAAs, and would have + * cached an A if it existed. + */ + if (result == ISC_R_SUCCESS) { + qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED; + if (qctx->sigrdataset != NULL && + dns_rdataset_isassociated(qctx->sigrdataset)) + { + qctx->sigrdataset->attributes |= + DNS_RDATASETATTR_RENDERED; + } + qctx->client->hookflags |= FILTER_AAAA_FILTERED; + } else if (!qctx->authoritative && + RECURSIONOK(qctx->client) && + (result == DNS_R_DELEGATION || + result == ISC_R_NOTFOUND)) + { + /* + * This is an ugly kludge to recurse + * for the A and discard the result. + * + * Continue to add the AAAA now. + * We'll make a note to not render it + * if the recursion for the A succeeds. + */ + result = ns_query_recurse(qctx->client, + dns_rdatatype_a, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); + if (result == ISC_R_SUCCESS) { + qctx->client->hookflags |= + FILTER_AAAA_RECURSING; + qctx->client->query.attributes |= + NS_QUERYATTR_RECURSING; + } + } + } else if (qctx->qtype == dns_rdatatype_a && + ((qctx->client->hookflags & FILTER_AAAA_RECURSING) != 0)) + { + + dns_rdataset_t *mrdataset = NULL; + dns_rdataset_t *sigrdataset = NULL; + + result = dns_message_findname(qctx->client->message, + DNS_SECTION_ANSWER, qctx->fname, + dns_rdatatype_aaaa, 0, + NULL, &mrdataset); + if (result == ISC_R_SUCCESS) { + mrdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } + + result = dns_message_findname(qctx->client->message, + DNS_SECTION_ANSWER, qctx->fname, + dns_rdatatype_rrsig, + dns_rdatatype_aaaa, + NULL, &sigrdataset); + if (result == ISC_R_SUCCESS) { + sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } + + qctx->client->hookflags &= ~FILTER_AAAA_RECURSING; + + result = ns_query_done(qctx); + + *resp = result; + return (true); + + } + + *resp = result; + return (false); +} + +static bool +filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) hookdata; + dns_name_t *name = NULL; + dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; + dns_rdataset_t *a = NULL; + bool have_a = true; + + UNUSED(cbdata); + + if (qctx->filter_aaaa == dns_aaaa_ok) { + *resp = ISC_R_UNSET; + return (false); + } + + dns_message_findname(qctx->client->message, DNS_SECTION_ANSWER, + (qctx->fname != NULL) + ? qctx->fname + : qctx->tname, + dns_rdatatype_any, 0, &name, NULL); + + /* + * If we're not authoritative, just assume there's an + * A even if it wasn't in the cache and therefore isn't + * in the message. But if we're authoritative, then + * if there was an A, it should be here. + */ + if (qctx->authoritative && name != NULL) { + dns_message_findtype(name, dns_rdatatype_a, 0, &a); + if (a == NULL) { + have_a = false; + } + } + + if (name != NULL) { + dns_message_findtype(name, dns_rdatatype_aaaa, 0, &aaaa); + dns_message_findtype(name, dns_rdatatype_rrsig, + dns_rdatatype_aaaa, &aaaa_sig); + } + + if (have_a && aaaa != NULL && + (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || + qctx->filter_aaaa == dns_aaaa_break_dnssec)) + { + aaaa->attributes |= DNS_RDATASETATTR_RENDERED; + if (aaaa_sig != NULL) { + aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED; + } + } + + *resp = ISC_R_UNSET; + return (false); +} + +/* + * Hide AAAA rrsets in the additional section if there is a matching A, + * and hide NS in the additional section if AAAA was filtered in the answer + * section. + */ +static bool +filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) hookdata; + isc_result_t result; + + UNUSED(cbdata); + + if (qctx->filter_aaaa == dns_aaaa_ok) { + *resp = ISC_R_UNSET; + return (false); + } + + result = dns_message_firstname(qctx->client->message, + DNS_SECTION_ADDITIONAL); + while (result == ISC_R_SUCCESS) { + dns_name_t *name = NULL; + dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; + dns_rdataset_t *a = NULL; + + dns_message_currentname(qctx->client->message, + DNS_SECTION_ADDITIONAL, + &name); + + result = dns_message_nextname(qctx->client->message, + DNS_SECTION_ADDITIONAL); + + dns_message_findtype(name, dns_rdatatype_a, 0, &a); + if (a == NULL) { + continue; + } + + dns_message_findtype(name, dns_rdatatype_aaaa, 0, + &aaaa); + if (aaaa == NULL) { + continue; + } + + dns_message_findtype(name, dns_rdatatype_rrsig, + dns_rdatatype_aaaa, &aaaa_sig); + + if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || + qctx->filter_aaaa == dns_aaaa_break_dnssec) + { + aaaa->attributes |= DNS_RDATASETATTR_RENDERED; + if (aaaa_sig != NULL) { + aaaa_sig->attributes |= + DNS_RDATASETATTR_RENDERED; + } + } + } + + if ((qctx->client->hookflags & FILTER_AAAA_FILTERED) != 0) { + result = dns_message_firstname(qctx->client->message, + DNS_SECTION_AUTHORITY); + while (result == ISC_R_SUCCESS) { + dns_name_t *name = NULL; + dns_rdataset_t *ns = NULL, *ns_sig = NULL; + + dns_message_currentname(qctx->client->message, + DNS_SECTION_AUTHORITY, + &name); + + result = dns_message_findtype(name, dns_rdatatype_ns, + 0, &ns); + if (result == ISC_R_SUCCESS) { + ns->attributes |= DNS_RDATASETATTR_RENDERED; + } + + result = dns_message_findtype(name, dns_rdatatype_rrsig, + dns_rdatatype_ns, + &ns_sig); + if (result == ISC_R_SUCCESS) { + ns_sig->attributes |= DNS_RDATASETATTR_RENDERED; + } + + result = dns_message_nextname(qctx->client->message, + DNS_SECTION_AUTHORITY); + } + } + + *resp = ISC_R_UNSET; + return (false); +} diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 4b97c5b3d5f..66438f6604f 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -42,7 +42,6 @@ struct ns_hook_module { char *filename; ns_hook_register_t *register_func; ns_hook_destroy_t *destroy_func; - char *name; void *inst; LINK(ns_hook_module_t) link; }; @@ -108,11 +107,6 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { REQUIRE(hmodp != NULL && *hmodp == NULL); - isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "loading module '%s'", - filename); - flags = RTLD_NOW|RTLD_LOCAL; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; @@ -140,16 +134,12 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, filename, "hook_init", + CHECK(load_symbol(handle, filename, "hook_register", (void **)®ister_func)); CHECK(load_symbol(handle, filename, "hook_destroy", (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); - if (hmod == NULL) { - CHECK(ISC_R_NOMEMORY); - } - hmod->mctx = NULL; isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; @@ -200,7 +190,7 @@ unload_library(ns_hook_module_t **hmodp) { isc_mem_free(hmod->mctx, hmod->filename); } - isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(ns_hook_module_t)); + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); } #elif _WIN32 static isc_result_t @@ -240,10 +230,6 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { REQUIRE(hmodp != NULL && *hmodp == NULL); - isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "loading module '%s'", filename); - handle = LoadLibraryA(filename); if (handle == NULL) { CHECK(ISC_R_FAILURE); @@ -263,16 +249,12 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, filename, "hook_init", + CHECK(load_symbol(handle, filename, "hook_register", (void **)®ister_func)); CHECK(load_symbol(handle, filename, "hook_destroy", (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); - if (hmod == NULL) { - CHECK(ISC_R_NOMEMORY); - } - hmod->mctx = NULL; isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; @@ -347,21 +329,25 @@ unload_library(ns_hook_module_t **hmodp) { isc_result_t ns_hookmodule_load(const char *libname, const char *parameters, - const char *file, unsigned long line, isc_mem_t *mctx) + const char *file, unsigned long line, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable) { isc_result_t result; ns_hook_module_t *module = NULL; - RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); + if (hooktable == NULL) { + hooktable = ns__hook_table; + } + + REQUIRE(NS_HOOKCTX_VALID(hctx)); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, "loading module '%s'", libname); - CHECK(load_library(mctx, libname, &module)); - CHECK(module->register_func(mctx, parameters, file, line, - &module->inst)); - + CHECK(load_library(hctx->mctx, libname, &module)); + CHECK(module->register_func(parameters, file, line, hctx, + hooktable, &module->inst)); APPEND(hook_modules, module, link); result = ISC_R_SUCCESS; @@ -386,7 +372,7 @@ ns_hookmodule_cleanup(void) { UNLINK(hook_modules, hmod, link); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "unloading module '%s'", hmod->name); + "unloading module '%s'", hmod->filename); hmod->destroy_func(&hmod->inst); ENSURE(hmod->inst == NULL); unload_library(&hmod); @@ -394,6 +380,40 @@ ns_hookmodule_cleanup(void) { } } +isc_result_t +ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { + ns_hookctx_t *hctx; + + REQUIRE(hctxp != NULL && *hctxp == NULL); + + hctx = isc_mem_get(mctx, sizeof(*hctx)); + memset(hctx, 0, sizeof(*hctx)); + hctx->lctx = ns_lctx; + + isc_mem_attach(mctx, &hctx->mctx); + hctx->magic = NS_HOOKCTX_MAGIC; + + *hctxp = hctx; + + return (ISC_R_SUCCESS); +} + +void +ns_hook_destroyctx(ns_hookctx_t **hctxp) { + ns_hookctx_t *hctx; + + REQUIRE(hctxp != NULL && NS_HOOKCTX_VALID(*hctxp)); + + hctx = *hctxp; + *hctxp = NULL; + + hctx->magic = 0; + + hctx->lctx = NULL; + + isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx)); +} + void ns_hooktable_init(ns_hooktable_t *hooktable) { int i; diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index aa6d8d1548b..3001661a43c 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -17,8 +17,13 @@ #include #include +#include #include +#include + +#include +#include /* * Hooks provide a way of running a callback function once a certain place in * code is reached. Current use is limited to libns unit tests and thus: @@ -185,6 +190,38 @@ typedef enum { typedef bool (*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp); +typedef struct ns_hook { + ns_hook_cb_t callback; + void *callback_data; + ISC_LINK(struct ns_hook) link; +} ns_hook_t; + +/* + * ns__hook_table is a globally visible pointer to the active hook + * table. It's initialized to point to 'hooktab', which is the default + * global hook table. + */ +typedef ISC_LIST(ns_hook_t) ns_hooklist_t; +typedef ns_hooklist_t ns_hooktable_t[NS_QUERY_HOOKS_COUNT]; +LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; + +/*! + * Context for intializing a hook module. + * + * This structure passes data to which a hook module will need + * access -- server memory context, hash initializer, log context, etc. + * The structure doesn't persist beyond configuring the hook module. + * The module's register function should attach to all reference-counted + * variables and its destroy function should detach from them. + */ +typedef struct ns_hookctx { + unsigned int magic; + isc_mem_t *mctx; + isc_log_t *lctx; +} ns_hookctx_t; + +#define NS_HOOKCTX_MAGIC ISC_MAGIC('H', 'k', 'c', 'x') +#define NS_HOOKCTX_VALID(d) ISC_MAGIC_VALID(d, NS_HOOKCTX_MAGIC) /* * API version * @@ -198,10 +235,11 @@ typedef bool #define NS_HOOK_AGE 0 #endif -typedef isc_result_t ns_hook_register_t(isc_mem_t *mctx, - const char *parameters, +typedef isc_result_t ns_hook_register_t(const char *parameters, const char *file, unsigned long line, + ns_hookctx_t *hctx, + ns_hooktable_t *hooktable, void **instp); /*% * Called when registering a new module. @@ -236,21 +274,6 @@ typedef int ns_hook_version_t(unsigned int *flags); * the future to pass back driver capabilities or other information. */ -typedef struct ns_hook { - ns_hook_cb_t callback; - void *callback_data; - ISC_LINK(struct ns_hook) link; -} ns_hook_t; - -/* - * ns__hook_table is a globally visible pointer to the active hook - * table. It's initialized to point to 'hooktab', which is the default - * global hook table. - */ -typedef ISC_LIST(ns_hook_t) ns_hooklist_t; -typedef ns_hooklist_t ns_hooktable_t[NS_QUERY_HOOKS_COUNT]; -LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; - /* * Run a hook. Calls the function or functions registered at hookpoint 'id'. * If one of them returns true, we interrupt processing and return the @@ -280,9 +303,16 @@ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; #define NS_PROCESS_HOOK_VOID(table, id, data) \ _NS_PROCESS_HOOK(table, id, data) +isc_result_t +ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp); + +void +ns_hook_destroyctx(ns_hookctx_t **hctxp); + isc_result_t ns_hookmodule_load(const char *libname, const char *parameters, - const char *file, unsigned long line, isc_mem_t *mctx); + const char *file, unsigned long line, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable); void ns_hookmodule_cleanup(void); diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index ad59b2b48c2..853c7e5a90f 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -98,27 +98,28 @@ struct ns_query { bool root_key_sentinel_not_ta; }; -#define NS_QUERYATTR_RECURSIONOK 0x0001 -#define NS_QUERYATTR_CACHEOK 0x0002 -#define NS_QUERYATTR_PARTIALANSWER 0x0004 -#define NS_QUERYATTR_NAMEBUFUSED 0x0008 -#define NS_QUERYATTR_RECURSING 0x0010 -#define NS_QUERYATTR_QUERYOKVALID 0x0040 -#define NS_QUERYATTR_QUERYOK 0x0080 -#define NS_QUERYATTR_WANTRECURSION 0x0100 -#define NS_QUERYATTR_SECURE 0x0200 -#define NS_QUERYATTR_NOAUTHORITY 0x0400 -#define NS_QUERYATTR_NOADDITIONAL 0x0800 -#define NS_QUERYATTR_CACHEACLOKVALID 0x1000 -#define NS_QUERYATTR_CACHEACLOK 0x2000 -#define NS_QUERYATTR_DNS64 0x4000 -#define NS_QUERYATTR_DNS64EXCLUDE 0x8000 +#define NS_QUERYATTR_RECURSIONOK 0x00001 +#define NS_QUERYATTR_CACHEOK 0x00002 +#define NS_QUERYATTR_PARTIALANSWER 0x00004 +#define NS_QUERYATTR_NAMEBUFUSED 0x00008 +#define NS_QUERYATTR_RECURSING 0x00010 +#define NS_QUERYATTR_QUERYOKVALID 0x00040 +#define NS_QUERYATTR_QUERYOK 0x00080 +#define NS_QUERYATTR_WANTRECURSION 0x00100 +#define NS_QUERYATTR_SECURE 0x00200 +#define NS_QUERYATTR_NOAUTHORITY 0x00400 +#define NS_QUERYATTR_NOADDITIONAL 0x00800 +#define NS_QUERYATTR_CACHEACLOKVALID 0x01000 +#define NS_QUERYATTR_CACHEACLOK 0x02000 +#define NS_QUERYATTR_DNS64 0x04000 +#define NS_QUERYATTR_DNS64EXCLUDE 0x08000 #define NS_QUERYATTR_RRL_CHECKED 0x10000 #define NS_QUERYATTR_REDIRECT 0x20000 -/* query context structure */ +typedef struct query_ctx query_ctx_t; -typedef struct query_ctx { +/* query context structure */ +struct query_ctx { isc_buffer_t *dbuf; /* name buffer */ dns_name_t *fname; /* found name from DB lookup */ dns_name_t *tname; /* temporary name, used @@ -169,7 +170,7 @@ typedef struct query_ctx { isc_result_t result; /* query result */ int line; /* line to report error */ -} query_ctx_t; +}; /* * The following functions are expected to be used only within query.c @@ -212,24 +213,53 @@ ns_query_start(ns_client_t *client); void ns_query_cancel(ns_client_t *client); -/*% - * (Must not be used outside this module and its associated unit tests.) +/* + * The following functions are expected to be used only within query.c + * and query modules. */ + isc_result_t -ns__query_sfcache(query_ctx_t *qctx); +ns_query_done(query_ctx_t *qctx); +/*%< + * Finalize this phase of the query process: + * + * - Clean up. + * - If we have an answer ready (positive or negative), send it. + * - If we need to restart for a chaining query, call ns__query_start() again. + * - If we've started recursion, then just clean up; things will be + * restarted via fetch_callback()/query_resume(). + */ + +isc_result_t +ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, + dns_name_t *qdomain, dns_rdataset_t *nameservers, + bool resuming); +/*%< + * Prepare client for recursion, then create a resolver fetch, with + * the event callback set to fetch_callback(). Afterward we terminate + * this phase of the query, and resume with a new query context when + * recursion completes. + */ + +isc_result_t +ns__query_sfcache(query_ctx_t *qctx); /*% * (Must not be used outside this module and its associated unit tests.) */ + isc_result_t ns__query_start(query_ctx_t *qctx); +/*% + * (Must not be used outside this module and its associated unit tests.) + */ +void +ns__query_inithooks(void); /* * XXX: * Temporary function used to initialize the filter-aaaa hooks, * which are currently hard-coded rather than loaded as a module. */ -void -ns__query_inithooks(void); #endif /* NS_QUERY_H */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 104ef4d7cf7..93e1d8fdf44 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -420,47 +420,6 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata); static void query_addauth(query_ctx_t *qctx); -/* - * XXX: - * This is a temporary hooks table, pre-populated with functions - * implementing filter-aaaa. Later, this will be redesigned to be set up at - * initialization time when the filter-aaaa module is loaded. - * - * To activate this hooks table at runtime, call ns__query_inithooks(). - */ -static bool -filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp); - -static bool -filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp); - -static bool -filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp); - -static bool -filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp); - -ns_hook_t filter_respbegin = { - .callback = filter_respond_begin, - .callback_data = NULL, - .link = { (void *) -1, (void *) -1 }, -}; -ns_hook_t filter_respanyfound = { - .callback = filter_respond_any_found, - .callback_data = NULL, - .link = { (void *) -1, (void *) -1 }, -}; -ns_hook_t filter_prepresp = { - .callback = filter_prep_response_begin, - .callback_data = NULL, - .link = { (void *) -1, (void *) -1 }, -}; -ns_hook_t filter_donesend = { - .callback = filter_query_done_send, - .callback_data = NULL, - .link = { (void *) -1, (void *) -1 }, -}; - /*% * Increment query statistics counters. */ @@ -4443,24 +4402,6 @@ query_findclosestnsec3(dns_name_t *qname, dns_db_t *db, return; } -static bool -is_v4_client(ns_client_t *client) { - if (isc_sockaddr_pf(&client->peeraddr) == AF_INET) - return (true); - if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && - IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) - return (true); - return (false); -} - -static bool -is_v6_client(ns_client_t *client) { - if (isc_sockaddr_pf(&client->peeraddr) == AF_INET6 && - !IN6_IS_ADDR_V4MAPPED(&client->peeraddr.type.sin6.sin6_addr)) - return (true); - return (false); -} - static uint32_t dns64_ttl(dns_db_t *db, dns_dbversion_t *version) { dns_dbnode_t *node = NULL; @@ -5549,12 +5490,6 @@ recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype, } } -/*% - * Prepare client for recursion, then create a resolver fetch, with - * the event callback set to fetch_callback(). Afterward we terminate - * this phase of the query, and resume with a new query context when - * recursion completes. - */ isc_result_t ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, dns_name_t *qdomain, dns_rdataset_t *nameservers, @@ -6555,8 +6490,9 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { !dns_name_equal(qctx->client->query.qname, dns_rootname)) { result = query_checkrpz(qctx, result); - if (result == ISC_R_COMPLETE) + if (result == ISC_R_COMPLETE) { return (ns_query_done(qctx)); + } } /* @@ -6875,6 +6811,7 @@ query_respond_any(query_ctx_t *qctx) { CCTRACE(ISC_LOG_ERROR, "query_respond_any: rdataset iterator failed"); QUERY_ERROR(qctx, DNS_R_SERVFAIL); + return (ns_query_done(qctx)); } if (found) { @@ -7787,7 +7724,7 @@ query_delegation(query_ctx_t *qctx) { if (dns_rdatatype_atparent(qctx->type)) { /* * Parent is recursive for this rdata - * type (i.e., DS) + * type (i.e., DS). */ result = ns_query_recurse(qctx->client, qctx->qtype, qname, @@ -7796,7 +7733,7 @@ query_delegation(query_ctx_t *qctx) { } else if (qctx->dns64) { /* * Look up an A record so we can - * synthesize DNS64 + * synthesize DNS64. */ result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname, @@ -7804,7 +7741,7 @@ query_delegation(query_ctx_t *qctx) { qctx->resuming); } else { /* - * Any other recursion + * Any other recursion. */ result = ns_query_recurse(qctx->client, qctx->qtype, qname, @@ -10905,326 +10842,3 @@ ns_query_start(ns_client_t *client) { ns_client_attach(client, &qclient); (void)query_setup(qclient, qtype); } - -/* - * Per-client flags set by this module - */ -#define FILTER_AAAA_RECURSING 0x0001 /* Recursing for A */ -#define FILTER_AAAA_FILTERED 0x0002 /* AAAA was removed from answer */ - -/* - * The filter-aaaa-on-v4 option suppresses AAAAs for IPv4 - * clients if there is an A; filter-aaaa-on-v6 option does - * the same for IPv6 clients. - */ -static bool -filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - isc_result_t result; - - UNUSED(cbdata); - - qctx->filter_aaaa = dns_aaaa_ok; - if (qctx->client->view->v4_aaaa != dns_aaaa_ok || - qctx->client->view->v6_aaaa != dns_aaaa_ok) - { - result = ns_client_checkaclsilent(qctx->client, NULL, - qctx->client->view->aaaa_acl, - true); - if (result == ISC_R_SUCCESS && - qctx->client->view->v4_aaaa != dns_aaaa_ok && - is_v4_client(qctx->client)) - { - qctx->filter_aaaa = qctx->client->view->v4_aaaa; - } else if (result == ISC_R_SUCCESS && - qctx->client->view->v6_aaaa != dns_aaaa_ok && - is_v6_client(qctx->client)) - { - qctx->filter_aaaa = qctx->client->view->v6_aaaa; - } - } - - *resp = ISC_R_UNSET; - return (false); -} - -/* - * Optionally hide AAAA rrsets if there is a matching A. - * (This version is for processing answers to explicit AAAA - * queries; ANY queries are handled in query_filter_aaaa_any().) - */ -static bool -filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - isc_result_t result = ISC_R_UNSET; - - UNUSED(cbdata); - - if (qctx->filter_aaaa != dns_aaaa_break_dnssec && - (qctx->filter_aaaa != dns_aaaa_filter || - (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && - dns_rdataset_isassociated(qctx->sigrdataset)))) - { - *resp = result; - return (false); - } - - if (qctx->qtype == dns_rdatatype_aaaa) { - dns_rdataset_t *trdataset; - trdataset = ns_client_newrdataset(qctx->client); - result = dns_db_findrdataset(qctx->db, qctx->node, - qctx->version, - dns_rdatatype_a, 0, - qctx->client->now, - trdataset, NULL); - if (dns_rdataset_isassociated(trdataset)) { - dns_rdataset_disassociate(trdataset); - } - ns_client_putrdataset(qctx->client, &trdataset); - - /* - * We found an AAAA. If we also found an A, then the AAAA - * must not be rendered. - * - * If the A is not in our cache, then any result other than - * DNS_R_DELEGATION or ISC_R_NOTFOUND means there is no A, - * and so AAAAs are okay. - * - * We assume there is no A if we can't recurse for this - * client. That might be the wrong answer, but what else - * can we do? Besides, the fact that we have the AAAA and - * are using this mechanism in the first place suggests - * that we care more about As than AAAAs, and would have - * cached an A if it existed. - */ - if (result == ISC_R_SUCCESS) { - qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED; - if (qctx->sigrdataset != NULL && - dns_rdataset_isassociated(qctx->sigrdataset)) - { - qctx->sigrdataset->attributes |= - DNS_RDATASETATTR_RENDERED; - } - qctx->client->hookflags |= FILTER_AAAA_FILTERED; - } else if (!qctx->authoritative && - RECURSIONOK(qctx->client) && - (result == DNS_R_DELEGATION || - result == ISC_R_NOTFOUND)) - { - /* - * This is an ugly kludge to recurse - * for the A and discard the result. - * - * Continue to add the AAAA now. - * We'll make a note to not render it - * if the recursion for the A succeeds. - */ - INSIST(!REDIRECT(qctx->client)); - result = ns_query_recurse(qctx->client, - dns_rdatatype_a, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->hookflags |= - FILTER_AAAA_RECURSING; - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - } - } - } else if (qctx->qtype == dns_rdatatype_a && - ((qctx->client->hookflags & FILTER_AAAA_RECURSING) != 0)) - { - - dns_rdataset_t *mrdataset = NULL; - dns_rdataset_t *sigrdataset = NULL; - - result = dns_message_findname(qctx->client->message, - DNS_SECTION_ANSWER, qctx->fname, - dns_rdatatype_aaaa, 0, - NULL, &mrdataset); - if (result == ISC_R_SUCCESS) { - mrdataset->attributes |= DNS_RDATASETATTR_RENDERED; - } - - result = dns_message_findname(qctx->client->message, - DNS_SECTION_ANSWER, qctx->fname, - dns_rdatatype_rrsig, - dns_rdatatype_aaaa, - NULL, &sigrdataset); - if (result == ISC_R_SUCCESS) { - sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; - } - - qctx->client->hookflags &= ~FILTER_AAAA_RECURSING; - - result = ns_query_done(qctx); - - *resp = result; - return (true); - - } - - *resp = result; - return (false); -} - -static bool -filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - dns_name_t *name = NULL; - dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; - dns_rdataset_t *a = NULL; - bool have_a = true; - - UNUSED(cbdata); - - if (qctx->filter_aaaa == dns_aaaa_ok) { - *resp = ISC_R_UNSET; - return (false); - } - - dns_message_findname(qctx->client->message, DNS_SECTION_ANSWER, - (qctx->fname != NULL) - ? qctx->fname - : qctx->tname, - dns_rdatatype_any, 0, &name, NULL); - - /* - * If we're not authoritative, just assume there's an - * A even if it wasn't in the cache and therefore isn't - * in the message. But if we're authoritative, then - * if there was an A, it should be here. - */ - if (qctx->authoritative && name != NULL) { - dns_message_findtype(name, dns_rdatatype_a, 0, &a); - if (a == NULL) { - have_a = false; - } - } - - if (name != NULL) { - dns_message_findtype(name, dns_rdatatype_aaaa, 0, &aaaa); - dns_message_findtype(name, dns_rdatatype_rrsig, - dns_rdatatype_aaaa, &aaaa_sig); - } - - if (have_a && aaaa != NULL && - (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || - qctx->filter_aaaa == dns_aaaa_break_dnssec)) - { - aaaa->attributes |= DNS_RDATASETATTR_RENDERED; - if (aaaa_sig != NULL) { - aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED; - } - } - - *resp = ISC_R_UNSET; - return (false); -} - -/* - * Hide AAAA rrsets in the additional section if there is a matching A, - * and hide NS in the additional section if AAAA was filtered in the answer - * section. - */ -static bool -filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - isc_result_t result; - - UNUSED(cbdata); - - if (qctx->filter_aaaa == dns_aaaa_ok) { - *resp = ISC_R_UNSET; - return (false); - } - - result = dns_message_firstname(qctx->client->message, - DNS_SECTION_ADDITIONAL); - while (result == ISC_R_SUCCESS) { - dns_name_t *name = NULL; - dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; - dns_rdataset_t *a = NULL; - - dns_message_currentname(qctx->client->message, - DNS_SECTION_ADDITIONAL, - &name); - - result = dns_message_nextname(qctx->client->message, - DNS_SECTION_ADDITIONAL); - - dns_message_findtype(name, dns_rdatatype_a, 0, &a); - if (a == NULL) { - continue; - } - - dns_message_findtype(name, dns_rdatatype_aaaa, 0, - &aaaa); - if (aaaa == NULL) { - continue; - } - - dns_message_findtype(name, dns_rdatatype_rrsig, - dns_rdatatype_aaaa, &aaaa_sig); - - if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || - qctx->filter_aaaa == dns_aaaa_break_dnssec) - { - aaaa->attributes |= DNS_RDATASETATTR_RENDERED; - if (aaaa_sig != NULL) { - aaaa_sig->attributes |= - DNS_RDATASETATTR_RENDERED; - } - } - } - - if ((qctx->client->hookflags & FILTER_AAAA_FILTERED) != 0) { - result = dns_message_firstname(qctx->client->message, - DNS_SECTION_AUTHORITY); - while (result == ISC_R_SUCCESS) { - dns_name_t *name = NULL; - dns_rdataset_t *ns = NULL, *ns_sig = NULL; - - dns_message_currentname(qctx->client->message, - DNS_SECTION_AUTHORITY, - &name); - - result = dns_message_findtype(name, dns_rdatatype_ns, - 0, &ns); - if (result == ISC_R_SUCCESS) { - ns->attributes |= DNS_RDATASETATTR_RENDERED; - } - - result = dns_message_findtype(name, dns_rdatatype_rrsig, - dns_rdatatype_ns, - &ns_sig); - if (result == ISC_R_SUCCESS) { - ns_sig->attributes |= DNS_RDATASETATTR_RENDERED; - } - - result = dns_message_nextname(qctx->client->message, - DNS_SECTION_AUTHORITY); - } - } - - *resp = ISC_R_UNSET; - return (false); -} - -void -ns__query_inithooks() { - /* - * XXX: This function is temporary. Later, the hook table - * will be set up when initializing hook modules after - * configuring the server. - * - * For now, however, we just call this once when initializing named - * and it will set up all the filter-aaaa hooks. - */ - - ns_hooktable_init(NULL); - ns_hook_add(NULL, NS_QUERY_RESPOND_BEGIN, &filter_respbegin); - ns_hook_add(NULL, NS_QUERY_RESPOND_ANY_FOUND, &filter_respanyfound); - ns_hook_add(NULL, NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp); - ns_hook_add(NULL, NS_QUERY_DONE_SEND, &filter_donesend); -} diff --git a/lib/ns/server.c b/lib/ns/server.c index fde2c459d5a..a328ceebeb6 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -108,11 +108,6 @@ ns_server_create(isc_mem_t *mctx, ns_matchview_t matchingview, ISC_LIST_INIT(sctx->altsecrets); - /* - * XXX: temporary. - */ - ns__query_inithooks(); - sctx->magic = SCTX_MAGIC; *sctxp = sctx; diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index 9918d505122..ab5efa25ddb 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -17,14 +17,23 @@ ns_client_checkaclsilent ns_client_detach ns_client_dumprecursing ns_client_error -ns_client_getsockaddr +ns_client_findversion ns_client_getdestaddr +ns_client_getnamebuf +ns_client_getsockaddr +ns_client_keepname ns_client_killoldestquery ns_client_log ns_client_logv +ns_client_newdbversion +ns_client_newname +ns_client_newnamebuf +ns_client_newrdataset ns_client_next +ns_client_putrdataset ns_client_qnamereplace ns_client_recursing +ns_client_releasename ns_client_replace ns_client_send ns_client_sendraw @@ -34,6 +43,16 @@ ns_client_sourceip ns_clientmgr_create ns_clientmgr_createclients ns_clientmgr_destroy +ns_hook_add +ns_hook_createctx +ns_hook_destroyctx +ns_hookmodule_cleanup +ns_hookmodule_load +ns_hooktable_create +ns_hooktable_free +ns_hooktable_init +ns_hooktable_reset +ns_hooktable_save ns_interface_attach ns_interface_detach ns_interface_shutdown