From 70cc3f803e40e60c9127edf458f6ada11ac0d737 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 3 Aug 2018 14:16:41 -0700 Subject: [PATCH 01/26] set up hooks.c to enable setting hook points and loading modules - move hooks.h to public include directory - ns_hooktable_init() initializes a hook table. if NULL is passed in, it initializes the global hook table - ns_hooktable_save() saves a pointer to the current global hook table. - ns_hooktable_reset() replaces the global hook table with different one - ns_hook_add() adds hooks at specified hook points in a hook table (or the global hook table if the specified table is NULL) - load and unload functions support dlopen() of hook modules (this is adapted from dyndb and not yet functional) - began adding new hook points to query.c --- bin/named/server.c | 2 + configure | 2 +- configure.ac | 2 +- lib/dns/dyndb.c | 6 +- lib/dns/include/dns/dyndb.h | 4 +- lib/ns/Makefile.in | 4 +- lib/ns/hooks.c | 439 ++++++++++++++++++++++++++++++++ lib/ns/include/ns/Makefile.in | 2 +- lib/ns/{ => include/ns}/hooks.h | 156 +++++++++++- lib/ns/include/ns/log.h | 1 + lib/ns/log.c | 1 + lib/ns/query.c | 59 +++-- lib/ns/tests/listenlist_test.c | 14 - lib/ns/tests/notify_test.c | 14 - lib/ns/tests/nstest.c | 29 +-- lib/ns/tests/query_test.c | 50 ++-- util/copyrights | 3 +- 17 files changed, 671 insertions(+), 117 deletions(-) create mode 100644 lib/ns/hooks.c rename lib/ns/{ => include/ns}/hooks.h (61%) diff --git a/bin/named/server.c b/bin/named/server.c index 923e25a63b..9e6c75a15f 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -8030,6 +8030,7 @@ load_configuration(const char *filename, named_server_t *server, * Shut down all dyndb instances. */ dns_dyndb_cleanup(false); + ns_hookmodule_cleanup(); /* * Parse the global default pseudo-config file. @@ -9511,6 +9512,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { } dns_dyndb_cleanup(true); + ns_hookmodule_cleanup(); while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { ISC_LIST_UNLINK(server->cachelist, nsc, link); diff --git a/configure b/configure index 85f07cd4e1..5031db85a3 100755 --- a/configure +++ b/configure @@ -11916,7 +11916,7 @@ fi XTARGETS= case "$enable_developer" in yes) - STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1 -DNS_HOOKS_ENABLE=1" + STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1" test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes test "${enable_querytrace+set}" = set || enable_querytrace=yes test "${with_cmocka+set}" = set || with_cmocka=yes diff --git a/configure.ac b/configure.ac index df3683ba83..d831bae619 100644 --- a/configure.ac +++ b/configure.ac @@ -76,7 +76,7 @@ AC_ARG_ENABLE(developer, XTARGETS= case "$enable_developer" in yes) - STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1 -DNS_HOOKS_ENABLE=1" + STD_CDEFINES="$STD_CDEFINES -DISC_MEM_DEFAULTFILL=1 -DISC_LIST_CHECKINIT=1" test "${enable_fixed_rrset+set}" = set || enable_fixed_rrset=yes test "${enable_querytrace+set}" = set || enable_querytrace=yes test "${with_cmocka+set}" = set || with_cmocka=yes diff --git a/lib/dns/dyndb.c b/lib/dns/dyndb.c index 0faf393878..932244a8db 100644 --- a/lib/dns/dyndb.c +++ b/lib/dns/dyndb.c @@ -190,7 +190,8 @@ cleanup: "driver '%s': %s (%s)", instname, filename, dlerror(), isc_result_totext(result)); if (imp != NULL) - isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); + isc_mem_putanddetach(&imp->mctx, imp, + sizeof(dyndb_implementation_t)); if (result != ISC_R_SUCCESS && handle != NULL) dlclose(handle); @@ -305,7 +306,8 @@ cleanup: "driver '%s': %d (%s)", instname, filename, GetLastError(), isc_result_totext(result)); if (imp != NULL) - isc_mem_putanddetach(&imp->mctx, imp, sizeof(dyndb_implementation_t)); + isc_mem_putanddetach(&imp->mctx, imp, + sizeof(dyndb_implementation_t)); if (result != ISC_R_SUCCESS && handle != NULL) FreeLibrary(handle); diff --git a/lib/dns/include/dns/dyndb.h b/lib/dns/include/dns/dyndb.h index d5fedb5fda..d5faf92069 100644 --- a/lib/dns/include/dns/dyndb.h +++ b/lib/dns/include/dns/dyndb.h @@ -40,7 +40,7 @@ struct dns_dyndbctx { dns_zonemgr_t *zmgr; isc_task_t *task; isc_timermgr_t *timermgr; - bool *refvar; + bool *refvar; }; #define DNS_DYNDBCTX_MAGIC ISC_MAGIC('D', 'd', 'b', 'c') @@ -71,7 +71,7 @@ typedef isc_result_t dns_dyndb_register_t(isc_mem_t *mctx, * 'parameters' contains the driver configuration text. 'dctx' is the * initialization context set up in dns_dyndb_createctx(). * - * '*instp' must be set to the driver instance handle if the functino + * '*instp' will be set to the driver instance handle if the function * is successful. * * Returns: diff --git a/lib/ns/Makefile.in b/lib/ns/Makefile.in index 51d21377c6..2e6c0183da 100644 --- a/lib/ns/Makefile.in +++ b/lib/ns/Makefile.in @@ -43,12 +43,12 @@ DNSDEPLIBS = ../../lib/dns/libdns.@A@ LIBS = @LIBS@ # Alphabetically -OBJS = client.@O@ interfacemgr.@O@ lib.@O@ \ +OBJS = client.@O@ hooks.@O@ interfacemgr.@O@ lib.@O@ \ listenlist.@O@ log.@O@ notify.@O@ query.@O@ \ server.@O@ sortlist.@O@ stats.@O@ update.@O@ \ version.@O@ xfrout.@O@ -SRCS = client.c interfacemgr.c lib.c listenlist.c \ +SRCS = client.c hooks.c interfacemgr.c lib.c listenlist.c \ log.c notify.c query.c server.c sortlist.c stats.c \ update.c version.c xfrout.c diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c new file mode 100644 index 0000000000..4b97c5b3d5 --- /dev/null +++ b/lib/ns/hooks.c @@ -0,0 +1,439 @@ +/* + * 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 + +#if HAVE_DLFCN_H +#include +#elif _WIN32 +#include +#endif + +#include +#include +#include +#include +#include + +#include +#include + +#define CHECK(op) \ + do { result = (op); \ + if (result != ISC_R_SUCCESS) goto cleanup; \ + } while (0) + +typedef struct ns_hook_module ns_hook_module_t; +struct ns_hook_module { + isc_mem_t *mctx; + void *handle; + char *filename; + ns_hook_register_t *register_func; + ns_hook_destroy_t *destroy_func; + char *name; + void *inst; + LINK(ns_hook_module_t) link; +}; + +static ns_hooklist_t hooktab[NS_QUERY_HOOKS_COUNT]; +LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &hooktab; + +/* + * List of hook modules. + * + * These are stored here so they can be cleaned up on shutdown. + * (The order in which they are stored is not important.) + */ +static LIST(ns_hook_module_t) hook_modules; + +static isc_once_t once = ISC_ONCE_INIT; + +static void +init_modules(void) { + INIT_LIST(hook_modules); +} + +#if HAVE_DLFCN_H && HAVE_DLOPEN +static isc_result_t +load_symbol(void *handle, const char *filename, + const char *symbol_name, void **symbolp) +{ + const char *errmsg; + void *symbol; + + REQUIRE(handle != NULL); + REQUIRE(symbolp != NULL && *symbolp == NULL); + + symbol = dlsym(handle, symbol_name); + if (symbol == NULL) { + errmsg = dlerror(); + if (errmsg == NULL) { + errmsg = "returned function pointer is NULL"; + } + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "failed to look upsymbol %s in " + "hook module '%s': %s", + symbol_name, filename, errmsg); + return (ISC_R_FAILURE); + } + dlerror(); + + *symbolp = symbol; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { + isc_result_t result; + void *handle = NULL; + ns_hook_module_t *hmod = NULL; + ns_hook_register_t *register_func = NULL; + ns_hook_destroy_t *destroy_func = NULL; + ns_hook_version_t *version_func = NULL; + int version, flags; + + 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; +#endif + + handle = dlopen(filename, flags); + if (handle == NULL) { + CHECK(ISC_R_FAILURE); + } + + /* Clear dlerror */ + dlerror(); + + CHECK(load_symbol(handle, filename, "hook_version", + (void **)&version_func)); + + version = version_func(NULL); + if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || + version > NS_HOOK_VERSION) + { + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "driver API version mismatch: %d/%d", + version, NS_HOOK_VERSION); + CHECK(ISC_R_FAILURE); + } + + CHECK(load_symbol(handle, filename, "hook_init", + (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; + hmod->register_func = register_func; + hmod->destroy_func = destroy_func; + + hmod->inst = NULL; + + ISC_LINK_INIT(hmod, link); + + *hmodp = hmod; + hmod = NULL; + +cleanup: + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "failed to dynamically load " + "module '%s': %s (%s)", filename, + dlerror(), isc_result_totext(result)); + + if (hmod != NULL) { + isc_mem_putanddetach(&hmod->mctx, hmod, + sizeof(*hmod)); + } + + if (handle != NULL) { + dlclose(handle); + } + } + + return (result); +} + +static void +unload_library(ns_hook_module_t **hmodp) { + ns_hook_module_t *hmod; + + REQUIRE(hmodp != NULL && *hmodp != NULL); + + hmod = *hmodp; + *hmodp = NULL; + + if (hmod->handle != NULL) { + dlclose(hmod->handle); + } + if (hmod->filename != NULL) { + isc_mem_free(hmod->mctx, hmod->filename); + } + + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(ns_hook_module_t)); +} +#elif _WIN32 +static isc_result_t +load_symbol(HMODULE handle, const char *filename, + const char *symbol_name, void **symbolp) +{ + void *symbol; + + REQUIRE(handle != NULL); + REQUIRE(symbolp != NULL && *symbolp == NULL); + + symbol = GetProcAddress(handle, symbol_name); + if (symbol == NULL) { + int errstatus = GetLastError(); + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "failed to look up symbol %s in " + "module '%s': %d", + symbol_name, filename, errstatus); + return (ISC_R_FAILURE); + } + + *symbolp = symbol; + + return (ISC_R_SUCCESS); +} + +static isc_result_t +load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { + isc_result_t result; + HMODULE handle; + ns_hook_module_t *hmod = NULL; + ns_hook_register_t *register_func = NULL; + ns_hook_destroy_t *destroy_func = NULL; + ns_hook_version_t *version_func = NULL; + int version; + + 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); + } + + CHECK(load_symbol(handle, filename, "hook_version", + (void **)&version_func)); + + version = version_func(NULL); + if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || + version > NS_HOOK_VERSION) + { + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "driver API version mismatch: %d/%d", + version, NS_HOOK_VERSION); + CHECK(ISC_R_FAILURE); + } + + CHECK(load_symbol(handle, filename, "hook_init", + (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; + hmod->register_func = register_func; + hmod->destroy_func = destroy_func; + + hmod->inst = NULL; + + ISC_LINK_INIT(hmod, link); + + *hmodp = hmod; + hmod = NULL; + +cleanup: + if (result != ISC_R_SUCCESS) { + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "failed to dynamically load " + "hook module '%s': %d (%s)", filename, + GetLastError(), isc_result_totext(result)); + if (hmod != NULL) { + isc_mem_putanddetach(&hmod->mctx, hmod, + sizeof(*hmod)); + } + + if (handle != NULL) { + FreeLibrary(handle); + } + } + + return (result); +} + +static void +unload_library(ns_hook_module_t **hmodp) { + ns_hook_module_t *hmod; + + REQUIRE(hmodp != NULL && *hmodp != NULL); + + hmod = *hmodp; + *hmodp = NULL; + + if (hmod->handle != NULL) { + FreeLibrary(hmod->handle); + } + + if (hmod->filename != NULL) { + isc_mem_free(hmod->mctx, hmod->filename); + } + + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); +} +#else /* HAVE_DLFCN_H || _WIN32 */ +static isc_result_t +load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { + UNUSED(mctx); + UNUSED(filename); + UNUSED(hmodp); + + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "hook module support is not hmodlemented"); + + return (ISC_R_NOTIMPLEMENTED); +} + +static void +unload_library(ns_hook_module_t **hmodp) { + UNUSED(hmodp); +} +#endif /* HAVE_DLFCN_H */ + +isc_result_t +ns_hookmodule_load(const char *libname, const char *parameters, + const char *file, unsigned long line, isc_mem_t *mctx) +{ + isc_result_t result; + ns_hook_module_t *module = NULL; + + RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); + + 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)); + + + APPEND(hook_modules, module, link); + result = ISC_R_SUCCESS; + +cleanup: + if (result != ISC_R_SUCCESS && module != NULL) { + unload_library(&module); + } + + return (result); +} + +void +ns_hookmodule_cleanup(void) { + ns_hook_module_t *hmod, *prev; + + RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); + + hmod = ISC_LIST_TAIL(hook_modules); + while (hmod != NULL) { + prev = PREV(hmod, link); + UNLINK(hook_modules, hmod, link); + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "unloading module '%s'", hmod->name); + hmod->destroy_func(&hmod->inst); + ENSURE(hmod->inst == NULL); + unload_library(&hmod); + hmod = prev; + } +} + +void +ns_hooktable_init(ns_hooktable_t *hooktable) { + int i; + + RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); + + if (hooktable == NULL) { + hooktable = ns__hook_table; + } + + for (i = 0; i < NS_QUERY_HOOKS_COUNT; i++) { + ISC_LIST_INIT((*hooktable)[i]); + } +} + +ns_hooktable_t * +ns_hooktable_save() { + return (ns__hook_table); +} + +void +ns_hooktable_reset(ns_hooktable_t *hooktable) { + if (hooktable != NULL) { + ns__hook_table = hooktable; + } else { + ns__hook_table = &hooktab; + } +} + +void +ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, + ns_hook_t *hook) +{ + REQUIRE(hookpoint < NS_QUERY_HOOKS_COUNT); + REQUIRE(hook != NULL); + + if (hooktable == NULL) { + hooktable = ns__hook_table; + } + + ISC_LINK_INIT(hook, link); + ISC_LIST_APPEND((*hooktable)[hookpoint], hook, link); +} diff --git a/lib/ns/include/ns/Makefile.in b/lib/ns/include/ns/Makefile.in index 9bfa9f1598..2009d9a73a 100644 --- a/lib/ns/include/ns/Makefile.in +++ b/lib/ns/include/ns/Makefile.in @@ -13,7 +13,7 @@ top_srcdir = @top_srcdir@ VERSION=@BIND9_VERSION@ -HEADERS = client.h interfacemgr.h lib.h listenlist.h log.h \ +HEADERS = client.h hooks.h interfacemgr.h lib.h listenlist.h log.h \ notify.h query.h server.h sortlist.h stats.h \ types.h update.h version.h xfrout.h SUBDIRS = diff --git a/lib/ns/hooks.h b/lib/ns/include/ns/hooks.h similarity index 61% rename from lib/ns/hooks.h rename to lib/ns/include/ns/hooks.h index 5c3aa14409..0475227750 100644 --- a/lib/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -12,12 +12,11 @@ #ifndef NS_HOOKS_H #define NS_HOOKS_H 1 -#ifdef NS_HOOKS_ENABLE - /*! \file */ #include +#include #include /* @@ -158,40 +157,171 @@ * called this time and foo_bar() will return ISC_R_SUCCESS. */ -enum { +typedef enum { NS_QUERY_SETUP_QCTX_INITIALIZED, + NS_QUERY_START_BEGIN, NS_QUERY_LOOKUP_BEGIN, + NS_QUERY_RESUME_BEGIN, + NS_QUERY_PREP_RESPONSE_BEGIN, + NS_QUERY_RESPOND_ANY_BEGIN, + NS_QUERY_RESPOND_ANY_POST_LOOKUP, + NS_QUERY_RESPOND_ANY_FOUND, + NS_QUERY_RESPOND_ANY_NOT_FOUND, + NS_QUERY_RESPOND_BEGIN, + NS_QUERY_GOT_ANSWER_BEGIN, + NS_QUERY_NOTFOUND_BEGIN, + NS_QUERY_PREP_DELEGATION_BEGIN, + NS_QUERY_ZONE_DELEGATION_BEGIN, + NS_QUERY_DELEGATION_BEGIN, + NS_QUERY_NODATA_BEGIN, + NS_QUERY_NXDOMAIN_BEGIN, + NS_QUERY_CNAME_BEGIN, + NS_QUERY_DNAME_BEGIN, + NS_QUERY_ADDITIONAL_BEGIN, NS_QUERY_DONE_BEGIN, + NS_QUERY_DONE_SEND, NS_QUERY_HOOKS_COUNT /* MUST BE LAST */ -}; +} ns_hookpoint_t; typedef bool (*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp); +/* + * API version + * + * When the API changes, increment NS_HOOK_VERSION. If the + * change is backward-compatible (e.g., adding a new function call + * but not changing or removing an old one), increment NS_HOOK_AGE + * as well; if not, set NS_HOOK_AGE to 0. + */ +#ifndef NS_HOOK_VERSION +#define NS_HOOK_VERSION 1 +#define NS_HOOK_AGE 0 +#endif + +typedef isc_result_t ns_hook_register_t(isc_mem_t *mctx, + const char *parameters, + const char *file, + unsigned long line, + void **instp); +/*% + * Called when registering a new module. + * + * 'parameters' contains the module configuration text. + * + * '*instp' will be set to the module instance handle if the function + * is successful. + * + * Returns: + *\li #ISC_R_SUCCESS + *\li #ISC_R_NOMEMORY + *\li Other errors are possible + */ + +typedef void ns_hook_destroy_t(void **instp); +/*% + * Destroy a module instance. + * + * '*instp' must be set to NULL by the function before it returns. + */ + +typedef int ns_hook_version_t(unsigned int *flags); +/*% + * Return the API version number a hook module was compiled with. + * + * If the returned version number is no greater than than + * NS_HOOK_VERSION, and no less than NS_HOOK_VERSION - NS_HOOK_AGE, + * then the module is API-compatible with named. + * + * 'flags' is currently unused and may be NULL, but could be used in + * 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 + * result that was returned by the hook function. If none of them return + * true, we continue processing. + */ #define _NS_PROCESS_HOOK(table, id, data, ...) \ - if (table != NULL) { \ - ns_hook_cb_t _callback = table[id].callback; \ - void *_callback_data = table[id].callback_data; \ + if (table != NULL) { \ + ns_hook_t *_hook = ISC_LIST_HEAD((*table)[id]); \ isc_result_t _result; \ \ - if (_callback != NULL && \ - _callback(data, _callback_data, &_result)) { \ - return __VA_ARGS__; \ + while (_hook != NULL) { \ + ns_hook_cb_t _callback = _hook->callback; \ + void *_callback_data = _hook->callback_data; \ + if (_callback != NULL && \ + _callback(data, _callback_data, &_result)) \ + { \ + return __VA_ARGS__; \ + } else { \ + _hook = ISC_LIST_NEXT(_hook, link); \ + } \ } \ } #define NS_PROCESS_HOOK(table, id, data) \ _NS_PROCESS_HOOK(table, id, data, _result) - #define NS_PROCESS_HOOK_VOID(table, id, data) \ _NS_PROCESS_HOOK(table, id, data) -LIBNS_EXTERNAL_DATA extern ns_hook_t *ns__hook_table; +isc_result_t +ns_hookmodule_load(const char *libname, const char *parameters, + const char *file, unsigned long line, isc_mem_t *mctx); +void +ns_hookmodule_cleanup(void); + +void +ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, + ns_hook_t *hook); +/*% + * Append hook function 'hook' to the list of hooks at 'hookpoint' in + * 'hooktable'. If 'hooktable' is NULL, the global hook table + * ns__hook_table is used. + * + * Requires: + *\li 'hook' is not NULL + * + *\li 'hookpoint' is less than NS_QUERY_HOOKS_COUNT + * + */ + +ns_hooktable_t * +ns_hooktable_save(void); +/*% + * Returns a pointer to the current global hook table so it can + * be restored after replacing it. + */ + +void +ns_hooktable_reset(ns_hooktable_t *hooktable); +/*% + * Set the global hooks table pointer to 'hooktable'. + * + * If 'hooktable' is NULL, restores the default global hook table. + */ + +void +ns_hooktable_init(ns_hooktable_t *hooktable); +/*% + * Initialize a hook table. If 'hooktable' is NULL, initialize + * the global hooktable ns__hook_table. + */ -#endif /* NS_HOOKS_ENABLE */ #endif /* NS_HOOKS_H */ diff --git a/lib/ns/include/ns/log.h b/lib/ns/include/ns/log.h index aab57aca09..24689a652c 100644 --- a/lib/ns/include/ns/log.h +++ b/lib/ns/include/ns/log.h @@ -42,6 +42,7 @@ LIBNS_EXTERNAL_DATA extern isc_logmodule_t ns_modules[]; #define NS_LOGMODULE_XFER_IN (&ns_modules[4]) #define NS_LOGMODULE_XFER_OUT (&ns_modules[5]) #define NS_LOGMODULE_NOTIFY (&ns_modules[6]) +#define NS_LOGMODULE_HOOKS (&ns_modules[7]) void ns_log_init(isc_log_t *lctx); diff --git a/lib/ns/log.c b/lib/ns/log.c index f167674b32..3e83d98401 100644 --- a/lib/ns/log.c +++ b/lib/ns/log.c @@ -50,6 +50,7 @@ LIBNS_EXTERNAL_DATA isc_logmodule_t ns_modules[] = { { "ns/xfer-in", 0 }, { "ns/xfer-out", 0 }, { "ns/notify", 0 }, + { "ns/hooks", 0 }, { NULL, 0 } }; diff --git a/lib/ns/query.c b/lib/ns/query.c index 64a38e4562..54af7eac7c 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -62,14 +62,13 @@ #include #include +#include #include #include #include #include #include -#include "hooks.h" - #if 0 /* * It has been recommended that DNS64 be changed to return excluded @@ -240,22 +239,11 @@ static void log_noexistnodata(void *val, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); -#ifdef NS_HOOKS_ENABLE - -LIBNS_EXTERNAL_DATA ns_hook_t *ns__hook_table = NULL; - #define PROCESS_HOOK(...) \ NS_PROCESS_HOOK(ns__hook_table, __VA_ARGS__) #define PROCESS_HOOK_VOID(...) \ NS_PROCESS_HOOK_VOID(ns__hook_table, __VA_ARGS__) -#else - -#define PROCESS_HOOK(...) do {} while (0) -#define PROCESS_HOOK_VOID(...) do {} while (0) - -#endif - /* * The functions defined below implement the query logic that previously lived * in the single very complex function query_find(). The query_ctx_t structure @@ -433,8 +421,7 @@ static void query_addbestns(query_ctx_t *qctx); static void -query_addwildcardproof(query_ctx_t *qctx, bool ispositive, - bool nodata); +query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata); static void query_addauth(query_ctx_t *qctx); @@ -1989,6 +1976,7 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { (!WANTDNSSEC(client) || sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))))) goto addname; + if (additionaltype == dns_rdatasetadditional_fromcache && (DNS_TRUST_PENDING(rdataset->trust) || @@ -5253,6 +5241,8 @@ ns__query_start(query_ctx_t *qctx) { qctx->need_wildcardproof = false; qctx->rpz = false; + PROCESS_HOOK(NS_QUERY_START_BEGIN, qctx); + /* * If we require a server cookie then send back BADCOOKIE * before we have done too much work. @@ -5881,6 +5871,8 @@ query_resume(query_ctx_t *qctx) { char tbuf[DNS_RDATATYPE_FORMATSIZE]; #endif + PROCESS_HOOK(NS_QUERY_RESUME_BEGIN, qctx); + qctx->want_restart = false; qctx->rpz_st = qctx->client->query.rpz_st; @@ -6703,6 +6695,8 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer"); + PROCESS_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx); + if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) { return (query_done(qctx)); } @@ -6893,6 +6887,8 @@ query_respond_any(query_ctx_t *qctx) { have_a = !qctx->authoritative; have_sig = false; + PROCESS_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); + result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, &rdsiter); if (result != ISC_R_SUCCESS) { @@ -7044,6 +7040,8 @@ query_respond_any(query_ctx_t *qctx) { result = dns_rdatasetiter_next(rdsiter); } + PROCESS_HOOK(NS_QUERY_RESPOND_ANY_POST_LOOKUP, qctx); + /* * Filter AAAAs if there is an A and there is no signature * or we are supposed to break DNSSEC. @@ -7273,6 +7271,8 @@ query_respond(query_ctx_t *qctx) { dns_rdataset_t **sigrdatasetp = NULL; isc_result_t result; + PROCESS_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); + /* * If we have a zero ttl from the cache, refetch. */ @@ -7761,6 +7761,8 @@ static isc_result_t query_notfound(query_ctx_t *qctx) { isc_result_t result; + PROCESS_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx); + INSIST(!qctx->is_zone); if (qctx->db != NULL) @@ -7837,6 +7839,8 @@ query_prepare_delegation_response(query_ctx_t *qctx) { dns_rdataset_t **sigrdatasetp = NULL; bool detach = false; + PROCESS_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx); + /* * qctx->fname could be released in query_addrrset(), so save a copy of * it here in case we need it. @@ -7886,6 +7890,8 @@ static isc_result_t query_zone_delegation(query_ctx_t *qctx) { isc_result_t result; + PROCESS_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx); + /* * If the query type is DS, look to see if we are * authoritative for the child zone @@ -7977,6 +7983,8 @@ static isc_result_t query_delegation(query_ctx_t *qctx) { isc_result_t result; + PROCESS_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx); + qctx->authoritative = false; if (qctx->is_zone) { @@ -8223,6 +8231,8 @@ query_addds(query_ctx_t *qctx) { */ static isc_result_t query_nodata(query_ctx_t *qctx, isc_result_t result) { + PROCESS_HOOK(NS_QUERY_NODATA_BEGIN, qctx); + #ifdef dns64_bis_return_excluded_addresses if (qctx->dns64) #else @@ -8534,6 +8544,8 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { uint32_t ttl; isc_result_t result; + PROCESS_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx); + INSIST(qctx->is_zone || REDIRECT(qctx->client)); if (!empty_wild) { @@ -9437,6 +9449,8 @@ query_cname(query_ctx_t *qctx) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_cname_t cname; + PROCESS_HOOK(NS_QUERY_CNAME_BEGIN, qctx); + /* * If we have a zero ttl from the cache refetch it. */ @@ -9565,6 +9579,8 @@ query_dname(query_ctx_t *qctx) { isc_result_t result; unsigned int nlabels; + PROCESS_HOOK(NS_QUERY_DNAME_BEGIN, qctx); + /* * Compare the current qname to the found name. We need * to know how many labels and bits are in common because @@ -9773,6 +9789,8 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { */ static isc_result_t query_prepresponse(query_ctx_t *qctx) { + PROCESS_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx); + if (WANTDNSSEC(qctx->client) && (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0) { @@ -9798,11 +9816,14 @@ query_prepresponse(query_ctx_t *qctx) { if (result == ISC_R_SUCCESS && qctx->client->view->v4_aaaa != dns_aaaa_ok && is_v4_client(qctx->client)) + { qctx->client->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)) + } else if (result == ISC_R_SUCCESS && + qctx->client->view->v6_aaaa != dns_aaaa_ok && + is_v6_client(qctx->client)) + { qctx->client->filter_aaaa = qctx->client->view->v6_aaaa; + } } @@ -10778,6 +10799,8 @@ query_done(query_ctx_t *qctx) { qctx->result = ISC_R_FAILURE; } + PROCESS_HOOK(NS_QUERY_DONE_SEND, qctx); + query_send(qctx->client); ns_client_detach(&qctx->client); diff --git a/lib/ns/tests/listenlist_test.c b/lib/ns/tests/listenlist_test.c index 40415c1d7c..24b5b970f0 100644 --- a/lib/ns/tests/listenlist_test.c +++ b/lib/ns/tests/listenlist_test.c @@ -20,8 +20,6 @@ #include -#ifdef NS_HOOKS_ENABLE - #include #include #include @@ -126,18 +124,6 @@ main(void) { return (cmocka_run_group_tests(tests, NULL, NULL)); } -#else - -#include - -int -main(void) { - printf("1..0 # Skipped: libns hooks not enabled\n"); - return (0); -} - -#endif /* NS_HOOKS_ENABLE */ - #else /* HAVE_CMOCKA */ #include diff --git a/lib/ns/tests/notify_test.c b/lib/ns/tests/notify_test.c index e1e2654ca3..b6884ea7df 100644 --- a/lib/ns/tests/notify_test.c +++ b/lib/ns/tests/notify_test.c @@ -20,8 +20,6 @@ #include -#ifdef NS_HOOKS_ENABLE - #include #include #include @@ -154,18 +152,6 @@ main(void) { return (cmocka_run_group_tests(tests, NULL, NULL)); } -#else - -#include - -int -main(void) { - printf("1..0 # Skipped: libns hooks not enabled\n"); - return (0); -} - -#endif /* NS_HOOKS_ENABLE */ - #else /* HAVE_CMOCKA */ #include diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 85c641bcd4..f0a589ed15 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -13,8 +13,6 @@ #include -#ifdef NS_HOOKS_ENABLE - #include #include #include @@ -47,11 +45,10 @@ #include #include +#include #include #include -#include "../hooks.h" - #include "nstest.h" isc_mem_t *mctx = NULL; @@ -287,8 +284,6 @@ ns_test_begin(FILE *logfile, bool start_managers) { CHECK(ISC_R_FAILURE); } - ns__hook_table = NULL; - return (ISC_R_SUCCESS); cleanup: @@ -677,12 +672,10 @@ extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) { */ static isc_result_t create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { - ns_hook_t *saved_hook_table; - ns_hook_t query_hooks[NS_QUERY_HOOKS_COUNT + 1] = { - [NS_QUERY_SETUP_QCTX_INITIALIZED] = { - .callback = extract_qctx, - .callback_data = qctxp, - }, + ns_hooktable_t *saved_hook_table, query_hooks; + ns_hook_t hook = { + .callback = extract_qctx, + .callback_data = qctxp, }; REQUIRE(client != NULL); @@ -696,10 +689,15 @@ create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { * further processing. Make sure we do not overwrite any previously * set hooks. */ - saved_hook_table = ns__hook_table; - ns__hook_table = query_hooks; + + ns_hooktable_init(&query_hooks); + ns_hook_add(&query_hooks, NS_QUERY_SETUP_QCTX_INITIALIZED, &hook); + + saved_hook_table = ns_hooktable_save(); + + ns_hooktable_reset(&query_hooks); ns_query_start(client); - ns__hook_table = saved_hook_table; + ns_hooktable_reset(saved_hook_table); if (*qctxp == NULL) { return (ISC_R_NOMEMORY); @@ -927,4 +925,3 @@ ns_test_getdata(const char *file, unsigned char *buf, isc_stdio_close(f); return (result); } -#endif diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index 21c68e4c76..b47b775fda 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -19,8 +19,6 @@ #include -#ifdef NS_HOOKS_ENABLE - #include #include #include @@ -31,12 +29,12 @@ #include #include + #include +#include #include #include -#include "../hooks.h" - #include "nstest.h" static int @@ -95,13 +93,14 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) { /* * Interrupt execution if query_done() is called. */ - ns_hook_t query_hooks[NS_QUERY_HOOKS_COUNT + 1] = { - [NS_QUERY_DONE_BEGIN] = { - .callback = ns_test_hook_catch_call, - .callback_data = NULL, - }, + ns_hook_t hook = { + .callback = ns_test_hook_catch_call, }; - ns__hook_table = query_hooks; + ns_hooktable_t query_hooks; + + ns_hooktable_init(&query_hooks); + ns_hook_add(&query_hooks, NS_QUERY_DONE_BEGIN, &hook); + ns_hooktable_reset(&query_hooks); /* * Construct a query context for a ./NS query with given flags. @@ -295,17 +294,16 @@ run_start_test(const ns__query_start_test_params_t *test) { /* * Interrupt execution if query_lookup() or query_done() is called. */ - ns_hook_t query_hooks[NS_QUERY_HOOKS_COUNT + 1] = { - [NS_QUERY_LOOKUP_BEGIN] = { - .callback = ns_test_hook_catch_call, - .callback_data = NULL, - }, - [NS_QUERY_DONE_BEGIN] = { - .callback = ns_test_hook_catch_call, - .callback_data = NULL, - }, + ns_hook_t hook = { + .callback = ns_test_hook_catch_call, }; - ns__hook_table = query_hooks; + ns_hooktable_t query_hooks; + + ns_hooktable_init(&query_hooks); + ns_hook_add(&query_hooks, NS_QUERY_LOOKUP_BEGIN, &hook); + ns_hook_add(&query_hooks, NS_QUERY_DONE_BEGIN, &hook); + + ns_hooktable_reset(&query_hooks); /* * Construct a query context using the supplied parameters. @@ -604,18 +602,6 @@ main(void) { return (cmocka_run_group_tests(tests, NULL, NULL)); } -#else - -#include - -int -main(void) { - printf("1..0 # Skipped: libns hooks not enabled\n"); - return (0); -} - -#endif /* NS_HOOKS_ENABLE */ - #else /* HAVE_CMOCKA */ #include diff --git a/util/copyrights b/util/copyrights index 0622c2c9de..3845fe4f59 100644 --- a/util/copyrights +++ b/util/copyrights @@ -2480,8 +2480,9 @@ ./lib/ns/Kyuafile X 2017,2018 ./lib/ns/api X 2017,2018 ./lib/ns/client.c C 2017,2018 -./lib/ns/hooks.h C 2017,2018 +./lib/ns/hooks.c C 2018 ./lib/ns/include/ns/client.h C 2017,2018 +./lib/ns/include/ns/hooks.h C 2017,2018 ./lib/ns/include/ns/interfacemgr.h C 2017,2018 ./lib/ns/include/ns/lib.h C 2017,2018 ./lib/ns/include/ns/listenlist.h C 2017,2018 From 29897b14dcf80e246464a67db9aef6c885506148 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 7 Aug 2018 01:05:55 -0700 Subject: [PATCH 02/26] refactor query.c to make qctx more accessible - the purpose of this change is allow for more well-defined hook points to be available in the query processing logic. some functions that formerly didn't have access to 'qctx' do now; this is needed because 'qctx' is what gets passed when calling a hook function. - query_addrdataset() has been broken up into three separate functions since it used to do three unrelated things, and what was formerly query_addadditional() has been renamed query_additional_cb() for clarity. - client->filter_aaaa is now qctx->filter_aaaa. (later, it will be moved into opaque storage in the qctx, for use by the filter-aaaa module.) - cleaned up style and braces --- lib/ns/client.c | 4 +- lib/ns/include/ns/client.h | 1 - lib/ns/include/ns/query.h | 2 + lib/ns/query.c | 385 ++++++++++++++++++++++--------------- 4 files changed, 237 insertions(+), 155 deletions(-) diff --git a/lib/ns/client.c b/lib/ns/client.c index 1f9f47218c..3f15e5f76d 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -3046,8 +3046,8 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { client->interface = NULL; client->peeraddr_valid = false; dns_ecs_init(&client->ecs); - client->filter_aaaa = dns_aaaa_ok; - client->needshutdown = (client->sctx->options & NS_SERVER_CLIENTTEST); + client->needshutdown = ((client->sctx->options & + NS_SERVER_CLIENTTEST) != 0); ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL, NS_EVENT_CLIENTCONTROL, client_start, client, client, diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 8852d7c7ae..10e47fe53a 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -148,7 +148,6 @@ struct ns_client { struct in6_pktinfo pktinfo; isc_dscp_t dscp; isc_event_t ctlevent; - dns_aaaa_t filter_aaaa; /*% * Information about recent FORMERR response(s), for * FORMERR loop avoidance. This is separate for each diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index 04b38f0a31..ec07d2821a 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -162,6 +162,8 @@ typedef struct query_ctx { dns_rpz_st_t *rpz_st; /* RPZ state */ dns_zone_t *zone; /* zone to search */ + dns_aaaa_t filter_aaaa; /* AAAA filtering */ + isc_result_t result; /* query result */ int line; /* line to report error */ } query_ctx_t; diff --git a/lib/ns/query.c b/lib/ns/query.c index 54af7eac7c..d0b079b75f 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -1619,45 +1619,34 @@ query_isduplicate(ns_client_t *client, dns_name_t *name, } static isc_result_t -query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { - ns_client_t *client = arg; - isc_result_t result, eresult; - dns_dbnode_t *node; - dns_db_t *db; - dns_name_t *fname, *mname; - dns_rdataset_t *rdataset, *sigrdataset, *trdataset; - isc_buffer_t *dbuf; +query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { + query_ctx_t *qctx = arg; + ns_client_t *client = qctx->client; + isc_result_t result, eresult = ISC_R_SUCCESS; + dns_dbnode_t *node = NULL; + dns_db_t *db = NULL; + dns_name_t *fname = NULL, *mname = NULL; + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + dns_rdataset_t *trdataset = NULL; + isc_buffer_t *dbuf = NULL; isc_buffer_t b; - ns_dbversion_t *dbversion; - dns_dbversion_t *version; - bool added_something, need_addname; + ns_dbversion_t *dbversion = NULL; + dns_dbversion_t *version = NULL; + bool added_something = false, need_addname = false; dns_rdatatype_t type; dns_clientinfomethods_t cm; dns_clientinfo_t ci; - dns_rdatasetadditional_t additionaltype; + dns_rdatasetadditional_t additionaltype = + dns_rdatasetadditional_fromauth; REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(qtype != dns_rdatatype_any); - if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) + if (!WANTDNSSEC(client) && dns_rdatatype_isdnssec(qtype)) { return (ISC_R_SUCCESS); + } - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional"); - - /* - * Initialization. - */ - eresult = ISC_R_SUCCESS; - fname = NULL; - rdataset = NULL; - sigrdataset = NULL; - trdataset = NULL; - db = NULL; - version = NULL; - node = NULL; - added_something = false; - need_addname = false; - additionaltype = dns_rdatasetadditional_fromauth; + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb"); dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, client, NULL); @@ -1668,49 +1657,56 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * To avoid multiple lookups, we do an 'any' database * lookup and iterate over the node. */ - if (qtype == dns_rdatatype_a) + if (qtype == dns_rdatatype_a) { type = dns_rdatatype_any; - else + } else { type = qtype; + } /* * Get some resources. */ dbuf = query_getnamebuf(client); - if (dbuf == NULL) + if (dbuf == NULL) { goto cleanup; + } fname = query_newname(client, dbuf, &b); rdataset = query_newrdataset(client); - if (fname == NULL || rdataset == NULL) + if (fname == NULL || rdataset == NULL) { goto cleanup; + } if (WANTDNSSEC(client)) { sigrdataset = query_newrdataset(client); - if (sigrdataset == NULL) + if (sigrdataset == NULL) { goto cleanup; + } } /* * If we want only minimal responses and are here, then it must * be for glue. */ - if (client->view->minimalresponses == dns_minimal_yes) + if (client->view->minimalresponses == dns_minimal_yes) { goto try_glue; + } /* * Look within the same zone database for authoritative * additional data. */ - if (!client->query.authdbset || client->query.authdb == NULL) + if (!client->query.authdbset || client->query.authdb == NULL) { goto try_cache; + } dbversion = query_findversion(client, client->query.authdb); - if (dbversion == NULL) + if (dbversion == NULL) { goto try_cache; + } dns_db_attach(client->query.authdb, &db); version = dbversion->version; - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: db_find"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: db_find"); /* * Since we are looking for authoritative data, we do not set @@ -1724,16 +1720,21 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { if (result == ISC_R_SUCCESS) { if (sigrdataset != NULL && !dns_db_issecure(db) && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } goto found; } - if (dns_rdataset_isassociated(rdataset)) + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + } + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_disassociate(sigrdataset); - if (node != NULL) + } + if (node != NULL) { dns_db_detachnode(db, &node); + } version = NULL; dns_db_detach(&db); @@ -1742,8 +1743,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ try_cache: - if (!client->view->recursion) + if (!client->view->recursion) { goto try_glue; + } additionaltype = dns_rdatasetadditional_fromcache; result = query_getcachedb(client, name, qtype, &db, DNS_GETDB_NOLOG); @@ -1758,8 +1760,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ if (sigrdataset == NULL) { sigrdataset = query_newrdataset(client); - if (sigrdataset == NULL) + if (sigrdataset == NULL) { goto cleanup; + } } version = NULL; @@ -1770,17 +1773,21 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { rdataset, sigrdataset); dns_cache_updatestats(client->view->cache, result); - if (!WANTDNSSEC(client)) + if (!WANTDNSSEC(client)) { query_putrdataset(client, &sigrdataset); + } if (result == ISC_R_SUCCESS) goto found; - if (dns_rdataset_isassociated(rdataset)) + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); - if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + } + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_disassociate(sigrdataset); - if (node != NULL) + } + if (node != NULL) { dns_db_detachnode(db, &node); + } dns_db_detach(&db); try_glue: @@ -1799,18 +1806,21 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * case (identified by client->query.gluedb being set). */ - if (client->query.gluedb == NULL) + if (client->query.gluedb == NULL) { goto cleanup; + } /* * Don't poison caches using the bailiwick protection model. */ - if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) + if (!dns_name_issubdomain(name, dns_db_origin(client->query.gluedb))) { goto cleanup; + } dbversion = query_findversion(client, client->query.gluedb); - if (dbversion == NULL) + if (dbversion == NULL) { goto cleanup; + } dns_db_attach(client->query.gluedb, &db); version = dbversion->version; @@ -1819,10 +1829,12 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { client->query.dboptions | DNS_DBFIND_GLUEOK, client->now, &node, fname, &cm, &ci, rdataset, sigrdataset); - if (!(result == ISC_R_SUCCESS || - result == DNS_R_ZONECUT || - result == DNS_R_GLUE)) + if (result != ISC_R_SUCCESS && + result != DNS_R_ZONECUT && + result != DNS_R_GLUE) + { goto cleanup; + } found: /* @@ -1837,13 +1849,15 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ mname = NULL; if (dns_rdataset_isassociated(rdataset) && - !query_isduplicate(client, fname, type, &mname)) { + !query_isduplicate(client, fname, type, &mname)) + { if (mname != NULL) { INSIST(mname != fname); query_releasename(client, &fname); fname = mname; - } else + } else { need_addname = true; + } ISC_LIST_APPEND(fname->list, rdataset, link); trdataset = rdataset; rdataset = NULL; @@ -1871,23 +1885,28 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * XXXRTH This code could be more efficient. */ if (rdataset != NULL) { - if (dns_rdataset_isassociated(rdataset)) + if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); + } } else { rdataset = query_newrdataset(client); - if (rdataset == NULL) + if (rdataset == NULL) { goto addname; + } } if (sigrdataset != NULL) { - if (dns_rdataset_isassociated(sigrdataset)) + if (dns_rdataset_isassociated(sigrdataset)) { dns_rdataset_disassociate(sigrdataset); + } } else if (WANTDNSSEC(client)) { sigrdataset = query_newrdataset(client); - if (sigrdataset == NULL) + if (sigrdataset == NULL) { goto addname; + } } - if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) + if (query_isduplicate(client, fname, dns_rdatatype_a, NULL)) { goto aaaa_lookup; + } result = dns_db_findrdataset(db, node, version, dns_rdatatype_a, 0, client->now, @@ -1898,7 +1917,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (result == ISC_R_SUCCESS) { bool invalid = false; mname = NULL; @@ -1917,7 +1938,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (!query_isduplicate(client, fname, dns_rdatatype_a, &mname)) { if (mname != fname) { @@ -1925,8 +1948,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { query_releasename(client, &fname); fname = mname; - } else + } else { need_addname = true; + } } ISC_LIST_APPEND(fname->list, rdataset, link); added_something = true; @@ -1939,20 +1963,26 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { query_newrdataset(client); } rdataset = query_newrdataset(client); - if (rdataset == NULL) + if (rdataset == NULL) { goto addname; - if (WANTDNSSEC(client) && sigrdataset == NULL) + } + if (WANTDNSSEC(client) && sigrdataset == NULL) { goto addname; + } } else { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } } aaaa_lookup: if (query_isduplicate(client, fname, dns_rdatatype_aaaa, NULL)) + { goto addname; + } result = dns_db_findrdataset(db, node, version, dns_rdatatype_aaaa, 0, client->now, @@ -1963,7 +1993,9 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (result == ISC_R_SUCCESS) { bool invalid = false; mname = NULL; @@ -1971,11 +2003,13 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * There's an A; check whether we're filtering AAAA */ if (have_a && - (client->filter_aaaa == dns_aaaa_break_dnssec || - (client->filter_aaaa == dns_aaaa_filter && + (qctx->filter_aaaa == dns_aaaa_break_dnssec || + (qctx->filter_aaaa == dns_aaaa_filter && (!WANTDNSSEC(client) || sigrdataset == NULL || !dns_rdataset_isassociated(sigrdataset))))) + { goto addname; + } if (additionaltype == dns_rdatasetadditional_fromcache && @@ -1991,16 +2025,20 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) + { dns_rdataset_disassociate(sigrdataset); + } } else if (!query_isduplicate(client, fname, - dns_rdatatype_aaaa, &mname)) { + dns_rdatatype_aaaa, &mname)) + { if (mname != fname) { if (mname != NULL) { query_releasename(client, &fname); fname = mname; - } else + } else { need_addname = true; + } } ISC_LIST_APPEND(fname->list, rdataset, link); added_something = true; @@ -2017,21 +2055,23 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } addname: - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: addname"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: addname"); /* * If we haven't added anything, then we're done. */ - if (!added_something) + if (!added_something) { goto cleanup; + } /* * We may have added our rdatasets to an existing name, if so, then * need_addname will be false. Whether we used an existing name * or a new one, we must set fname to NULL to prevent cleanup. */ - if (need_addname) + if (need_addname) { dns_message_addname(client->message, fname, DNS_SECTION_ADDITIONAL); + } fname = NULL; /* @@ -2052,49 +2092,68 @@ query_addadditional(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * as well. */ eresult = dns_rdataset_additionaldata(trdataset, - query_addadditional, - client); + query_additional_cb, + qctx); } cleanup: - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: cleanup"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup"); query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) + if (sigrdataset != NULL) { query_putrdataset(client, &sigrdataset); - if (fname != NULL) + } + if (fname != NULL) { query_releasename(client, &fname); - if (node != NULL) + } + if (node != NULL) { dns_db_detachnode(db, &node); - if (db != NULL) + } + if (db != NULL) { dns_db_detach(&db); + } - CTRACE(ISC_LOG_DEBUG(3), "query_addadditional: done"); + CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: done"); return (eresult); } +/* + * Add 'rdataset' to 'name'. + */ +static inline void +query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) { + ISC_LIST_APPEND(name->list, rdataset, link); +} + +/* + * Set the ordering for 'rdataset'. + */ static void -query_addrdataset(ns_client_t *client, dns_section_t section, - dns_name_t *fname, dns_rdataset_t *rdataset) -{ - UNUSED(section); +query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { + ns_client_t *client = qctx->client; - /* - * Add 'rdataset' and any pertinent additional data to - * 'fname', a name in the response message for 'client'. - */ + CTRACE(ISC_LOG_DEBUG(3), "query_setorder"); - CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset"); - - ISC_LIST_APPEND(fname->list, rdataset, link); - - if (client->view->order != NULL) - rdataset->attributes |= dns_order_find(client->view->order, - fname, rdataset->type, - rdataset->rdclass); + if (client->view->order != NULL) { + rdataset->attributes |= + dns_order_find(qctx->client->view->order, + name, rdataset->type, + rdataset->rdclass); + } rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; +}; - if (NOADDITIONAL(client)) +/* + * Handle glue and fetch any other needed additional data for 'rdataset' + */ +static void +query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { + ns_client_t *client = qctx->client; + + CTRACE(ISC_LOG_DEBUG(3), "query_additional"); + + if (NOADDITIONAL(client)) { return; + } /* * Try to process glue directly. @@ -2109,48 +2168,50 @@ query_addrdataset(ns_client_t *client, dns_section_t section, unsigned int options = 0; dbversion = query_findversion(client, client->query.gluedb); - if (dbversion == NULL) + if (dbversion == NULL) { goto regular; + } - if (client->filter_aaaa == dns_aaaa_filter || - client->filter_aaaa == dns_aaaa_break_dnssec) + if (qctx->filter_aaaa == dns_aaaa_filter || + qctx->filter_aaaa == dns_aaaa_break_dnssec) { options |= DNS_RDATASETADDGLUE_FILTERAAAA; } result = dns_rdataset_addglue(rdataset, dbversion->version, options, client->message); - if (result == ISC_R_SUCCESS) + if (result == ISC_R_SUCCESS) { return; + } } regular: /* - * Add additional data. - * + * Add other additional data if needed. * We don't care if dns_rdataset_additionaldata() fails. */ - (void)dns_rdataset_additionaldata(rdataset, query_addadditional, - client); - CTRACE(ISC_LOG_DEBUG(3), "query_addrdataset: done"); + (void)dns_rdataset_additionaldata(rdataset, query_additional_cb, qctx); + CTRACE(ISC_LOG_DEBUG(3), "query_additional: done"); } static void -query_addrrset(ns_client_t *client, dns_name_t **namep, +query_addrrset(query_ctx_t *qctx, dns_name_t **namep, dns_rdataset_t **rdatasetp, dns_rdataset_t **sigrdatasetp, isc_buffer_t *dbuf, dns_section_t section) { + isc_result_t result; + ns_client_t *client = qctx->client; dns_name_t *name = *namep, *mname = NULL; dns_rdataset_t *rdataset = *rdatasetp, *mrdataset = NULL; dns_rdataset_t *sigrdataset = NULL; - isc_result_t result; CTRACE(ISC_LOG_DEBUG(3), "query_addrrset"); REQUIRE(name != NULL); - if (sigrdatasetp != NULL) + if (sigrdatasetp != NULL) { sigrdataset = *sigrdatasetp; + } /*% * To the current response for 'client', add the answer RRset @@ -2171,37 +2232,50 @@ query_addrrset(ns_client_t *client, dns_name_t **namep, */ CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname succeeded: done"); - if (dbuf != NULL) + if (dbuf != NULL) { query_releasename(client, namep); - if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) + } + if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) { mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED; + } return; } else if (result == DNS_R_NXDOMAIN) { /* * The name doesn't exist. */ - if (dbuf != NULL) + if (dbuf != NULL) { query_keepname(client, name, dbuf); + } dns_message_addname(client->message, name, section); *namep = NULL; mname = name; } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); - if (dbuf != NULL) + if (dbuf != NULL) { query_releasename(client, namep); + } } if (rdataset->trust != dns_trust_secure && (section == DNS_SECTION_ANSWER || section == DNS_SECTION_AUTHORITY)) + { client->query.attributes &= ~NS_QUERYATTR_SECURE; + } + + /* + * Update message name, set rdataset order, and do additional + * section processing if needed. + */ + query_addtoname(mname, rdataset); + query_setorder(qctx, mname, rdataset); + query_additional(qctx, rdataset); /* * Note: we only add SIGs if we've added the type they cover, so * we do not need to check if the SIG rdataset is already in the * response. */ - query_addrdataset(client, section, mname, rdataset); *rdatasetp = NULL; if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { /* @@ -5027,6 +5101,7 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, qctx->nxrewrite = false; qctx->answer_has_ns = false; qctx->authoritative = false; + qctx->filter_aaaa = dns_aaaa_ok; } /*% @@ -6820,7 +6895,7 @@ query_addnoqnameproof(query_ctx_t *qctx) { result = dns_rdataset_getnoqname(qctx->noqname, fname, neg, negsig); RUNTIME_CHECK(result == ISC_R_SUCCESS); - query_addrrset(client, &fname, &neg, &negsig, dbuf, + query_addrrset(qctx, &fname, &neg, &negsig, dbuf, DNS_SECTION_AUTHORITY); if ((qctx->noqname->attributes & DNS_RDATASETATTR_CLOSEST) == 0) { @@ -6851,7 +6926,7 @@ query_addnoqnameproof(query_ctx_t *qctx) { result = dns_rdataset_getclosest(qctx->noqname, fname, neg, negsig); RUNTIME_CHECK(result == ISC_R_SUCCESS); - query_addrrset(client, &fname, &neg, &negsig, dbuf, + query_addrrset(qctx, &fname, &neg, &negsig, dbuf, DNS_SECTION_AUTHORITY); cleanup: @@ -6919,7 +6994,7 @@ query_respond_any(query_ctx_t *qctx) { * Notice the presence of A and AAAAs so * that AAAAs can be hidden from IPv4 clients. */ - if (qctx->client->filter_aaaa != dns_aaaa_ok) { + if (qctx->filter_aaaa != dns_aaaa_ok) { if (qctx->rdataset->type == dns_rdatatype_aaaa) have_aaaa = true; else if (qctx->rdataset->type == dns_rdatatype_a) @@ -7007,7 +7082,7 @@ query_respond_any(query_ctx_t *qctx) { else onetype = qctx->rdataset->type; - query_addrrset(qctx->client, + query_addrrset(qctx, (qctx->fname != NULL) ? &qctx->fname : &tname, @@ -7046,9 +7121,9 @@ query_respond_any(query_ctx_t *qctx) { * Filter AAAAs if there is an A and there is no signature * or we are supposed to break DNSSEC. */ - if (qctx->client->filter_aaaa == dns_aaaa_break_dnssec) + if (qctx->filter_aaaa == dns_aaaa_break_dnssec) qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; - else if (qctx->client->filter_aaaa != dns_aaaa_ok && + else if (qctx->filter_aaaa != dns_aaaa_ok && have_aaaa && have_a && (!have_sig || !WANTDNSSEC(qctx->client))) qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; @@ -7181,8 +7256,8 @@ static isc_result_t query_filter_aaaa(query_ctx_t *qctx) { isc_result_t result; - if (qctx->client->filter_aaaa != dns_aaaa_break_dnssec && - (qctx->client->filter_aaaa != dns_aaaa_filter || + 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)))) { @@ -7409,7 +7484,7 @@ query_respond(query_ctx_t *qctx) { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, qctx->rdataset); - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER); } @@ -7581,7 +7656,10 @@ query_dns64(query_ctx_t *qctx) { dns_rdataset_setownercase(dns64_rdataset, mname); client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; dns64_rdataset->trust = qctx->rdataset->trust; - query_addrdataset(client, section, mname, dns64_rdataset); + + query_addtoname(mname, dns64_rdataset); + query_setorder(qctx, mname, dns64_rdataset); + dns64_rdataset = NULL; dns64_rdatalist = NULL; dns_message_takebuffer(client->message, &buffer); @@ -7721,7 +7799,10 @@ query_filter64(query_ctx_t *qctx) { qctx->dbuf = NULL; } myrdataset->trust = qctx->rdataset->trust; - query_addrdataset(client, section, mname, myrdataset); + + query_addtoname(mname, myrdataset); + query_setorder(qctx, mname, myrdataset); + myrdataset = NULL; myrdatalist = NULL; dns_message_takebuffer(client->message, &buffer); @@ -7866,7 +7947,7 @@ query_prepare_delegation_response(query_ctx_t *qctx) { if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { sigrdatasetp = &qctx->sigrdataset; } - query_addrrset(qctx->client, &qctx->fname, &qctx->rdataset, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_AUTHORITY); if (detach) { dns_db_detach(&qctx->client->query.gluedb); @@ -8191,7 +8272,7 @@ query_addds(query_ctx_t *qctx) { dns_fixedname_name(&fixed)); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); /* * Did we find the closest provable encloser instead? @@ -8213,7 +8294,7 @@ query_addds(query_ctx_t *qctx) { false, NULL); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } @@ -8386,7 +8467,7 @@ query_sign_nodata(query_ctx_t *qctx) { /* * Add the closest provable encloser. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, qctx->dbuf, @@ -8486,7 +8567,7 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { INSIST(qctx->fname != NULL); if ((qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) == 0) { - query_addrrset(client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); return; @@ -8531,7 +8612,7 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { /* This will succeed, since we've stripped labels. */ RUNTIME_CHECK(dns_name_concatenate(dns_wildcardname, fname, fname, NULL) == ISC_R_SUCCESS); - query_addrrset(client, &fname, &qctx->rdataset, &qctx->sigrdataset, + query_addrrset(qctx, &fname, &qctx->rdataset, &qctx->sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } @@ -8598,7 +8679,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { * Add NSEC record if we found one. */ if (dns_rdataset_isassociated(qctx->rdataset)) - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); query_addwildcardproof(qctx, false, false); @@ -8789,14 +8870,14 @@ query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer, if (!WANTDNSSEC(qctx->client)) { sigsoardatasetp = NULL; } - query_addrrset(qctx->client, &name, soardatasetp, sigsoardatasetp, + query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf, DNS_SECTION_AUTHORITY); if (WANTDNSSEC(qctx->client)) { /* * Add NODATA proof. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); } @@ -8870,14 +8951,14 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, sigrdatasetp = NULL; } - query_addrrset(qctx->client, &name, &clone, sigrdatasetp, + query_addrrset(qctx, &name, &clone, sigrdatasetp, dbuf, DNS_SECTION_ANSWER); if (WANTDNSSEC(qctx->client)) { /* * Add NOQNAME proof. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); } @@ -9016,14 +9097,14 @@ query_synthnxdomain(query_ctx_t *qctx, if (!WANTDNSSEC(qctx->client)) { sigsoardatasetp = NULL; } - query_addrrset(qctx->client, &name, soardatasetp, sigsoardatasetp, + query_addrrset(qctx, &name, soardatasetp, sigsoardatasetp, dbuf, DNS_SECTION_AUTHORITY); if (WANTDNSSEC(qctx->client)) { /* * Add NOQNAME proof. */ - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); @@ -9054,7 +9135,7 @@ query_synthnxdomain(query_ctx_t *qctx, /* * Add NOWILDCARD proof. */ - query_addrrset(qctx->client, &name, &clone, &sigclone, + query_addrrset(qctx, &name, &clone, &sigclone, dbuf, DNS_SECTION_AUTHORITY); } @@ -9187,7 +9268,7 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (qctx->client->filter_aaaa != dns_aaaa_ok && + if (qctx->filter_aaaa != dns_aaaa_ok && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ { @@ -9257,7 +9338,7 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (qctx->client->filter_aaaa != dns_aaaa_ok && + if (qctx->filter_aaaa != dns_aaaa_ok && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ { @@ -9511,7 +9592,7 @@ query_cname(query_ctx_t *qctx) { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, qctx->rdataset); - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER); @@ -9614,7 +9695,7 @@ query_dname(query_ctx_t *qctx) { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, qctx->rdataset); - query_addrrset(qctx->client, &qctx->fname, + query_addrrset(qctx, &qctx->fname, &qctx->rdataset, sigrdatasetp, qctx->dbuf, DNS_SECTION_ANSWER); @@ -9769,7 +9850,7 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { rdataset->trust = trust; dns_rdataset_setownercase(rdataset, aname); - query_addrrset(client, &aname, &rdataset, NULL, NULL, + query_addrrset(qctx, &aname, &rdataset, NULL, NULL, DNS_SECTION_ANSWER); if (rdataset != NULL) { if (dns_rdataset_isassociated(rdataset)) @@ -9805,7 +9886,7 @@ query_prepresponse(query_ctx_t *qctx) { * clients if there is an A; filter-aaaa-on-v6 option does the same * for IPv6 clients. */ - qctx->client->filter_aaaa = dns_aaaa_ok; + qctx->filter_aaaa = dns_aaaa_ok; if (qctx->client->view->v4_aaaa != dns_aaaa_ok || qctx->client->view->v6_aaaa != dns_aaaa_ok) { @@ -9817,12 +9898,12 @@ query_prepresponse(query_ctx_t *qctx) { qctx->client->view->v4_aaaa != dns_aaaa_ok && is_v4_client(qctx->client)) { - qctx->client->filter_aaaa = qctx->client->view->v4_aaaa; + 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->client->filter_aaaa = qctx->client->view->v6_aaaa; + qctx->filter_aaaa = qctx->client->view->v6_aaaa; } } @@ -9960,7 +10041,7 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, if (section == DNS_SECTION_ADDITIONAL) rdataset->attributes |= DNS_RDATASETATTR_REQUIRED; - query_addrrset(client, &name, &rdataset, + query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL, section); } @@ -10059,7 +10140,7 @@ query_addns(query_ctx_t *qctx) { if (sigrdataset != NULL) { sigrdatasetp = &sigrdataset; } - query_addrrset(client, &name, &rdataset, sigrdatasetp, NULL, + query_addrrset(qctx, &name, &rdataset, sigrdatasetp, NULL, DNS_SECTION_AUTHORITY); } @@ -10250,7 +10331,7 @@ query_addbestns(query_ctx_t *qctx) { query_putrdataset(client, &sigrdataset); } - query_addrrset(client, &fname, &rdataset, &sigrdataset, dbuf, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); cleanup: @@ -10418,7 +10499,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, if (!dns_rdataset_isassociated(rdataset)) goto cleanup; if (!ispositive) - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); /* @@ -10457,7 +10538,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, fname, false, NULL); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); if (ispositive) @@ -10498,7 +10579,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, fname, nodata, NULL); if (!dns_rdataset_isassociated(rdataset)) goto cleanup; - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); goto cleanup; @@ -10530,7 +10611,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, have_wname = true; dns_rdata_freestruct(&nsec); } - query_addrrset(client, &fname, &rdataset, &sigrdataset, + query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } if (rdataset != NULL) From d43dcef139c71523fccaa88bae155b51e6c5196d Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 6 Aug 2018 19:34:20 -0700 Subject: [PATCH 03/26] refactor filter-aaaa implementation - the goal of this change is for AAAA filtering to be fully contained in the query logic, and implemented at discrete points that can be replaced with hook callouts later on. - the new code may be slightly less efficient than the old filter-aaaa implementation, but maximum efficiency was never a priority for AAAA filtering anyway. - we now use the rdataset RENDERED attribute to indicate that an AAAA rdataset should not be included when rendering the message. (this flag was originally meant to indicate that an rdataset has already been rendered and should not be repeated, but it can also be used to prevent rendering in the first place.) - the DNS_MESSAGERENDER_FILTER_AAAA, NS_CLIENTATTR_FILTER_AAAA, and DNS_RDATASETGLUE_FILTERAAAA flags are all now unnecessary and have been removed. --- bin/tests/system/filter-aaaa/tests.sh | 3 - lib/dns/include/dns/db.h | 2 +- lib/dns/include/dns/message.h | 2 +- lib/dns/include/dns/rdataset.h | 16 +- lib/dns/message.c | 58 --- lib/dns/rbtdb.c | 91 ++-- lib/dns/rdataset.c | 7 +- lib/ns/client.c | 18 +- lib/ns/include/ns/client.h | 10 +- lib/ns/include/ns/hooks.h | 7 +- lib/ns/include/ns/query.h | 11 + lib/ns/query.c | 694 +++++++++++++++++--------- lib/ns/server.c | 6 + 13 files changed, 540 insertions(+), 385 deletions(-) diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh index 16a9332518..f3e06b4fe4 100644 --- a/bin/tests/system/filter-aaaa/tests.sh +++ b/bin/tests/system/filter-aaaa/tests.sh @@ -117,7 +117,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS any dual.signed -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1 grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1 -grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1 grep "1.0.0.3" dig.out.ns1.test$n > /dev/null || ret=1 grep "::3" dig.out.ns1.test$n > /dev/null && ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi @@ -128,7 +127,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS any dual.unsigned -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1 grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1 -grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1 grep "1.0.0.6" dig.out.ns1.test$n > /dev/null || ret=1 grep "::6" dig.out.ns1.test$n > /dev/null && ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi @@ -150,7 +148,6 @@ echo_i "checking that A and not AAAA is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS any dual.unsigned +dnssec -b 10.53.0.1 @10.53.0.1 > dig.out.ns1.test$n || ret=1 grep "status: NOERROR" dig.out.ns1.test$n > /dev/null || ret=1 -grep "AUTHORITY: 0," dig.out.ns1.test$n > /dev/null || ret=1 grep "1.0.0.6" dig.out.ns1.test$n > /dev/null || ret=1 grep "::6" dig.out.ns1.test$n > /dev/null && ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi diff --git a/lib/dns/include/dns/db.h b/lib/dns/include/dns/db.h index b7b28c4ed7..4f77471e79 100644 --- a/lib/dns/include/dns/db.h +++ b/lib/dns/include/dns/db.h @@ -1142,7 +1142,7 @@ dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version, * * \li 'sigrdataset' is a valid, disassociated rdataset, or it is NULL. * - * \li If 'covers' != 0, 'type' must be SIG. + * \li If 'covers' != 0, 'type' must be RRSIG. * * \li 'type' is not a meta-RR type such as 'ANY' or 'OPT'. * diff --git a/lib/dns/include/dns/message.h b/lib/dns/include/dns/message.h index 28290e0be5..6f389aa2df 100644 --- a/lib/dns/include/dns/message.h +++ b/lib/dns/include/dns/message.h @@ -181,7 +181,7 @@ typedef int dns_messagetextflag_t; additional section. */ #define DNS_MESSAGERENDER_PREFER_AAAA 0x0010 /*%< prefer AAAA records in additional section. */ -#define DNS_MESSAGERENDER_FILTER_AAAA 0x0020 /*%< filter AAAA records */ +/* Obsolete: DNS_MESSAGERENDER_FILTER_AAAA 0x0020 */ typedef struct dns_msgblock dns_msgblock_t; diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index f48e32d55c..6a07d214c9 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -92,7 +92,6 @@ typedef struct dns_rdatasetmethods { dns_name_t *name); isc_result_t (*addglue)(dns_rdataset_t *rdataset, dns_dbversion_t *version, - unsigned int options, dns_message_t *msg); } dns_rdatasetmethods_t; @@ -197,13 +196,6 @@ struct dns_rdataset { */ #define DNS_RDATASETTOWIRE_OMITDNSSEC 0x0001 -/*% - * _FILTERAAAA - * If A records are present, omit AAAA records when adding - * glue - */ -#define DNS_RDATASETADDGLUE_FILTERAAAA 0x0001 - void dns_rdataset_init(dns_rdataset_t *rdataset); /*%< @@ -580,14 +572,11 @@ dns_rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); */ isc_result_t -dns_rdataset_addglue(dns_rdataset_t *rdataset, - dns_dbversion_t *version, - unsigned int options, +dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, dns_message_t *msg); /*%< * Add glue records for rdataset to the additional section of message in - * 'msg'. 'rdataset' must be of type NS. If DNS_RDATASETADDGLUE_FILTERAAAA - * is set in 'options' there is type A glue, type AAAA glue is not added. + * 'msg'. 'rdataset' must be of type NS. * * In case a successful result is not returned, the caller should try to * add glue directly to the message by iterating for additional data. @@ -595,7 +584,6 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset, * Requires: * \li 'rdataset' is a valid NS rdataset. * \li 'version' is the DB version. - * \li 'options' is options; currently only _FILTERAAAA is defined. * \li 'msg' is the DNS message to which the glue should be added. * * Returns: diff --git a/lib/dns/message.c b/lib/dns/message.c index 4a811d28db..f584700628 100644 --- a/lib/dns/message.c +++ b/lib/dns/message.c @@ -1903,48 +1903,6 @@ wrong_priority(dns_rdataset_t *rds, int pass, dns_rdatatype_t preferred_glue) { return (true); } -/* - * Decide whether to not answer with an AAAA record and its RRSIG - */ -static inline bool -norender_rdataset(const dns_rdataset_t *rdataset, unsigned int options, - dns_section_t sectionid) -{ - if (sectionid == DNS_SECTION_QUESTION) - return (false); - - switch (rdataset->type) { - case dns_rdatatype_ns: - if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 || - sectionid != DNS_SECTION_AUTHORITY) - return (false); - break; - - case dns_rdatatype_aaaa: - if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0) - return (false); - break; - - case dns_rdatatype_rrsig: - if ((options & DNS_MESSAGERENDER_FILTER_AAAA) == 0 || - (rdataset->covers != dns_rdatatype_ns && - rdataset->covers != dns_rdatatype_aaaa)) - return (false); - if ((rdataset->covers == dns_rdatatype_ns) && - (sectionid != DNS_SECTION_AUTHORITY)) - return (false); - break; - - default: - return (false); - } - - if (rdataset->rdclass != dns_rdataclass_in) - return (false); - - return (true); -} - static isc_result_t renderset(dns_rdataset_t *rdataset, const dns_name_t *owner_name, dns_compress_t *cctx, isc_buffer_t *target, @@ -2104,22 +2062,6 @@ dns_message_rendersection(dns_message_t *msg, dns_section_t sectionid, preferred_glue)) goto next; - /* - * Suppress AAAAs if asked and we are - * not doing DNSSEC or are breaking DNSSEC. - * Say so in the AD bit if we break DNSSEC. - */ - if (norender_rdataset(rdataset, options, - sectionid)) - { - if (sectionid == DNS_SECTION_ANSWER || - sectionid == DNS_SECTION_AUTHORITY) - msg->flags &= ~DNS_MESSAGEFLAG_AD; - if (OPTOUT(rdataset)) - msg->flags &= ~DNS_MESSAGEFLAG_AD; - goto next; - } - st = *(msg->buffer); count = 0; diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 2f5db4fa7b..22dd60519e 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -561,7 +561,6 @@ static void rdataset_getownercase(const dns_rdataset_t *rdataset, dns_name_t *name); static isc_result_t rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, - unsigned int options, dns_message_t *msg); static void free_gluetable(rbtdb_version_t *version); @@ -9807,9 +9806,7 @@ out: } static isc_result_t -rdataset_addglue(dns_rdataset_t *rdataset, - dns_dbversion_t *version, - unsigned int options, +rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, dns_message_t *msg) { dns_rbtdb_t *rbtdb = rdataset->private1; @@ -9926,42 +9923,39 @@ restart: } } - if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0)) - { - if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) { - result = dns_message_gettemprdataset(msg, - &rdataset_aaaa); - if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) { - dns_message_puttempname(msg, &name); - if (rdataset_a != NULL) { - dns_message_puttemprdataset(msg, - &rdataset_a); - } - if (sigrdataset_a != NULL) { - dns_message_puttemprdataset(msg, - &sigrdataset_a); - } - goto no_glue; + if (dns_rdataset_isassociated(&ge->rdataset_aaaa)) { + result = dns_message_gettemprdataset(msg, + &rdataset_aaaa); + if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) { + dns_message_puttempname(msg, &name); + if (rdataset_a != NULL) { + dns_message_puttemprdataset(msg, + &rdataset_a); } + if (sigrdataset_a != NULL) { + dns_message_puttemprdataset(msg, + &sigrdataset_a); + } + goto no_glue; } + } - if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) { - result = dns_message_gettemprdataset(msg, - &sigrdataset_aaaa); - if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) { - dns_message_puttempname(msg, &name); - if (rdataset_a != NULL) { - dns_message_puttemprdataset(msg, - &rdataset_a); - } - if (sigrdataset_a != NULL) - dns_message_puttemprdataset(msg, - &sigrdataset_a); - if (rdataset_aaaa != NULL) - dns_message_puttemprdataset(msg, - &rdataset_aaaa); - goto no_glue; + if (dns_rdataset_isassociated(&ge->sigrdataset_aaaa)) { + result = dns_message_gettemprdataset(msg, + &sigrdataset_aaaa); + if (ISC_UNLIKELY(result != ISC_R_SUCCESS)) { + dns_message_puttempname(msg, &name); + if (rdataset_a != NULL) { + dns_message_puttemprdataset(msg, + &rdataset_a); } + if (sigrdataset_a != NULL) + dns_message_puttemprdataset(msg, + &sigrdataset_a); + if (rdataset_aaaa != NULL) + dns_message_puttemprdataset(msg, + &rdataset_aaaa); + goto no_glue; } } @@ -9975,20 +9969,17 @@ restart: ISC_LIST_APPEND(name->list, sigrdataset_a, link); } - if (ISC_LIKELY((options & DNS_RDATASETADDGLUE_FILTERAAAA) == 0)) - { - if (rdataset_aaaa != NULL) { - dns_rdataset_clone(&ge->rdataset_aaaa, - rdataset_aaaa); - ISC_LIST_APPEND(name->list, rdataset_aaaa, - link); - } - if (sigrdataset_aaaa != NULL) { - dns_rdataset_clone(&ge->sigrdataset_aaaa, - sigrdataset_aaaa); - ISC_LIST_APPEND(name->list, sigrdataset_aaaa, - link); - } + if (rdataset_aaaa != NULL) { + dns_rdataset_clone(&ge->rdataset_aaaa, + rdataset_aaaa); + ISC_LIST_APPEND(name->list, rdataset_aaaa, + link); + } + if (sigrdataset_aaaa != NULL) { + dns_rdataset_clone(&ge->sigrdataset_aaaa, + sigrdataset_aaaa); + ISC_LIST_APPEND(name->list, sigrdataset_aaaa, + link); } dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL); diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c index d6dcc91b48..576e9475b5 100644 --- a/lib/dns/rdataset.c +++ b/lib/dns/rdataset.c @@ -751,9 +751,7 @@ dns_rdataset_trimttl(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, } isc_result_t -dns_rdataset_addglue(dns_rdataset_t *rdataset, - dns_dbversion_t *version, - unsigned int options, +dns_rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, dns_message_t *msg) { REQUIRE(DNS_RDATASET_VALID(rdataset)); @@ -763,6 +761,5 @@ dns_rdataset_addglue(dns_rdataset_t *rdataset, if (rdataset->methods->addglue == NULL) return (ISC_R_NOTIMPLEMENTED); - return ((rdataset->methods->addglue)(rdataset, version, - options, msg)); + return ((rdataset->methods->addglue)(rdataset, version, msg)); } diff --git a/lib/ns/client.c b/lib/ns/client.c index 3f15e5f76d..1100db7ffc 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -1097,23 +1097,6 @@ client_send(ns_client_t *client) { preferred_glue = DNS_MESSAGERENDER_PREFER_AAAA; } - /* - * filter-aaaa-on-v4 yes or break-dnssec option to suppress - * AAAA records. - * - * We already know that request came via IPv4, - * that we have both AAAA and A records, - * and that we either have no signatures that the client wants - * or we are supposed to break DNSSEC. - * - * Override preferred glue if necessary. - */ - if ((client->attributes & NS_CLIENTATTR_FILTER_AAAA) != 0) { - render_opts |= DNS_MESSAGERENDER_FILTER_AAAA; - if (preferred_glue == DNS_MESSAGERENDER_PREFER_AAAA) - preferred_glue = DNS_MESSAGERENDER_PREFER_A; - } - /* * Create an OPT for our reply. */ @@ -3064,6 +3047,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { ISC_QLINK_INIT(client, ilink); client->keytag = NULL; client->keytag_len = 0; + client->hookflags = 0; /* * We call the init routines for the various kinds of client here, diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 10e47fe53a..d855cb7a18 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -170,6 +170,12 @@ struct ns_client { uint32_t expire; unsigned char *keytag; uint16_t keytag_len; + + /*% + * Allows a hook module to set flags + * that persist across recursion. + */ + uint32_t hookflags; }; typedef ISC_QUEUE(ns_client_t) client_queue_t; @@ -184,8 +190,8 @@ typedef ISC_LIST(ns_client_t) client_list_t; #define NS_CLIENTATTR_MULTICAST 0x00008 /*%< recv'd from multicast */ #define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */ #define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */ -#define NS_CLIENTATTR_FILTER_AAAA 0x00040 /*%< suppress AAAAs */ -#define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 /*%< recursing for A against AAAA */ +/* Obsolete: NS_CLIENTATTR_FILTER_AAAA 0x00040 */ +/* Obsolete: define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */ #define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */ #define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */ #define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */ diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 0475227750..aa6d8d1548 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -162,13 +162,11 @@ typedef enum { NS_QUERY_START_BEGIN, NS_QUERY_LOOKUP_BEGIN, NS_QUERY_RESUME_BEGIN, - NS_QUERY_PREP_RESPONSE_BEGIN, + NS_QUERY_GOT_ANSWER_BEGIN, NS_QUERY_RESPOND_ANY_BEGIN, - NS_QUERY_RESPOND_ANY_POST_LOOKUP, NS_QUERY_RESPOND_ANY_FOUND, NS_QUERY_RESPOND_ANY_NOT_FOUND, NS_QUERY_RESPOND_BEGIN, - NS_QUERY_GOT_ANSWER_BEGIN, NS_QUERY_NOTFOUND_BEGIN, NS_QUERY_PREP_DELEGATION_BEGIN, NS_QUERY_ZONE_DELEGATION_BEGIN, @@ -177,9 +175,10 @@ typedef enum { NS_QUERY_NXDOMAIN_BEGIN, NS_QUERY_CNAME_BEGIN, NS_QUERY_DNAME_BEGIN, - NS_QUERY_ADDITIONAL_BEGIN, + NS_QUERY_PREP_RESPONSE_BEGIN, NS_QUERY_DONE_BEGIN, NS_QUERY_DONE_SEND, + NS_QUERY_HOOKS_COUNT /* MUST BE LAST */ } ns_hookpoint_t; diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index ec07d2821a..2c67e7182b 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -121,6 +121,9 @@ struct ns_query { typedef 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 + * when processing ANY + * queries */ dns_rdataset_t *rdataset; /* found rdataset */ dns_rdataset_t *sigrdataset; /* found sigrdataset */ dns_rdataset_t *noqname; /* rdataset needing @@ -192,4 +195,12 @@ ns__query_sfcache(query_ctx_t *qctx); isc_result_t ns__query_start(query_ctx_t *qctx); +/* + * 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 d0b079b75f..64e2c6483c 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -191,7 +191,6 @@ client_trace(ns_client_t *client, int level, const char *message) { #define CCTRACE(l,m) ((void)m) #endif /* WANT_QUERYTRACE */ - #define DNS_GETDB_NOEXACT 0x01U #define DNS_GETDB_NOLOG 0x02U #define DNS_GETDB_PARTIAL 0x04U @@ -429,6 +428,64 @@ query_addauth(query_ctx_t *qctx); static isc_result_t query_done(query_ctx_t *qctx); +/* + * XXX: + * Functions implementing filter-aaaa. Later, these will be moved + * out to a loadable module. + */ +static isc_result_t +query_filter_aaaa_check(query_ctx_t *qctx); + +static isc_result_t +query_filter_aaaa(query_ctx_t *qctx); + +static isc_result_t +query_filter_aaaa_any(query_ctx_t *qctx); + +static isc_result_t +query_filter_aaaa_additional(query_ctx_t *qctx); + +/* + * XXX: + * This is a temporary hooks table, pre-populated with pointers to + * the 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. */ @@ -1876,8 +1933,6 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } if (qtype == dns_rdatatype_a) { - bool have_a = false; - /* * We now go looking for A and AAAA records, along with * their signatures. @@ -1923,8 +1978,6 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } else if (result == ISC_R_SUCCESS) { bool invalid = false; mname = NULL; - - have_a = true; if (additionaltype == dns_rdatasetadditional_fromcache && (DNS_TRUST_PENDING(rdataset->trust) || @@ -1999,17 +2052,6 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { } else if (result == ISC_R_SUCCESS) { bool invalid = false; mname = NULL; - /* - * There's an A; check whether we're filtering AAAA - */ - if (have_a && - (qctx->filter_aaaa == dns_aaaa_break_dnssec || - (qctx->filter_aaaa == dns_aaaa_filter && - (!WANTDNSSEC(client) || sigrdataset == NULL || - !dns_rdataset_isassociated(sigrdataset))))) - { - goto addname; - } if (additionaltype == dns_rdatasetadditional_fromcache && @@ -2165,21 +2207,14 @@ query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { { isc_result_t result; ns_dbversion_t *dbversion; - unsigned int options = 0; dbversion = query_findversion(client, client->query.gluedb); if (dbversion == NULL) { goto regular; } - if (qctx->filter_aaaa == dns_aaaa_filter || - qctx->filter_aaaa == dns_aaaa_break_dnssec) - { - options |= DNS_RDATASETADDGLUE_FILTERAAAA; - } - result = dns_rdataset_addglue(rdataset, dbversion->version, - options, client->message); + client->message); if (result == ISC_R_SUCCESS) { return; } @@ -4518,7 +4553,6 @@ static dns_name_t rfc1918names[] = { DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets) }; - static unsigned char prisoner_data[] = "\010prisoner\004iana\003org"; static unsigned char hostmaster_data[] = "\012hostmaster\014root-servers\003org"; @@ -6946,21 +6980,10 @@ query_addnoqnameproof(query_ctx_t *qctx) { */ static isc_result_t query_respond_any(query_ctx_t *qctx) { - dns_name_t *tname; - int rdatasets_found = 0; + bool found = false; dns_rdatasetiter_t *rdsiter = NULL; isc_result_t result; dns_rdatatype_t onetype = 0; /* type to use for minimal-any */ - bool have_aaaa, have_a, have_sig; - - /* - * If we are not authoritative, assume there is an A record - * even in if it is not in our cache. This assumption could - * be wrong but it is a good bet. - */ - have_aaaa = false; - have_a = !qctx->authoritative; - have_sig = false; PROCESS_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); @@ -6985,21 +7008,11 @@ query_respond_any(query_ctx_t *qctx) { * cleanup qctx->fname even though we're using it! */ query_keepname(qctx->client, qctx->fname, qctx->dbuf); - tname = qctx->fname; + qctx->tname = qctx->fname; result = dns_rdatasetiter_first(rdsiter); while (result == ISC_R_SUCCESS) { dns_rdatasetiter_current(rdsiter, qctx->rdataset); - /* - * Notice the presence of A and AAAAs so - * that AAAAs can be hidden from IPv4 clients. - */ - if (qctx->filter_aaaa != dns_aaaa_ok) { - if (qctx->rdataset->type == dns_rdatatype_aaaa) - have_aaaa = true; - else if (qctx->rdataset->type == dns_rdatatype_a) - have_a = true; - } /* * We found an NS RRset; no need to add one later. @@ -7047,9 +7060,6 @@ query_respond_any(query_ctx_t *qctx) { qctx->rdataset->type == qctx->qtype) && qctx->rdataset->type != 0) { - if (dns_rdatatype_isdnssec(qctx->rdataset->type)) - have_sig = true; - if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) { qctx->noqname = qctx->rdataset; @@ -7067,7 +7077,7 @@ query_respond_any(query_ctx_t *qctx) { dns_name_t *name; name = (qctx->fname != NULL) ? qctx->fname - : tname; + : qctx->tname; query_prefetch(qctx->client, name, qctx->rdataset); } @@ -7078,29 +7088,32 @@ query_respond_any(query_ctx_t *qctx) { */ if (qctx->rdataset->type == dns_rdatatype_sig || qctx->rdataset->type == dns_rdatatype_rrsig) + { onetype = qctx->rdataset->covers; - else + } else { onetype = qctx->rdataset->type; + } query_addrrset(qctx, (qctx->fname != NULL) ? &qctx->fname - : &tname, + : &qctx->tname, &qctx->rdataset, NULL, NULL, DNS_SECTION_ANSWER); query_addnoqnameproof(qctx); - rdatasets_found++; - INSIST(tname != NULL); + found = true; + INSIST(qctx->tname != NULL); /* * rdataset is non-NULL only in certain * pathological cases involving DNAMEs. */ - if (qctx->rdataset != NULL) + if (qctx->rdataset != NULL) { query_putrdataset(qctx->client, &qctx->rdataset); + } qctx->rdataset = query_newrdataset(qctx->client); if (qctx->rdataset == NULL) @@ -7115,36 +7128,40 @@ query_respond_any(query_ctx_t *qctx) { result = dns_rdatasetiter_next(rdsiter); } - PROCESS_HOOK(NS_QUERY_RESPOND_ANY_POST_LOOKUP, qctx); + dns_rdatasetiter_destroy(&rdsiter); - /* - * Filter AAAAs if there is an A and there is no signature - * or we are supposed to break DNSSEC. - */ - if (qctx->filter_aaaa == dns_aaaa_break_dnssec) - qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; - else if (qctx->filter_aaaa != dns_aaaa_ok && - have_aaaa && have_a && - (!have_sig || !WANTDNSSEC(qctx->client))) - qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; + if (result != ISC_R_NOMORE) { + CCTRACE(ISC_LOG_ERROR, + "query_respond_any: rdataset iterator failed"); + QUERY_ERROR(qctx, DNS_R_SERVFAIL); + } - if (qctx->fname != NULL) - dns_message_puttempname(qctx->client->message, &qctx->fname); + if (found) { + PROCESS_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx); + + if (qctx->fname != NULL) { + dns_message_puttempname(qctx->client->message, + &qctx->fname); + } + } else { + PROCESS_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx); + + if (qctx->fname != NULL) { + dns_message_puttempname(qctx->client->message, + &qctx->fname); + } - if (rdatasets_found == 0) { /* * No matching rdatasets found in cache. If we were * searching for RRSIG/SIG, that's probably okay; * otherwise this is an error condition. */ - if ((qctx->qtype == dns_rdatatype_rrsig || - qctx->qtype == dns_rdatatype_sig) && - result == ISC_R_NOMORE) + if (qctx->qtype == dns_rdatatype_rrsig || + qctx->qtype == dns_rdatatype_sig) { isc_buffer_t b; if (!qctx->is_zone) { qctx->authoritative = false; - dns_rdatasetiter_destroy(&rdsiter); qctx->client->attributes &= ~NS_CLIENTATTR_RA; query_addauth(qctx); return (query_done(qctx)); @@ -7164,7 +7181,6 @@ query_respond_any(query_ctx_t *qctx) { namebuf); } - dns_rdatasetiter_destroy(&rdsiter); qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); return (query_sign_nodata(qctx)); @@ -7176,14 +7192,7 @@ query_respond_any(query_ctx_t *qctx) { } } - dns_rdatasetiter_destroy(&rdsiter); - if (result != ISC_R_NOMORE) { - CCTRACE(ISC_LOG_ERROR, - "query_respond_any: dns_rdatasetiter_destroy failed"); - QUERY_ERROR(qctx, result); - } else { - query_addauth(qctx); - } + query_addauth(qctx); return (query_done(qctx)); } @@ -7242,101 +7251,6 @@ query_getexpire(query_ctx_t *qctx) { } } -/* - * Optionally hide AAAAs from IPv4 clients if there is an A. - * - * We add the AAAAs now, but might refuse to render them later - * after DNSSEC is figured out. - * - * This could be more efficient, but the whole idea is - * so fundamentally wrong, unavoidably inaccurate, and - * unneeded that it is best to keep it as short as possible. - */ -static isc_result_t -query_filter_aaaa(query_ctx_t *qctx) { - isc_result_t result; - - 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)))) - { - return (ISC_R_COMPLETE); - } - - if (qctx->qtype == dns_rdatatype_aaaa) { - dns_rdataset_t *trdataset; - trdataset = query_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); - } - query_putrdataset(qctx->client, &trdataset); - - /* - * We have an AAAA but the A is not in our cache. - * Assume any result other than DNS_R_DELEGATION - * or ISC_R_NOTFOUND means there is no A and - * so AAAAs are ok. - * - * Assume there is no A if we can't recurse - * for this client, although that could be - * the wrong answer. What else can we do? - * Besides, that we have the AAAA and are using - * this mechanism suggests that we care more - * about As than AAAAs and would have cached - * the A if it existed. - */ - if (result == ISC_R_SUCCESS) { - qctx->client->attributes |= - NS_CLIENTATTR_FILTER_AAAA; - - } else if (qctx->authoritative || - !RECURSIONOK(qctx->client) || - (result != DNS_R_DELEGATION && - result != ISC_R_NOTFOUND)) - { - qctx->client->attributes &= - ~NS_CLIENTATTR_FILTER_AAAA; - } else { - /* - * 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 = query_recurse(qctx->client, - dns_rdatatype_a, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->attributes |= - NS_CLIENTATTR_FILTER_AAAA_RC; - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - } - } - } else if (qctx->qtype == dns_rdatatype_a && - (qctx->client->attributes & - NS_CLIENTATTR_FILTER_AAAA_RC) != 0) - { - qctx->client->attributes &= ~NS_CLIENTATTR_FILTER_AAAA_RC; - qctx->client->attributes |= NS_CLIENTATTR_FILTER_AAAA; - qctx_clean(qctx); - - return (query_done(qctx)); - } - - return (ISC_R_COMPLETE); -} - /*% * Build a repsonse for a "normal" query, for a type other than ANY, * for which we have an answer (either positive or negative). @@ -7379,12 +7293,6 @@ query_respond(query_ctx_t *qctx) { /* * Check to see if the AAAA RRset has non-excluded addresses * in it. If not look for a A RRset. - * - * Note: the order of dns64_aaaaok() and query_filter_aaaa() is - * important. query_filter_aaaa() calls query_recurse() but - * continues so that the AAAA records are added. If the - * order is reversed client->query.fetch will be non-NULL - * when query_lookup() is called leading to a assertion. */ INSIST(qctx->client->query.dns64_aaaaok == NULL); @@ -7407,10 +7315,6 @@ query_respond(query_ctx_t *qctx) { return (query_lookup(qctx)); } - result = query_filter_aaaa(qctx); - if (result != ISC_R_COMPLETE) - return (result); - if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { sigrdatasetp = &qctx->sigrdataset; } @@ -9268,12 +9172,6 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (qctx->filter_aaaa != dns_aaaa_ok && - (qctx->type == dns_rdatatype_a || - qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ - { - goto cleanup; - } if (!ISC_LIST_EMPTY(qctx->client->view->dns64) && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ @@ -9338,12 +9236,6 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (qctx->filter_aaaa != dns_aaaa_ok && - (qctx->type == dns_rdatatype_a || - qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ - { - goto cleanup; - } if (!ISC_LIST_EMPTY(qctx->client->view->dns64) && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ @@ -9865,8 +9757,8 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { /*% * Prepare to respond: determine whether a wildcard proof is needed, - * check whether to filter AAAA answers, then hand off to query_respond() - * or (for type ANY queries) query_respond_any(). + * then hand off to query_respond() or (for type ANY queries) + * query_respond_any(). */ static isc_result_t query_prepresponse(query_ctx_t *qctx) { @@ -9881,33 +9773,6 @@ query_prepresponse(query_ctx_t *qctx) { qctx->need_wildcardproof = true; } - /* - * The filter-aaaa-on-v4 option should suppress AAAAs for IPv4 - * clients if there is an A; filter-aaaa-on-v6 option does the same - * for IPv6 clients. - */ - qctx->filter_aaaa = dns_aaaa_ok; - if (qctx->client->view->v4_aaaa != dns_aaaa_ok || - qctx->client->view->v6_aaaa != dns_aaaa_ok) - { - isc_result_t result; - 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; - } - } - - if (qctx->type == dns_rdatatype_any) { return (query_respond_any(qctx)); } else { @@ -10783,6 +10648,7 @@ query_glueanswer(query_ctx_t *qctx) { static isc_result_t query_done(query_ctx_t *qctx) { const dns_namelist_t *secs = qctx->client->message->sections; + CCTRACE(ISC_LOG_DEBUG(3), "query_done"); PROCESS_HOOK(NS_QUERY_DONE_BEGIN, qctx); @@ -11284,3 +11150,371 @@ 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 isc_result_t +query_filter_aaaa_check(query_ctx_t *qctx) { + qctx->filter_aaaa = dns_aaaa_ok; + if (qctx->client->view->v4_aaaa != dns_aaaa_ok || + qctx->client->view->v6_aaaa != dns_aaaa_ok) + { + isc_result_t result; + 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; + } + } + + return (ISC_R_COMPLETE); +} + +/* + * 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 isc_result_t +query_filter_aaaa(query_ctx_t *qctx) { + isc_result_t result; + + 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)))) + { + return (ISC_R_COMPLETE); + } + + if (qctx->qtype == dns_rdatatype_aaaa) { + dns_rdataset_t *trdataset; + trdataset = query_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); + } + query_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 = 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; + + return (query_done(qctx)); + } + + return (ISC_R_COMPLETE); +} + +/* + * Optionally hide AAAA rrsets if there is a matching A. + * (This version is for processing answers to ANY queries; + * explicit AAAA queries are handled in query_filter_aaaa().) + */ +static isc_result_t +query_filter_aaaa_any(query_ctx_t *qctx) { + dns_name_t *name = NULL; + dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; + dns_rdataset_t *a = NULL; + bool have_a = true; + + if (qctx->filter_aaaa == dns_aaaa_ok) { + return (ISC_R_COMPLETE); + } + + 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; + } + } + + return (ISC_R_COMPLETE); +} + +/* + * 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 isc_result_t +query_filter_aaaa_additional(query_ctx_t *qctx) { + isc_result_t result; + + if (qctx->filter_aaaa == dns_aaaa_ok) { + return (ISC_R_COMPLETE); + } + + 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); + } + } + + return (ISC_R_COMPLETE); +} + +static bool +filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { + isc_result_t result; + + UNUSED(cbdata); + + result = query_filter_aaaa((query_ctx_t *) hookdata); + if (result != ISC_R_COMPLETE) { + *resp = result; + return (true); + } + + *resp = ISC_R_SUCCESS; + return (false); +} + +static bool +filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { + isc_result_t result; + + UNUSED(cbdata); + + result = query_filter_aaaa_any((query_ctx_t *) hookdata); + if (result != ISC_R_COMPLETE) { + *resp = result; + return (true); + } + + *resp = ISC_R_SUCCESS; + return (false); +} + +static bool +filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { + isc_result_t result; + + UNUSED(cbdata); + + result = query_filter_aaaa_check((query_ctx_t *) hookdata); + if (result != ISC_R_COMPLETE) { + *resp = result; + return (true); + } + + *resp = ISC_R_SUCCESS; + return (false); +} + +static bool +filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { + isc_result_t result; + + UNUSED(cbdata); + + result = query_filter_aaaa_additional((query_ctx_t *) hookdata); + if (result != ISC_R_COMPLETE) { + *resp = result; + return (true); + } + + *resp = ISC_R_SUCCESS; + 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 828ce344e8..fde2c459d5 100644 --- a/lib/ns/server.c +++ b/lib/ns/server.c @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -107,6 +108,11 @@ 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; From 0d7ab9bafc565de9157b9ab5d14024630a3350b8 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 7 Aug 2018 19:39:00 -0700 Subject: [PATCH 04/26] move filter-aaaa implementation into hook functions directly --- lib/ns/query.c | 154 +++++++++++++++---------------------------------- 1 file changed, 46 insertions(+), 108 deletions(-) diff --git a/lib/ns/query.c b/lib/ns/query.c index 64e2c6483c..46b64a75a1 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -430,28 +430,11 @@ query_done(query_ctx_t *qctx); /* * XXX: - * Functions implementing filter-aaaa. Later, these will be moved - * out to a loadable module. - */ -static isc_result_t -query_filter_aaaa_check(query_ctx_t *qctx); - -static isc_result_t -query_filter_aaaa(query_ctx_t *qctx); - -static isc_result_t -query_filter_aaaa_any(query_ctx_t *qctx); - -static isc_result_t -query_filter_aaaa_additional(query_ctx_t *qctx); - -/* - * XXX: - * This is a temporary hooks table, pre-populated with pointers to - * the 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(). + * 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); @@ -11162,13 +11145,17 @@ ns_query_start(ns_client_t *client) { * clients if there is an A; filter-aaaa-on-v6 option does * the same for IPv6 clients. */ -static isc_result_t -query_filter_aaaa_check(query_ctx_t *qctx) { +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) { - isc_result_t result; result = ns_client_checkaclsilent(qctx->client, NULL, qctx->client->view->aaaa_acl, true); @@ -11185,7 +11172,8 @@ query_filter_aaaa_check(query_ctx_t *qctx) { } } - return (ISC_R_COMPLETE); + *resp = ISC_R_UNSET; + return (false); } /* @@ -11193,16 +11181,20 @@ query_filter_aaaa_check(query_ctx_t *qctx) { * (This version is for processing answers to explicit AAAA * queries; ANY queries are handled in query_filter_aaaa_any().) */ -static isc_result_t -query_filter_aaaa(query_ctx_t *qctx) { - isc_result_t result; +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)))) { - return (ISC_R_COMPLETE); + *resp = result; + return (false); } if (qctx->qtype == dns_rdatatype_aaaa) { @@ -11293,26 +11285,30 @@ query_filter_aaaa(query_ctx_t *qctx) { qctx->client->hookflags &= ~FILTER_AAAA_RECURSING; - return (query_done(qctx)); + result = query_done(qctx); + + *resp = result; + return (true); + } - return (ISC_R_COMPLETE); + *resp = result; + return (false); } -/* - * Optionally hide AAAA rrsets if there is a matching A. - * (This version is for processing answers to ANY queries; - * explicit AAAA queries are handled in query_filter_aaaa().) - */ -static isc_result_t -query_filter_aaaa_any(query_ctx_t *qctx) { +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) { - return (ISC_R_COMPLETE); + *resp = ISC_R_UNSET; + return (false); } dns_message_findname(qctx->client->message, DNS_SECTION_ANSWER, @@ -11350,7 +11346,8 @@ query_filter_aaaa_any(query_ctx_t *qctx) { } } - return (ISC_R_COMPLETE); + *resp = ISC_R_UNSET; + return (false); } /* @@ -11358,12 +11355,16 @@ query_filter_aaaa_any(query_ctx_t *qctx) { * and hide NS in the additional section if AAAA was filtered in the answer * section. */ -static isc_result_t -query_filter_aaaa_additional(query_ctx_t *qctx) { +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) { - return (ISC_R_COMPLETE); + *resp = ISC_R_UNSET; + return (false); } result = dns_message_firstname(qctx->client->message, @@ -11434,70 +11435,7 @@ query_filter_aaaa_additional(query_ctx_t *qctx) { } } - return (ISC_R_COMPLETE); -} - -static bool -filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { - isc_result_t result; - - UNUSED(cbdata); - - result = query_filter_aaaa((query_ctx_t *) hookdata); - if (result != ISC_R_COMPLETE) { - *resp = result; - return (true); - } - - *resp = ISC_R_SUCCESS; - return (false); -} - -static bool -filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { - isc_result_t result; - - UNUSED(cbdata); - - result = query_filter_aaaa_any((query_ctx_t *) hookdata); - if (result != ISC_R_COMPLETE) { - *resp = result; - return (true); - } - - *resp = ISC_R_SUCCESS; - return (false); -} - -static bool -filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { - isc_result_t result; - - UNUSED(cbdata); - - result = query_filter_aaaa_check((query_ctx_t *) hookdata); - if (result != ISC_R_COMPLETE) { - *resp = result; - return (true); - } - - *resp = ISC_R_SUCCESS; - return (false); -} - -static bool -filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { - isc_result_t result; - - UNUSED(cbdata); - - result = query_filter_aaaa_additional((query_ctx_t *) hookdata); - if (result != ISC_R_COMPLETE) { - *resp = result; - return (true); - } - - *resp = ISC_R_SUCCESS; + *resp = ISC_R_UNSET; return (false); } From e4f0a98b4d58884971567da426d5f5064a8a0ef7 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 10 Aug 2018 15:54:14 -0700 Subject: [PATCH 05/26] move several query.c helper functions to client.c and rename - these formerly static helper functions have been moved into client.c and made external so that they can be used in hook modules as well as internally in libns: query_newrdataset, query_putrdataset, query_newnamebuf, query_newname, query_getnamebuf, query_keepname, query_releasename, query_newdbversion, query_findversion - made query_recurse() and query_done() into public functions ns_query_recurse() and ns_query_done() so they can be called from modules. --- bin/named/server.c | 1 + lib/ns/client.c | 236 +++++++++ lib/ns/include/ns/client.h | 67 +++ lib/ns/include/ns/query.h | 29 ++ lib/ns/query.c | 996 ++++++++++++++----------------------- lib/ns/tests/query_test.c | 4 +- lib/ns/win32/libns.def | 2 + 7 files changed, 721 insertions(+), 614 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 9e6c75a15f..c453396dd0 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -102,6 +102,7 @@ #include #include +#include #include #include diff --git a/lib/ns/client.c b/lib/ns/client.c index 1100db7ffc..525cad499d 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -3981,3 +3981,239 @@ ns_client_sourceip(dns_clientinfo_t *ci, isc_sockaddr_t **addrp) { *addrp = &client->peeraddr; return (ISC_R_SUCCESS); } + +dns_rdataset_t * +ns_client_newrdataset(ns_client_t *client) { + dns_rdataset_t *rdataset; + isc_result_t result; + + REQUIRE(NS_CLIENT_VALID(client)); + + rdataset = NULL; + result = dns_message_gettemprdataset(client->message, &rdataset); + if (result != ISC_R_SUCCESS) { + return (NULL); + } + + return (rdataset); +} + +void +ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { + dns_rdataset_t *rdataset; + + REQUIRE(NS_CLIENT_VALID(client)); + REQUIRE(rdatasetp != NULL); + + rdataset = *rdatasetp; + + if (rdataset != NULL) { + if (dns_rdataset_isassociated(rdataset)) { + dns_rdataset_disassociate(rdataset); + } + dns_message_puttemprdataset(client->message, rdatasetp); + } +} + +isc_result_t +ns_client_newnamebuf(ns_client_t *client) { + isc_buffer_t *dbuf; + isc_result_t result; + + CTRACE("ns_client_newnamebuf"); + + dbuf = NULL; + result = isc_buffer_allocate(client->mctx, &dbuf, 1024); + if (result != ISC_R_SUCCESS) { + CTRACE("ns_client_newnamebuf: " + "isc_buffer_allocate failed: done"); + return (result); + } + ISC_LIST_APPEND(client->query.namebufs, dbuf, link); + + CTRACE("ns_client_newnamebuf: done"); + return (ISC_R_SUCCESS); +} + +dns_name_t * +ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf) { + dns_name_t *name; + isc_region_t r; + isc_result_t result; + + REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); + + CTRACE("ns_client_newname"); + name = NULL; + result = dns_message_gettempname(client->message, &name); + if (result != ISC_R_SUCCESS) { + CTRACE("ns_client_newname: " + "dns_message_gettempname failed: done"); + return (NULL); + } + isc_buffer_availableregion(dbuf, &r); + isc_buffer_init(nbuf, r.base, r.length); + dns_name_init(name, NULL); + dns_name_setbuffer(name, nbuf); + client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED; + + CTRACE("ns_client_newname: done"); + return (name); +} + +isc_buffer_t * +ns_client_getnamebuf(ns_client_t *client) { + isc_buffer_t *dbuf; + isc_result_t result; + isc_region_t r; + + CTRACE("ns_client_getnamebuf"); + + /*% + * Return a name buffer with space for a maximal name, allocating + * a new one if necessary. + */ + if (ISC_LIST_EMPTY(client->query.namebufs)) { + result = ns_client_newnamebuf(client); + if (result != ISC_R_SUCCESS) { + CTRACE("ns_client_getnamebuf: " + "ns_client_newnamebuf failed: done"); + return (NULL); + } + } + + dbuf = ISC_LIST_TAIL(client->query.namebufs); + INSIST(dbuf != NULL); + isc_buffer_availableregion(dbuf, &r); + if (r.length < DNS_NAME_MAXWIRE) { + result = ns_client_newnamebuf(client); + if (result != ISC_R_SUCCESS) { + CTRACE("ns_client_getnamebuf: " + "ns_client_newnamebuf failed: done"); + return (NULL); + + } + dbuf = ISC_LIST_TAIL(client->query.namebufs); + isc_buffer_availableregion(dbuf, &r); + INSIST(r.length >= 255); + } + CTRACE("ns_client_getnamebuf: done"); + return (dbuf); +} + +void +ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { + isc_region_t r; + + CTRACE("ns_client_keepname"); + + /*% + * 'name' is using space in 'dbuf', but 'dbuf' has not yet been + * adjusted to take account of that. We do the adjustment. + */ + REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); + + dns_name_toregion(name, &r); + isc_buffer_add(dbuf, r.length); + dns_name_setbuffer(name, NULL); + client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; +} + +void +ns_client_releasename(ns_client_t *client, dns_name_t **namep) { + dns_name_t *name = *namep; + + /*% + * 'name' is no longer needed. Return it to our pool of temporary + * names. If it is using a name buffer, relinquish its exclusive + * rights on the buffer. + */ + + CTRACE("ns_client_releasename"); + if (dns_name_hasbuffer(name)) { + INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) + != 0); + client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; + } + dns_message_puttempname(client->message, namep); + CTRACE("ns_client_releasename: done"); +} + +isc_result_t +ns_client_newdbversion(ns_client_t *client, unsigned int n) { + unsigned int i; + ns_dbversion_t *dbversion; + + for (i = 0; i < n; i++) { + dbversion = isc_mem_get(client->mctx, sizeof(*dbversion)); + if (dbversion != NULL) { + dbversion->db = NULL; + dbversion->version = NULL; + ISC_LIST_INITANDAPPEND(client->query.freeversions, + dbversion, link); + } else { + /* + * We only return ISC_R_NOMEMORY if we couldn't + * allocate anything. + */ + if (i == 0) { + return (ISC_R_NOMEMORY); + } else { + return (ISC_R_SUCCESS); + } + } + } + + return (ISC_R_SUCCESS); +} + +static inline ns_dbversion_t * +client_getdbversion(ns_client_t *client) { + isc_result_t result; + ns_dbversion_t *dbversion; + + if (ISC_LIST_EMPTY(client->query.freeversions)) { + result = ns_client_newdbversion(client, 1); + if (result != ISC_R_SUCCESS) { + return (NULL); + } + } + dbversion = ISC_LIST_HEAD(client->query.freeversions); + INSIST(dbversion != NULL); + ISC_LIST_UNLINK(client->query.freeversions, dbversion, link); + + return (dbversion); +} + +ns_dbversion_t * +ns_client_findversion(ns_client_t *client, dns_db_t *db) { + ns_dbversion_t *dbversion; + + for (dbversion = ISC_LIST_HEAD(client->query.activeversions); + dbversion != NULL; + dbversion = ISC_LIST_NEXT(dbversion, link)) + { + if (dbversion->db == db) { + break; + } + } + + if (dbversion == NULL) { + /* + * This is a new zone for this query. Add it to + * the active list. + */ + dbversion = client_getdbversion(client); + if (dbversion == NULL) { + return (NULL); + } + dns_db_attach(db, &dbversion->db); + dns_db_currentversion(db, &dbversion->version); + dbversion->acl_checked = false; + dbversion->queryok = false; + ISC_LIST_APPEND(client->query.activeversions, + dbversion, link); + } + + return (dbversion); +} diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index d855cb7a18..12845141fb 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -432,4 +432,71 @@ ns__client_request(isc_task_t *task, isc_event_t *event); * Handle client requests. * (Not intended for use outside this module and associated tests.) */ + +dns_rdataset_t * +ns_client_newrdataset(ns_client_t *client); + +void +ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp); +/*% + * Get and release temporary rdatasets in the client message; + * used in query.c and in hook modules. + */ + +isc_result_t +ns_client_newnamebuf(ns_client_t *client); +/*% + * Allocate a name buffer for the client message. + */ + +dns_name_t * +ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf); +/*% + * Get a temporary name for the client message. + */ + +isc_buffer_t * +ns_client_getnamebuf(ns_client_t *client); +/*% + * Get a name buffer from the pool, or allocate a new one if needed. + */ + +void +ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf); +/*% + * Adjust buffer 'dbuf' to reflect that 'name' is using space in it, + * and set client attributes appropriately. + */ + +void +ns_client_releasename(ns_client_t *client, dns_name_t **namep); +/*% + * Release 'name' back to the pool of temporary names for the client + * message. If it is using a name buffer, relinquish its exclusive + * rights on the buffer. + */ + +isc_result_t +ns_client_newdbversion(ns_client_t *client, unsigned int n); +/*% + * Allocate 'n' new database versions for use by client queries. + */ + +ns_dbversion_t * +ns_client_getdbversion(ns_client_t *client); +/*% + * Get a free database version for use by a client query, allocating + * a new one if necessary. + */ + +ns_dbversion_t * +ns_client_findversion(ns_client_t *client, dns_db_t *db); +/*% + * Find the correct database version to use with a client query. + * If we have already done a query related to the database 'db', + * make sure subsequent queries are from the same version; + * otherwise, take a database version from the list of dbversions + * allocated by ns_client_newdbversion(). + */ + #endif /* NS_CLIENT_H */ diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index 2c67e7182b..ad59b2b48c 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -171,6 +171,35 @@ typedef struct query_ctx { int line; /* line to report error */ } query_ctx_t; +/* + * The following functions are expected to be used only within query.c + * and query modules. + */ + +isc_result_t +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_init(ns_client_t *client); diff --git a/lib/ns/query.c b/lib/ns/query.c index 46b64a75a1..104ef4d7cf 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -261,7 +261,7 @@ log_noexistnodata(void *val, int level, const char *fmt, ...) * (query_lookup() again, using the cache database) to find a better * answer. If an answer is found, go to 7. * - * 5. If recursion is allowed, begin recursion (query_recurse()). + * 5. If recursion is allowed, begin recursion (ns_query_recurse()). * Go to 15 to clean up this phase of the query. When recursion * is complete, processing will resume at 6. * @@ -329,11 +329,6 @@ static void recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype, const dns_name_t *qname, const dns_name_t *qdomain); -static isc_result_t -query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, - dns_name_t *qdomain, dns_rdataset_t *nameservers, - bool resuming); - static isc_result_t query_resume(query_ctx_t *qctx); @@ -425,9 +420,6 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata); static void query_addauth(query_ctx_t *qctx); -static isc_result_t -query_done(query_ctx_t *qctx); - /* * XXX: * This is a temporary hooks table, pre-populated with functions @@ -609,19 +601,6 @@ ns_query_cancel(ns_client_t *client) { UNLOCK(&client->query.fetchlock); } -static inline void -query_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp) { - dns_rdataset_t *rdataset = *rdatasetp; - - CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset"); - if (rdataset != NULL) { - if (dns_rdataset_isassociated(rdataset)) - dns_rdataset_disassociate(rdataset); - dns_message_puttemprdataset(client->message, rdatasetp); - } - CTRACE(ISC_LOG_DEBUG(3), "query_putrdataset: done"); -} - static inline void query_reset(ns_client_t *client, bool everything) { isc_buffer_t *dbuf, *dbuf_next; @@ -659,9 +638,9 @@ query_reset(ns_client_t *client, bool everything) { dns_zone_detach(&client->query.authzone); if (client->query.dns64_aaaa != NULL) - query_putrdataset(client, &client->query.dns64_aaaa); + ns_client_putrdataset(client, &client->query.dns64_aaaa); if (client->query.dns64_sigaaaa != NULL) - query_putrdataset(client, &client->query.dns64_sigaaaa); + ns_client_putrdataset(client, &client->query.dns64_sigaaaa); if (client->query.dns64_aaaaok != NULL) { isc_mem_put(client->mctx, client->query.dns64_aaaaok, client->query.dns64_aaaaoklen * @@ -670,8 +649,8 @@ query_reset(ns_client_t *client, bool everything) { client->query.dns64_aaaaoklen = 0; } - query_putrdataset(client, &client->query.redirect.rdataset); - query_putrdataset(client, &client->query.redirect.sigrdataset); + ns_client_putrdataset(client, &client->query.redirect.rdataset); + ns_client_putrdataset(client, &client->query.redirect.sigrdataset); if (client->query.redirect.db != NULL) { if (client->query.redirect.node != NULL) dns_db_detachnode(client->query.redirect.db, @@ -741,198 +720,6 @@ ns_query_free(ns_client_t *client) { query_reset(client, true); } -/*% - * Allocate a name buffer. - */ -static inline isc_result_t -query_newnamebuf(ns_client_t *client) { - isc_buffer_t *dbuf; - isc_result_t result; - - CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf"); - - dbuf = NULL; - result = isc_buffer_allocate(client->mctx, &dbuf, 1024); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_newnamebuf: isc_buffer_allocate failed: done"); - return (result); - } - ISC_LIST_APPEND(client->query.namebufs, dbuf, link); - - CTRACE(ISC_LOG_DEBUG(3), "query_newnamebuf: done"); - return (ISC_R_SUCCESS); -} - -/*% - * Get a name buffer from the pool, or allocate a new one if needed. - */ -static inline isc_buffer_t * -query_getnamebuf(ns_client_t *client) { - isc_buffer_t *dbuf; - isc_result_t result; - isc_region_t r; - - CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf"); - /*% - * Return a name buffer with space for a maximal name, allocating - * a new one if necessary. - */ - - if (ISC_LIST_EMPTY(client->query.namebufs)) { - result = query_newnamebuf(client); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_getnamebuf: query_newnamebuf failed: done"); - return (NULL); - } - } - - dbuf = ISC_LIST_TAIL(client->query.namebufs); - INSIST(dbuf != NULL); - isc_buffer_availableregion(dbuf, &r); - if (r.length < DNS_NAME_MAXWIRE) { - result = query_newnamebuf(client); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_getnamebuf: query_newnamebuf failed: done"); - return (NULL); - - } - dbuf = ISC_LIST_TAIL(client->query.namebufs); - isc_buffer_availableregion(dbuf, &r); - INSIST(r.length >= 255); - } - CTRACE(ISC_LOG_DEBUG(3), "query_getnamebuf: done"); - return (dbuf); -} - -static inline void -query_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf) { - isc_region_t r; - - CTRACE(ISC_LOG_DEBUG(3), "query_keepname"); - /*% - * 'name' is using space in 'dbuf', but 'dbuf' has not yet been - * adjusted to take account of that. We do the adjustment. - */ - - REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) != 0); - - dns_name_toregion(name, &r); - isc_buffer_add(dbuf, r.length); - dns_name_setbuffer(name, NULL); - client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; -} - -static inline void -query_releasename(ns_client_t *client, dns_name_t **namep) { - dns_name_t *name = *namep; - - /*% - * 'name' is no longer needed. Return it to our pool of temporary - * names. If it is using a name buffer, relinquish its exclusive - * rights on the buffer. - */ - - CTRACE(ISC_LOG_DEBUG(3), "query_releasename"); - if (dns_name_hasbuffer(name)) { - INSIST((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) - != 0); - client->query.attributes &= ~NS_QUERYATTR_NAMEBUFUSED; - } - dns_message_puttempname(client->message, namep); - CTRACE(ISC_LOG_DEBUG(3), "query_releasename: done"); -} - -static inline dns_name_t * -query_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf) { - dns_name_t *name; - isc_region_t r; - isc_result_t result; - - REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); - - CTRACE(ISC_LOG_DEBUG(3), "query_newname"); - name = NULL; - result = dns_message_gettempname(client->message, &name); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), - "query_newname: dns_message_gettempname failed: done"); - return (NULL); - } - isc_buffer_availableregion(dbuf, &r); - isc_buffer_init(nbuf, r.base, r.length); - dns_name_init(name, NULL); - dns_name_setbuffer(name, nbuf); - client->query.attributes |= NS_QUERYATTR_NAMEBUFUSED; - - CTRACE(ISC_LOG_DEBUG(3), "query_newname: done"); - return (name); -} - -static inline dns_rdataset_t * -query_newrdataset(ns_client_t *client) { - dns_rdataset_t *rdataset; - isc_result_t result; - - CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset"); - rdataset = NULL; - result = dns_message_gettemprdataset(client->message, &rdataset); - if (result != ISC_R_SUCCESS) { - CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset: " - "dns_message_gettemprdataset failed: done"); - return (NULL); - } - - CTRACE(ISC_LOG_DEBUG(3), "query_newrdataset: done"); - return (rdataset); -} - -static inline isc_result_t -query_newdbversion(ns_client_t *client, unsigned int n) { - unsigned int i; - ns_dbversion_t *dbversion; - - for (i = 0; i < n; i++) { - dbversion = isc_mem_get(client->mctx, sizeof(*dbversion)); - if (dbversion != NULL) { - dbversion->db = NULL; - dbversion->version = NULL; - ISC_LIST_INITANDAPPEND(client->query.freeversions, - dbversion, link); - } else { - /* - * We only return ISC_R_NOMEMORY if we couldn't - * allocate anything. - */ - if (i == 0) - return (ISC_R_NOMEMORY); - else - return (ISC_R_SUCCESS); - } - } - - return (ISC_R_SUCCESS); -} - -static inline ns_dbversion_t * -query_getdbversion(ns_client_t *client) { - isc_result_t result; - ns_dbversion_t *dbversion; - - if (ISC_LIST_EMPTY(client->query.freeversions)) { - result = query_newdbversion(client, 1); - if (result != ISC_R_SUCCESS) - return (NULL); - } - dbversion = ISC_LIST_HEAD(client->query.freeversions); - INSIST(dbversion != NULL); - ISC_LIST_UNLINK(client->query.freeversions, dbversion, link); - - return (dbversion); -} - isc_result_t ns_query_init(ns_client_t *client) { isc_result_t result; @@ -974,12 +761,12 @@ ns_query_init(ns_client_t *client) { client->query.redirect.fname = dns_fixedname_initname(&client->query.redirect.fixed); query_reset(client, false); - result = query_newdbversion(client, 3); + result = ns_client_newdbversion(client, 3); if (result != ISC_R_SUCCESS) { isc_mutex_destroy(&client->query.fetchlock); return (result); } - result = query_newnamebuf(client); + result = ns_client_newnamebuf(client); if (result != ISC_R_SUCCESS) { query_freefreeversions(client, true); isc_mutex_destroy(&client->query.fetchlock); @@ -988,41 +775,6 @@ ns_query_init(ns_client_t *client) { return (result); } -static ns_dbversion_t * -query_findversion(ns_client_t *client, dns_db_t *db) { - ns_dbversion_t *dbversion; - - /*% - * We may already have done a query related to this - * database. If so, we must be sure to make subsequent - * queries from the same version. - */ - for (dbversion = ISC_LIST_HEAD(client->query.activeversions); - dbversion != NULL; - dbversion = ISC_LIST_NEXT(dbversion, link)) { - if (dbversion->db == db) - break; - } - - if (dbversion == NULL) { - /* - * This is a new zone for this query. Add it to - * the active list. - */ - dbversion = query_getdbversion(client); - if (dbversion == NULL) - return (NULL); - dns_db_attach(db, &dbversion->db); - dns_db_currentversion(db, &dbversion->version); - dbversion->acl_checked = false; - dbversion->queryok = false; - ISC_LIST_APPEND(client->query.activeversions, - dbversion, link); - } - - return (dbversion); -} - /*% * Check if 'client' is allowed to query the cache of its associated view. * Unless 'options' has DNS_GETDB_NOLOG set, log the result of cache ACL @@ -1160,7 +912,7 @@ query_validatezonedb(ns_client_t *client, const dns_name_t *name, /* * Get the current version of this database. */ - dbversion = query_findversion(client, db); + dbversion = ns_client_findversion(client, db); if (dbversion == NULL) { CTRACE(ISC_LOG_ERROR, "unable to get db version"); return (DNS_R_SERVFAIL); @@ -1585,7 +1337,7 @@ query_getdb(ns_client_t *client, dns_name_t *name, dns_rdatatype_t qtype, */ *versionp = NULL; - dbversion = query_findversion(client, tdbp); + dbversion = ns_client_findversion(client, tdbp); if (dbversion == NULL) { tresult = ISC_R_NOMEMORY; } else { @@ -1706,17 +1458,17 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { /* * Get some resources. */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { goto cleanup; } - fname = query_newname(client, dbuf, &b); - rdataset = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + rdataset = ns_client_newrdataset(client); if (fname == NULL || rdataset == NULL) { goto cleanup; } if (WANTDNSSEC(client)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { goto cleanup; } @@ -1738,7 +1490,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { goto try_cache; } - dbversion = query_findversion(client, client->query.authdb); + dbversion = ns_client_findversion(client, client->query.authdb); if (dbversion == NULL) { goto try_cache; } @@ -1799,7 +1551,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * Attempt to validate glue. */ if (sigrdataset == NULL) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { goto cleanup; } @@ -1814,7 +1566,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_cache_updatestats(client->view->cache, result); if (!WANTDNSSEC(client)) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (result == ISC_R_SUCCESS) goto found; @@ -1857,7 +1609,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { goto cleanup; } - dbversion = query_findversion(client, client->query.gluedb); + dbversion = ns_client_findversion(client, client->query.gluedb); if (dbversion == NULL) { goto cleanup; } @@ -1881,7 +1633,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * We have found a potential additional data rdataset, or * at least a node to iterate over. */ - query_keepname(client, fname, dbuf); + ns_client_keepname(client, fname, dbuf); /* * If we have an rdataset, add it to the additional data @@ -1893,7 +1645,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { { if (mname != NULL) { INSIST(mname != fname); - query_releasename(client, &fname); + ns_client_releasename(client, &fname); fname = mname; } else { need_addname = true; @@ -1927,7 +1679,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(rdataset); } } else { - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { goto addname; } @@ -1937,7 +1689,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdataset_disassociate(sigrdataset); } } else if (WANTDNSSEC(client)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { goto addname; } @@ -1981,8 +1733,8 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { dns_rdatatype_a, &mname)) { if (mname != fname) { if (mname != NULL) { - query_releasename(client, - &fname); + ns_client_releasename(client, + &fname); fname = mname; } else { need_addname = true; @@ -1996,9 +1748,9 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { ISC_LIST_APPEND(fname->list, sigrdataset, link); sigrdataset = - query_newrdataset(client); + ns_client_newrdataset(client); } - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { goto addname; } @@ -2058,8 +1810,8 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { { if (mname != fname) { if (mname != NULL) { - query_releasename(client, - &fname); + ns_client_releasename(client, + &fname); fname = mname; } else { need_addname = true; @@ -2123,12 +1875,12 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { cleanup: CTRACE(ISC_LOG_DEBUG(3), "query_additional_cb: cleanup"); - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (fname != NULL) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); } if (node != NULL) { dns_db_detachnode(db, &node); @@ -2191,7 +1943,7 @@ query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { isc_result_t result; ns_dbversion_t *dbversion; - dbversion = query_findversion(client, client->query.gluedb); + dbversion = ns_client_findversion(client, client->query.gluedb); if (dbversion == NULL) { goto regular; } @@ -2251,7 +2003,7 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep, CTRACE(ISC_LOG_DEBUG(3), "query_addrrset: dns_message_findname succeeded: done"); if (dbuf != NULL) { - query_releasename(client, namep); + ns_client_releasename(client, namep); } if ((rdataset->attributes & DNS_RDATASETATTR_REQUIRED) != 0) { mrdataset->attributes |= DNS_RDATASETATTR_REQUIRED; @@ -2262,7 +2014,7 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep, * The name doesn't exist. */ if (dbuf != NULL) { - query_keepname(client, name, dbuf); + ns_client_keepname(client, name, dbuf); } dns_message_addname(client->message, name, section); *namep = NULL; @@ -2270,7 +2022,7 @@ query_addrrset(query_ctx_t *qctx, dns_name_t **namep, } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); if (dbuf != NULL) { - query_releasename(client, namep); + ns_client_releasename(client, namep); } } @@ -2480,7 +2232,7 @@ validate(ns_client_t *client, dns_db_t *db, dns_name_t *name, static void fixrdataset(ns_client_t *client, dns_rdataset_t **rdataset) { if (*rdataset == NULL) - *rdataset = query_newrdataset(client); + *rdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(*rdataset)) dns_rdataset_disassociate(*rdataset); } @@ -2490,10 +2242,10 @@ fixfname(ns_client_t *client, dns_name_t **fname, isc_buffer_t **dbuf, isc_buffer_t *nbuf) { if (*fname == NULL) { - *dbuf = query_getnamebuf(client); + *dbuf = ns_client_getnamebuf(client); if (*dbuf == NULL) return; - *fname = query_newname(client, *dbuf, nbuf); + *fname = ns_client_newname(client, *dbuf, nbuf); } } @@ -2505,16 +2257,21 @@ free_devent(ns_client_t *client, isc_event_t **eventp, REQUIRE((void*)(*eventp) == (void *)(*deventp)); - if (devent->fetch != NULL) + if (devent->fetch != NULL) { dns_resolver_destroyfetch(&devent->fetch); - if (devent->node != NULL) + } + if (devent->node != NULL) { dns_db_detachnode(devent->db, &devent->node); - if (devent->db != NULL) + } + if (devent->db != NULL) { dns_db_detach(&devent->db); - if (devent->rdataset != NULL) - query_putrdataset(client, &devent->rdataset); - if (devent->sigrdataset != NULL) - query_putrdataset(client, &devent->sigrdataset); + } + if (devent->rdataset != NULL) { + ns_client_putrdataset(client, &devent->rdataset); + } + if (devent->sigrdataset != NULL) { + ns_client_putrdataset(client, &devent->sigrdataset); + } /* * If the two pointers are the same then leave the setting of * (*deventp) to NULL to isc_event_free. @@ -2573,7 +2330,7 @@ query_prefetch(ns_client_t *client, dns_name_t *qname, ns_statscounter_recursclients); } - tmprdataset = query_newrdataset(client); + tmprdataset = ns_client_newrdataset(client); if (tmprdataset == NULL) return; if (!TCP(client)) @@ -2590,7 +2347,7 @@ query_prefetch(ns_client_t *client, dns_name_t *qname, tmprdataset, NULL, &client->query.prefetch); if (result != ISC_R_SUCCESS) { - query_putrdataset(client, &tmprdataset); + ns_client_putrdataset(client, &tmprdataset); ns_client_detach(&dummy); } dns_rdataset_clearprefetch(rdataset); @@ -2628,10 +2385,10 @@ rpz_ready(ns_client_t *client, dns_rdataset_t **rdatasetp) { CTRACE(ISC_LOG_DEBUG(3), "rpz_ready"); if (*rdatasetp == NULL) { - *rdatasetp = query_newrdataset(client); + *rdatasetp = ns_client_newrdataset(client); if (*rdatasetp == NULL) { CTRACE(ISC_LOG_ERROR, - "rpz_ready: query_newrdataset failed"); + "rpz_ready: ns_client_newrdataset failed"); return (DNS_R_SERVFAIL); } } else if (dns_rdataset_isassociated(*rdatasetp)) { @@ -2647,24 +2404,24 @@ rpz_st_clear(ns_client_t *client) { CTRACE(ISC_LOG_DEBUG(3), "rpz_st_clear"); if (st->m.rdataset != NULL) { - query_putrdataset(client, &st->m.rdataset); + ns_client_putrdataset(client, &st->m.rdataset); } rpz_match_clear(st); rpz_clean(NULL, &st->r.db, NULL, NULL); if (st->r.ns_rdataset != NULL) { - query_putrdataset(client, &st->r.ns_rdataset); + ns_client_putrdataset(client, &st->r.ns_rdataset); } if (st->r.r_rdataset != NULL) { - query_putrdataset(client, &st->r.r_rdataset); + ns_client_putrdataset(client, &st->r.r_rdataset); } rpz_clean(&st->q.zone, &st->q.db, &st->q.node, NULL); if (st->q.rdataset != NULL) { - query_putrdataset(client, &st->q.rdataset); + ns_client_putrdataset(client, &st->q.rdataset); } if (st->q.sigrdataset != NULL) { - query_putrdataset(client, &st->q.sigrdataset); + ns_client_putrdataset(client, &st->q.sigrdataset); } st->state = 0; st->m.type = DNS_RPZ_TYPE_BAD; @@ -2780,7 +2537,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) { ns_statscounter_recursclients); } - tmprdataset = query_newrdataset(client); + tmprdataset = ns_client_newrdataset(client); if (tmprdataset == NULL) return; if (!TCP(client)) @@ -2796,7 +2553,7 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) { client, tmprdataset, NULL, &client->query.prefetch); if (result != ISC_R_SUCCESS) { - query_putrdataset(client, &tmprdataset); + ns_client_putrdataset(client, &tmprdataset); ns_client_detach(&dummy); } } @@ -2830,8 +2587,9 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, !dns_rdataset_isassociated(*rdatasetp)); st->state &= ~DNS_RPZ_RECURSING; RESTORE(*dbp, st->r.db); - if (*rdatasetp != NULL) - query_putrdataset(client, rdatasetp); + if (*rdatasetp != NULL) { + ns_client_putrdataset(client, rdatasetp); + } RESTORE(*rdatasetp, st->r.r_rdataset); result = st->r.r_result; if (result == DNS_R_DELEGATION) { @@ -2903,8 +2661,8 @@ rpz_rrset_find(ns_client_t *client, dns_name_t *name, dns_rdatatype_t type, result = DNS_R_NXRRSET; } else { dns_name_copy(name, st->r_name, NULL); - result = query_recurse(client, type, st->r_name, - NULL, NULL, resuming); + result = ns_query_recurse(client, type, st->r_name, + NULL, NULL, resuming); if (result == ISC_R_SUCCESS) { st->state |= DNS_RPZ_RECURSING; result = DNS_R_DELEGATION; @@ -3739,7 +3497,7 @@ rpz_rewrite_ip_rrsets(ns_client_t *client, dns_name_t *name, } if (ip_db != NULL) dns_db_detach(&ip_db); - query_putrdataset(client, &p_rdataset); + ns_client_putrdataset(client, &p_rdataset); return (result); } @@ -4389,7 +4147,7 @@ cleanup: st->m.type = DNS_RPZ_TYPE_BAD; result = DNS_R_SERVFAIL; } - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if ((st->state & DNS_RPZ_RECURSING) == 0) rpz_clean(NULL, &st->r.db, NULL, &st->r.ns_rdataset); @@ -4860,7 +4618,7 @@ redirect(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, if (result != ISC_R_SUCCESS) return (ISC_R_NOTFOUND); - dbversion = query_findversion(client, db); + dbversion = ns_client_findversion(client, db); if (dbversion == NULL) { dns_db_detach(&db); return (ISC_R_NOTFOUND); @@ -5018,8 +4776,8 @@ redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, * Don't loop forever if the lookup failed last time. */ if (!REDIRECT(client)) { - result = query_recurse(client, qtype, redirectname, - NULL, NULL, true); + result = ns_query_recurse(client, qtype, redirectname, + NULL, NULL, true); if (result == ISC_R_SUCCESS) { client->query.attributes |= NS_QUERYATTR_RECURSING; @@ -5147,15 +4905,15 @@ qctx_clean(query_ctx_t *qctx) { static void qctx_freedata(query_ctx_t *qctx) { if (qctx->rdataset != NULL) { - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); } if (qctx->sigrdataset != NULL) { - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); } if (qctx->fname != NULL) { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } if (qctx->db != NULL) { @@ -5168,9 +4926,9 @@ qctx_freedata(query_ctx_t *qctx) { } if (qctx->zdb != NULL) { - query_putrdataset(qctx->client, &qctx->zsigrdataset); - query_putrdataset(qctx->client, &qctx->zrdataset); - query_releasename(qctx->client, &qctx->zfname); + ns_client_putrdataset(qctx->client, &qctx->zsigrdataset); + ns_client_putrdataset(qctx->client, &qctx->zrdataset); + ns_client_releasename(qctx->client, &qctx->zfname); dns_db_detachnode(qctx->zdb, &qctx->znode); dns_db_detach(&qctx->zdb); } @@ -5345,7 +5103,7 @@ ns__query_start(query_ctx_t *qctx) { qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA; qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; qctx->client->message->rcode = dns_rcode_badcookie; - return (query_done(qctx)); + return (ns_query_done(qctx)); } if (qctx->client->view->checknames && @@ -5367,7 +5125,7 @@ ns__query_start(query_ctx_t *qctx) { "check-names failure %s/%s/%s", namebuf, typebuf, classbuf); QUERY_ERROR(qctx, DNS_R_REFUSED); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -5428,7 +5186,7 @@ ns__query_start(query_ctx_t *qctx) { * zone to query context, set result to ISC_R_SUCCESS. */ qctx->options &= ~DNS_GETDB_NOEXACT; - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); if (qctx->db != NULL) { dns_db_detach(&qctx->db); } @@ -5476,7 +5234,7 @@ ns__query_start(query_ctx_t *qctx) { "ns__query_start: query_getdb failed"); QUERY_ERROR(qctx, result); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -5530,7 +5288,7 @@ ns__query_start(query_ctx_t *qctx) { /*% * Perform a local database lookup, in either an authoritative or - * cache database. If unable to answer, call query_done(); otherwise + * cache database. If unable to answer, call ns_query_done(); otherwise * hand off processing to query_gotanswer(). */ static isc_result_t @@ -5552,33 +5310,33 @@ query_lookup(query_ctx_t *qctx) { /* * We'll need some resources... */ - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (ISC_UNLIKELY(qctx->dbuf == NULL)) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: query_getnamebuf failed (2)"); + "query_lookup: ns_client_getnamebuf failed (2)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } - qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); - qctx->rdataset = query_newrdataset(qctx->client); + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); + qctx->rdataset = ns_client_newrdataset(qctx->client); if (ISC_UNLIKELY(qctx->fname == NULL || qctx->rdataset == NULL)) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: query_newname failed (2)"); + "query_lookup: ns_client_newname failed (2)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } if ((WANTDNSSEC(qctx->client) || qctx->findcoveringnsec) && (!qctx->is_zone || dns_db_issecure(qctx->db))) { - qctx->sigrdataset = query_newrdataset(qctx->client); + qctx->sigrdataset = ns_client_newrdataset(qctx->client); if (qctx->sigrdataset == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_lookup: query_newrdataset failed (2)"); + "query_lookup: ns_client_newrdataset failed (2)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } } @@ -5645,7 +5403,7 @@ query_lookup(query_ctx_t *qctx) { if (!success) { QUERY_ERROR(qctx, DNS_R_SERVFAIL); - return (query_done(qctx)); + return (ns_query_done(qctx)); } } @@ -5797,16 +5555,16 @@ recparam_update(ns_query_recparam_t *param, dns_rdatatype_t qtype, * this phase of the query, and resume with a new query context when * recursion completes. */ -static isc_result_t -query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, - dns_name_t *qdomain, dns_rdataset_t *nameservers, - bool resuming) +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) { isc_result_t result; dns_rdataset_t *rdataset, *sigrdataset; isc_sockaddr_t *peeraddr = NULL; - CTRACE(ISC_LOG_DEBUG(3), "query_recurse"); + CTRACE(ISC_LOG_DEBUG(3), "ns_query_recurse"); /* * Check recursion parameters from the previous query to see if they @@ -5902,15 +5660,15 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, REQUIRE(nameservers == NULL || nameservers->type == dns_rdatatype_ns); REQUIRE(client->query.fetch == NULL); - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { return (ISC_R_NOMEMORY); } if (WANTDNSSEC(client)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); return (ISC_R_NOMEMORY); } } else { @@ -5933,9 +5691,9 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, client, rdataset, sigrdataset, &client->query.fetch); if (result != ISC_R_SUCCESS) { - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } } @@ -6010,7 +5768,7 @@ query_resume(query_ctx_t *qctx) { SAVE(qctx->rpz_st->r.db, qctx->event->db); qctx->rpz_st->r.r_type = qctx->event->qtype; SAVE(qctx->rpz_st->r.r_rdataset, qctx->event->rdataset); - query_putrdataset(qctx->client, &qctx->event->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset); } else if (REDIRECT(qctx->client)) { /* * Restore saved state. @@ -6043,8 +5801,8 @@ query_resume(query_ctx_t *qctx) { /* * Free resources used while recursing. */ - query_putrdataset(qctx->client, &qctx->event->rdataset); - query_putrdataset(qctx->client, &qctx->event->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->event->rdataset); + ns_client_putrdataset(qctx->client, &qctx->event->sigrdataset); if (qctx->event->node != NULL) dns_db_detachnode(qctx->event->db, &qctx->event->node); if (qctx->event->db != NULL) @@ -6097,27 +5855,27 @@ query_resume(query_ctx_t *qctx) { qctx->client->view->rpzs->rpz_ver, qctx->rpz_st->rpz_ver); QUERY_ERROR(qctx, DNS_R_SERVFAIL); - return (query_done(qctx)); + return (ns_query_done(qctx)); } } /* * We'll need some resources... */ - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (qctx->dbuf == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_resume: query_getnamebuf failed (1)"); + "query_resume: ns_client_getnamebuf failed (1)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } - qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); if (qctx->fname == NULL) { CCTRACE(ISC_LOG_ERROR, - "query_resume: query_newname failed (1)"); + "query_resume: ns_client_newname failed (1)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } if (qctx->rpz_st != NULL && @@ -6134,7 +5892,7 @@ query_resume(query_ctx_t *qctx) { CCTRACE(ISC_LOG_ERROR, "query_resume: dns_name_copy failed"); QUERY_ERROR(qctx, result); - return (query_done(qctx)); + return (ns_query_done(qctx)); } if (qctx->rpz_st != NULL && @@ -6216,7 +5974,7 @@ ns__query_sfcache(query_ctx_t *qctx) { qctx->client->attributes |= NS_CLIENTATTR_NOSETFC; QUERY_ERROR(qctx, DNS_R_SERVFAIL); - return (query_done(qctx)); + return (ns_query_done(qctx)); } return (ISC_R_COMPLETE); @@ -6453,7 +6211,7 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) { RUNTIME_CHECK(rresult == ISC_R_SUCCESS); rpz_clean(&qctx->zone, &qctx->db, &qctx->node, NULL); if (qctx->rpz_st->m.rdataset != NULL) { - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); RESTORE(qctx->rdataset, qctx->rpz_st->m.rdataset); } else { qctx_clean(qctx); @@ -6569,7 +6327,7 @@ query_checkrpz(query_ctx_t *qctx, isc_result_t result) { qctx->client->attributes &= ~(NS_CLIENTATTR_WANTDNSSEC | NS_CLIENTATTR_WANTAD); qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); qctx->rpz_st->q.is_zone = qctx->is_zone; qctx->is_zone = true; rpz_log_rewrite(qctx->client, false, @@ -6618,7 +6376,7 @@ query_rpzcname(query_ctx_t *qctx, dns_name_t *cname) { RUNTIME_CHECK(result == ISC_R_SUCCESS); } - query_keepname(client, qctx->fname, qctx->dbuf); + ns_client_keepname(client, qctx->fname, qctx->dbuf); result = query_addcname(qctx, dns_trust_authanswer, qctx->rpz_st->m.ttl); if (result != ISC_R_SUCCESS) { @@ -6790,7 +6548,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { PROCESS_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx); if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) { - return (query_done(qctx)); + return (ns_query_done(qctx)); } if (!RECURSING(qctx->client) && @@ -6798,7 +6556,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { { result = query_checkrpz(qctx, result); if (result == ISC_R_COMPLETE) - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -6811,7 +6569,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { */ qctx->client->attributes |= NS_CLIENTATTR_NOSETFC; QUERY_ERROR(qctx, DNS_R_SERVFAIL); - return (query_done(qctx)); + return (ns_query_done(qctx)); } switch (result) { @@ -6861,7 +6619,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { case DNS_R_FORMERR: QUERY_ERROR(qctx, DNS_R_SERVFAIL); - return (query_done(qctx)); + return (ns_query_done(qctx)); default: /* @@ -6879,7 +6637,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { return (query_lookup(qctx)); } QUERY_ERROR(qctx, result); - return (query_done(qctx)); + return (ns_query_done(qctx)); } } @@ -6897,14 +6655,14 @@ query_addnoqnameproof(query_ctx_t *qctx) { return; } - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { goto cleanup; } - fname = query_newname(client, dbuf, &b); - neg = query_newrdataset(client); - negsig = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + neg = ns_client_newrdataset(client); + negsig = ns_client_newrdataset(client); if (fname == NULL || neg == NULL || negsig == NULL) { goto cleanup; } @@ -6920,20 +6678,20 @@ query_addnoqnameproof(query_ctx_t *qctx) { } if (fname == NULL) { - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); } if (neg == NULL) { - neg = query_newrdataset(client); + neg = ns_client_newrdataset(client); } else if (dns_rdataset_isassociated(neg)) { dns_rdataset_disassociate(neg); } if (negsig == NULL) { - negsig = query_newrdataset(client); + negsig = ns_client_newrdataset(client); } else if (dns_rdataset_isassociated(negsig)) { dns_rdataset_disassociate(negsig); } @@ -6948,13 +6706,13 @@ query_addnoqnameproof(query_ctx_t *qctx) { cleanup: if (neg != NULL) { - query_putrdataset(client, &neg); + ns_client_putrdataset(client, &neg); } if (negsig != NULL) { - query_putrdataset(client, &negsig); + ns_client_putrdataset(client, &negsig); } if (fname != NULL) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); } } @@ -6976,21 +6734,21 @@ query_respond_any(query_ctx_t *qctx) { CCTRACE(ISC_LOG_ERROR, "query_respond_any: allrdatasets failed"); QUERY_ERROR(qctx, result); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* * Calling query_addrrset() with a non-NULL dbuf is going * to either keep or release the name. We don't want it to * release fname, since we may have to call query_addrrset() - * more than once. That means we have to call query_keepname() + * more than once. That means we have to call ns_client_keepname() * now, and pass a NULL dbuf to query_addrrset(). * * If we do a query_addrrset() below, we must set qctx->fname to * NULL before leaving this block, otherwise we might try to * cleanup qctx->fname even though we're using it! */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); qctx->tname = qctx->fname; result = dns_rdatasetiter_first(rdsiter); @@ -7094,11 +6852,11 @@ query_respond_any(query_ctx_t *qctx) { * pathological cases involving DNAMEs. */ if (qctx->rdataset != NULL) { - query_putrdataset(qctx->client, - &qctx->rdataset); + ns_client_putrdataset(qctx->client, + &qctx->rdataset); } - qctx->rdataset = query_newrdataset(qctx->client); + qctx->rdataset = ns_client_newrdataset(qctx->client); if (qctx->rdataset == NULL) break; } else { @@ -7147,7 +6905,7 @@ query_respond_any(query_ctx_t *qctx) { qctx->authoritative = false; qctx->client->attributes &= ~NS_CLIENTATTR_RA; query_addauth(qctx); - return (query_done(qctx)); + return (ns_query_done(qctx)); } if (qctx->qtype == dns_rdatatype_rrsig && @@ -7164,8 +6922,8 @@ query_respond_any(query_ctx_t *qctx) { namebuf); } - qctx->fname = query_newname(qctx->client, - qctx->dbuf, &b); + qctx->fname = ns_client_newname(qctx->client, + qctx->dbuf, &b); return (query_sign_nodata(qctx)); } else { CCTRACE(ISC_LOG_ERROR, @@ -7177,7 +6935,7 @@ query_respond_any(query_ctx_t *qctx) { query_addauth(qctx); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -7254,9 +7012,9 @@ query_respond(query_ctx_t *qctx) { qctx_clean(qctx); INSIST(!REDIRECT(qctx->client)); - result = query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); + result = ns_query_recurse(qctx->client, qctx->qtype, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; @@ -7270,7 +7028,7 @@ query_respond(query_ctx_t *qctx) { QUERY_ERROR(qctx, result); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -7290,7 +7048,7 @@ query_respond(query_ctx_t *qctx) { qctx->client->query.dns64_ttl = qctx->rdataset->ttl; SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset); SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset); - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); dns_db_detachnode(qctx->db, &qctx->node); qctx->type = qctx->qtype = dns_rdatatype_a; qctx->dns64_exclude = qctx->dns64 = true; @@ -7346,13 +7104,13 @@ query_respond(query_ctx_t *qctx) { #ifndef dns64_bis_return_excluded_addresses if (qctx->dns64_exclude) { if (!qctx->is_zone) - return (query_done(qctx)); + return (ns_query_done(qctx)); /* * Add a fake SOA record. */ (void)query_addsoa(qctx, 600, DNS_SECTION_AUTHORITY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } #endif if (qctx->is_zone) { @@ -7362,11 +7120,11 @@ query_respond(query_ctx_t *qctx) { } } else if (result != ISC_R_SUCCESS) { qctx->result = result; - return (query_done(qctx)); + return (ns_query_done(qctx)); } } else if (qctx->client->query.dns64_aaaaok != NULL) { query_filter64(qctx); - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); } else { if (!qctx->is_zone && RECURSIONOK(qctx->client)) query_prefetch(qctx->client, qctx->fname, @@ -7386,7 +7144,7 @@ query_respond(query_ctx_t *qctx) { query_addauth(qctx); - return (query_done(qctx)); + return (ns_query_done(qctx)); } static isc_result_t @@ -7441,22 +7199,25 @@ query_dns64(query_ctx_t *qctx) { */ CTRACE(ISC_LOG_DEBUG(3), "query_dns64: dns_message_findname succeeded: done"); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } return (ISC_R_SUCCESS); } else if (result == DNS_R_NXDOMAIN) { /* * The name doesn't exist. */ - if (qctx->dbuf != NULL) - query_keepname(client, name, qctx->dbuf); + if (qctx->dbuf != NULL) { + ns_client_keepname(client, name, qctx->dbuf); + } dns_message_addname(client->message, name, section); qctx->fname = NULL; mname = name; } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } } if (qctx->rdataset->trust != dns_trust_secure) { @@ -7616,16 +7377,18 @@ query_filter64(query_ctx_t *qctx) { */ CTRACE(ISC_LOG_DEBUG(3), "query_filter64: dns_message_findname succeeded: done"); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } return; } else if (result == DNS_R_NXDOMAIN) { mname = name; qctx->fname = NULL; } else { RUNTIME_CHECK(result == DNS_R_NXRRSET); - if (qctx->dbuf != NULL) - query_releasename(client, &qctx->fname); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &qctx->fname); + } qctx->dbuf = NULL; } @@ -7679,8 +7442,9 @@ query_filter64(query_ctx_t *qctx) { dns_rdataset_setownercase(myrdataset, name); client->query.attributes |= NS_QUERYATTR_NOADDITIONAL; if (mname == name) { - if (qctx->dbuf != NULL) - query_keepname(client, name, qctx->dbuf); + if (qctx->dbuf != NULL) { + ns_client_keepname(client, name, qctx->dbuf); + } dns_message_addname(client->message, name, section); qctx->dbuf = NULL; @@ -7714,8 +7478,9 @@ query_filter64(query_ctx_t *qctx) { } dns_message_puttemprdatalist(client->message, &myrdatalist); } - if (qctx->dbuf != NULL) - query_releasename(client, &name); + if (qctx->dbuf != NULL) { + ns_client_releasename(client, &name); + } CTRACE(ISC_LOG_DEBUG(3), "query_filter64: done"); } @@ -7770,9 +7535,9 @@ query_notfound(query_ctx_t *qctx) { */ if (RECURSIONOK(qctx->client)) { INSIST(!REDIRECT(qctx->client)); - result = query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); + result = ns_query_recurse(qctx->client, qctx->qtype, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; @@ -7785,13 +7550,13 @@ query_notfound(query_ctx_t *qctx) { } else { QUERY_ERROR(qctx, result); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } else { /* Unable to give root server referral. */ CCTRACE(ISC_LOG_ERROR, "unable to give root server referral"); QUERY_ERROR(qctx, result); - return (query_done(qctx)); + return (ns_query_done(qctx)); } } @@ -7845,14 +7610,14 @@ query_prepare_delegation_response(query_ctx_t *qctx) { */ query_addds(qctx); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /*% * Handle a delegation response from an authoritative lookup. This * may trigger additional lookups, e.g. from the cache database to * see if we have a better answer; if that is not allowed, return the - * delegation to the client and call query_done(). + * delegation to the client and call ns_query_done(). */ static isc_result_t query_zone_delegation(query_ctx_t *qctx) { @@ -7884,14 +7649,16 @@ query_zone_delegation(query_ctx_t *qctx) { dns_zone_detach(&tzone); } else { qctx->options &= ~DNS_GETDB_NOEXACT; - query_putrdataset(qctx->client, - &qctx->rdataset); - if (qctx->sigrdataset != NULL) - query_putrdataset(qctx->client, - &qctx->sigrdataset); - if (qctx->fname != NULL) - query_releasename(qctx->client, - &qctx->fname); + ns_client_putrdataset(qctx->client, + &qctx->rdataset); + if (qctx->sigrdataset != NULL) { + ns_client_putrdataset(qctx->client, + &qctx->sigrdataset); + } + if (qctx->fname != NULL) { + ns_client_releasename(qctx->client, + &qctx->fname); + } if (qctx->node != NULL) dns_db_detachnode(qctx->db, &qctx->node); @@ -7923,7 +7690,7 @@ query_zone_delegation(query_ctx_t *qctx) { * query_notfound() which calls query_delegation(), and * we'll restore these values there. */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); SAVE(qctx->zdb, qctx->db); SAVE(qctx->znode, qctx->node); SAVE(qctx->zfname, qctx->fname); @@ -7945,7 +7712,7 @@ query_zone_delegation(query_ctx_t *qctx) { * If the delegation was returned from authoritative data, * call query_zone_delgation(). Otherwise, we can start * recursion if allowed; or else return the delegation to the - * client and call query_done(). + * client and call ns_query_done(). */ static isc_result_t query_delegation(query_ctx_t *qctx) { @@ -7979,19 +7746,20 @@ query_delegation(query_ctx_t *qctx) { * the nameservers configured in the * static-stub zone. */ - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); /* - * We've already done query_keepname() on + * We've already done ns_client_keepname() on * qctx->zfname, so we must set dbuf to NULL to * prevent query_addrrset() from trying to - * call query_keepname() again. + * call ns_client_keepname() again. */ qctx->dbuf = NULL; - query_putrdataset(qctx->client, &qctx->rdataset); - if (qctx->sigrdataset != NULL) - query_putrdataset(qctx->client, - &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); + if (qctx->sigrdataset != NULL) { + ns_client_putrdataset(qctx->client, + &qctx->sigrdataset); + } qctx->version = NULL; dns_db_detachnode(qctx->db, &qctx->node); @@ -8007,7 +7775,7 @@ query_delegation(query_ctx_t *qctx) { if (RECURSIONOK(qctx->client)) { /* * We have a delegation and recursion is allowed, - * so we call query_recurse() to follow it. + * so we call ns_query_recurse() to follow it. * This phase of the query processing is done; * we'll resume via fetch_callback() and * query_resume() when the recursion is complete. @@ -8021,28 +7789,28 @@ query_delegation(query_ctx_t *qctx) { * Parent is recursive for this rdata * type (i.e., DS) */ - result = query_recurse(qctx->client, - qctx->qtype, qname, - NULL, NULL, - qctx->resuming); + result = ns_query_recurse(qctx->client, + qctx->qtype, qname, + NULL, NULL, + qctx->resuming); } else if (qctx->dns64) { /* * Look up an A record so we can * synthesize DNS64 */ - result = query_recurse(qctx->client, - dns_rdatatype_a, qname, - NULL, NULL, - qctx->resuming); + result = ns_query_recurse(qctx->client, + dns_rdatatype_a, qname, + NULL, NULL, + qctx->resuming); } else { /* * Any other recursion */ - result = query_recurse(qctx->client, - qctx->qtype, qname, - qctx->fname, - qctx->rdataset, - qctx->resuming); + result = ns_query_recurse(qctx->client, + qctx->qtype, qname, + qctx->fname, + qctx->rdataset, + qctx->resuming); } if (result == ISC_R_SUCCESS) { qctx->client->query.attributes |= @@ -8057,7 +7825,7 @@ query_delegation(query_ctx_t *qctx) { QUERY_ERROR(qctx, result); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } return (query_prepare_delegation_response(qctx)); @@ -8090,8 +7858,8 @@ query_addds(query_ctx_t *qctx) { /* * We'll need some resources... */ - rdataset = query_newrdataset(client); - sigrdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (rdataset == NULL || sigrdataset == NULL) goto cleanup; @@ -8144,10 +7912,10 @@ query_addds(query_ctx_t *qctx) { /* * Add the NSEC3 which proves the DS does not exist. */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); dns_fixedname_init(&fixed); if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); @@ -8186,12 +7954,15 @@ query_addds(query_ctx_t *qctx) { } cleanup: - if (rdataset != NULL) - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } } /*% @@ -8212,28 +7983,28 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { * Restore the answers from the previous AAAA lookup. */ if (qctx->rdataset != NULL) - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); if (qctx->sigrdataset != NULL) - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); RESTORE(qctx->rdataset, qctx->client->query.dns64_aaaa); RESTORE(qctx->sigrdataset, qctx->client->query.dns64_sigaaaa); if (qctx->fname == NULL) { - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (qctx->dbuf == NULL) { CCTRACE(ISC_LOG_ERROR, "query_nodata: " - "query_getnamebuf failed (3)"); + "ns_client_getnamebuf failed (3)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx));; + return (ns_query_done(qctx));; } - qctx->fname = query_newname(qctx->client, - qctx->dbuf, &b); + qctx->fname = ns_client_newname(qctx->client, + qctx->dbuf, &b); if (qctx->fname == NULL) { CCTRACE(ISC_LOG_ERROR, "query_nodata: " - "query_newname failed (3)"); + "ns_client_newname failed (3)"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx));; + return (ns_query_done(qctx));; } } dns_name_copy(qctx->client->query.qname, qctx->fname, NULL); @@ -8281,7 +8052,7 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { SAVE(qctx->client->query.dns64_aaaa, qctx->rdataset); SAVE(qctx->client->query.dns64_sigaaaa, qctx->sigrdataset); - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); dns_db_detachnode(qctx->db, &qctx->node); qctx->type = qctx->qtype = dns_rdatatype_a; qctx->dns64 = true; @@ -8296,7 +8067,8 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { * of its extra features (and things would probably break!). */ if (dns_rdataset_isassociated(qctx->rdataset)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, + qctx->dbuf); dns_message_addname(qctx->client->message, qctx->fname, DNS_SECTION_AUTHORITY); @@ -8307,7 +8079,7 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { } } - return (query_done(qctx)); + return (ns_query_done(qctx)); } /*% @@ -8320,7 +8092,7 @@ query_sign_nodata(query_ctx_t *qctx) { * Look for a NSEC3 record if we don't have a NSEC record. */ if (qctx->redirected) - return (query_done(qctx)); + return (ns_query_done(qctx)); if (!dns_rdataset_isassociated(qctx->rdataset) && WANTDNSSEC(qctx->client)) { @@ -8380,7 +8152,7 @@ query_sign_nodata(query_ctx_t *qctx) { "failure getting " "closest encloser"); QUERY_ERROR(qctx, ISC_R_NOMEMORY); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* * 'nearest' doesn't exist so @@ -8396,7 +8168,7 @@ query_sign_nodata(query_ctx_t *qctx) { NULL); } } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); query_addwildcardproof(qctx, false, true); } } @@ -8406,14 +8178,14 @@ query_sign_nodata(query_ctx_t *qctx) { * name now because we're going call query_addsoa() * below, and it needs to use the name buffer. */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else if (qctx->fname != NULL) { /* * We're not going to use fname, and need to release * our hold on the name buffer so query_addsoa() * may use it. */ - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } /* @@ -8425,7 +8197,7 @@ query_sign_nodata(query_ctx_t *qctx) { DNS_SECTION_AUTHORITY); if (result != ISC_R_SUCCESS) { QUERY_ERROR(qctx, result); - return (query_done(qctx)); + return (ns_query_done(qctx)); } } @@ -8438,7 +8210,7 @@ query_sign_nodata(query_ctx_t *qctx) { query_addnxrrsetnsec(qctx); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } static void @@ -8485,12 +8257,12 @@ query_addnxrrsetnsec(query_ctx_t *qctx) { /* * We'll need some resources... */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { return; } - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); if (fname == NULL) { return; } @@ -8528,14 +8300,14 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { * name now because we're going call query_addsoa() * below, and it needs to use the name buffer. */ - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else if (qctx->fname != NULL) { /* * We're not going to use fname, and need to release * our hold on the name buffer so query_addsoa() * may use it. */ - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } /* @@ -8558,7 +8330,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { result = query_addsoa(qctx, ttl, section); if (result != ISC_R_SUCCESS) { QUERY_ERROR(qctx, result); - return (query_done(qctx)); + return (ns_query_done(qctx)); } if (WANTDNSSEC(qctx->client)) { @@ -8580,7 +8352,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { else qctx->client->message->rcode = dns_rcode_nxdomain; - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -8643,7 +8415,7 @@ query_redirect(query_ctx_t *qctx) { qctx->client->query.redirect.authoritative = qctx->authoritative; qctx->client->query.redirect.is_zone = qctx->is_zone; - return (query_done(qctx)); + return (ns_query_done(qctx)); case DNS_R_NXRRSET: qctx->redirected = true; qctx->is_zone = true; @@ -8732,18 +8504,18 @@ query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer, * NODATA proof's name now or else discard it. */ if (WANTDNSSEC(qctx->client)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8774,7 +8546,7 @@ query_synthnodata(query_ctx_t *qctx, const dns_name_t *signer, cleanup: if (name != NULL) { - query_releasename(qctx->client, &name); + ns_client_releasename(qctx->client, &name); } return (result); } @@ -8798,25 +8570,25 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, * NOQNAME proof's name now or else discard it. */ if (WANTDNSSEC(qctx->client)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } dns_name_copy(qctx->client->query.qname, name, NULL); - clone = query_newrdataset(qctx->client); + clone = ns_client_newrdataset(qctx->client); if (clone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8827,7 +8599,7 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, * Add answer RRset. Omit the RRSIG if DNSSEC was not requested. */ if (WANTDNSSEC(qctx->client)) { - sigclone = query_newrdataset(qctx->client); + sigclone = ns_client_newrdataset(qctx->client); if (sigclone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8855,13 +8627,13 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, cleanup: if (name != NULL) { - query_releasename(qctx->client, &name); + ns_client_releasename(qctx->client, &name); } if (clone != NULL) { - query_putrdataset(qctx->client, &clone); + ns_client_putrdataset(qctx->client, &clone); } if (sigclone != NULL) { - query_putrdataset(qctx->client, &sigclone); + ns_client_putrdataset(qctx->client, &sigclone); } return (result); } @@ -8959,18 +8731,18 @@ query_synthnxdomain(query_ctx_t *qctx, * NOQNAME proof's name now or else discard it. */ if (WANTDNSSEC(qctx->client)) { - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); } else { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -8995,13 +8767,13 @@ query_synthnxdomain(query_ctx_t *qctx, &qctx->rdataset, &qctx->sigrdataset, NULL, DNS_SECTION_AUTHORITY); - dbuf = query_getnamebuf(qctx->client); + dbuf = ns_client_getnamebuf(qctx->client); if (dbuf == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - name = query_newname(qctx->client, dbuf, &b); + name = ns_client_newname(qctx->client, dbuf, &b); if (name == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -9009,8 +8781,8 @@ query_synthnxdomain(query_ctx_t *qctx, dns_name_copy(nowild, name, NULL); - clone = query_newrdataset(qctx->client); - sigclone = query_newrdataset(qctx->client); + clone = ns_client_newrdataset(qctx->client); + sigclone = ns_client_newrdataset(qctx->client); if (clone == NULL || sigclone == NULL) { result = ISC_R_NOMEMORY; goto cleanup; @@ -9032,13 +8804,13 @@ query_synthnxdomain(query_ctx_t *qctx, cleanup: if (name != NULL) { - query_releasename(qctx->client, &name); + ns_client_releasename(qctx->client, &name); } if (clone != NULL) { - query_putrdataset(qctx->client, &clone); + ns_client_putrdataset(qctx->client, &clone); } if (sigclone != NULL) { - query_putrdataset(qctx->client, &sigclone); + ns_client_putrdataset(qctx->client, &sigclone); } return (result); } @@ -9167,8 +8939,8 @@ query_coveringnsec(query_ctx_t *qctx) { goto cleanup; } - soardataset = query_newrdataset(qctx->client); - sigsoardataset = query_newrdataset(qctx->client); + soardataset = ns_client_newrdataset(qctx->client); + sigsoardataset = ns_client_newrdataset(qctx->client); if (soardataset == NULL || sigsoardataset == NULL) { goto cleanup; } @@ -9290,8 +9062,8 @@ query_coveringnsec(query_ctx_t *qctx) { dns_db_detachnode(db, &node); } - soardataset = query_newrdataset(qctx->client); - sigsoardataset = query_newrdataset(qctx->client); + soardataset = ns_client_newrdataset(qctx->client); + sigsoardataset = ns_client_newrdataset(qctx->client); if (soardataset == NULL || sigsoardataset == NULL) { goto cleanup; } @@ -9321,10 +9093,10 @@ query_coveringnsec(query_ctx_t *qctx) { dns_rdataset_disassociate(&sigrdataset); } if (soardataset != NULL) { - query_putrdataset(qctx->client, &soardataset); + ns_client_putrdataset(qctx->client, &soardataset); } if (sigsoardataset != NULL) { - query_putrdataset(qctx->client, &sigsoardataset); + ns_client_putrdataset(qctx->client, &sigsoardataset); } if (db != NULL) { if (node != NULL) { @@ -9343,19 +9115,19 @@ query_coveringnsec(query_ctx_t *qctx) { */ qctx->findcoveringnsec = false; if (qctx->fname != NULL) { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, &qctx->fname); } if (qctx->node != NULL) { dns_db_detachnode(qctx->db, &qctx->node); } - query_putrdataset(qctx->client, &qctx->rdataset); + ns_client_putrdataset(qctx->client, &qctx->rdataset); if (qctx->sigrdataset != NULL) { - query_putrdataset(qctx->client, &qctx->sigrdataset); + ns_client_putrdataset(qctx->client, &qctx->sigrdataset); } return (query_lookup(qctx)); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } /*% @@ -9417,9 +9189,9 @@ query_cname(query_ctx_t *qctx) { INSIST(!REDIRECT(qctx->client)); - result = query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); + result = ns_query_recurse(qctx->client, qctx->qtype, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; @@ -9433,7 +9205,7 @@ query_cname(query_ctx_t *qctx) { QUERY_ERROR(qctx, result); } - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -9486,12 +9258,12 @@ query_cname(query_ctx_t *qctx) { tname = NULL; result = dns_message_gettempname(qctx->client->message, &tname); if (result != ISC_R_SUCCESS) - return (query_done(qctx)); + return (ns_query_done(qctx)); result = dns_rdataset_first(trdataset); if (result != ISC_R_SUCCESS) { dns_message_puttempname(qctx->client->message, &tname); - return (query_done(qctx)); + return (ns_query_done(qctx)); } dns_rdataset_current(trdataset, &rdata); @@ -9504,7 +9276,7 @@ query_cname(query_ctx_t *qctx) { if (result != ISC_R_SUCCESS) { dns_message_puttempname(qctx->client->message, &tname); dns_rdata_freestruct(&cname); - return (query_done(qctx)); + return (ns_query_done(qctx)); } dns_rdata_freestruct(&cname); @@ -9515,7 +9287,7 @@ query_cname(query_ctx_t *qctx) { query_addauth(qctx); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /* @@ -9586,12 +9358,12 @@ query_dname(query_ctx_t *qctx) { tname = NULL; result = dns_message_gettempname(qctx->client->message, &tname); if (result != ISC_R_SUCCESS) - return (query_done(qctx)); + return (ns_query_done(qctx)); result = dns_rdataset_first(trdataset); if (result != ISC_R_SUCCESS) { dns_message_puttempname(qctx->client->message, &tname); - return (query_done(qctx)); + return (ns_query_done(qctx)); } dns_rdataset_current(trdataset, &rdata); @@ -9609,15 +9381,15 @@ query_dname(query_ctx_t *qctx) { prefix = dns_fixedname_initname(&fixed); dns_name_split(qctx->client->query.qname, nlabels, prefix, NULL); INSIST(qctx->fname == NULL); - qctx->dbuf = query_getnamebuf(qctx->client); + qctx->dbuf = ns_client_getnamebuf(qctx->client); if (qctx->dbuf == NULL) { dns_message_puttempname(qctx->client->message, &tname); - return (query_done(qctx)); + return (ns_query_done(qctx)); } - qctx->fname = query_newname(qctx->client, qctx->dbuf, &b); + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); if (qctx->fname == NULL) { dns_message_puttempname(qctx->client->message, &tname); - return (query_done(qctx)); + return (ns_query_done(qctx)); } result = dns_name_concatenate(prefix, tname, qctx->fname, NULL); dns_message_puttempname(qctx->client->message, &tname); @@ -9630,9 +9402,9 @@ query_dname(query_ctx_t *qctx) { if (result == DNS_R_NAMETOOLONG) qctx->client->message->rcode = dns_rcode_yxdomain; if (result != ISC_R_SUCCESS) - return (query_done(qctx)); + return (ns_query_done(qctx)); - query_keepname(qctx->client, qctx->fname, qctx->dbuf); + ns_client_keepname(qctx->client, qctx->fname, qctx->dbuf); /* * Synthesize a CNAME consisting of @@ -9650,7 +9422,7 @@ query_dname(query_ctx_t *qctx) { */ result = query_addcname(qctx, trdataset->trust, trdataset->ttl); if (result != ISC_R_SUCCESS) - return (query_done(qctx)); + return (ns_query_done(qctx)); /* * Switch to the new qname and restart. @@ -9663,7 +9435,7 @@ query_dname(query_ctx_t *qctx) { query_addauth(qctx); - return (query_done(qctx)); + return (ns_query_done(qctx)); } /*% @@ -9810,14 +9582,14 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, return (result); dns_name_init(name, NULL); dns_name_clone(dns_db_origin(qctx->db), name); - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { CTRACE(ISC_LOG_ERROR, "unable to allocate rdataset"); eresult = DNS_R_SERVFAIL; goto cleanup; } if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { CTRACE(ISC_LOG_ERROR, "unable to allocate sigrdataset"); eresult = DNS_R_SERVFAIL; @@ -9894,11 +9666,11 @@ query_addsoa(query_ctx_t *qctx, unsigned int override_ttl, } cleanup: - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); if (name != NULL) - query_releasename(client, &name); + ns_client_releasename(client, &name); if (node != NULL) dns_db_detachnode(qctx->db, &node); @@ -9942,19 +9714,19 @@ query_addns(query_ctx_t *qctx) { } dns_name_init(name, NULL); dns_name_clone(dns_db_origin(qctx->db), name); - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); if (rdataset == NULL) { CTRACE(ISC_LOG_ERROR, - "query_addns: query_newrdataset failed"); + "query_addns: ns_client_newrdataset failed"); eresult = DNS_R_SERVFAIL; goto cleanup; } if (WANTDNSSEC(client) && dns_db_issecure(qctx->db)) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { CTRACE(ISC_LOG_ERROR, - "query_addns: query_newrdataset failed"); + "query_addns: ns_client_newrdataset failed"); eresult = DNS_R_SERVFAIL; goto cleanup; } @@ -9994,12 +9766,12 @@ query_addns(query_ctx_t *qctx) { cleanup: CTRACE(ISC_LOG_DEBUG(3), "query_addns: cleanup"); - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (name != NULL) { - query_releasename(client, &name); + ns_client_releasename(client, &name); } if (node != NULL) { dns_db_detachnode(qctx->db, &node); @@ -10046,12 +9818,12 @@ query_addbestns(query_ctx_t *qctx) { /* * We'll need some resources... */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) { goto cleanup; } - fname = query_newname(client, dbuf, &b); - rdataset = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + rdataset = ns_client_newrdataset(client); if (fname == NULL || rdataset == NULL) { goto cleanup; } @@ -10061,7 +9833,7 @@ query_addbestns(query_ctx_t *qctx) { * need to validate answers from the cache. */ if (WANTDNSSEC(client) || !is_zone) { - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (sigrdataset == NULL) { goto cleanup; } @@ -10080,7 +9852,7 @@ query_addbestns(query_ctx_t *qctx) { goto cleanup; } if (USECACHE(client)) { - query_keepname(client, fname, dbuf); + ns_client_keepname(client, fname, dbuf); dns_db_detachnode(db, &node); SAVE(zdb, db); SAVE(zfname, fname); @@ -10117,17 +9889,17 @@ query_addbestns(query_ctx_t *qctx) { } if (use_zone) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); /* - * We've already done query_keepname() on + * We've already done ns_client_keepname() on * zfname, so we must set dbuf to NULL to * prevent query_addrrset() from trying to - * call query_keepname() again. + * call ns_client_keepname() again. */ dbuf = NULL; - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (node != NULL) { @@ -10176,7 +9948,7 @@ query_addbestns(query_ctx_t *qctx) { * now. */ if (!WANTDNSSEC(client)) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, @@ -10184,13 +9956,13 @@ query_addbestns(query_ctx_t *qctx) { cleanup: if (rdataset != NULL) { - query_putrdataset(client, &rdataset); + ns_client_putrdataset(client, &rdataset); } if (sigrdataset != NULL) { - query_putrdataset(client, &sigrdataset); + ns_client_putrdataset(client, &sigrdataset); } if (fname != NULL) { - query_releasename(client, &fname); + ns_client_releasename(client, &fname); } if (node != NULL) { dns_db_detachnode(db, &node); @@ -10202,11 +9974,13 @@ query_addbestns(query_ctx_t *qctx) { dns_zone_detach(&zone); } if (zdb != NULL) { - query_putrdataset(client, &zrdataset); - if (zsigrdataset != NULL) - query_putrdataset(client, &zsigrdataset); - if (zfname != NULL) - query_releasename(client, &zfname); + ns_client_putrdataset(client, &zrdataset); + if (zsigrdataset != NULL) { + ns_client_putrdataset(client, &zsigrdataset); + } + if (zfname != NULL) { + ns_client_releasename(client, &zfname); + } dns_db_detach(&zdb); } } @@ -10301,12 +10075,12 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, /* * We'll need some resources... */ - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); - rdataset = query_newrdataset(client); - sigrdataset = query_newrdataset(client); + fname = ns_client_newname(client, dbuf, &b); + rdataset = ns_client_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); if (fname == NULL || rdataset == NULL || sigrdataset == NULL) goto cleanup; @@ -10354,19 +10128,19 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, * Replace resources which were consumed by query_addrrset. */ if (fname == NULL) { - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); } if (rdataset == NULL) - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset == NULL) - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); @@ -10396,19 +10170,19 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, * Replace resources which were consumed by query_addrrset. */ if (fname == NULL) { - dbuf = query_getnamebuf(client); + dbuf = ns_client_getnamebuf(client); if (dbuf == NULL) goto cleanup; - fname = query_newname(client, dbuf, &b); + fname = ns_client_newname(client, dbuf, &b); } if (rdataset == NULL) - rdataset = query_newrdataset(client); + rdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(rdataset)) dns_rdataset_disassociate(rdataset); if (sigrdataset == NULL) - sigrdataset = query_newrdataset(client); + sigrdataset = ns_client_newrdataset(client); else if (dns_rdataset_isassociated(sigrdataset)) dns_rdataset_disassociate(sigrdataset); @@ -10462,12 +10236,15 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, query_addrrset(qctx, &fname, &rdataset, &sigrdataset, dbuf, DNS_SECTION_AUTHORITY); } - if (rdataset != NULL) - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } if (have_wname) { ispositive = true; /* prevent loop */ if (!dns_name_equal(name, wname)) { @@ -10476,12 +10253,15 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, } } cleanup: - if (rdataset != NULL) - query_putrdataset(client, &rdataset); - if (sigrdataset != NULL) - query_putrdataset(client, &sigrdataset); - if (fname != NULL) - query_releasename(client, &fname); + if (rdataset != NULL) { + ns_client_putrdataset(client, &rdataset); + } + if (sigrdataset != NULL) { + ns_client_putrdataset(client, &sigrdataset); + } + if (fname != NULL) { + ns_client_releasename(client, &fname); + } } /*% @@ -10504,7 +10284,8 @@ query_addauth(query_ctx_t *qctx) { qctx->qtype != dns_rdatatype_ns) { if (qctx->fname != NULL) { - query_releasename(qctx->client, &qctx->fname); + ns_client_releasename(qctx->client, + &qctx->fname); } query_addbestns(qctx); } @@ -10619,20 +10400,11 @@ query_glueanswer(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(). - */ -static isc_result_t -query_done(query_ctx_t *qctx) { +isc_result_t +ns_query_done(query_ctx_t *qctx) { const dns_namelist_t *secs = qctx->client->message->sections; - CCTRACE(ISC_LOG_DEBUG(3), "query_done"); + CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done"); PROCESS_HOOK(NS_QUERY_DONE_BEGIN, qctx); @@ -11199,7 +10971,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { if (qctx->qtype == dns_rdatatype_aaaa) { dns_rdataset_t *trdataset; - trdataset = query_newrdataset(qctx->client); + trdataset = ns_client_newrdataset(qctx->client); result = dns_db_findrdataset(qctx->db, qctx->node, qctx->version, dns_rdatatype_a, 0, @@ -11208,7 +10980,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { if (dns_rdataset_isassociated(trdataset)) { dns_rdataset_disassociate(trdataset); } - query_putrdataset(qctx->client, &trdataset); + ns_client_putrdataset(qctx->client, &trdataset); /* * We found an AAAA. If we also found an A, then the AAAA @@ -11248,10 +11020,10 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { * if the recursion for the A succeeds. */ INSIST(!REDIRECT(qctx->client)); - result = query_recurse(qctx->client, - dns_rdatatype_a, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); + 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; @@ -11285,7 +11057,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { qctx->client->hookflags &= ~FILTER_AAAA_RECURSING; - result = query_done(qctx); + result = ns_query_done(qctx); *resp = result; return (true); diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index b47b775fda..d88de02f45 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -91,7 +91,7 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) { test->cache_entry_flags == 0); /* - * Interrupt execution if query_done() is called. + * Interrupt execution if ns_query_done() is called. */ ns_hook_t hook = { .callback = ns_test_hook_catch_call, @@ -292,7 +292,7 @@ run_start_test(const ns__query_start_test_params_t *test) { test->auth_zone_path != NULL)); /* - * Interrupt execution if query_lookup() or query_done() is called. + * Interrupt execution if query_lookup() or ns_query_done() is called. */ ns_hook_t hook = { .callback = ns_test_hook_catch_call, diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index 196acd47ac..9918d50512 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -62,8 +62,10 @@ ns_log_init ns_log_setcontext ns_notify_start ns_query_cancel +ns_query_done ns_query_free ns_query_init +ns_query_recurse ns_query_start ns_server_attach ns_server_create From d3f0f71b6b6fbe60753a67e245cfa9238a265859 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 10 Aug 2018 19:32:12 -0700 Subject: [PATCH 06/26] 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. --- bin/named/server.c | 24 +- configure | 2 +- configure.ac | 2 +- lib/ns/Makefile.in | 16 +- lib/ns/filter-aaaa.c | 447 ++++++++++++++++++++++++++++++++++++++ lib/ns/hooks.c | 76 ++++--- lib/ns/include/ns/hooks.h | 66 ++++-- lib/ns/include/ns/query.h | 76 +++++-- lib/ns/query.c | 398 +-------------------------------- lib/ns/server.c | 5 - lib/ns/win32/libns.def | 21 +- 11 files changed, 661 insertions(+), 472 deletions(-) create mode 100644 lib/ns/filter-aaaa.c diff --git a/bin/named/server.c b/bin/named/server.c index c453396dd0..37282e9e09 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 5031db85a3..bbca641c1b 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 d831bae619..af7f90cead 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 2e6c0183da..ede65f8674 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 0000000000..a0e8141fcf --- /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 4b97c5b3d5..66438f6604 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 aa6d8d1548..3001661a43 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 ad59b2b48c..853c7e5a90 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_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 104ef4d7cf..93e1d8fdf4 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 fde2c459d5..a328ceebeb 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 9918d50512..ab5efa25dd 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 From e2ac439e286ec542f18cd576bf04d1828656123d Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sat, 11 Aug 2018 17:07:51 -0700 Subject: [PATCH 07/26] move filter-aaaa.so build from lib/ns to bin/hooks --- bin/Makefile.in | 2 +- bin/hooks/Makefile.in | 84 +++++++++++++++ bin/hooks/filter-aaaa.8 | 116 +++++++++++++++++++++ {lib/ns => bin/hooks}/filter-aaaa.c | 0 bin/hooks/filter-aaaa.docbook | 146 ++++++++++++++++++++++++++ bin/hooks/filter-aaaa.html | 115 +++++++++++++++++++++ configure | 3 +- configure.ac | 1 + doc/arm/Bv9ARM-book.xml | 76 +------------- doc/arm/man.filter-aaaa.html | 153 ++++++++++++++++++++++++++++ lib/ns/Makefile.in | 13 +-- 11 files changed, 621 insertions(+), 88 deletions(-) create mode 100644 bin/hooks/Makefile.in create mode 100644 bin/hooks/filter-aaaa.8 rename {lib/ns => bin/hooks}/filter-aaaa.c (100%) create mode 100644 bin/hooks/filter-aaaa.docbook create mode 100644 bin/hooks/filter-aaaa.html create mode 100644 doc/arm/man.filter-aaaa.html diff --git a/bin/Makefile.in b/bin/Makefile.in index f0c504a17e..8e55b450dc 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -12,7 +12,7 @@ VPATH = @srcdir@ top_srcdir = @top_srcdir@ SUBDIRS = named rndc dig delv dnssec tools nsupdate check confgen \ - @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ tests + @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ hooks tests TARGETS = @BIND9_MAKE_RULES@ diff --git a/bin/hooks/Makefile.in b/bin/hooks/Makefile.in new file mode 100644 index 0000000000..69e571d199 --- /dev/null +++ b/bin/hooks/Makefile.in @@ -0,0 +1,84 @@ +# 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. + +srcdir = @srcdir@ +VPATH = @srcdir@ +top_srcdir = @top_srcdir@ + +VERSION=@BIND9_VERSION@ + +@BIND9_PRODUCT@ + +@BIND9_DESCRIPTION@ + +@BIND9_SRCID@ + +@BIND9_CONFIGARGS@ + +@BIND9_MAKE_INCLUDES@ + +CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ + ${NS_INCLUDES} ${DNS_INCLUDES} \ + ${ISCCFG_INCLUDES} ${ISC_INCLUDES} + +DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ +ISCLIBS = ../../lib/isc/libisc.@A@ @OPENSSL_LIBS@ +NSLIBS = ../../lib/ns/libns.@A@ + +LIBS = + +SO_TARGETS = lib/filter-aaaa.@SO@ +TARGETS = @SO_TARGETS@ + +SO_OBJS = filter-aaaa.@O@ +SO_SRCS = filter-aaaa.c + +OBJS = + +CFLAGS = @CFLAGS@ @SO_CFLAGS@ +SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ + +MANPAGES = filter-aaaa.8 + +HTMLPAGES = filter-aaaa.html + +MANOBJS = ${MANPAGES} ${HTMLPAGES} + +@BIND9_MAKE_RULES@ + +lib/filter-aaaa.@SO@: filter-aaaa.@SO@ + $(SHELL) ${top_srcdir}/mkinstalldirs `pwd`/lib + ${LIBTOOL_MODE_INSTALL} ${INSTALL} filter-aaaa.@SO@ `pwd`/lib + +filter-aaaa.@SO@: filter-aaaa.@O@ + ${LIBTOOL_MODE_LINK} @SO_LD@ ${SO_LDFLAGS} -o $@ \ + filter-aaaa.@O@ ${LIBS} + +doc man:: ${MANOBJS} + +docclean manclean maintainer-clean:: + rm -f ${MANOBJS} + +clean distclean:: + rm -f filter-aaaa.so + rm -f ${TARGETS} ${OBJS} + +installdirs: + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${libdir} + $(SHELL) ${top_srcdir}/mkinstalldirs ${DESTDIR}${mandir}/man8 + +install:: filter-aaaa.@SO@ installdirs + ${LIBTOOL_MODE_INSTALL} ${INSTALL_LIBRARY} filter-aaaa.@SO@ \ + ${DESTDIR}${libdir} + ${INSTALL_DATA} ${srcdir}/filter-aaaa.8 ${DESTDIR}${mandir}/man8 + +uninstall:: + ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/filter-aaaa.@SO@ + rm -f ${DESTDIR}${mandir}/man8/filter-aaaa.8 diff --git a/bin/hooks/filter-aaaa.8 b/bin/hooks/filter-aaaa.8 new file mode 100644 index 0000000000..f9204904c1 --- /dev/null +++ b/bin/hooks/filter-aaaa.8 @@ -0,0 +1,116 @@ +.\" Copyright (C) 2018 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/. +.\" +.hy 0 +.ad l +'\" t +.\" Title: filter-aaaa.so +.\" Author: +.\" Generator: DocBook XSL Stylesheets v1.79.1 +.\" Date: 2018-08-13 +.\" Manual: BIND9 +.\" Source: ISC +.\" Language: English +.\" +.TH "FILTER\-AAAA\&.SO" "8" "2018\-08\-13" "ISC" "BIND9" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +filter-aaaa.so \- filter AAAA in DNS responses when A is present +.SH "SYNOPSIS" +.HP 28 +\fBhook query "filter\-aaaa\&.so"\fR [\fI{\ parameters\ }\fR]; +.SH "DESCRIPTION" +.PP +\fBfilter\-aaaa\&.so\fR +is a query hook module for +\fBnamed\fR, enabling +\fBnamed\fR +to omit some IPv6 addresses when responding to clients\&. +.PP +Until BIND 9\&.12, this feature was implemented natively in +\fBnamed\fR +and enabled with the +\fBfilter\-aaaa\fR +ACL and the +\fBfilter\-aaaa\-on\-v4\fR +and +\fBfilter\-aaaa\-on\-v6\fR +options\&. These options are now deprecated in +named\&.conf, but can be passed as parameters to the +\fBfilter\-aaaa\&.so\fR +hook module, for example: +.sp +.if n \{\ +.RS 4 +.\} +.nf +hook query "/usr/local/lib/filter\-aaaa\&.so" { + filter\-aaaa\-on\-v4 yes; + filter\-aaaa\-on\-v6 yes; + filter\-aaaa { 192\&.0\&.2\&.1; 2001:db8:2::1; }; +}; +.fi +.if n \{\ +.RE +.\} +.PP +This module is intended to aid transition from IPv4 to IPv6 by withholding IPv6 addresses from DNS clients which are not connected to the IPv6 Internet, when the name being looked up has an IPv4 address available\&. Use of this module is not recommended unless absolutely necessary\&. +.PP +Note: This mechanism can erroneously cause other servers not to give AAAA records to their clients\&. If a recursing server with both IPv6 and IPv4 network connections queries an authoritative server using this mechanism via IPv4, it will be denied AAAA records even if its client is using IPv6\&. +.SH "OPTIONS" +.PP +\fBfilter\-aaaa\fR +.RS 4 +Specifies a list of client addresses for which AAAA filtering is to be applied\&. The default is +\fBany\fR\&. +.RE +.PP +\fBfilter\-aaaa\-on\-v4\fR +.RS 4 +If set to +\fByes\fR, the DNS client is at an IPv4 address, in +\fBfilter\-aaaa\fR, and if the response does not include DNSSEC signatures, then all AAAA records are deleted from the response\&. This filtering applies to all responses and not only authoritative responses\&. +.sp +If set to +\fBbreak\-dnssec\fR, then AAAA records are deleted even when DNSSEC is enabled\&. As suggested by the name, this causes the response to fail to verify, because the DNSSEC protocol is designed to detect deletions\&. +.sp +This mechanism can erroneously cause other servers not to give AAAA records to their clients\&. A recursing server with both IPv6 and IPv4 network connections that queries an authoritative server using this mechanism via IPv4 will be denied AAAA records even if its client is using IPv6\&. +.RE +.PP +\fBfilter\-aaaa\-on\-v6\fR +.RS 4 +Identical to +\fBfilter\-aaaa\-on\-v4\fR, except it filters AAAA responses to queries from IPv6 clients instead of IPv4 clients\&. To filter all responses, set both options to +\fByes\fR\&. +.RE +.SH "SEE ALSO" +.PP +BIND 9 Administrator Reference Manual\&. +.SH "AUTHOR" +.PP +\fBInternet Systems Consortium, Inc\&.\fR +.SH "COPYRIGHT" +.br +Copyright \(co 2018 Internet Systems Consortium, Inc. ("ISC") +.br diff --git a/lib/ns/filter-aaaa.c b/bin/hooks/filter-aaaa.c similarity index 100% rename from lib/ns/filter-aaaa.c rename to bin/hooks/filter-aaaa.c diff --git a/bin/hooks/filter-aaaa.docbook b/bin/hooks/filter-aaaa.docbook new file mode 100644 index 0000000000..3a0581e9cd --- /dev/null +++ b/bin/hooks/filter-aaaa.docbook @@ -0,0 +1,146 @@ + + + + + + 2018-08-13 + + + ISC + Internet Systems Consortium, Inc. + + + filter-aaaa.so + 8 + BIND9 + + + + filter-aaaa.so + filter AAAA in DNS responses when A is present + + + + + 2018 + Internet Systems Consortium, Inc. ("ISC") + + + + + + hook query "filter-aaaa.so" + { parameters }; + + + + DESCRIPTION + + filter-aaaa.so is a query hook module for + named, enabling named + to omit some IPv6 addresses when responding to clients. + + + Until BIND 9.12, this feature was impleented natively in + named and enabled with the + filter-aaaa ACL and the + filter-aaaa-on-v4 and + filter-aaaa-on-v6 options. These options are + now deprecated in named.conf, but can be + passed as parameters to the filter-aaaa.so + hook module, for example: + + +hook query "/usr/local/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa-on-v6 yes; + filter-aaaa { 192.0.2.1; 2001:db8:2::1; }; +}; + + + This module is intended to aid transition from IPv4 to IPv6 by + withholding IPv6 addresses from DNS clients which are not connected + to the IPv6 Internet, when the name being looked up has an IPv4 + address available. Use of this module is not recommended unless + absolutely necessary. + + + Note: This mechanism can erroneously cause other servers not to + give AAAA records to their clients. If a recursing server with + both IPv6 and IPv4 network connections queries an authoritative + server using this mechanism via IPv4, it will be denied AAAA + records even if its client is using IPv6. + + + + OPTIONS + + + filter-aaaa + + + Specifies a list of client addresses for which AAAA + filtering is to be applied. The default is + any. + + + + + + filter-aaaa-on-v4 + + + If set to yes, the DNS client is + at an IPv4 address, in filter-aaaa, + and if the response does not include DNSSEC signatures, + then all AAAA records are deleted from the response. + This filtering applies to all responses and not only + authoritative responses. + + + If set to break-dnssec, + then AAAA records are deleted even when DNSSEC is + enabled. As suggested by the name, this causes the + response to fail to verify, because the DNSSEC protocol is + designed to detect deletions. + + + This mechanism can erroneously cause other servers not to + give AAAA records to their clients. A recursing server with + both IPv6 and IPv4 network connections that queries an + authoritative server using this mechanism via IPv4 will be + denied AAAA records even if its client is using IPv6. + + + + + + filter-aaaa-on-v6 + + + Identical to filter-aaaa-on-v4, + except it filters AAAA responses to queries from IPv6 + clients instead of IPv4 clients. To filter all + responses, set both options to yes. + + + + + + + SEE ALSO + + BIND 9 Administrator Reference Manual. + + + + diff --git a/bin/hooks/filter-aaaa.html b/bin/hooks/filter-aaaa.html new file mode 100644 index 0000000000..e505f4ead2 --- /dev/null +++ b/bin/hooks/filter-aaaa.html @@ -0,0 +1,115 @@ + + + + + +filter-aaaa.so + + +
+
+
+

Name

+

filter-aaaa.so — filter AAAA in DNS responses when A is present

+
+
+

Synopsis

+

hook query "filter-aaaa.so" [{ parameters }]; +

+
+
+

DESCRIPTION

+

+ filter-aaaa.so is a query hook module for + named, enabling named + to omit some IPv6 addresses when responding to clients. +

+

+ Until BIND 9.12, this feature was implemented natively in + named and enabled with the + filter-aaaa ACL and the + filter-aaaa-on-v4 and + filter-aaaa-on-v6 options. These options are + now deprecated in named.conf, but can be + passed as parameters to the filter-aaaa.so + hook module, for example: +

+
+hook query "/usr/local/lib/filter-aaaa.so" {
+        filter-aaaa-on-v4 yes;
+        filter-aaaa-on-v6 yes;
+        filter-aaaa { 192.0.2.1; 2001:db8:2::1; };
+};
+
+

+ This module is intended to aid transition from IPv4 to IPv6 by + withholding IPv6 addresses from DNS clients which are not connected + to the IPv6 Internet, when the name being looked up has an IPv4 + address available. Use of this module is not recommended unless + absolutely necessary. +

+

+ Note: This mechanism can erroneously cause other servers not to + give AAAA records to their clients. If a recursing server with + both IPv6 and IPv4 network connections queries an authoritative + server using this mechanism via IPv4, it will be denied AAAA + records even if its client is using IPv6. +

+
+
+

OPTIONS

+
+
filter-aaaa
+

+ Specifies a list of client addresses for which AAAA + filtering is to be applied. The default is + any. +

+
filter-aaaa-on-v4
+
+

+ If set to yes, the DNS client is + at an IPv4 address, in filter-aaaa, + and if the response does not include DNSSEC signatures, + then all AAAA records are deleted from the response. + This filtering applies to all responses and not only + authoritative responses. +

+

+ If set to break-dnssec, + then AAAA records are deleted even when DNSSEC is + enabled. As suggested by the name, this causes the + response to fail to verify, because the DNSSEC protocol is + designed to detect deletions. +

+

+ This mechanism can erroneously cause other servers not to + give AAAA records to their clients. A recursing server with + both IPv6 and IPv4 network connections that queries an + authoritative server using this mechanism via IPv4 will be + denied AAAA records even if its client is using IPv6. +

+
+
filter-aaaa-on-v6
+

+ Identical to filter-aaaa-on-v4, + except it filters AAAA responses to queries from IPv6 + clients instead of IPv4 clients. To filter all + responses, set both options to yes. +

+
+
+
+

SEE ALSO

+

+ BIND 9 Administrator Reference Manual. +

+
+
+ diff --git a/configure b/configure index bbca641c1b..4839c207dc 100755 --- a/configure +++ b/configure @@ -21548,7 +21548,7 @@ ac_config_commands="$ac_config_commands chmod" # elsewhere if there's a good reason for doing so. # -ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile" +ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/hooks/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile" # @@ -22558,6 +22558,7 @@ do "bin/delv/Makefile") CONFIG_FILES="$CONFIG_FILES bin/delv/Makefile" ;; "bin/dig/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dig/Makefile" ;; "bin/dnssec/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dnssec/Makefile" ;; + "bin/hooks/Makefile") CONFIG_FILES="$CONFIG_FILES bin/hooks/Makefile" ;; "bin/named/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/Makefile" ;; "bin/named/unix/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/unix/Makefile" ;; "bin/nsupdate/Makefile") CONFIG_FILES="$CONFIG_FILES bin/nsupdate/Makefile" ;; diff --git a/configure.ac b/configure.ac index af7f90cead..b7f1037712 100644 --- a/configure.ac +++ b/configure.ac @@ -2957,6 +2957,7 @@ AC_CONFIG_FILES([ bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile + bin/hooks/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index d03dfa1434..00e5142d41 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -6432,69 +6432,6 @@ options { - - filter-aaaa-on-v4 - - - This option is intended to help the - transition from IPv4 to IPv6 by not giving IPv6 addresses - to DNS clients unless they have connections to the IPv6 - Internet. This is not recommended unless absolutely - necessary. The default is no. - The filter-aaaa-on-v4 option - may also be specified in view statements - to override the global filter-aaaa-on-v4 - option. - - - If yes, - the DNS client is at an IPv4 address, in filter-aaaa, - and if the response does not include DNSSEC signatures, - then all AAAA records are deleted from the response. - This filtering applies to all responses and not only - authoritative responses. - - - If break-dnssec, - then AAAA records are deleted even when DNSSEC is enabled. - As suggested by the name, this makes the response not verify, - because the DNSSEC protocol is designed detect deletions. - - - This mechanism can erroneously cause other servers to - not give AAAA records to their clients. - A recursing server with both IPv6 and IPv4 network connections - that queries an authoritative server using this mechanism - via IPv4 will be denied AAAA records even if its client is - using IPv6. - - - This mechanism is applied to authoritative as well as - non-authoritative records. - A client using IPv4 that is not allowed recursion can - erroneously be given AAAA records because the server is not - allowed to check for A records. - - - Some AAAA records are given to IPv4 clients in glue records. - IPv4 clients that are servers can then erroneously - answer requests for AAAA records received via IPv4. - - - - - - filter-aaaa-on-v6 - - - Identical to filter-aaaa-on-v4, - except it filters AAAA responses to queries from IPv6 - clients instead of IPv4 clients. To filter all - responses, set both options to yes. - - - - ixfr-from-differences @@ -7347,18 +7284,6 @@ options { - - filter-aaaa - - - Specifies a list of addresses to which - filter-aaaa-on-v4 - and filter-aaaa-on-v6 - apply. The default is any. - - - - keep-response-order @@ -18351,6 +18276,7 @@ allow-query { !{ !10/8; any; }; key example; }; + diff --git a/doc/arm/man.filter-aaaa.html b/doc/arm/man.filter-aaaa.html new file mode 100644 index 0000000000..ad4c62b5a7 --- /dev/null +++ b/doc/arm/man.filter-aaaa.html @@ -0,0 +1,153 @@ + + + + + +filter-aaaa.so + + + + + + + + +
+
+
+

Name

+

filter-aaaa.so — filter AAAA in DNS responses when A is present

+
+
+

Synopsis

+

hook query "filter-aaaa.so" [{ parameters }]; +

+
+
+

DESCRIPTION

+

+ filter-aaaa.so is a query hook module for + named, enabling named + to omit some IPv6 addresses when responding to clients. +

+

+ Until BIND 9.12, this feature was impleented natively in + named and enabled with the + filter-aaaa ACL and the + filter-aaaa-on-v4 and + filter-aaaa-on-v6 options. These options are + now deprecated in named.conf, but can be + passed as parameters to the filter-aaaa.so + hook module, for example: +

+
+hook query "/usr/local/lib/filter-aaaa.so" {
+        filter-aaaa-on-v4 yes;
+        filter-aaaa-on-v6 yes;
+        filter-aaaa { 192.0.2.1; 2001:db8:2::1; };
+};
+
+

+ This module is intended to aid transition from IPv4 to IPv6 by + withholding IPv6 addresses from DNS clients which are not connected + to the IPv6 Internet, when the name being looked up has an IPv4 + address available. Use of this module is not recommended unless + absolutely necessary. +

+

+ Note: This mechanism can erroneously cause other servers not to + give AAAA records to their clients. If a recursing server with + both IPv6 and IPv4 network connections queries an authoritative + server using this mechanism via IPv4, it will be denied AAAA + records even if its client is using IPv6. +

+
+
+

OPTIONS

+
+
filter-aaaa
+

+ Specifies a list of client addresses for which AAAA + filtering is to be applied. The default is + any. +

+
filter-aaaa-on-v4
+
+

+ If set to yes, the DNS client is + at an IPv4 address, in filter-aaaa, + and if the response does not include DNSSEC signatures, + then all AAAA records are deleted from the response. + This filtering applies to all responses and not only + authoritative responses. +

+

+ If set to break-dnssec, + then AAAA records are deleted even when DNSSEC is + enabled. As suggested by the name, this causes the + response to fail to verify, because the DNSSEC protocol is + designed to detect deletions. +

+

+ This mechanism can erroneously cause other servers not to + give AAAA records to their clients. A recursing server with + both IPv6 and IPv4 network connections that queries an + authoritative server using this mechanism via IPv4 will be + denied AAAA records even if its client is using IPv6. +

+
+
filter-aaaa-on-v6
+

+ Identical to filter-aaaa-on-v4, + except it filters AAAA responses to queries from IPv6 + clients instead of IPv4 clients. To filter all + responses, set both options to yes. +

+
+
+
+

SEE ALSO

+

+ BIND 9 Administrator Reference Manual. +

+
+
+ +

BIND 9.13.2 (Development Release)

+ + diff --git a/lib/ns/Makefile.in b/lib/ns/Makefile.in index ede65f8674..e785969b51 100644 --- a/lib/ns/Makefile.in +++ b/lib/ns/Makefile.in @@ -54,8 +54,7 @@ SRCS = client.c hooks.c interfacemgr.c lib.c listenlist.c \ SUBDIRS = include TESTDIRS = @UNITTESTS@ -SO_TARGETS = filter-aaaa.@SO@ -TARGETS = timestamp @SO_TARGETS@ +TARGETS = timestamp SO_CFLAGS = @CFLAGS@ @SO_CFLAGS@ SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ @@ -84,14 +83,6 @@ 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} @@ -103,4 +94,4 @@ uninstall:: ${LIBTOOL_MODE_UNINSTALL} rm -f ${DESTDIR}${libdir}/libns.@A@ clean distclean:: - rm -f libns.@A@ timestamp filter-aaaa.@O@ filter-aaaa.@SO@ + rm -f libns.@A@ timestamp From d2f4644388121c640cc2ef78be7cfe0befc7c66e Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 12 Aug 2018 11:19:36 -0700 Subject: [PATCH 08/26] add hook statement to configuration parser - allow multiple "hook" statements at global or view level - add "optional bracketed text" type for optional parameter list - load hook module from specified path rather than hardcoded path - add a hooktable pointer (and a callback for freeing it) to the view structure - change the hooktable functions so they no longer update ns__hook_table by default, and modify PROCESS_HOOK so it uses the view hooktable, if set, rather than ns__hook_table. (ns__hook_table is retained for use by unit tests.) - update the filter-aaaa system test to load filter-aaaa.so - add a prereq script to check for dlopen support before running the filter-aaaa system test not yet done: - configuration parameters are not being passed to the filter-aaaa module; the filter-aaaa ACL and filter-aaaa-on-{v4,v6} settings are still stored in dns_view --- bin/hooks/filter-aaaa.c | 17 +++- bin/named/server.c | 89 ++++++++++++++++--- .../system/filter-aaaa/ns1/named1.conf.in | 2 + .../system/filter-aaaa/ns1/named2.conf.in | 2 + .../system/filter-aaaa/ns2/named1.conf.in | 2 + .../system/filter-aaaa/ns2/named2.conf.in | 2 + .../system/filter-aaaa/ns3/named1.conf.in | 2 + .../system/filter-aaaa/ns3/named2.conf.in | 2 + .../system/filter-aaaa/ns4/named1.conf.in | 2 + .../system/filter-aaaa/ns4/named2.conf.in | 2 + .../system/filter-aaaa/ns5/named.conf.in | 2 + bin/tests/system/filter-aaaa/prereq.sh | 19 ++++ lib/dns/include/dns/view.h | 3 + lib/dns/view.c | 6 ++ lib/isccfg/include/isccfg/grammar.h | 1 + lib/isccfg/namedconf.c | 25 ++++++ lib/isccfg/parser.c | 48 +++++++++- lib/ns/hooks.c | 35 ++++---- lib/ns/include/ns/hooks.h | 50 +++++------ lib/ns/query.c | 31 ++++++- lib/ns/tests/nstest.c | 7 +- lib/ns/tests/query_test.c | 27 +++--- 22 files changed, 289 insertions(+), 87 deletions(-) create mode 100644 bin/tests/system/filter-aaaa/prereq.sh diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index a0e8141fcf..2f316dbc35 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -77,10 +77,19 @@ hook_register(const char *parameters, const char *file, unsigned long line, 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); + if (parameters != NULL) { + 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); + } else { + isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "loading 'filter-aaaa' " + "module from %s:%lu, no parameters", + file, line); + } /* * TODO: diff --git a/bin/named/server.c b/bin/named/server.c index 37282e9e09..c3da40ed25 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1535,6 +1535,50 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, name, isc_result_totext(result)); return (result); } + +static isc_result_t +configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, + ns_hookctx_t *hctx) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *obj; + const char *type, *library; + + /* Get the path to the hook module. */ + obj = cfg_tuple_get(hook, "type"); + type = cfg_obj_asstring(obj); + + /* Only query hooks are supported currently. */ + if (strcasecmp(type, "query") != 0) { + cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, + "unsupported hook type"); + return (ISC_R_FAILURE); + } + + library = cfg_obj_asstring(cfg_tuple_get(hook, "library")); + + obj = cfg_tuple_get(hook, "parameters"); + if (obj != NULL && cfg_obj_isstring(obj)) { + result = ns_hookmodule_load(library, + cfg_obj_asstring(obj), + cfg_obj_file(obj), + cfg_obj_line(obj), + hctx, hooktable); + } else { + result = ns_hookmodule_load(library, NULL, + cfg_obj_file(hook), + cfg_obj_line(hook), + hctx, hooktable); + } + + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "%s: hook module configuration failed: %s", + library, isc_result_totext(result)); + } + return (result); +} #endif @@ -3675,7 +3719,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, const cfg_obj_t *dlvobj = NULL; unsigned int dlzargc; char **dlzargv; - const cfg_obj_t *dyndb_list; + const cfg_obj_t *dyndb_list, *hook_list; const cfg_obj_t *disabled; const cfg_obj_t *obj, *obj2; const cfg_listelt_t *element; @@ -5271,10 +5315,11 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, * Load DynDB modules. */ dyndb_list = NULL; - if (voptions != NULL) + if (voptions != NULL) { (void)cfg_map_get(voptions, "dyndb", &dyndb_list); - else + } else { (void)cfg_map_get(config, "dyndb", &dyndb_list); + } #ifdef HAVE_DLOPEN for (element = cfg_list_first(dyndb_list); @@ -5294,21 +5339,37 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, CHECK(configure_dyndb(dyndb, mctx, dctx)); } +#endif /* - * 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. + * Load hook modules. */ - if (hctx == NULL) { - CHECK(ns_hook_createctx(mctx, &hctx)); + hook_list = NULL; + if (voptions != NULL) { + (void)cfg_map_get(voptions, "hook", &hook_list); + } else { + (void)cfg_map_get(config, "hook", &hook_list); + } + +#ifdef HAVE_DLOPEN + for (element = cfg_list_first(hook_list); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *hook = cfg_listelt_value(element); + + if (view->hooktable == NULL) { + ns_hooktable_create(view->mctx, + (ns_hooktable_t **) &view->hooktable); + view->hooktable_free = ns_hooktable_free; + } + + if (hctx == NULL) { + CHECK(ns_hook_createctx(mctx, &hctx)); + } + + CHECK(configure_hook(view->hooktable, hook, hctx)); } - ns_hooktable_init(NULL); - (void) ns_hookmodule_load("/tmp/filter-aaaa.so", "", "", 0, - hctx, NULL); #endif /* diff --git a/bin/tests/system/filter-aaaa/ns1/named1.conf.in b/bin/tests/system/filter-aaaa/ns1/named1.conf.in index 55c1afe093..bde197748e 100644 --- a/bin/tests/system/filter-aaaa/ns1/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named1.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns1/named2.conf.in b/bin/tests/system/filter-aaaa/ns1/named2.conf.in index 6cf9d0d333..8d29d583aa 100644 --- a/bin/tests/system/filter-aaaa/ns1/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named2.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns2/named1.conf.in b/bin/tests/system/filter-aaaa/ns2/named1.conf.in index 7b43a97a46..5d8e06cdfd 100644 --- a/bin/tests/system/filter-aaaa/ns2/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named1.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns2/named2.conf.in b/bin/tests/system/filter-aaaa/ns2/named2.conf.in index 6a6b9baef7..56e388ce49 100644 --- a/bin/tests/system/filter-aaaa/ns2/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named2.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns3/named1.conf.in b/bin/tests/system/filter-aaaa/ns3/named1.conf.in index 60c97d2aa6..b0f4ba0667 100644 --- a/bin/tests/system/filter-aaaa/ns3/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named1.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns3/named2.conf.in b/bin/tests/system/filter-aaaa/ns3/named2.conf.in index fd7b8c04d1..847bdfe0d3 100644 --- a/bin/tests/system/filter-aaaa/ns3/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named2.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns4/named1.conf.in b/bin/tests/system/filter-aaaa/ns4/named1.conf.in index 3f7cbcb16e..915f55d44b 100644 --- a/bin/tests/system/filter-aaaa/ns4/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named1.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns4/named2.conf.in b/bin/tests/system/filter-aaaa/ns4/named2.conf.in index 56a546e359..c6818b8f76 100644 --- a/bin/tests/system/filter-aaaa/ns4/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named2.conf.in @@ -25,6 +25,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/ns5/named.conf.in b/bin/tests/system/filter-aaaa/ns5/named.conf.in index 47b3aff31a..a27ee016d6 100644 --- a/bin/tests/system/filter-aaaa/ns5/named.conf.in +++ b/bin/tests/system/filter-aaaa/ns5/named.conf.in @@ -30,6 +30,8 @@ options { minimal-responses no; }; +hook query "../../../../hooks/lib/filter-aaaa.so"; + key rndc_key { secret "1234abcd8765"; algorithm hmac-sha256; diff --git a/bin/tests/system/filter-aaaa/prereq.sh b/bin/tests/system/filter-aaaa/prereq.sh new file mode 100644 index 0000000000..7b8a7f4a91 --- /dev/null +++ b/bin/tests/system/filter-aaaa/prereq.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# +# 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. + +SYSTEMTESTTOP=.. +. $SYSTEMTESTTOP/conf.sh + +$FEATURETEST --have-dlopen || { + echo_i "dlopen() not supported - skipping filter-aaaa test" + exit 255 +} +exit 0 diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index ad626593c0..0032bd0dc0 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -238,6 +238,9 @@ struct dns_view { dns_dtenv_t *dtenv; /* Dnstap environment */ dns_dtmsgtype_t dttypes; /* Dnstap message types to log */ + + void *hooktable; /* ns_hooktable */ + void (*hooktable_free)(isc_mem_t *, void **); }; #define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w') diff --git a/lib/dns/view.c b/lib/dns/view.c index 8820a95c6d..05a656e9ef 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -259,6 +259,9 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->dtenv = NULL; view->dttypes = 0; + view->hooktable = NULL; + view->hooktable_free = NULL; + isc_mutex_init(&view->new_zone_lock); result = dns_order_create(view->mctx, &view->order); @@ -550,6 +553,9 @@ destroy(dns_view_t *view) { isc_mutex_destroy(&view->lock); isc_mem_free(view->mctx, view->nta_file); isc_mem_free(view->mctx, view->name); + if (view->hooktable != NULL && view->hooktable_free != NULL) { + view->hooktable_free(view->mctx, &view->hooktable); + } isc_mem_putanddetach(&view->mctx, view, sizeof(*view)); } diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index 93ff3df156..f813f41bf2 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -302,6 +302,7 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sstring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_text; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_optional_bracketed_text; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddrdscp; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr; diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 15ab4e580b..7a8f3a71f0 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -109,6 +109,7 @@ static cfg_type_t cfg_type_dnstap; static cfg_type_t cfg_type_dnstapoutput; static cfg_type_t cfg_type_dyndb; static cfg_type_t cfg_type_filter_aaaa; +static cfg_type_t cfg_type_hook; static cfg_type_t cfg_type_ixfrdifftype; static cfg_type_t cfg_type_key; static cfg_type_t cfg_type_logfile; @@ -1007,6 +1008,7 @@ namedconf_or_view_clauses[] = { { "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI }, { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, + { "hook", &cfg_type_hook, CFG_CLAUSEFLAG_MULTI }, { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, @@ -2394,6 +2396,29 @@ static cfg_type_t cfg_type_dyndb = { &cfg_rep_tuple, dyndb_fields }; +/*% + * The "hook" statement syntax. + * Currently only one hook type is supported: query. + */ + +static const char *hook_enums[] = { + "query", NULL +}; +static cfg_type_t cfg_type_hooktype = { + "hooktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, hook_enums +}; +static cfg_tuplefielddef_t hook_fields[] = { + { "type", &cfg_type_hooktype, 0 }, + { "library", &cfg_type_astring, 0 }, + { "parameters", &cfg_type_optional_bracketed_text, 0 }, + { NULL, NULL, 0 } +}; +static cfg_type_t cfg_type_hook = { + "hook", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, hook_fields +}; + /*% * Clauses that can be found within the 'key' statement. */ diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 7211d9ef76..233eb26b52 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -1134,7 +1134,6 @@ doc_btext(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, "{ }"); } - bool cfg_is_enum(const char *s, const char *const *enums) { const char * const *p; @@ -1275,6 +1274,51 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = { &cfg_rep_string, NULL }; +/* + * Optional bracketed text + */ +static isc_result_t +parse_optional_btext(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + + UNUSED(type); + + CHECK(cfg_peektoken(pctx, ISC_LEXOPT_BTEXT)); + if (pctx->token.type == isc_tokentype_btext) { + CHECK(cfg_parse_obj(pctx, &cfg_type_bracketed_text, ret)); + } else { + CHECK(cfg_parse_obj(pctx, &cfg_type_void, ret)); + } + cleanup: + return (result); +} + +static void +print_optional_btext(cfg_printer_t *pctx, const cfg_obj_t *obj) { + if (obj->type == &cfg_type_void) { + return; + } + + pctx->indent++; + cfg_print_cstr(pctx, "{"); + cfg_print_chars(pctx, obj->value.string.base, obj->value.string.length); + print_close(pctx); +} + +static void +doc_optional_btext(cfg_printer_t *pctx, const cfg_type_t *type) { + UNUSED(type); + + cfg_print_cstr(pctx, "[ { } ]"); +} + +cfg_type_t cfg_type_optional_bracketed_text = { + "optional_btext", parse_optional_btext, print_optional_btext, + doc_optional_btext, NULL, NULL +}; + /* * Booleans */ @@ -1485,7 +1529,7 @@ print_list(cfg_printer_t *pctx, const cfg_obj_t *obj) { isc_result_t cfg_parse_bracketed_list(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) + cfg_obj_t **ret) { isc_result_t result; diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 66438f6604..902cb8915c 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -335,10 +335,6 @@ ns_hookmodule_load(const char *libname, const char *parameters, isc_result_t result; ns_hook_module_t *module = NULL; - if (hooktable == NULL) { - hooktable = ns__hook_table; - } - REQUIRE(NS_HOOKCTX_VALID(hctx)); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, @@ -420,27 +416,32 @@ ns_hooktable_init(ns_hooktable_t *hooktable) { RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); - if (hooktable == NULL) { - hooktable = ns__hook_table; - } - for (i = 0; i < NS_QUERY_HOOKS_COUNT; i++) { ISC_LIST_INIT((*hooktable)[i]); } } -ns_hooktable_t * -ns_hooktable_save() { - return (ns__hook_table); +isc_result_t +ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { + ns_hooktable_t *hooktable; + + REQUIRE(tablep != NULL && *tablep == NULL); + + hooktable = isc_mem_get(mctx, sizeof(ns_hooktable_t)); + + ns_hooktable_init(hooktable); + + *tablep = hooktable; + + return (ISC_R_SUCCESS); } void -ns_hooktable_reset(ns_hooktable_t *hooktable) { - if (hooktable != NULL) { - ns__hook_table = hooktable; - } else { - ns__hook_table = &hooktab; - } +ns_hooktable_free(isc_mem_t *mctx, void **tablep) { + REQUIRE(tablep != NULL && *tablep != NULL); + + isc_mem_put(mctx, *tablep, sizeof(ns_hooktable_t)); + *tablep = NULL; } void diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 3001661a43..8c249274d1 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -196,13 +196,13 @@ typedef struct ns_hook { 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]; + +/* + * ns__hook_table is a global hook table, which is used if view->hooktable + * is NULL. It's intended only for use by unit tests. + */ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; /*! @@ -281,7 +281,7 @@ typedef int ns_hook_version_t(unsigned int *flags); * true, we continue processing. */ #define _NS_PROCESS_HOOK(table, id, data, ...) \ - if (table != NULL) { \ + if (table != NULL) { \ ns_hook_t *_hook = ISC_LIST_HEAD((*table)[id]); \ isc_result_t _result; \ \ @@ -298,9 +298,9 @@ typedef int ns_hook_version_t(unsigned int *flags); } \ } -#define NS_PROCESS_HOOK(table, id, data) \ +#define NS_PROCESS_HOOK(table, id, data, ...) \ _NS_PROCESS_HOOK(table, id, data, _result) -#define NS_PROCESS_HOOK_VOID(table, id, data) \ +#define NS_PROCESS_HOOK_VOID(table, id, data, ...) \ _NS_PROCESS_HOOK(table, id, data) isc_result_t @@ -321,8 +321,7 @@ ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, ns_hook_t *hook); /*% * Append hook function 'hook' to the list of hooks at 'hookpoint' in - * 'hooktable'. If 'hooktable' is NULL, the global hook table - * ns__hook_table is used. + * 'hooktable'. * * Requires: *\li 'hook' is not NULL @@ -331,26 +330,23 @@ ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, * */ -ns_hooktable_t * -ns_hooktable_save(void); -/*% - * Returns a pointer to the current global hook table so it can - * be restored after replacing it. - */ - -void -ns_hooktable_reset(ns_hooktable_t *hooktable); -/*% - * Set the global hooks table pointer to 'hooktable'. - * - * If 'hooktable' is NULL, restores the default global hook table. - */ - void ns_hooktable_init(ns_hooktable_t *hooktable); /*% - * Initialize a hook table. If 'hooktable' is NULL, initialize - * the global hooktable ns__hook_table. + * Initialize a hook table. */ +isc_result_t +ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep); +/*% + * Allocate and initialize a hook table. + */ + +void +ns_hooktable_free(isc_mem_t *mctx, void **tablep); +/*% + * Free a hook table. + */ + + #endif /* NS_HOOKS_H */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 93e1d8fdf4..57d25f3f82 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -238,10 +238,33 @@ static void log_noexistnodata(void *val, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); -#define PROCESS_HOOK(...) \ - NS_PROCESS_HOOK(ns__hook_table, __VA_ARGS__) -#define PROCESS_HOOK_VOID(...) \ - NS_PROCESS_HOOK_VOID(ns__hook_table, __VA_ARGS__) +#define PROCESS_HOOK(_id, _qctx, ...) \ + do { \ + ns_hooktable_t *_tab = ns__hook_table; \ + query_ctx_t *_q = (_qctx); \ + if (_q != NULL && \ + _q->client != NULL && \ + _q->client->view != NULL && \ + _q->client->view->hooktable != NULL) \ + { \ + _tab = _q->client->view->hooktable; \ + } \ + NS_PROCESS_HOOK(_tab, _id, _q, __VA_ARGS__); \ + } while (false) + +#define PROCESS_HOOK_VOID(_id, _qctx, ...) \ + do { \ + ns_hooktable_t *_tab = ns__hook_table; \ + query_ctx_t *_q = (_qctx); \ + if (_q != NULL && \ + _q->client != NULL && \ + _q->client->view != NULL && \ + _q->client->view->hooktable != NULL) \ + { \ + _tab = _q->client->view->hooktable; \ + } \ + NS_PROCESS_HOOK_VOID(_tab, _id, _q, __VA_ARGS__); \ + } while (false) /* * The functions defined below implement the query logic that previously lived diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index f0a589ed15..c6311ec39b 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -693,11 +693,12 @@ create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { ns_hooktable_init(&query_hooks); ns_hook_add(&query_hooks, NS_QUERY_SETUP_QCTX_INITIALIZED, &hook); - saved_hook_table = ns_hooktable_save(); + saved_hook_table = ns__hook_table; + ns__hook_table = &query_hooks; - ns_hooktable_reset(&query_hooks); ns_query_start(client); - ns_hooktable_reset(saved_hook_table); + + ns__hook_table = saved_hook_table; if (*qctxp == NULL) { return (ISC_R_NOMEMORY); diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index d88de02f45..f8f59a23b3 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -84,6 +84,9 @@ static void run_sfcache_test(const ns__query_sfcache_test_params_t *test) { query_ctx_t *qctx = NULL; isc_result_t result; + ns_hook_t hook = { + .callback = ns_test_hook_catch_call, + }; REQUIRE(test != NULL); REQUIRE(test->id.description != NULL); @@ -93,14 +96,9 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) { /* * Interrupt execution if ns_query_done() is called. */ - ns_hook_t hook = { - .callback = ns_test_hook_catch_call, - }; - ns_hooktable_t query_hooks; - ns_hooktable_init(&query_hooks); - ns_hook_add(&query_hooks, NS_QUERY_DONE_BEGIN, &hook); - ns_hooktable_reset(&query_hooks); + ns_hooktable_init(ns__hook_table); + ns_hook_add(ns__hook_table, NS_QUERY_DONE_BEGIN, &hook); /* * Construct a query context for a ./NS query with given flags. @@ -283,6 +281,9 @@ static void run_start_test(const ns__query_start_test_params_t *test) { query_ctx_t *qctx = NULL; isc_result_t result; + ns_hook_t hook = { + .callback = ns_test_hook_catch_call, + }; REQUIRE(test != NULL); REQUIRE(test->id.description != NULL); @@ -294,16 +295,10 @@ run_start_test(const ns__query_start_test_params_t *test) { /* * Interrupt execution if query_lookup() or ns_query_done() is called. */ - ns_hook_t hook = { - .callback = ns_test_hook_catch_call, - }; - ns_hooktable_t query_hooks; - ns_hooktable_init(&query_hooks); - ns_hook_add(&query_hooks, NS_QUERY_LOOKUP_BEGIN, &hook); - ns_hook_add(&query_hooks, NS_QUERY_DONE_BEGIN, &hook); - - ns_hooktable_reset(&query_hooks); + ns_hooktable_init(ns__hook_table); + ns_hook_add(ns__hook_table, NS_QUERY_LOOKUP_BEGIN, &hook); + ns_hook_add(ns__hook_table, NS_QUERY_DONE_BEGIN, &hook); /* * Construct a query context using the supplied parameters. From 9911c835d33ee263e1b147d48dc9cc0f5bdd1286 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 12 Aug 2018 23:06:00 -0700 Subject: [PATCH 09/26] add a parser to filter-aaaa.so and pass in the parameters - make some cfg-parsing functions global so they can be run from filter-aaaa.so - add filter-aaaa options to the hook module's parser - mark filter-aaaa options in named.conf as obsolete, remove from named and checkconf, and update the filter-aaaa test not to use checkconf anymore - remove filter-aaaa-related struct members from dns_view --- bin/hooks/filter-aaaa.c | 150 ++++++++++-- bin/named/config.c | 5 +- bin/named/server.c | 48 +--- bin/tests/system/filter-aaaa/conf/bad1.conf | 15 -- bin/tests/system/filter-aaaa/conf/bad2.conf | 24 -- bin/tests/system/filter-aaaa/conf/bad3.conf | 18 -- bin/tests/system/filter-aaaa/conf/bad4.conf | 18 -- bin/tests/system/filter-aaaa/conf/bad5.conf | 18 -- bin/tests/system/filter-aaaa/conf/bad6.conf | 18 -- bin/tests/system/filter-aaaa/conf/good1.conf | 14 -- bin/tests/system/filter-aaaa/conf/good2.conf | 14 -- bin/tests/system/filter-aaaa/conf/good3.conf | 15 -- bin/tests/system/filter-aaaa/conf/good4.conf | 15 -- bin/tests/system/filter-aaaa/conf/good5.conf | 18 -- bin/tests/system/filter-aaaa/conf/good6.conf | 18 -- bin/tests/system/filter-aaaa/conf/good7.conf | 18 -- bin/tests/system/filter-aaaa/conf/good8.conf | 19 -- .../system/filter-aaaa/ns1/named1.conf.in | 9 +- .../system/filter-aaaa/ns1/named2.conf.in | 7 +- .../system/filter-aaaa/ns2/named1.conf.in | 7 +- .../system/filter-aaaa/ns2/named2.conf.in | 7 +- .../system/filter-aaaa/ns3/named1.conf.in | 7 +- .../system/filter-aaaa/ns3/named2.conf.in | 7 +- .../system/filter-aaaa/ns4/named1.conf.in | 7 +- .../system/filter-aaaa/ns4/named2.conf.in | 7 +- .../system/filter-aaaa/ns5/named.conf.in | 7 +- bin/tests/system/filter-aaaa/tests.sh | 20 -- lib/bind9/check.c | 103 +------- lib/dns/include/dns/view.h | 3 - lib/dns/view.c | 5 - lib/isccfg/include/isccfg/grammar.h | 10 + lib/isccfg/namedconf.c | 226 +++--------------- lib/isccfg/parser.c | 148 ++++++++++++ lib/isccfg/win32/libisccfg.def | 2 + lib/ns/hooks.c | 6 +- lib/ns/include/ns/hooks.h | 3 + lib/ns/query.c | 12 +- 37 files changed, 386 insertions(+), 662 deletions(-) delete mode 100644 bin/tests/system/filter-aaaa/conf/bad1.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/bad2.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/bad3.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/bad4.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/bad5.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/bad6.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good1.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good2.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good3.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good4.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good5.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good6.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good7.conf delete mode 100644 bin/tests/system/filter-aaaa/conf/good8.conf diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 2f316dbc35..6bd1cdc9d8 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -19,6 +19,10 @@ #include #include +#include +#include +#include + #include #include @@ -27,6 +31,13 @@ #include #include +#define CHECK(r) \ + do { \ + result = (r); \ + if (result != ISC_R_SUCCESS) \ + goto cleanup; \ + } while (0) + ns_hook_destroy_t hook_destroy; ns_hook_register_t hook_register; ns_hook_version_t hook_version; @@ -70,11 +81,120 @@ ns_hook_t filter_donesend = { .callback = filter_query_done_send, }; +/* + * Configuration support. + */ + +static dns_aaaa_t v4_aaaa; +static dns_aaaa_t v6_aaaa; +static dns_acl_t *aaaa_acl = NULL; + +static const char *filter_aaaa_enums[] = { "break-dnssec", NULL }; +static isc_result_t +parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); +} +static void +doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) { + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); +} +static cfg_type_t cfg_type_filter_aaaa = { + "filter_aaaa", parse_filter_aaaa, cfg_print_ustring, + doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums, +}; + +static cfg_clausedef_t param_clauses[] = { + { "filter-aaaa", &cfg_type_bracketed_aml, 0 }, + { "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 }, + { "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 }, +}; + +static cfg_clausedef_t *param_clausesets[] = { + param_clauses, + NULL +}; + +static cfg_type_t cfg_type_parameters = { + "filter-aaaa-params", cfg_parse_mapbody, cfg_print_mapbody, + cfg_doc_mapbody, &cfg_rep_map, param_clausesets +}; + +static isc_result_t +parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, + dns_aaaa_t *dstp) +{ + const cfg_obj_t *obj = NULL; + isc_result_t result; + + result = cfg_map_get(param_obj, param_name, &obj); + if (result != ISC_R_SUCCESS) { + return (ISC_R_SUCCESS); + } + + if (cfg_obj_isboolean(obj)) { + if (cfg_obj_asboolean(obj)) { + *dstp = dns_aaaa_filter; + } else { + *dstp = dns_aaaa_ok; + } + } else if (strcasecmp(cfg_obj_asstring(obj), "break-dnssec") == 0) { + *dstp = dns_aaaa_break_dnssec; + } else { + result = ISC_R_UNEXPECTED; + } + + return (result); +} + +static isc_result_t +parse_parameters(const char *parameters, const void *cfg, + void *actx, ns_hookctx_t *hctx) +{ + isc_result_t result = ISC_R_SUCCESS; + cfg_parser_t *parser = NULL; + cfg_obj_t *param_obj = NULL; + const cfg_obj_t *obj = NULL; + isc_buffer_t b; + + CHECK(cfg_parser_create(hctx->mctx, hctx->lctx, &parser)); + + isc_buffer_constinit(&b, parameters, strlen(parameters)); + isc_buffer_add(&b, strlen(parameters)); + CHECK(cfg_parse_buffer(parser, &b, &cfg_type_parameters, + ¶m_obj)); + + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &v4_aaaa)); + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6", &v6_aaaa)); + + obj = NULL; + result = cfg_map_get(param_obj, "filter-aaaa", &obj); + if (result == ISC_R_SUCCESS) { + CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *) cfg, + hctx->lctx, + (cfg_aclconfctx_t *) actx, + hctx->mctx, 0, &aaaa_acl)); + } else { + CHECK(dns_acl_any(hctx->mctx, &aaaa_acl)); + } + + cleanup: + if (param_obj != NULL) { + cfg_obj_destroy(parser, ¶m_obj); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + return (result); +} + +/* + * Mandatory hook API functions. + */ isc_result_t hook_register(const char *parameters, const char *file, unsigned long line, - ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp) + const void *cfg, void *actx, ns_hookctx_t *hctx, + ns_hooktable_t *hooktable, void **instp) { - UNUSED(parameters); UNUSED(instp); if (parameters != NULL) { @@ -83,6 +203,8 @@ hook_register(const char *parameters, const char *file, unsigned long line, "loading params for 'filter-aaaa' " "module from %s:%lu", file, line); + + parse_parameters(parameters, cfg, actx, hctx); } else { isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, @@ -91,11 +213,6 @@ hook_register(const char *parameters, const char *file, unsigned long line, 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, @@ -118,6 +235,10 @@ void hook_destroy(void **instp) { UNUSED(instp); + if (aaaa_acl != NULL) { + dns_acl_detach(&aaaa_acl); + } + return; } @@ -170,22 +291,19 @@ filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { 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) - { + if (v4_aaaa != dns_aaaa_ok || v6_aaaa != dns_aaaa_ok) { result = ns_client_checkaclsilent(qctx->client, NULL, - qctx->client->view->aaaa_acl, - true); + aaaa_acl, true); if (result == ISC_R_SUCCESS && - qctx->client->view->v4_aaaa != dns_aaaa_ok && + v4_aaaa != dns_aaaa_ok && is_v4_client(qctx->client)) { - qctx->filter_aaaa = qctx->client->view->v4_aaaa; + qctx->filter_aaaa = v4_aaaa; } else if (result == ISC_R_SUCCESS && - qctx->client->view->v6_aaaa != dns_aaaa_ok && + v6_aaaa != dns_aaaa_ok && is_v6_client(qctx->client)) { - qctx->filter_aaaa = qctx->client->view->v6_aaaa; + qctx->filter_aaaa = v6_aaaa; } } diff --git a/bin/named/config.c b/bin/named/config.c index 039d2632b4..6b81e35d2d 100644 --- a/bin/named/config.c +++ b/bin/named/config.c @@ -154,10 +154,7 @@ options {\n\ # fetch-glue ;\n\ fetch-quota-params 100 0.1 0.3 0.7;\n\ fetches-per-server 0;\n\ - fetches-per-zone 0;\n\ - filter-aaaa-on-v4 no;\n\ - filter-aaaa-on-v6 no;\n\ - filter-aaaa { any; };\n" + fetches-per-zone 0;\n" #ifdef HAVE_GEOIP " geoip-use-ecs yes;\n" #endif diff --git a/bin/named/server.c b/bin/named/server.c index c3da40ed25..a6a55bd11b 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1538,7 +1538,7 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, static isc_result_t configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, - ns_hookctx_t *hctx) + const cfg_obj_t *config, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; const cfg_obj_t *obj; @@ -1563,11 +1563,15 @@ configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, cfg_obj_asstring(obj), cfg_obj_file(obj), cfg_obj_line(obj), + config, + named_g_aclconfctx, hctx, hooktable); } else { result = ns_hookmodule_load(library, NULL, cfg_obj_file(hook), cfg_obj_line(hook), + config, + named_g_aclconfctx, hctx, hooktable); } @@ -5134,46 +5138,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, dns_quotatype_zone, r); } - obj = NULL; - result = named_config_get(maps, "filter-aaaa-on-v4", &obj); - INSIST(result == ISC_R_SUCCESS); - if (cfg_obj_isboolean(obj)) { - if (cfg_obj_asboolean(obj)) - view->v4_aaaa = dns_aaaa_filter; - else - view->v4_aaaa = dns_aaaa_ok; - } else { - const char *v4_aaaastr = cfg_obj_asstring(obj); - if (strcasecmp(v4_aaaastr, "break-dnssec") == 0) { - view->v4_aaaa = dns_aaaa_break_dnssec; - } else { - INSIST(0); - ISC_UNREACHABLE(); - } - } - - obj = NULL; - result = named_config_get(maps, "filter-aaaa-on-v6", &obj); - INSIST(result == ISC_R_SUCCESS); - if (cfg_obj_isboolean(obj)) { - if (cfg_obj_asboolean(obj)) - view->v6_aaaa = dns_aaaa_filter; - else - view->v6_aaaa = dns_aaaa_ok; - } else { - const char *v6_aaaastr = cfg_obj_asstring(obj); - if (strcasecmp(v6_aaaastr, "break-dnssec") == 0) { - view->v6_aaaa = dns_aaaa_break_dnssec; - } else { - INSIST(0); - ISC_UNREACHABLE(); - } - } - - CHECK(configure_view_acl(vconfig, config, named_g_config, - "filter-aaaa", NULL, actx, - named_g_mctx, &view->aaaa_acl)); - obj = NULL; result = named_config_get(maps, "prefetch", &obj); if (result == ISC_R_SUCCESS) { @@ -5368,7 +5332,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, CHECK(ns_hook_createctx(mctx, &hctx)); } - CHECK(configure_hook(view->hooktable, hook, hctx)); + CHECK(configure_hook(view->hooktable, hook, config, hctx)); } #endif diff --git a/bin/tests/system/filter-aaaa/conf/bad1.conf b/bin/tests/system/filter-aaaa/conf/bad1.conf deleted file mode 100644 index 9a23fd8b96..0000000000 --- a/bin/tests/system/filter-aaaa/conf/bad1.conf +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 yes; - filter-aaaa { none; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad2.conf b/bin/tests/system/filter-aaaa/conf/bad2.conf deleted file mode 100644 index 798f4fd6e2..0000000000 --- a/bin/tests/system/filter-aaaa/conf/bad2.conf +++ /dev/null @@ -1,24 +0,0 @@ -/* - * 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. - */ - -options { - /* - * While this matches the defaults, it is not a good configuration - * to have in named.conf as the two options contradict each other - * indicating a error on behalf of the operator. - * - * The default is to have filter-aaaa-on-v4 off, but if it is turned - * on then it applies to all IPv4 queries. This results in - * contradictory defaults. - */ - filter-aaaa-on-v4 no; - filter-aaaa { any; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad3.conf b/bin/tests/system/filter-aaaa/conf/bad3.conf deleted file mode 100644 index 3c068bbb71..0000000000 --- a/bin/tests/system/filter-aaaa/conf/bad3.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 no; -}; - -view myview { - filter-aaaa { any; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad4.conf b/bin/tests/system/filter-aaaa/conf/bad4.conf deleted file mode 100644 index 5744c8b2c5..0000000000 --- a/bin/tests/system/filter-aaaa/conf/bad4.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa { any; }; -}; - -view myview { - filter-aaaa-on-v4 no; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad5.conf b/bin/tests/system/filter-aaaa/conf/bad5.conf deleted file mode 100644 index 39f9acca51..0000000000 --- a/bin/tests/system/filter-aaaa/conf/bad5.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa { none; }; -}; - -view myview { - filter-aaaa-on-v4 yes; -}; diff --git a/bin/tests/system/filter-aaaa/conf/bad6.conf b/bin/tests/system/filter-aaaa/conf/bad6.conf deleted file mode 100644 index e92bb1e5f2..0000000000 --- a/bin/tests/system/filter-aaaa/conf/bad6.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 yes; -}; - -view myview { - filter-aaaa { none; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good1.conf b/bin/tests/system/filter-aaaa/conf/good1.conf deleted file mode 100644 index 2a93ef6fb0..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good1.conf +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 yes; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good2.conf b/bin/tests/system/filter-aaaa/conf/good2.conf deleted file mode 100644 index 916af8e971..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good2.conf +++ /dev/null @@ -1,14 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 break-dnssec; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good3.conf b/bin/tests/system/filter-aaaa/conf/good3.conf deleted file mode 100644 index b3f8de4d95..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good3.conf +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 break-dnssec; - filter-aaaa { 1.0.0.0/8; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good4.conf b/bin/tests/system/filter-aaaa/conf/good4.conf deleted file mode 100644 index d789f30b57..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good4.conf +++ /dev/null @@ -1,15 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 yes; - filter-aaaa { 1.0.0.0/8; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good5.conf b/bin/tests/system/filter-aaaa/conf/good5.conf deleted file mode 100644 index 95baae5b28..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good5.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 yes; -}; - -view myview { - filter-aaaa { 1.0.0.0/8; }; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good6.conf b/bin/tests/system/filter-aaaa/conf/good6.conf deleted file mode 100644 index 9e783670a0..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good6.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa { 1.0.0.0/8; }; -}; - -view myview { - filter-aaaa-on-v4 yes; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good7.conf b/bin/tests/system/filter-aaaa/conf/good7.conf deleted file mode 100644 index 2531de95b6..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good7.conf +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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. - */ - -options { -}; - -view myview { - filter-aaaa { 1.0.0.0/8; }; - filter-aaaa-on-v4 yes; -}; diff --git a/bin/tests/system/filter-aaaa/conf/good8.conf b/bin/tests/system/filter-aaaa/conf/good8.conf deleted file mode 100644 index f28fdd96ab..0000000000 --- a/bin/tests/system/filter-aaaa/conf/good8.conf +++ /dev/null @@ -1,19 +0,0 @@ -/* - * 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. - */ - -options { - filter-aaaa-on-v4 no; -}; - -view myview { - filter-aaaa { 1.0.0.0/8; }; - filter-aaaa-on-v4 yes; -}; diff --git a/bin/tests/system/filter-aaaa/ns1/named1.conf.in b/bin/tests/system/filter-aaaa/ns1/named1.conf.in index bde197748e..cd05abc9e9 100644 --- a/bin/tests/system/filter-aaaa/ns1/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named1.conf.in @@ -20,12 +20,15 @@ options { recursion no; dnssec-validation yes; notify yes; - filter-aaaa-on-v4 yes; - filter-aaaa { 10.53.0.1; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +acl filterees { 10.53.0.1; }; + +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { filterees; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns1/named2.conf.in b/bin/tests/system/filter-aaaa/ns1/named2.conf.in index 8d29d583aa..3201f7c9b3 100644 --- a/bin/tests/system/filter-aaaa/ns1/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named2.conf.in @@ -20,12 +20,13 @@ options { recursion no; dnssec-validation yes; notify yes; - filter-aaaa-on-v6 yes; - filter-aaaa { fd92:7065:b8e:ffff::1; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v6 yes; + filter-aaaa { fd92:7065:b8e:ffff::1; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns2/named1.conf.in b/bin/tests/system/filter-aaaa/ns2/named1.conf.in index 5d8e06cdfd..5d9aeec8a4 100644 --- a/bin/tests/system/filter-aaaa/ns2/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named1.conf.in @@ -20,12 +20,13 @@ options { recursion yes; dnssec-validation yes; notify yes; - filter-aaaa-on-v4 yes; - filter-aaaa { 10.53.0.2; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 10.53.0.2; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns2/named2.conf.in b/bin/tests/system/filter-aaaa/ns2/named2.conf.in index 56e388ce49..a313403c98 100644 --- a/bin/tests/system/filter-aaaa/ns2/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named2.conf.in @@ -20,12 +20,13 @@ options { recursion yes; dnssec-validation yes; notify yes; - filter-aaaa-on-v6 yes; - filter-aaaa { fd92:7065:b8e:ffff::2; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v6 yes; + filter-aaaa { fd92:7065:b8e:ffff::2; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns3/named1.conf.in b/bin/tests/system/filter-aaaa/ns3/named1.conf.in index b0f4ba0667..7c24809a0c 100644 --- a/bin/tests/system/filter-aaaa/ns3/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named1.conf.in @@ -20,12 +20,13 @@ options { recursion yes; dnssec-validation yes; notify yes; - filter-aaaa-on-v4 break-dnssec; - filter-aaaa { 10.53.0.3; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; + filter-aaaa { 10.53.0.3; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns3/named2.conf.in b/bin/tests/system/filter-aaaa/ns3/named2.conf.in index 847bdfe0d3..cd5df44938 100644 --- a/bin/tests/system/filter-aaaa/ns3/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named2.conf.in @@ -20,12 +20,13 @@ options { recursion yes; dnssec-validation yes; notify yes; - filter-aaaa-on-v6 break-dnssec; - filter-aaaa { fd92:7065:b8e:ffff::3; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v6 break-dnssec; + filter-aaaa { fd92:7065:b8e:ffff::3; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns4/named1.conf.in b/bin/tests/system/filter-aaaa/ns4/named1.conf.in index 915f55d44b..87e2eadcf5 100644 --- a/bin/tests/system/filter-aaaa/ns4/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named1.conf.in @@ -20,12 +20,13 @@ options { recursion no; dnssec-validation no; notify yes; - filter-aaaa-on-v4 break-dnssec; - filter-aaaa { 10.53.0.4; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; + filter-aaaa { 10.53.0.4; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns4/named2.conf.in b/bin/tests/system/filter-aaaa/ns4/named2.conf.in index c6818b8f76..79b5ce8eff 100644 --- a/bin/tests/system/filter-aaaa/ns4/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named2.conf.in @@ -20,12 +20,13 @@ options { recursion no; dnssec-validation no; notify yes; - filter-aaaa-on-v6 break-dnssec; - filter-aaaa { fd92:7065:b8e:ffff::4; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v6 break-dnssec; + filter-aaaa { fd92:7065:b8e:ffff::4; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/ns5/named.conf.in b/bin/tests/system/filter-aaaa/ns5/named.conf.in index a27ee016d6..df507b3016 100644 --- a/bin/tests/system/filter-aaaa/ns5/named.conf.in +++ b/bin/tests/system/filter-aaaa/ns5/named.conf.in @@ -25,12 +25,13 @@ options { exclude { any; }; mapped { any; }; }; - filter-aaaa-on-v4 break-dnssec; - filter-aaaa { any; }; minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so"; +hook query "../../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; + filter-aaaa { any; }; +}; key rndc_key { secret "1234abcd8765"; diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh index f3e06b4fe4..86d0c7cb7b 100644 --- a/bin/tests/system/filter-aaaa/tests.sh +++ b/bin/tests/system/filter-aaaa/tests.sh @@ -20,26 +20,6 @@ rm -f dig.out.* DIGOPTS="+tcp +noadd +nosea +nostat +nocmd -p ${PORT}" RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" -for conf in conf/good*.conf -do - n=`expr $n + 1` - echo_i "checking that $conf is accepted ($n)" - ret=0 - $CHECKCONF "$conf" || ret=1 - if [ $ret != 0 ]; then echo_i "failed"; fi - status=`expr $status + $ret` -done - -for conf in conf/bad*.conf -do - n=`expr $n + 1` - echo_i "checking that $conf is rejected ($n)" - ret=0 - $CHECKCONF "$conf" >/dev/null && ret=1 - if [ $ret != 0 ]; then echo_i "failed"; fi - status=`expr $status + $ret` -done - # # Authoritative tests against: # filter-aaaa-on-v4 yes; diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 953b7746a4..4fac8e9b85 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -471,7 +471,7 @@ check_viewacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, static const char *acls[] = { "allow-query", "allow-query-on", "allow-query-cache", "allow-query-cache-on", "blackhole", "keep-response-order", "match-clients", - "match-destinations", "sortlist", "filter-aaaa", NULL }; + "match-destinations", "sortlist", NULL }; while (acls[i] != NULL) { tresult = checkacl(acls[i++], actx, NULL, voptions, config, @@ -789,102 +789,6 @@ check_recursionacls(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, return (result); } -static isc_result_t -check_filteraaaa(cfg_aclconfctx_t *actx, const cfg_obj_t *voptions, - const char *viewname, const cfg_obj_t *config, - isc_log_t *logctx, isc_mem_t *mctx) -{ - const cfg_obj_t *options, *aclobj, *obj; - dns_acl_t *acl = NULL; - isc_result_t result = ISC_R_SUCCESS; - dns_aaaa_t filter4, filter6; - const char *forview = " for view "; - - if (viewname == NULL) { - viewname = ""; - forview = ""; - } - - aclobj = options = NULL; - acl = NULL; - - if (voptions != NULL) - cfg_map_get(voptions, "filter-aaaa", &aclobj); - if (config != NULL && aclobj == NULL) { - options = NULL; - cfg_map_get(config, "options", &options); - if (options != NULL) - cfg_map_get(options, "filter-aaaa", &aclobj); - } - if (aclobj == NULL) - return (result); - - result = cfg_acl_fromconfig(aclobj, config, logctx, - actx, mctx, 0, &acl); - if (result != ISC_R_SUCCESS) - goto failure; - - obj = NULL; - if (voptions != NULL) - cfg_map_get(voptions, "filter-aaaa-on-v4", &obj); - if (obj == NULL && config != NULL) { - options = NULL; - cfg_map_get(config, "options", &options); - if (options != NULL) - cfg_map_get(options, "filter-aaaa-on-v4", &obj); - } - - if (obj == NULL) - filter4 = dns_aaaa_ok; /* default */ - else if (cfg_obj_isboolean(obj)) - filter4 = cfg_obj_asboolean(obj) ? dns_aaaa_filter : - dns_aaaa_ok; - else - filter4 = dns_aaaa_break_dnssec; /* break-dnssec */ - - obj = NULL; - if (voptions != NULL) - cfg_map_get(voptions, "filter-aaaa-on-v6", &obj); - if (obj == NULL && config != NULL) { - options = NULL; - cfg_map_get(config, "options", &options); - if (options != NULL) - cfg_map_get(options, "filter-aaaa-on-v6", &obj); - } - - if (obj == NULL) - filter6 = dns_aaaa_ok; /* default */ - else if (cfg_obj_isboolean(obj)) - filter6 = cfg_obj_asboolean(obj) ? dns_aaaa_filter : - dns_aaaa_ok; - else - filter6 = dns_aaaa_break_dnssec; /* break-dnssec */ - - if ((filter4 != dns_aaaa_ok || filter6 != dns_aaaa_ok) && - dns_acl_isnone(acl)) - { - cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING, - "\"filter-aaaa\" is 'none;' but " - "either filter-aaaa-on-v4 or filter-aaaa-on-v6 " - "is enabled%s%s", forview, viewname); - result = ISC_R_FAILURE; - } else if (filter4 == dns_aaaa_ok && filter6 == dns_aaaa_ok && - !dns_acl_isnone(acl)) - { - cfg_obj_log(aclobj, logctx, ISC_LOG_WARNING, - "\"filter-aaaa\" is set but " - "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 " - "is enabled%s%s", forview, viewname); - result = ISC_R_FAILURE; - } - - failure: - if (acl != NULL) - dns_acl_detach(&acl); - - return (result); -} - typedef struct { const char *name; unsigned int scale; @@ -3750,11 +3654,6 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, if (tresult != ISC_R_SUCCESS) result = tresult; - tresult = check_filteraaaa(actx, voptions, viewname, config, - logctx, mctx); - if (tresult != ISC_R_SUCCESS) - result = tresult; - tresult = check_dns64(actx, voptions, config, logctx, mctx); if (tresult != ISC_R_SUCCESS) result = tresult; diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 0032bd0dc0..c80dc5da5e 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -179,9 +179,6 @@ struct dns_view { uint16_t padding; dns_acl_t * pad_acl; unsigned int maxbits; - dns_aaaa_t v4_aaaa; - dns_aaaa_t v6_aaaa; - dns_acl_t * aaaa_acl; dns_dns64list_t dns64; unsigned int dns64cnt; dns_rpz_zones_t *rpzs; diff --git a/lib/dns/view.c b/lib/dns/view.c index 05a656e9ef..357f102625 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -225,9 +225,6 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->padding = 0; view->pad_acl = NULL; view->maxbits = 0; - view->v4_aaaa = dns_aaaa_ok; - view->v6_aaaa = dns_aaaa_ok; - view->aaaa_acl = NULL; view->rpzs = NULL; view->catzs = NULL; dns_fixedname_init(&view->dlv_fixed); @@ -457,8 +454,6 @@ destroy(dns_view_t *view) { dns_acl_detach(&view->upfwdacl); if (view->denyansweracl != NULL) dns_acl_detach(&view->denyansweracl); - if (view->aaaa_acl != NULL) - dns_acl_detach(&view->aaaa_acl); if (view->pad_acl != NULL) dns_acl_detach(&view->pad_acl); if (view->answeracl_exclude != NULL) diff --git a/lib/isccfg/include/isccfg/grammar.h b/lib/isccfg/include/isccfg/grammar.h index f813f41bf2..ba9115458c 100644 --- a/lib/isccfg/include/isccfg/grammar.h +++ b/lib/isccfg/include/isccfg/grammar.h @@ -301,8 +301,10 @@ LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_qstring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_astring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_ustring; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sstring; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_aml; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_bracketed_text; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_optional_bracketed_text; +LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_keyref; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddr; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_sockaddrdscp; LIBISCCFG_EXTERNAL_DATA extern cfg_type_t cfg_type_netaddr; @@ -433,6 +435,14 @@ cfg_parse_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); void cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type); +isc_result_t +cfg_parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, + const cfg_type_t *othertype, cfg_obj_t **ret); + +void +cfg_doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype, + const cfg_type_t *othertype); + void cfg_print_chars(cfg_printer_t *pctx, const char *text, int len); /*%< Print 'len' characters at 'text' */ diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 7a8f3a71f0..9ac2235b0a 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -49,14 +49,6 @@ * Forward declarations of static functions. */ -static isc_result_t -parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, - const cfg_type_t *othertype, cfg_obj_t **ret); - -static void -doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype, - const cfg_type_t *othertype); - static isc_result_t parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret); @@ -94,8 +86,6 @@ doc_geoip(cfg_printer_t *pctx, const cfg_type_t *type); #endif /* HAVE_GEOIP */ static cfg_type_t cfg_type_acl; -static cfg_type_t cfg_type_addrmatchelt; -static cfg_type_t cfg_type_bracketed_aml; static cfg_type_t cfg_type_bracketed_dscpsockaddrlist; static cfg_type_t cfg_type_bracketed_namesockaddrkeylist; static cfg_type_t cfg_type_bracketed_netaddrlist; @@ -108,7 +98,6 @@ static cfg_type_t cfg_type_dlz; static cfg_type_t cfg_type_dnstap; static cfg_type_t cfg_type_dnstapoutput; static cfg_type_t cfg_type_dyndb; -static cfg_type_t cfg_type_filter_aaaa; static cfg_type_t cfg_type_hook; static cfg_type_t cfg_type_ixfrdifftype; static cfg_type_t cfg_type_key; @@ -121,7 +110,6 @@ static cfg_type_t cfg_type_masterselement; static cfg_type_t cfg_type_maxttl; static cfg_type_t cfg_type_minimal; static cfg_type_t cfg_type_nameportiplist; -static cfg_type_t cfg_type_negated; static cfg_type_t cfg_type_notifytype; static cfg_type_t cfg_type_optional_allow; static cfg_type_t cfg_type_optional_class; @@ -607,11 +595,11 @@ static cfg_type_t cfg_type_updatemethod = { static const char *zonestat_enums[] = { "full", "terse", "none", NULL }; static isc_result_t parse_zonestat(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } static void doc_zonestat(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } static cfg_type_t cfg_type_zonestat = { "zonestat", parse_zonestat, cfg_print_ustring, doc_zonestat, @@ -952,7 +940,7 @@ static isc_result_t parse_optional_enum(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_void, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_void, ret)); } static void @@ -1909,9 +1897,9 @@ view_clauses[] = { { "fetch-quota-params", &cfg_type_fetchquota, 0 }, { "fetches-per-server", &cfg_type_fetchesper, 0 }, { "fetches-per-zone", &cfg_type_fetchesper, 0 }, - { "filter-aaaa", &cfg_type_bracketed_aml, 0 }, - { "filter-aaaa-on-v4", &cfg_type_filter_aaaa, 0 }, - { "filter-aaaa-on-v6", &cfg_type_filter_aaaa, 0 }, + { "filter-aaaa", &cfg_type_bracketed_aml, CFG_CLAUSEFLAG_OBSOLETE }, + { "filter-aaaa-on-v4", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, + { "filter-aaaa-on-v6", &cfg_type_boolean, CFG_CLAUSEFLAG_OBSOLETE }, { "glue-cache", &cfg_type_boolean, 0 }, { "ixfr-from-differences", &cfg_type_ixfrdifftype, 0 }, { "lame-ttl", &cfg_type_ttlval, 0 }, @@ -2495,11 +2483,11 @@ static const char *printtime_enums[] = { }; static isc_result_t parse_printtime(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } static void doc_printtime(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } static cfg_type_t cfg_type_printtime = { "printtime", parse_printtime, cfg_print_ustring, doc_printtime, @@ -2715,12 +2703,12 @@ static cfg_type_t cfg_type_sizeval = { static isc_result_t parse_size(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval, ret)); } static void doc_size(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_sizeval); + cfg_doc_enum_or_other(pctx, type, &cfg_type_sizeval); } static const char *size_enums[] = { "default", "unlimited", NULL }; @@ -2754,13 +2742,18 @@ static isc_result_t parse_size_or_percent(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent, + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_sizeval_percent, ret)); } static void doc_parse_size_or_percent(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_sizeval_percent); + UNUSED(type); + cfg_print_cstr(pctx, "( default | unlimited | "); + cfg_doc_terminal(pctx, &cfg_type_sizeval); + cfg_print_cstr(pctx, " | "); + cfg_doc_terminal(pctx, &cfg_type_percentage); + cfg_print_cstr(pctx, " )"); } static const char *sizeorpercent_enums[] = { "default", "unlimited", NULL }; @@ -2801,59 +2794,6 @@ parse_maybe_optional_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, return (result); } -static isc_result_t -parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, - const cfg_type_t *othertype, cfg_obj_t **ret) -{ - isc_result_t result; - CHECK(cfg_peektoken(pctx, 0)); - if (pctx->token.type == isc_tokentype_string && - cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) { - CHECK(cfg_parse_enum(pctx, enumtype, ret)); - } else { - CHECK(cfg_parse_obj(pctx, othertype, ret)); - } - cleanup: - return (result); -} - -static void -doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype, - const cfg_type_t *othertype) -{ - const char * const *p; - bool first = true; - - /* - * If othertype is cfg_type_void, it means that enumtype is - * optional. - */ - - if (othertype == &cfg_type_void) - cfg_print_cstr(pctx, "[ "); - cfg_print_cstr(pctx, "( "); - for (p = enumtype->of; *p != NULL; p++) { - if (!first) - cfg_print_cstr(pctx, " | "); - first = false; - cfg_print_cstr(pctx, *p); - } - if (othertype == &cfg_type_sizeval_percent) { - if (!first) - cfg_print_cstr(pctx, " | "); - cfg_doc_terminal(pctx, &cfg_type_sizeval); - cfg_print_cstr(pctx, " | "); - cfg_doc_terminal(pctx, &cfg_type_percentage); - } else if (othertype != &cfg_type_void) { - if (!first) - cfg_print_cstr(pctx, " | "); - cfg_doc_terminal(pctx, othertype); - } - cfg_print_cstr(pctx, " )"); - if (othertype == &cfg_type_void) - cfg_print_cstr(pctx, " ]"); -} - static isc_result_t parse_keyvalue(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (parse_maybe_optional_keyvalue(pctx, type, false, ret)); @@ -2899,11 +2839,11 @@ static isc_result_t parse_dialup_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } static void doc_dialup_type(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } static cfg_type_t cfg_type_dialuptype = { "dialuptype", parse_dialup_type, cfg_print_ustring, doc_dialup_type, @@ -2915,11 +2855,11 @@ static isc_result_t parse_notify_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } static void doc_notify_type(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } static cfg_type_t cfg_type_notifytype = { "notifytype", parse_notify_type, cfg_print_ustring, doc_notify_type, @@ -2929,11 +2869,11 @@ static cfg_type_t cfg_type_notifytype = { static const char *minimal_enums[] = { "no-auth", "no-auth-recursive", NULL }; static isc_result_t parse_minimal(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } static void doc_minimal(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } static cfg_type_t cfg_type_minimal = { "mimimal", parse_minimal, cfg_print_ustring, doc_minimal, @@ -2947,32 +2887,17 @@ static isc_result_t parse_ixfrdiff_type(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } static void doc_ixfrdiff_type(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); + cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } static cfg_type_t cfg_type_ixfrdifftype = { "ixfrdiff", parse_ixfrdiff_type, cfg_print_ustring, doc_ixfrdiff_type, &cfg_rep_string, ixfrdiff_enums, }; -static const char *filter_aaaa_enums[] = { "break-dnssec", NULL }; -static isc_result_t -parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); -} -static void -doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_boolean); -} -static cfg_type_t cfg_type_filter_aaaa = { - "filter_aaaa", parse_filter_aaaa, cfg_print_ustring, - doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums, -}; - static keyword_type_t key_kw = { "key", &cfg_type_astring }; LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_keyref = { @@ -3419,99 +3344,6 @@ static cfg_type_t cfg_type_querysource = { "querysource", NULL, print_querysource, NULL, &cfg_rep_sockaddr, NULL }; -/*% addrmatchelt */ - -static isc_result_t -parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, - cfg_obj_t **ret) -{ - isc_result_t result; - UNUSED(type); - - CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); - - if (pctx->token.type == isc_tokentype_string || - pctx->token.type == isc_tokentype_qstring) { - if (pctx->token.type == isc_tokentype_string && - (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) { - CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret)); - } else if (pctx->token.type == isc_tokentype_string && - (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) { -#ifdef HAVE_GEOIP - CHECK(cfg_gettoken(pctx, 0)); - CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret)); -#else - cfg_parser_error(pctx, CFG_LOG_NEAR, "'geoip' " - "not supported in this build"); - return (ISC_R_UNEXPECTEDTOKEN); -#endif - } else { - if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | - CFG_ADDR_V4PREFIXOK | - CFG_ADDR_V6OK)) - { - CHECK(cfg_parse_netprefix(pctx, NULL, ret)); - } else { - CHECK(cfg_parse_astring(pctx, NULL, ret)); - } - } - } else if (pctx->token.type == isc_tokentype_special) { - if (pctx->token.value.as_char == '{') { - /* Nested match list. */ - CHECK(cfg_parse_obj(pctx, - &cfg_type_bracketed_aml, ret)); - } else if (pctx->token.value.as_char == '!') { - CHECK(cfg_gettoken(pctx, 0)); /* read "!" */ - CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret)); - } else { - goto bad; - } - } else { - bad: - cfg_parser_error(pctx, CFG_LOG_NEAR, - "expected IP match list element"); - return (ISC_R_UNEXPECTEDTOKEN); - } - cleanup: - return (result); -} - -/*% - * A negated address match list element (like "! 10.0.0.1"). - * Somewhat sneakily, the caller is expected to parse the - * "!", but not to print it. - */ - -static cfg_tuplefielddef_t negated_fields[] = { - { "negated", &cfg_type_addrmatchelt, 0 }, - { NULL, NULL, 0 } -}; - -static void -print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) { - cfg_print_cstr(pctx, "!"); - cfg_print_tuple(pctx, obj); -} - -static cfg_type_t cfg_type_negated = { - "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple, - &negated_fields -}; - -/*% An address match list element */ - -static cfg_type_t cfg_type_addrmatchelt = { - "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal, - NULL, NULL -}; - -/*% A bracketed address match list */ - -static cfg_type_t cfg_type_bracketed_aml = { - "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list, - cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt -}; - /*% * The socket address syntax in the "controls" statement is silly. * It allows both socket address families, but also allows "*", @@ -3656,12 +3488,12 @@ static isc_result_t parse_logversions(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_uint32, ret)); } static void doc_logversions(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_uint32); + cfg_doc_enum_or_other(pctx, type, &cfg_type_uint32); } static cfg_type_t cfg_type_logversions = { @@ -4070,12 +3902,12 @@ static cfg_type_t cfg_type_ttlval = { static isc_result_t parse_maxttl(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { - return (parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret)); + return (cfg_parse_enum_or_other(pctx, type, &cfg_type_ttlval, ret)); } static void doc_maxttl(cfg_printer_t *pctx, const cfg_type_t *type) { - doc_enum_or_other(pctx, type, &cfg_type_ttlval); + cfg_doc_enum_or_other(pctx, type, &cfg_type_ttlval); } /*% diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 233eb26b52..5af9ae2228 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -1192,6 +1192,58 @@ cfg_doc_enum(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, " )"); } +isc_result_t +cfg_parse_enum_or_other(cfg_parser_t *pctx, const cfg_type_t *enumtype, + const cfg_type_t *othertype, cfg_obj_t **ret) +{ + isc_result_t result; + CHECK(cfg_peektoken(pctx, 0)); + if (pctx->token.type == isc_tokentype_string && + cfg_is_enum(TOKEN_STRING(pctx), enumtype->of)) + { + CHECK(cfg_parse_enum(pctx, enumtype, ret)); + } else { + CHECK(cfg_parse_obj(pctx, othertype, ret)); + } + cleanup: + return (result); +} + +void +cfg_doc_enum_or_other(cfg_printer_t *pctx, const cfg_type_t *enumtype, + const cfg_type_t *othertype) +{ + const char * const *p; + bool first = true; + + /* + * If othertype is cfg_type_void, it means that enumtype is + * optional. + */ + + if (othertype == &cfg_type_void) { + cfg_print_cstr(pctx, "[ "); + } + cfg_print_cstr(pctx, "( "); + for (p = enumtype->of; *p != NULL; p++) { + if (!first) { + cfg_print_cstr(pctx, " | "); + } + first = false; + cfg_print_cstr(pctx, *p); + } + if (othertype != &cfg_type_void) { + if (!first) { + cfg_print_cstr(pctx, " | "); + } + cfg_doc_terminal(pctx, othertype); + } + cfg_print_cstr(pctx, " )"); + if (othertype == &cfg_type_void) { + cfg_print_cstr(pctx, " ]"); + } +} + void cfg_print_ustring(cfg_printer_t *pctx, const cfg_obj_t *obj) { REQUIRE(pctx != NULL); @@ -1274,6 +1326,101 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = { &cfg_rep_string, NULL }; +/*% + * A bracketed address match list + */ + +static cfg_type_t cfg_type_addrmatchelt; +static cfg_type_t cfg_type_negated; + +static isc_result_t +parse_addrmatchelt(cfg_parser_t *pctx, const cfg_type_t *type, + cfg_obj_t **ret) +{ + isc_result_t result; + UNUSED(type); + + CHECK(cfg_peektoken(pctx, CFG_LEXOPT_QSTRING)); + + if (pctx->token.type == isc_tokentype_string || + pctx->token.type == isc_tokentype_qstring) { + if (pctx->token.type == isc_tokentype_string && + (strcasecmp(TOKEN_STRING(pctx), "key") == 0)) { + CHECK(cfg_parse_obj(pctx, &cfg_type_keyref, ret)); + } else if (pctx->token.type == isc_tokentype_string && + (strcasecmp(TOKEN_STRING(pctx), "geoip") == 0)) { +#ifdef HAVE_GEOIP + CHECK(cfg_gettoken(pctx, 0)); + CHECK(cfg_parse_obj(pctx, &cfg_type_geoip, ret)); +#else + cfg_parser_error(pctx, CFG_LOG_NEAR, "'geoip' " + "not supported in this build"); + return (ISC_R_UNEXPECTEDTOKEN); +#endif + } else { + if (cfg_lookingat_netaddr(pctx, CFG_ADDR_V4OK | + CFG_ADDR_V4PREFIXOK | + CFG_ADDR_V6OK)) + { + CHECK(cfg_parse_netprefix(pctx, NULL, ret)); + } else { + CHECK(cfg_parse_astring(pctx, NULL, ret)); + } + } + } else if (pctx->token.type == isc_tokentype_special) { + if (pctx->token.value.as_char == '{') { + /* Nested match list. */ + CHECK(cfg_parse_obj(pctx, + &cfg_type_bracketed_aml, ret)); + } else if (pctx->token.value.as_char == '!') { + CHECK(cfg_gettoken(pctx, 0)); /* read "!" */ + CHECK(cfg_parse_obj(pctx, &cfg_type_negated, ret)); + } else { + goto bad; + } + } else { + bad: + cfg_parser_error(pctx, CFG_LOG_NEAR, + "expected IP match list element"); + return (ISC_R_UNEXPECTEDTOKEN); + } + cleanup: + return (result); +} + +/*% + * A negated address match list element (like "! 10.0.0.1"). + * Somewhat sneakily, the caller is expected to parse the + * "!", but not to print it. + */ +static cfg_tuplefielddef_t negated_fields[] = { + { "negated", &cfg_type_addrmatchelt, 0 }, + { NULL, NULL, 0 } +}; + +static void +print_negated(cfg_printer_t *pctx, const cfg_obj_t *obj) { + cfg_print_cstr(pctx, "!"); + cfg_print_tuple(pctx, obj); +} + +static cfg_type_t cfg_type_negated = { + "negated", cfg_parse_tuple, print_negated, NULL, &cfg_rep_tuple, + &negated_fields +}; + +/*% An address match list element */ + +static cfg_type_t cfg_type_addrmatchelt = { + "address_match_element", parse_addrmatchelt, NULL, cfg_doc_terminal, + NULL, NULL +}; + +LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_aml = { + "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list, + cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt +}; + /* * Optional bracketed text */ @@ -2045,6 +2192,7 @@ static struct flagtext { { CFG_CLAUSEFLAG_MULTI, "may occur multiple times" }, { CFG_CLAUSEFLAG_EXPERIMENTAL, "experimental" }, { CFG_CLAUSEFLAG_NOOP, "non-operational" }, + { CFG_CLAUSEFLAG_DEPRECATED, "deprecated" }, { 0, NULL } }; diff --git a/lib/isccfg/win32/libisccfg.def b/lib/isccfg/win32/libisccfg.def index c5e9be790c..3538e01e2f 100644 --- a/lib/isccfg/win32/libisccfg.def +++ b/lib/isccfg/win32/libisccfg.def @@ -14,6 +14,7 @@ cfg_create_obj cfg_create_tuple cfg_doc_bracketed_list cfg_doc_enum +cfg_doc_enum_or_other cfg_doc_map cfg_doc_mapbody cfg_doc_obj @@ -71,6 +72,7 @@ cfg_parse_buffer3 cfg_parse_buffer4 cfg_parse_dscp cfg_parse_enum +cfg_parse_enum_or_other cfg_parse_file cfg_parse_fixedpoint cfg_parse_listelt diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 902cb8915c..6835617b4c 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -330,6 +330,7 @@ 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, + const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable) { isc_result_t result; @@ -342,8 +343,9 @@ ns_hookmodule_load(const char *libname, const char *parameters, "loading module '%s'", libname); CHECK(load_library(hctx->mctx, libname, &module)); - CHECK(module->register_func(parameters, file, line, hctx, - hooktable, &module->inst)); + CHECK(module->register_func(parameters, file, line, + cfg, actx, hctx, hooktable, + &module->inst)); APPEND(hook_modules, module, link); result = ISC_R_SUCCESS; diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 8c249274d1..f89201a48b 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -238,6 +238,8 @@ typedef struct ns_hookctx { typedef isc_result_t ns_hook_register_t(const char *parameters, const char *file, unsigned long line, + const void *cfg, + void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp); @@ -312,6 +314,7 @@ 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, + const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable); void ns_hookmodule_cleanup(void); diff --git a/lib/ns/query.c b/lib/ns/query.c index 57d25f3f82..a83730c362 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -6961,8 +6961,6 @@ query_respond(query_ctx_t *qctx) { dns_rdataset_t **sigrdatasetp = NULL; isc_result_t result; - PROCESS_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); - /* * If we have a zero ttl from the cache, refetch. */ @@ -7016,6 +7014,16 @@ query_respond(query_ctx_t *qctx) { return (query_lookup(qctx)); } + /* + * XXX: This hook is meant to be at the top of this function, + * but is postponed until after DNS64 in order to avoid an + * assertion if the hook causes recursion. (When DNS64 also + * becomes a hook module, it will be necessary to find some + * other way to prevent that assertion, since the order in + * which hook modules are configured can't be enforced.) + */ + PROCESS_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); + if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { sigrdatasetp = &qctx->sigrdataset; } From 81f58e2ea2640bd010ddc8f5e0dca0740455966b Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 13 Aug 2018 01:18:09 -0700 Subject: [PATCH 10/26] enable modules to store data in qctx - added a 'hookdata' array to qctx to store pointers to up to 16 blobs of data which are allocated by modules as needed. each module is assigned an ID number as it's loaded, and this is the index into the hook data array. this is to be used for holding persistent state between calls to a hook module for a specific query. - instead of using qctx->filter_aaaa, we now use qctx->hookdata. (this was the last piece of filter-aaaa specific code outside the module.) - added hook points for qctx initialization and destruction. we get a filter-aaaa data pointer from the mempool when initializing and store it in the qctx->hookdata table; return to to the mempool when destroying the qctx. - link the view to the qctx so that detaching the client doesn't cause hooks to fail - added a qctx_destroy() function which must be called after qctx_init; this calls the QCTX_DESTROY hook and detaches the view - general cleanup and comments --- bin/hooks/filter-aaaa.c | 275 +++++++++++++++++++++++++++--------- bin/named/server.c | 13 +- doc/misc/options | 17 ++- lib/dns/include/dns/types.h | 6 - lib/ns/client.c | 2 +- lib/ns/hooks.c | 5 +- lib/ns/include/ns/client.h | 2 +- lib/ns/include/ns/hooks.h | 9 +- lib/ns/include/ns/query.h | 34 ++--- lib/ns/query.c | 176 +++++++++++++---------- lib/ns/tests/nstest.c | 2 +- win32utils/Configure | 1 - 12 files changed, 357 insertions(+), 185 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 6bd1cdc9d8..fa964fab69 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -23,8 +23,8 @@ #include #include +#include #include -#include #include #include @@ -38,9 +38,15 @@ goto cleanup; \ } while (0) -ns_hook_destroy_t hook_destroy; -ns_hook_register_t hook_register; -ns_hook_version_t hook_version; +/* + * Set up in the register function. + */ +static int module_id; + +/* + * Hook data pool. + */ +static isc_mempool_t *datapool = NULL; /* * Per-client flags set by this module @@ -48,56 +54,90 @@ ns_hook_version_t hook_version; #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 & \ +/* + * Client attribute tests. + */ +#define WANTDNSSEC(c) (((c)->attributes & NS_CLIENTATTR_WANTDNSSEC) != 0) +#define RECURSIONOK(c) (((c)->query.attributes & \ NS_QUERYATTR_RECURSIONOK) != 0) +/* + * Hook registration structures: pointers to these structures will + * be added to a hook table when this module is registered. + */ +static bool +filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_init = { + .callback = filter_qctx_initialize, +}; + static bool filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_respbegin = { + .callback = filter_respond_begin, +}; static bool filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_respanyfound = { + .callback = filter_respond_any_found, +}; static bool filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp); +static ns_hook_t filter_prepresp = { + .callback = filter_prep_response_begin, +}; 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 = { +static ns_hook_t filter_donesend = { .callback = filter_query_done_send, }; -/* - * Configuration support. - */ +static bool +filter_qctx_destroy(void *hookdata, void *cbdata, isc_result_t *resp); +ns_hook_t filter_destroy = { + .callback = filter_qctx_destroy, +}; -static dns_aaaa_t v4_aaaa; -static dns_aaaa_t v6_aaaa; +/** + ** Support for parsing of parameters and configuration of the module. + **/ + +/* + * Possible values for the settings of filter-aaaa-on-v4 and + * filter-aaaa-on-v6: "no" is NONE, "yes" is FILTER, "break-dnssec" + * is BREAK_DNSSEC. + */ +typedef enum { + NONE = 0, + FILTER = 1, + BREAK_DNSSEC = 2 +} filter_aaaa_t; + +/* + * Values configured when the module is loaded. + */ +static filter_aaaa_t v4_aaaa = NONE; +static filter_aaaa_t v6_aaaa = NONE; static dns_acl_t *aaaa_acl = NULL; +/* + * Support for parsing of parameters. + */ static const char *filter_aaaa_enums[] = { "break-dnssec", NULL }; + static isc_result_t parse_filter_aaaa(cfg_parser_t *pctx, const cfg_type_t *type, cfg_obj_t **ret) { return (cfg_parse_enum_or_other(pctx, type, &cfg_type_boolean, ret)); } + static void doc_filter_aaaa(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_doc_enum_or_other(pctx, type, &cfg_type_boolean); } + static cfg_type_t cfg_type_filter_aaaa = { "filter_aaaa", parse_filter_aaaa, cfg_print_ustring, doc_filter_aaaa, &cfg_rep_string, filter_aaaa_enums, @@ -121,7 +161,7 @@ static cfg_type_t cfg_type_parameters = { static isc_result_t parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, - dns_aaaa_t *dstp) + filter_aaaa_t *dstp) { const cfg_obj_t *obj = NULL; isc_result_t result; @@ -133,12 +173,12 @@ parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, if (cfg_obj_isboolean(obj)) { if (cfg_obj_asboolean(obj)) { - *dstp = dns_aaaa_filter; + *dstp = FILTER; } else { - *dstp = dns_aaaa_ok; + *dstp = NONE; } } else if (strcasecmp(cfg_obj_asstring(obj), "break-dnssec") == 0) { - *dstp = dns_aaaa_break_dnssec; + *dstp = BREAK_DNSSEC; } else { result = ISC_R_UNEXPECTED; } @@ -187,16 +227,33 @@ parse_parameters(const char *parameters, const void *cfg, return (result); } +/** + ** Mandatory hook API functions. + **/ + /* - * Mandatory hook API functions. + * Prototypes for the hook module API functions defined below. + */ +ns_hook_destroy_t hook_destroy; +ns_hook_register_t hook_register; +ns_hook_version_t hook_version; + +/* + * Called by ns_hookmodule_load() to register hook functions into + * a hook table. */ isc_result_t -hook_register(const char *parameters, const char *file, unsigned long line, - const void *cfg, void *actx, ns_hookctx_t *hctx, - ns_hooktable_t *hooktable, void **instp) +hook_register(const unsigned int modid, const char *parameters, + const char *file, unsigned long line, + const void *cfg, void *actx, + ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp) { + isc_result_t result; + UNUSED(instp); + module_id = modid; + if (parameters != NULL) { isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, @@ -204,7 +261,7 @@ hook_register(const char *parameters, const char *file, unsigned long line, "module from %s:%lu", file, line); - parse_parameters(parameters, cfg, actx, hctx); + CHECK(parse_parameters(parameters, cfg, actx, hctx)); } else { isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, @@ -213,28 +270,50 @@ hook_register(const char *parameters, const char *file, unsigned long line, file, line); } - ns_hook_add(hooktable, NS_QUERY_RESPOND_BEGIN, - &filter_respbegin); + ns_hook_add(hooktable, NS_QUERY_QCTX_INITIALIZED, &filter_init); + 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); + ns_hook_add(hooktable, NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp); + ns_hook_add(hooktable, NS_QUERY_DONE_SEND, &filter_donesend); + ns_hook_add(hooktable, NS_QUERY_QCTX_DESTROYED, &filter_destroy); + + CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_aaaa_t), + &datapool)); /* - * 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 + * Fill the mempool with 1K filter_aaaa state objects at + * a time; ideally after a single allocation, the mempool will + * have enough to handle all the simultaneous queries the system + * requires and it won't be necessary to allocate more. + * + * We don't set any limit on the number of free state objects + * so that they'll always be returned to the pool and not + * freed until the pool is destroyed on shutdown. */ - return (ISC_R_SUCCESS); + isc_mempool_setfillcount(datapool, 1024); + isc_mempool_setfreemax(datapool, UINT_MAX); + + cleanup: + if (result != ISC_R_SUCCESS) { + if (datapool != NULL) { + isc_mempool_destroy(&datapool); + } + } + return (result); } +/* + * Called by ns_hookmodule_cleanup(); frees memory allocated by + * the module when it was registered. + */ void hook_destroy(void **instp) { UNUSED(instp); + if (datapool != NULL) { + isc_mempool_destroy(&datapool); + } if (aaaa_acl != NULL) { dns_acl_detach(&aaaa_acl); } @@ -242,6 +321,9 @@ hook_destroy(void **instp) { return; } +/* + * Returns hook module API version for compatibility checks. + */ int hook_version(unsigned int *flags) { UNUSED(flags); @@ -249,6 +331,10 @@ hook_version(unsigned int *flags) { return (NS_HOOK_VERSION); } +/** + ** "filter-aaaa" feature implementation begins here + **/ + /* * Check whether this is a V4 client. */ @@ -279,31 +365,55 @@ is_v6_client(ns_client_t *client) { } /* - * 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. + * Shorthand to refer to the persistent data stored by this module in + * the query context structure. + */ +#define FILTER_MODE(qctx) ((filter_aaaa_t **) &qctx->hookdata[module_id]) + +/* + * Initialize hook data in the query context, fetching from a memory + * pool. + */ +static bool +filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) hookdata; + filter_aaaa_t **mode = FILTER_MODE(qctx); + + UNUSED(cbdata); + + *mode = isc_mempool_get(datapool); + **mode = NONE; + + *resp = ISC_R_UNSET; + return (false); +} + +/* + * Determine whether this client should have AAAA filtered nor not, + * based on the client address family and the settings of + * filter-aaaa-on-v4 and filter-aaaa-on-v6. */ static bool filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) hookdata; + filter_aaaa_t **mode = FILTER_MODE(qctx); isc_result_t result; UNUSED(cbdata); - qctx->filter_aaaa = dns_aaaa_ok; - if (v4_aaaa != dns_aaaa_ok || v6_aaaa != dns_aaaa_ok) { + if (v4_aaaa != NONE || v6_aaaa != NONE) { result = ns_client_checkaclsilent(qctx->client, NULL, aaaa_acl, true); if (result == ISC_R_SUCCESS && - v4_aaaa != dns_aaaa_ok && + v4_aaaa != NONE && is_v4_client(qctx->client)) { - qctx->filter_aaaa = v4_aaaa; + **mode = v4_aaaa; } else if (result == ISC_R_SUCCESS && - v6_aaaa != dns_aaaa_ok && + v6_aaaa != NONE && is_v6_client(qctx->client)) { - qctx->filter_aaaa = v6_aaaa; + **mode = v6_aaaa; } } @@ -312,19 +422,22 @@ filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { } /* - * Optionally hide AAAA rrsets if there is a matching A. + * Hide AAAA rrsets if there is a matching A. Trigger recursion if + * necessary to find out whether an A exists. + * * (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; + filter_aaaa_t **mode = FILTER_MODE(qctx); isc_result_t result = ISC_R_UNSET; UNUSED(cbdata); - if (qctx->filter_aaaa != dns_aaaa_break_dnssec && - (qctx->filter_aaaa != dns_aaaa_filter || + if (**mode != BREAK_DNSSEC && + (**mode != FILTER || (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && dns_rdataset_isassociated(qctx->sigrdataset)))) { @@ -368,7 +481,8 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { qctx->sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; } - qctx->client->hookflags |= FILTER_AAAA_FILTERED; + qctx->client->hookflags[module_id] |= + FILTER_AAAA_FILTERED; } else if (!qctx->authoritative && RECURSIONOK(qctx->client) && (result == DNS_R_DELEGATION || @@ -387,14 +501,15 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { qctx->client->query.qname, NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { - qctx->client->hookflags |= + qctx->client->hookflags[module_id] |= FILTER_AAAA_RECURSING; qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; } } } else if (qctx->qtype == dns_rdatatype_a && - ((qctx->client->hookflags & FILTER_AAAA_RECURSING) != 0)) + ((qctx->client->hookflags[module_id] & + FILTER_AAAA_RECURSING) != 0)) { dns_rdataset_t *mrdataset = NULL; @@ -417,22 +532,26 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; } - qctx->client->hookflags &= ~FILTER_AAAA_RECURSING; + qctx->client->hookflags[module_id] &= ~FILTER_AAAA_RECURSING; result = ns_query_done(qctx); *resp = result; - return (true); + return (true); } *resp = result; return (false); } +/* + * When answering an ANY query, remove AAAA if A is present. + */ static bool filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) hookdata; + filter_aaaa_t **mode = FILTER_MODE(qctx); dns_name_t *name = NULL; dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; dns_rdataset_t *a = NULL; @@ -440,7 +559,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { UNUSED(cbdata); - if (qctx->filter_aaaa == dns_aaaa_ok) { + if (**mode == NONE) { *resp = ISC_R_UNSET; return (false); } @@ -472,7 +591,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { if (have_a && aaaa != NULL && (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || - qctx->filter_aaaa == dns_aaaa_break_dnssec)) + **mode == BREAK_DNSSEC)) { aaaa->attributes |= DNS_RDATASETATTR_RENDERED; if (aaaa_sig != NULL) { @@ -492,11 +611,12 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { static bool filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) hookdata; + filter_aaaa_t **mode = FILTER_MODE(qctx); isc_result_t result; UNUSED(cbdata); - if (qctx->filter_aaaa == dns_aaaa_ok) { + if (**mode == NONE) { *resp = ISC_R_UNSET; return (false); } @@ -530,7 +650,7 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { dns_rdatatype_aaaa, &aaaa_sig); if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || - qctx->filter_aaaa == dns_aaaa_break_dnssec) + **mode == BREAK_DNSSEC) { aaaa->attributes |= DNS_RDATASETATTR_RENDERED; if (aaaa_sig != NULL) { @@ -540,7 +660,7 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { } } - if ((qctx->client->hookflags & FILTER_AAAA_FILTERED) != 0) { + if ((qctx->client->hookflags[module_id] & FILTER_AAAA_FILTERED) != 0) { result = dns_message_firstname(qctx->client->message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { @@ -572,3 +692,22 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { *resp = ISC_R_UNSET; return (false); } + +/* + * Return hook data to the mempool. + */ +static bool +filter_qctx_destroy(void *hookdata, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) hookdata; + filter_aaaa_t **mode = FILTER_MODE(qctx); + + UNUSED(cbdata); + + if (*mode != NULL) { + isc_mempool_put(datapool, *mode); + *mode = NULL; + } + + *resp = ISC_R_UNSET; + return (false); +} diff --git a/bin/named/server.c b/bin/named/server.c index a6a55bd11b..0fa0f7da31 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1537,7 +1537,8 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, } static isc_result_t -configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, +configure_hook(ns_hooktable_t *hooktable, const unsigned int modid, + const cfg_obj_t *hook, const cfg_obj_t *config, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; @@ -1559,7 +1560,7 @@ configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, obj = cfg_tuple_get(hook, "parameters"); if (obj != NULL && cfg_obj_isstring(obj)) { - result = ns_hookmodule_load(library, + result = ns_hookmodule_load(library, modid, cfg_obj_asstring(obj), cfg_obj_file(obj), cfg_obj_line(obj), @@ -1567,7 +1568,7 @@ configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, named_g_aclconfctx, hctx, hooktable); } else { - result = ns_hookmodule_load(library, NULL, + result = ns_hookmodule_load(library, modid, NULL, cfg_obj_file(hook), cfg_obj_line(hook), config, @@ -3768,6 +3769,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, unsigned int resolver_param; dns_ntatable_t *ntatable = NULL; const char *qminmode = NULL; + unsigned int module_counter = 0; REQUIRE(DNS_VIEW_VALID(view)); @@ -5332,7 +5334,10 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, CHECK(ns_hook_createctx(mctx, &hctx)); } - CHECK(configure_hook(view->hooktable, hook, config, hctx)); + CHECK(configure_hook(view->hooktable, module_counter, + hook, config, hctx)); + + module_counter++; } #endif diff --git a/doc/misc/options b/doc/misc/options index 371ae55664..1b54aeda19 100644 --- a/doc/misc/options +++ b/doc/misc/options @@ -24,6 +24,9 @@ dlz { dyndb { }; // may occur multiple times +hook ( query ) [ { } + ]; // may occur multiple times + key { algorithm ; secret ; @@ -172,9 +175,9 @@ options { fetches-per-server [ ( drop | fail ) ]; fetches-per-zone [ ( drop | fail ) ]; files ( default | unlimited | ); - filter-aaaa { ; ... }; - filter-aaaa-on-v4 ( break-dnssec | ); - filter-aaaa-on-v6 ( break-dnssec | ); + filter-aaaa { ; ... }; // obsolete + filter-aaaa-on-v4 ; // obsolete + filter-aaaa-on-v6 ; // obsolete flush-zones-on-shutdown ; forward ( first | only ); forwarders [ port ] [ dscp ] { ( @@ -533,13 +536,15 @@ view [ ] { fetch-quota-params ; fetches-per-server [ ( drop | fail ) ]; fetches-per-zone [ ( drop | fail ) ]; - filter-aaaa { ; ... }; - filter-aaaa-on-v4 ( break-dnssec | ); - filter-aaaa-on-v6 ( break-dnssec | ); + filter-aaaa { ; ... }; // obsolete + filter-aaaa-on-v4 ; // obsolete + filter-aaaa-on-v6 ; // obsolete forward ( first | only ); forwarders [ port ] [ dscp ] { ( | ) [ port ] [ dscp ]; ... }; glue-cache ; + hook ( query ) [ { + } ]; // may occur multiple times inline-signing ; ixfr-from-differences ( primary | master | secondary | slave | ); diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index c2e64287c1..17c605e69a 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -216,12 +216,6 @@ typedef enum { dns_masterformat_map = 3 } dns_masterformat_t; -typedef enum { - dns_aaaa_ok = 0, - dns_aaaa_filter = 1, - dns_aaaa_break_dnssec = 2 -} dns_aaaa_t; - /* * These are generated by gen.c. */ diff --git a/lib/ns/client.c b/lib/ns/client.c index 525cad499d..7739905d04 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -3047,7 +3047,7 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { ISC_QLINK_INIT(client, ilink); client->keytag = NULL; client->keytag_len = 0; - client->hookflags = 0; + memset(client->hookflags, 0, sizeof(client->hookflags)); /* * We call the init routines for the various kinds of client here, diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 6835617b4c..7f0ab4d4a2 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -328,7 +328,8 @@ unload_library(ns_hook_module_t **hmodp) { #endif /* HAVE_DLFCN_H */ isc_result_t -ns_hookmodule_load(const char *libname, const char *parameters, +ns_hookmodule_load(const char *libname, const unsigned int modid, + const char *parameters, const char *file, unsigned long line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable) @@ -343,7 +344,7 @@ ns_hookmodule_load(const char *libname, const char *parameters, "loading module '%s'", libname); CHECK(load_library(hctx->mctx, libname, &module)); - CHECK(module->register_func(parameters, file, line, + CHECK(module->register_func(modid, parameters, file, line, cfg, actx, hctx, hooktable, &module->inst)); diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 12845141fb..ea209d6b5f 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -175,7 +175,7 @@ struct ns_client { * Allows a hook module to set flags * that persist across recursion. */ - uint32_t hookflags; + uint32_t hookflags[NS_MAX_MODULES]; }; typedef ISC_QUEUE(ns_client_t) client_queue_t; diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index f89201a48b..95f9aca183 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -163,7 +163,8 @@ */ typedef enum { - NS_QUERY_SETUP_QCTX_INITIALIZED, + NS_QUERY_QCTX_INITIALIZED, + NS_QUERY_QCTX_DESTROYED, NS_QUERY_START_BEGIN, NS_QUERY_LOOKUP_BEGIN, NS_QUERY_RESUME_BEGIN, @@ -235,7 +236,8 @@ typedef struct ns_hookctx { #define NS_HOOK_AGE 0 #endif -typedef isc_result_t ns_hook_register_t(const char *parameters, +typedef isc_result_t ns_hook_register_t(const unsigned int modid, + const char *parameters, const char *file, unsigned long line, const void *cfg, @@ -312,7 +314,8 @@ void ns_hook_destroyctx(ns_hookctx_t **hctxp); isc_result_t -ns_hookmodule_load(const char *libname, const char *parameters, +ns_hookmodule_load(const char *libname, const unsigned int modid, + const char *parameters, const char *file, unsigned long line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable); diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index 853c7e5a90..987dfe804d 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -27,12 +27,18 @@ #include +/* + * Maximum number of query hook modules that can be configured; + * more than this will overflow qctx->hookdata. + */ +#define NS_MAX_MODULES 16 + /*% nameserver database version structure */ typedef struct ns_dbversion { dns_db_t *db; dns_dbversion_t *version; - bool acl_checked; - bool queryok; + bool acl_checked; + bool queryok; ISC_LINK(struct ns_dbversion) link; } ns_dbversion_t; @@ -52,7 +58,7 @@ typedef struct ns_query_recparam { struct ns_query { unsigned int attributes; unsigned int restarts; - bool timerset; + bool timerset; dns_name_t * qname; dns_name_t * origqname; dns_rdatatype_t qtype; @@ -61,8 +67,8 @@ struct ns_query { dns_db_t * gluedb; dns_db_t * authdb; dns_zone_t * authzone; - bool authdbset; - bool isreferral; + bool authdbset; + bool isreferral; isc_mutex_t fetchlock; dns_fetch_t * fetch; dns_fetch_t * prefetch; @@ -72,7 +78,7 @@ struct ns_query { ISC_LIST(ns_dbversion_t) freeversions; dns_rdataset_t * dns64_aaaa; dns_rdataset_t * dns64_sigaaaa; - bool * dns64_aaaaok; + bool * dns64_aaaaok; unsigned int dns64_aaaaoklen; unsigned int dns64_options; unsigned int dns64_ttl; @@ -87,8 +93,8 @@ struct ns_query { isc_result_t result; dns_rdataset_t * rdataset; dns_rdataset_t * sigrdataset; - bool authoritative; - bool is_zone; + bool authoritative; + bool is_zone; } redirect; ns_query_recparam_t recparam; @@ -166,7 +172,9 @@ struct query_ctx { dns_rpz_st_t *rpz_st; /* RPZ state */ dns_zone_t *zone; /* zone to search */ - dns_aaaa_t filter_aaaa; /* AAAA filtering */ + dns_view_t *view; /* client view */ + + void *hookdata[NS_MAX_MODULES]; /* data used by query hooks */ isc_result_t result; /* query result */ int line; /* line to report error */ @@ -254,12 +262,4 @@ 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. - */ - #endif /* NS_QUERY_H */ diff --git a/lib/ns/query.c b/lib/ns/query.c index a83730c362..dcfa5cc368 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -243,11 +243,10 @@ log_noexistnodata(void *val, int level, const char *fmt, ...) ns_hooktable_t *_tab = ns__hook_table; \ query_ctx_t *_q = (_qctx); \ if (_q != NULL && \ - _q->client != NULL && \ - _q->client->view != NULL && \ - _q->client->view->hooktable != NULL) \ + _q->view != NULL && \ + _q->view->hooktable != NULL) \ { \ - _tab = _q->client->view->hooktable; \ + _tab = _q->view->hooktable; \ } \ NS_PROCESS_HOOK(_tab, _id, _q, __VA_ARGS__); \ } while (false) @@ -257,11 +256,10 @@ log_noexistnodata(void *val, int level, const char *fmt, ...) ns_hooktable_t *_tab = ns__hook_table; \ query_ctx_t *_q = (_qctx); \ if (_q != NULL && \ - _q->client != NULL && \ - _q->client->view != NULL && \ - _q->client->view->hooktable != NULL) \ + _q->view != NULL && \ + _q->view->hooktable != NULL) \ { \ - _tab = _q->client->view->hooktable; \ + _tab = _q->view->hooktable; \ } \ NS_PROCESS_HOOK_VOID(_tab, _id, _q, __VA_ARGS__); \ } while (false) @@ -329,7 +327,8 @@ log_noexistnodata(void *val, int level, const char *fmt, ...) * return it to the client. * * (XXX: This description omits several special cases including - * DNS64, filter-aaaa, RPZ, RRL, and the SERVFAIL cache.) + * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss + * query hook modules.) */ static void @@ -1460,7 +1459,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { * If we want only minimal responses and are here, then it must * be for glue. */ - if (client->view->minimalresponses == dns_minimal_yes) { + if (qctx->view->minimalresponses == dns_minimal_yes) { goto try_glue; } @@ -1517,7 +1516,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { */ try_cache: - if (!client->view->recursion) { + if (!qctx->view->recursion) { goto try_glue; } @@ -1546,7 +1545,7 @@ query_additional_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype) { client->now, &node, fname, &cm, &ci, rdataset, sigrdataset); - dns_cache_updatestats(client->view->cache, result); + dns_cache_updatestats(qctx->view->cache, result); if (!WANTDNSSEC(client)) { ns_client_putrdataset(client, &sigrdataset); } @@ -1892,9 +1891,11 @@ query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { CTRACE(ISC_LOG_DEBUG(3), "query_setorder"); - if (client->view->order != NULL) { + UNUSED(client); + + if (qctx->view->order != NULL) { rdataset->attributes |= - dns_order_find(qctx->client->view->order, + dns_order_find(qctx->view->order, name, rdataset->type, rdataset->rdclass); } @@ -1917,7 +1918,7 @@ query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { /* * Try to process glue directly. */ - if (client->view->use_glue_cache && + if (qctx->view->use_glue_cache && (rdataset->type == dns_rdatatype_ns) && (client->query.gluedb != NULL) && dns_db_iszone(client->query.gluedb)) @@ -4800,6 +4801,9 @@ redirect2(ns_client_t *client, dns_name_t *name, dns_rdataset_t *rdataset, * Initialize query context 'qctx'. Run by query_setup() when * first handling a client query, and by query_resume() when * returning from recursion. + * + * Whenever this function is called, qctx_destroy() must be called + * when leaving the scope or freeing the qctx. */ static void qctx_init(ns_client_t *client, dns_fetchevent_t *event, @@ -4808,10 +4812,13 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, REQUIRE(qctx != NULL); REQUIRE(client != NULL); + memset(qctx, 0, sizeof(query_ctx_t)); + /* Set this first so CCTRACE will work */ qctx->client = client; + dns_view_attach(client->view, &qctx->view); - CCTRACE(ISC_LOG_DEBUG(3), "qctx_create"); + CCTRACE(ISC_LOG_DEBUG(3), "qctx_init"); qctx->event = event; qctx->qtype = qctx->type = qtype; @@ -4835,12 +4842,13 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, qctx->options = 0; qctx->resuming = false; qctx->is_zone = false; - qctx->findcoveringnsec = client->view->synthfromdnssec; + qctx->findcoveringnsec = qctx->view->synthfromdnssec; qctx->is_staticstub_zone = false; qctx->nxrewrite = false; qctx->answer_has_ns = false; qctx->authoritative = false; - qctx->filter_aaaa = dns_aaaa_ok; + + PROCESS_HOOK_VOID(NS_QUERY_QCTX_INITIALIZED, qctx); } /*% @@ -4903,6 +4911,12 @@ qctx_freedata(query_ctx_t *qctx) { } } +static void +qctx_destroy(query_ctx_t *qctx) { + PROCESS_HOOK_VOID(NS_QUERY_QCTX_DESTROYED, qctx); + dns_view_detach(&qctx->view); +} + /*% * Log detailed information about the query immediately after * the client request or a return from recursion. @@ -4962,17 +4976,18 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) { qctx.type = dns_rdatatype_any; } - PROCESS_HOOK(NS_QUERY_SETUP_QCTX_INITIALIZED, &qctx); - /* * Check SERVFAIL cache */ result = ns__query_sfcache(&qctx); if (result != ISC_R_COMPLETE) { + qctx_destroy(&qctx); return (result); } - return (ns__query_start(&qctx)); + result = ns__query_start(&qctx); + qctx_destroy(&qctx); + return (result); } static bool @@ -5061,7 +5076,7 @@ ns__query_start(query_ctx_t *qctx) { * If we require a server cookie then send back BADCOOKIE * before we have done too much work. */ - if (!TCP(qctx->client) && qctx->client->view->requireservercookie && + if (!TCP(qctx->client) && qctx->view->requireservercookie && WANTCOOKIE(qctx->client) && !HAVECOOKIE(qctx->client)) { qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AA; @@ -5070,7 +5085,7 @@ ns__query_start(query_ctx_t *qctx) { return (ns_query_done(qctx)); } - if (qctx->client->view->checknames && + if (qctx->view->checknames && !dns_rdata_checkowner(qctx->client->query.qname, qctx->client->message->rdclass, qctx->qtype, false)) @@ -5095,7 +5110,7 @@ ns__query_start(query_ctx_t *qctx) { /* * Setup for root key sentinel processing. */ - if (qctx->client->view->root_key_sentinel && + if (qctx->view->root_key_sentinel && qctx->client->query.restarts == 0 && (qctx->qtype == dns_rdatatype_a || qctx->qtype == dns_rdatatype_aaaa) && @@ -5340,7 +5355,7 @@ query_lookup(query_ctx_t *qctx) { } if (!qctx->is_zone) { - dns_cache_updatestats(qctx->client->view->cache, result); + dns_cache_updatestats(qctx->view->cache, result); } if ((qctx->client->query.dboptions & DNS_DBFIND_STALEOK) != 0) { @@ -5351,8 +5366,7 @@ query_lookup(query_ctx_t *qctx) { if (dns_rdataset_isassociated(qctx->rdataset) && dns_rdataset_count(qctx->rdataset) > 0 && STALE(qctx->rdataset)) { - qctx->rdataset->ttl = - qctx->client->view->staleanswerttl; + qctx->rdataset->ttl = qctx->view->staleanswerttl; success = true; } else { success = false; @@ -5443,6 +5457,10 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { } else { query_ctx_t qctx; + /* + * Initalize a new qctx and use it to resume + * from recursion. + */ qctx_init(client, devent, 0, &qctx); query_trace(&qctx); @@ -5460,6 +5478,8 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { errorloglevel, false); } } + + qctx_destroy(&qctx); } dns_resolver_destroyfetch(&fetch); @@ -5802,7 +5822,7 @@ query_resume(query_ctx_t *qctx) { /* * Has response policy changed out from under us? */ - if (qctx->rpz_st->rpz_ver != qctx->client->view->rpzs->rpz_ver) + if (qctx->rpz_st->rpz_ver != qctx->view->rpzs->rpz_ver) { ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, @@ -5810,7 +5830,7 @@ query_resume(query_ctx_t *qctx) { "query_resume: RPZ settings " "out of date " "(rpz_ver %d, expected %d)", - qctx->client->view->rpzs->rpz_ver, + qctx->view->rpzs->rpz_ver, qctx->rpz_st->rpz_ver); QUERY_ERROR(qctx, DNS_R_SERVFAIL); return (ns_query_done(qctx)); @@ -5896,13 +5916,13 @@ ns__query_sfcache(query_ctx_t *qctx) { failcache = false; } else { failcache = - dns_badcache_find(qctx->client->view->failcache, + dns_badcache_find(qctx->view->failcache, qctx->client->query.qname, qctx->qtype, &flags, &qctx->client->tnow); } #else - failcache = dns_badcache_find(qctx->client->view->failcache, + failcache = dns_badcache_find(qctx->view->failcache, qctx->client->query.qname, qctx->qtype, &flags, &qctx->client->tnow); @@ -5959,20 +5979,26 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { * is set when we are called the second time preventing the * response being dropped. */ - ns_client_log(qctx->client, DNS_LOGCATEGORY_RRL, NS_LOGMODULE_QUERY, - ISC_LOG_DEBUG(99), "rrl=%p, HAVECOOKIE=%u, result=%s, " + ns_client_log(qctx->client, DNS_LOGCATEGORY_RRL, + NS_LOGMODULE_QUERY, ISC_LOG_DEBUG(99), + "rrl=%p, HAVECOOKIE=%u, result=%s, " "fname=%p(%u), is_zone=%u, RECURSIONOK=%u, " "query.rpz_st=%p(%u), RRL_CHECKED=%u\n", qctx->client->view->rrl, HAVECOOKIE(qctx->client), isc_result_toid(result), qctx->fname, - qctx->fname?dns_name_isabsolute(qctx->fname) : 0, + qctx->fname != NULL + ? dns_name_isabsolute(qctx->fname) + : 0, qctx->is_zone, RECURSIONOK(qctx->client), qctx->client->query.rpz_st, - qctx->client->query.rpz_st ? - (qctx->client->query.rpz_st->state & DNS_RPZ_REWRITTEN) != 0 : 0, - (qctx->client->query.attributes & NS_QUERYATTR_RRL_CHECKED) != 0); + qctx->client->query.rpz_st != NULL + ? ((qctx->client->query.rpz_st->state & + DNS_RPZ_REWRITTEN) != 0) + : 0, + (qctx->client->query.attributes & + NS_QUERYATTR_RRL_CHECKED) != 0); - if (qctx->client->view->rrl != NULL && + if (qctx->view->rrl != NULL && !HAVECOOKIE(qctx->client) && ((qctx->fname != NULL && dns_name_isabsolute(qctx->fname)) || (result == ISC_R_NOTFOUND && !RECURSIONOK(qctx->client))) && @@ -6043,7 +6069,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { resp_result = ISC_R_SUCCESS; } - rrl_result = dns_rrl(qctx->client->view, + rrl_result = dns_rrl(qctx->view, &qctx->client->peeraddr, TCP(qctx->client), qctx->client->message->rdclass, @@ -6068,7 +6094,7 @@ query_checkrrl(query_ctx_t *qctx, isc_result_t result) { "%s", log_buf); } - if (!qctx->client->view->rrl->log_only) { + if (!qctx->view->rrl->log_only) { if (rrl_result == DNS_RRL_RESULT_DROP) { /* * These will also be counted in @@ -6370,7 +6396,7 @@ has_ta(query_ctx_t *qctx) { dns_keynode_t *keynode = NULL; isc_result_t result; - result = dns_view_getsecroots(qctx->client->view, &keytable); + result = dns_view_getsecroots(qctx->view, &keytable); if (result != ISC_R_SUCCESS) { return (false); } @@ -6739,7 +6765,7 @@ query_respond_any(query_ctx_t *qctx) { * ANY queries. */ dns_rdataset_disassociate(qctx->rdataset); - } else if (qctx->client->view->minimal_any && + } else if (qctx->view->minimal_any && !TCP(qctx->client) && !WANTDNSSEC(qctx->client) && qctx->qtype == dns_rdatatype_any && (qctx->rdataset->type == dns_rdatatype_sig || @@ -6748,7 +6774,7 @@ query_respond_any(query_ctx_t *qctx) { CCTRACE(ISC_LOG_DEBUG(5), "query_respond_any: " "minimal-any skip signature"); dns_rdataset_disassociate(qctx->rdataset); - } else if (qctx->client->view->minimal_any && + } else if (qctx->view->minimal_any && !TCP(qctx->client) && onetype != 0 && qctx->rdataset->type != onetype && qctx->rdataset->covers != onetype) @@ -6996,7 +7022,7 @@ query_respond(query_ctx_t *qctx) { INSIST(qctx->client->query.dns64_aaaaok == NULL); if (qctx->qtype == dns_rdatatype_aaaa && !qctx->dns64_exclude && - !ISC_LIST_EMPTY(qctx->client->view->dns64) && + !ISC_LIST_EMPTY(qctx->view->dns64) && qctx->client->message->rdclass == dns_rdataclass_in && !dns64_aaaaok(qctx->client, qctx->rdataset, qctx->sigrdataset)) { @@ -7473,14 +7499,14 @@ query_notfound(query_ctx_t *qctx) { * If the cache doesn't even have the root NS, * try to get that from the hints DB. */ - if (qctx->client->view->hints != NULL) { + if (qctx->view->hints != NULL) { dns_clientinfomethods_t cm; dns_clientinfo_t ci; dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, qctx->client, NULL); - dns_db_attach(qctx->client->view->hints, &qctx->db); + dns_db_attach(qctx->view->hints, &qctx->db); result = dns_db_findext(qctx->db, dns_rootname, NULL, dns_rdatatype_ns, 0, qctx->client->now, &qctx->node, @@ -7665,7 +7691,7 @@ query_zone_delegation(query_ctx_t *qctx) { SAVE(qctx->zversion, qctx->version); SAVE(qctx->zrdataset, qctx->rdataset); SAVE(qctx->zsigrdataset, qctx->sigrdataset); - dns_db_attach(qctx->client->view->cachedb, &qctx->db); + dns_db_attach(qctx->view->cachedb, &qctx->db); qctx->is_zone = false; return (query_lookup(qctx)); @@ -7986,7 +8012,7 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { #endif } else if ((result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) && - !ISC_LIST_EMPTY(qctx->client->view->dns64) && + !ISC_LIST_EMPTY(qctx->view->dns64) && qctx->client->message->rdclass == dns_rdataclass_in && qctx->qtype == dns_rdatatype_aaaa) { @@ -8530,7 +8556,7 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, dns_name_t *name = NULL; isc_buffer_t *dbuf, b; isc_result_t result; - dns_rdataset_t *clone = NULL, *sigclone = NULL; + dns_rdataset_t *cloneset = NULL, *clonesigset = NULL; dns_rdataset_t **sigrdatasetp; /* @@ -8556,29 +8582,29 @@ query_synthwildcard(query_ctx_t *qctx, dns_rdataset_t *rdataset, } dns_name_copy(qctx->client->query.qname, name, NULL); - clone = ns_client_newrdataset(qctx->client); - if (clone == NULL) { + cloneset = ns_client_newrdataset(qctx->client); + if (cloneset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - dns_rdataset_clone(rdataset, clone); + dns_rdataset_clone(rdataset, cloneset); /* * Add answer RRset. Omit the RRSIG if DNSSEC was not requested. */ if (WANTDNSSEC(qctx->client)) { - sigclone = ns_client_newrdataset(qctx->client); - if (sigclone == NULL) { + clonesigset = ns_client_newrdataset(qctx->client); + if (clonesigset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - dns_rdataset_clone(sigrdataset, sigclone); - sigrdatasetp = &sigclone; + dns_rdataset_clone(sigrdataset, clonesigset); + sigrdatasetp = &clonesigset; } else { sigrdatasetp = NULL; } - query_addrrset(qctx, &name, &clone, sigrdatasetp, + query_addrrset(qctx, &name, &cloneset, sigrdatasetp, dbuf, DNS_SECTION_ANSWER); if (WANTDNSSEC(qctx->client)) { @@ -8597,11 +8623,11 @@ cleanup: if (name != NULL) { ns_client_releasename(qctx->client, &name); } - if (clone != NULL) { - ns_client_putrdataset(qctx->client, &clone); + if (cloneset != NULL) { + ns_client_putrdataset(qctx->client, &cloneset); } - if (sigclone != NULL) { - ns_client_putrdataset(qctx->client, &sigclone); + if (clonesigset != NULL) { + ns_client_putrdataset(qctx->client, &clonesigset); } return (result); } @@ -8684,7 +8710,7 @@ query_synthnxdomain(query_ctx_t *qctx, dns_ttl_t ttl; isc_buffer_t *dbuf, b; isc_result_t result; - dns_rdataset_t *clone = NULL, *sigclone = NULL; + dns_rdataset_t *cloneset = NULL, *clonesigset = NULL; /* * Detemine the correct TTL to use for the SOA and RRSIG @@ -8749,20 +8775,20 @@ query_synthnxdomain(query_ctx_t *qctx, dns_name_copy(nowild, name, NULL); - clone = ns_client_newrdataset(qctx->client); - sigclone = ns_client_newrdataset(qctx->client); - if (clone == NULL || sigclone == NULL) { + cloneset = ns_client_newrdataset(qctx->client); + clonesigset = ns_client_newrdataset(qctx->client); + if (cloneset == NULL || clonesigset == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } - dns_rdataset_clone(nowildrdataset, clone); - dns_rdataset_clone(signowildrdataset, sigclone); + dns_rdataset_clone(nowildrdataset, cloneset); + dns_rdataset_clone(signowildrdataset, clonesigset); /* * Add NOWILDCARD proof. */ - query_addrrset(qctx, &name, &clone, &sigclone, + query_addrrset(qctx, &name, &cloneset, &clonesigset, dbuf, DNS_SECTION_AUTHORITY); } @@ -8774,11 +8800,11 @@ cleanup: if (name != NULL) { ns_client_releasename(qctx->client, &name); } - if (clone != NULL) { - ns_client_putrdataset(qctx->client, &clone); + if (cloneset != NULL) { + ns_client_putrdataset(qctx->client, &cloneset); } - if (sigclone != NULL) { - ns_client_putrdataset(qctx->client, &sigclone); + if (clonesigset != NULL) { + ns_client_putrdataset(qctx->client, &clonesigset); } return (result); } @@ -8895,7 +8921,7 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (!ISC_LIST_EMPTY(qctx->client->view->dns64) && + if (!ISC_LIST_EMPTY(qctx->view->dns64) && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ { @@ -8959,7 +8985,7 @@ query_coveringnsec(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { /* XXX not yet */ goto cleanup; } - if (!ISC_LIST_EMPTY(qctx->client->view->dns64) && + if (!ISC_LIST_EMPTY(qctx->view->dns64) && (qctx->type == dns_rdatatype_a || qctx->type == dns_rdatatype_aaaa)) /* XXX not yet */ { @@ -10452,7 +10478,7 @@ ns_query_done(query_ctx_t *qctx) { query_glueanswer(qctx); if (qctx->client->message->rcode == dns_rcode_nxdomain && - qctx->client->view->auth_nxdomain == true) + qctx->view->auth_nxdomain == true) { qctx->client->message->flags |= DNS_MESSAGEFLAG_AA; } diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index c6311ec39b..355d175865 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -691,7 +691,7 @@ create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { */ ns_hooktable_init(&query_hooks); - ns_hook_add(&query_hooks, NS_QUERY_SETUP_QCTX_INITIALIZED, &hook); + ns_hook_add(&query_hooks, NS_QUERY_QCTX_INITIALIZED, &hook); saved_hook_table = ns__hook_table; ns__hook_table = &query_hooks; diff --git a/win32utils/Configure b/win32utils/Configure index 40cddb9708..568386bafa 100644 --- a/win32utils/Configure +++ b/win32utils/Configure @@ -360,7 +360,6 @@ my @enablelist = ("developer", "isc-spnego", "native-pkcs11", "openssl-hash", - "filter-aaaa", "querytrace", "rpz-nsdname", "rpz-nsip"); From 055bf2665cf91aa8cf1592bf2a67a42f1f50f22e Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Mon, 13 Aug 2018 21:08:08 -0700 Subject: [PATCH 11/26] improve hook processing macros - use a get_hooktab() function to determine the hook table. - PROCESS_HOOK now jumps to a cleanup tag on failure - add PROCESS_ALL_HOOKS in query.c, to run all hook functions at a specified hook point without stopping. this is to be used for intiialization and destruction functions that must run in every module. - 'result' is set in PROCESS_HOOK only when a hook function interrupts processing. - revised terminology: a "callback" is now a "hook action" - remove unused NS_PROCESS_HOOK and NS_PROCESS_HOOK_VOID macros. --- bin/hooks/filter-aaaa.c | 12 +-- lib/ns/include/ns/hooks.h | 36 +-------- lib/ns/query.c | 155 +++++++++++++++++++++++++++++++------- lib/ns/tests/nstest.c | 27 ++++--- lib/ns/tests/nstest.h | 3 +- lib/ns/tests/query_test.c | 4 +- 6 files changed, 155 insertions(+), 82 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index fa964fab69..174725eac2 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -68,37 +68,37 @@ static isc_mempool_t *datapool = NULL; static bool filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp); static ns_hook_t filter_init = { - .callback = filter_qctx_initialize, + .action = filter_qctx_initialize, }; static bool filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp); static ns_hook_t filter_respbegin = { - .callback = filter_respond_begin, + .action = filter_respond_begin, }; static bool filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp); static ns_hook_t filter_respanyfound = { - .callback = filter_respond_any_found, + .action = filter_respond_any_found, }; static bool filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp); static ns_hook_t filter_prepresp = { - .callback = filter_prep_response_begin, + .action = filter_prep_response_begin, }; static bool filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp); static ns_hook_t filter_donesend = { - .callback = filter_query_done_send, + .action = filter_query_done_send, }; static bool filter_qctx_destroy(void *hookdata, void *cbdata, isc_result_t *resp); ns_hook_t filter_destroy = { - .callback = filter_qctx_destroy, + .action = filter_qctx_destroy, }; /** diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 95f9aca183..760292f0cc 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -165,6 +165,7 @@ typedef enum { NS_QUERY_QCTX_INITIALIZED, NS_QUERY_QCTX_DESTROYED, + NS_QUERY_SETUP, NS_QUERY_START_BEGIN, NS_QUERY_LOOKUP_BEGIN, NS_QUERY_RESUME_BEGIN, @@ -189,11 +190,11 @@ typedef enum { } ns_hookpoint_t; typedef bool -(*ns_hook_cb_t)(void *hook_data, void *callback_data, isc_result_t *resultp); +(*ns_hook_action_t)(void *arg, void *data, isc_result_t *resultp); typedef struct ns_hook { - ns_hook_cb_t callback; - void *callback_data; + ns_hook_action_t action; + void *action_data; ISC_LINK(struct ns_hook) link; } ns_hook_t; @@ -278,35 +279,6 @@ typedef int ns_hook_version_t(unsigned int *flags); * the future to pass back driver capabilities or other information. */ -/* - * Run a hook. Calls the function or functions registered at hookpoint 'id'. - * If one of them returns true, we interrupt processing and return the - * result that was returned by the hook function. If none of them return - * true, we continue processing. - */ -#define _NS_PROCESS_HOOK(table, id, data, ...) \ - if (table != NULL) { \ - ns_hook_t *_hook = ISC_LIST_HEAD((*table)[id]); \ - isc_result_t _result; \ - \ - while (_hook != NULL) { \ - ns_hook_cb_t _callback = _hook->callback; \ - void *_callback_data = _hook->callback_data; \ - if (_callback != NULL && \ - _callback(data, _callback_data, &_result)) \ - { \ - return __VA_ARGS__; \ - } else { \ - _hook = ISC_LIST_NEXT(_hook, link); \ - } \ - } \ - } - -#define NS_PROCESS_HOOK(table, id, data, ...) \ - _NS_PROCESS_HOOK(table, id, data, _result) -#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); diff --git a/lib/ns/query.c b/lib/ns/query.c index dcfa5cc368..5de1f2b1f2 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -238,30 +238,73 @@ static void log_noexistnodata(void *val, int level, const char *fmt, ...) ISC_FORMAT_PRINTF(3, 4); -#define PROCESS_HOOK(_id, _qctx, ...) \ + +/* + * Return the hooktable in use with 'qctx', or if there isn't one + * set, return the default hooktable. + */ +static inline ns_hooktable_t * +get_hooktab(query_ctx_t *qctx) { + if (qctx == NULL || qctx->view == NULL || + qctx->view->hooktable == NULL) + { + return (ns__hook_table); + } + + return (qctx->view->hooktable); +} + +/* + * Call the specified hook function in every configured module that + * implements that function. If any hook function returns 'true', we set + * 'result' and terminate processing by jumping to the 'cleanup' tag. + * + * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but + * still terminate processing within the calling function. That's why this + * is a macro instead of an inline function; it needs to be able to use + * 'goto cleanup' regardless of the return value.) + */ +#define PROCESS_HOOK(_id, _qctx) \ do { \ - ns_hooktable_t *_tab = ns__hook_table; \ - query_ctx_t *_q = (_qctx); \ - if (_q != NULL && \ - _q->view != NULL && \ - _q->view->hooktable != NULL) \ - { \ - _tab = _q->view->hooktable; \ + isc_result_t _res; \ + ns_hooktable_t *_tab = get_hooktab(_qctx); \ + ns_hook_t *_hook; \ + _hook = ISC_LIST_HEAD((*_tab)[_id]); \ + while (_hook != NULL) { \ + ns_hook_action_t _func = _hook->action; \ + void *_data = _hook->action_data; \ + INSIST(_func != NULL); \ + if (_func(_qctx, _data, &_res)) { \ + result = _res; \ + goto cleanup; \ + } else { \ + _hook = ISC_LIST_NEXT(_hook, link); \ + } \ } \ - NS_PROCESS_HOOK(_tab, _id, _q, __VA_ARGS__); \ } while (false) -#define PROCESS_HOOK_VOID(_id, _qctx, ...) \ +/* + * Call the specified hook function in every configured module that + * implements that function. All modules are called; hook function return + * codes are ignored. This is intended for use with initialization and + * destruction calls which *must* run in every configured module. + * + * (This could be implemented as an inline void function, but is left as a + * macro for symmetry with PROCESS_HOOK above.) + */ +#define PROCESS_ALL_HOOKS(_id, _qctx) \ do { \ - ns_hooktable_t *_tab = ns__hook_table; \ - query_ctx_t *_q = (_qctx); \ - if (_q != NULL && \ - _q->view != NULL && \ - _q->view->hooktable != NULL) \ - { \ - _tab = _q->view->hooktable; \ + isc_result_t _res; \ + ns_hooktable_t *_tab = get_hooktab(_qctx); \ + ns_hook_t *_hook; \ + _hook = ISC_LIST_HEAD((*_tab)[_id]); \ + while (_hook != NULL) { \ + ns_hook_action_t _func = _hook->action; \ + void *_data = _hook->action_data; \ + INSIST(_func != NULL); \ + _func(_qctx, _data, &_res); \ + _hook = ISC_LIST_NEXT(_hook, link); \ } \ - NS_PROCESS_HOOK_VOID(_tab, _id, _q, __VA_ARGS__); \ } while (false) /* @@ -1908,6 +1951,7 @@ query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { static void query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { ns_client_t *client = qctx->client; + isc_result_t result; CTRACE(ISC_LOG_DEBUG(3), "query_additional"); @@ -1923,7 +1967,6 @@ query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { (client->query.gluedb != NULL) && dns_db_iszone(client->query.gluedb)) { - isc_result_t result; ns_dbversion_t *dbversion; dbversion = ns_client_findversion(client, client->query.gluedb); @@ -1938,7 +1981,7 @@ query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { } } -regular: + regular: /* * Add other additional data if needed. * We don't care if dns_rdataset_additionaldata() fails. @@ -4848,7 +4891,7 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, qctx->answer_has_ns = false; qctx->authoritative = false; - PROCESS_HOOK_VOID(NS_QUERY_QCTX_INITIALIZED, qctx); + PROCESS_ALL_HOOKS(NS_QUERY_QCTX_INITIALIZED, qctx); } /*% @@ -4913,7 +4956,8 @@ qctx_freedata(query_ctx_t *qctx) { static void qctx_destroy(query_ctx_t *qctx) { - PROCESS_HOOK_VOID(NS_QUERY_QCTX_DESTROYED, qctx); + PROCESS_ALL_HOOKS(NS_QUERY_QCTX_DESTROYED, qctx); + dns_view_detach(&qctx->view); } @@ -4967,6 +5011,8 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) { qctx_init(client, NULL, qtype, &qctx); query_trace(&qctx); + PROCESS_HOOK(NS_QUERY_SETUP, &qctx); + /* * If it's a SIG query, we'll iterate the node. */ @@ -4986,6 +5032,8 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) { } result = ns__query_start(&qctx); + + cleanup: qctx_destroy(&qctx); return (result); } @@ -5263,6 +5311,9 @@ ns__query_start(query_ctx_t *qctx) { } return (query_lookup(qctx)); + + cleanup: + return (result); } /*% @@ -5386,6 +5437,9 @@ query_lookup(query_ctx_t *qctx) { } return (query_gotanswer(qctx, result)); + + cleanup: + return (result); } /* @@ -5889,6 +5943,9 @@ query_resume(query_ctx_t *qctx) { qctx->resuming = true; return (query_gotanswer(qctx, result)); + + cleanup: + return (result); } /*% @@ -6524,7 +6581,8 @@ query_usestale(query_ctx_t *qctx) { * result from the search. */ static isc_result_t -query_gotanswer(query_ctx_t *qctx, isc_result_t result) { +query_gotanswer(query_ctx_t *qctx, isc_result_t res) { + isc_result_t result = res; char errmsg[256]; CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer"); @@ -6624,6 +6682,9 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t result) { QUERY_ERROR(qctx, result); return (ns_query_done(qctx)); } + + cleanup: + return (result); } static void @@ -6922,6 +6983,9 @@ query_respond_any(query_ctx_t *qctx) { query_addauth(qctx); return (ns_query_done(qctx)); + + cleanup: + return (result); } /* @@ -7139,6 +7203,9 @@ query_respond(query_ctx_t *qctx) { query_addauth(qctx); return (ns_query_done(qctx)); + + cleanup: + return (result); } static isc_result_t @@ -7555,6 +7622,9 @@ query_notfound(query_ctx_t *qctx) { } return (query_delegation(qctx)); + + cleanup: + return (result); } /*% @@ -7563,6 +7633,7 @@ query_notfound(query_ctx_t *qctx) { */ static isc_result_t query_prepare_delegation_response(query_ctx_t *qctx) { + isc_result_t result; dns_rdataset_t **sigrdatasetp = NULL; bool detach = false; @@ -7605,6 +7676,9 @@ query_prepare_delegation_response(query_ctx_t *qctx) { query_addds(qctx); return (ns_query_done(qctx)); + + cleanup: + return (result); } /*% @@ -7698,6 +7772,9 @@ query_zone_delegation(query_ctx_t *qctx) { } return (query_prepare_delegation_response(qctx)); + + cleanup: + return (result); } /*% @@ -7823,6 +7900,9 @@ query_delegation(query_ctx_t *qctx) { } return (query_prepare_delegation_response(qctx)); + + cleanup: + return (result); } /*% @@ -7963,7 +8043,9 @@ query_addds(query_ctx_t *qctx) { * Handle authoritative NOERROR/NODATA responses. */ static isc_result_t -query_nodata(query_ctx_t *qctx, isc_result_t result) { +query_nodata(query_ctx_t *qctx, isc_result_t res) { + isc_result_t result = res; + PROCESS_HOOK(NS_QUERY_NODATA_BEGIN, qctx); #ifdef dns64_bis_return_excluded_addresses @@ -8074,6 +8156,9 @@ query_nodata(query_ctx_t *qctx, isc_result_t result) { } return (ns_query_done(qctx)); + + cleanup: + return (result); } /*% @@ -8347,6 +8432,9 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { qctx->client->message->rcode = dns_rcode_nxdomain; return (ns_query_done(qctx)); + + cleanup: + return (result); } /* @@ -9282,6 +9370,9 @@ query_cname(query_ctx_t *qctx) { query_addauth(qctx); return (ns_query_done(qctx)); + + cleanup: + return (result); } /* @@ -9430,6 +9521,9 @@ query_dname(query_ctx_t *qctx) { query_addauth(qctx); return (ns_query_done(qctx)); + + cleanup: + return (result); } /*% @@ -9511,6 +9605,8 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { */ static isc_result_t query_prepresponse(query_ctx_t *qctx) { + isc_result_t result = ISC_R_SUCCESS; + PROCESS_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx); if (WANTDNSSEC(qctx->client) && @@ -9524,9 +9620,12 @@ query_prepresponse(query_ctx_t *qctx) { if (qctx->type == dns_rdatatype_any) { return (query_respond_any(qctx)); - } else { - return (query_respond(qctx)); } + + return (query_respond(qctx)); + + cleanup: + return (result); } /*% @@ -10396,6 +10495,7 @@ query_glueanswer(query_ctx_t *qctx) { isc_result_t ns_query_done(query_ctx_t *qctx) { + isc_result_t result; const dns_namelist_t *secs = qctx->client->message->sections; CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done"); @@ -10501,6 +10601,9 @@ ns_query_done(query_ctx_t *qctx) { ns_client_detach(&qctx->client); return (qctx->result); + + cleanup: + return (result); } static inline void diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 355d175865..2532042e82 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -629,17 +629,17 @@ destroy_message: } /*% - * A hook callback which stores the query context pointed to by "hook_data" at - * "callback_data". Causes execution to be interrupted at hook insertion + * A hook action which stores the query context pointed to by "arg" at + * "data". Causes execution to be interrupted at hook insertion * point. */ static bool -extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) { +extract_qctx(void *arg, void *data, isc_result_t *resultp) { query_ctx_t **qctxp; query_ctx_t *qctx; - REQUIRE(hook_data != NULL); - REQUIRE(callback_data != NULL); + REQUIRE(arg != NULL); + REQUIRE(data != NULL); REQUIRE(resultp != NULL); /* @@ -649,10 +649,10 @@ extract_qctx(void *hook_data, void *callback_data, isc_result_t *resultp) { */ qctx = isc_mem_get(mctx, sizeof(*qctx)); if (qctx != NULL) { - memmove(qctx, (query_ctx_t *)hook_data, sizeof(*qctx)); + memmove(qctx, (query_ctx_t *)arg, sizeof(*qctx)); } - qctxp = (query_ctx_t **)callback_data; + qctxp = (query_ctx_t **)data; /* * If memory allocation failed, the supplied pointer will simply be set * to NULL. We rely on the user of this hook to react properly. @@ -674,8 +674,8 @@ static isc_result_t create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { ns_hooktable_t *saved_hook_table, query_hooks; ns_hook_t hook = { - .callback = extract_qctx, - .callback_data = qctxp, + .action = extract_qctx, + .action_data = qctxp, }; REQUIRE(client != NULL); @@ -691,7 +691,7 @@ create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { */ ns_hooktable_init(&query_hooks); - ns_hook_add(&query_hooks, NS_QUERY_QCTX_INITIALIZED, &hook); + ns_hook_add(&query_hooks, NS_QUERY_SETUP, &hook); saved_hook_table = ns__hook_table; ns__hook_table = &query_hooks; @@ -801,11 +801,10 @@ ns_test_qctx_destroy(query_ctx_t **qctxp) { } bool -ns_test_hook_catch_call(void *hook_data, void *callback_data, - isc_result_t *resultp) +ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp) { - UNUSED(hook_data); - UNUSED(callback_data); + UNUSED(arg); + UNUSED(data); *resultp = ISC_R_UNSET; diff --git a/lib/ns/tests/nstest.h b/lib/ns/tests/nstest.h index bc04487046..fc69befdc6 100644 --- a/lib/ns/tests/nstest.h +++ b/lib/ns/tests/nstest.h @@ -151,5 +151,4 @@ ns_test_qctx_destroy(query_ctx_t **qctxp); * A hook callback interrupting execution at given hook's insertion point. */ bool -ns_test_hook_catch_call(void *hook_data, void *callback_data, - isc_result_t *resultp); +ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp); diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index f8f59a23b3..4b7002ae9c 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -85,7 +85,7 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) { query_ctx_t *qctx = NULL; isc_result_t result; ns_hook_t hook = { - .callback = ns_test_hook_catch_call, + .action = ns_test_hook_catch_call, }; REQUIRE(test != NULL); @@ -282,7 +282,7 @@ run_start_test(const ns__query_start_test_params_t *test) { query_ctx_t *qctx = NULL; isc_result_t result; ns_hook_t hook = { - .callback = ns_test_hook_catch_call, + .action = ns_test_hook_catch_call, }; REQUIRE(test != NULL); From 427e9ca35725ffd03ef88391b90cd40c43c81eac Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 14 Sep 2018 12:32:36 -0700 Subject: [PATCH 12/26] clear AD flag when altering response messages - the AD flag was not being cleared correctly when filtering - enabled dnssec valdiation in the filter-aaaa test to confirm this works correctly now --- bin/hooks/Makefile.in | 12 -- bin/hooks/filter-aaaa.c | 90 +++++---- bin/hooks/filter-aaaa.docbook | 2 +- bin/named/server.c | 39 ++-- bin/tests/system/filter-aaaa/clean.sh | 3 + bin/tests/system/filter-aaaa/ns1/sign.sh | 15 +- .../system/filter-aaaa/ns2/named1.conf.in | 2 + .../system/filter-aaaa/ns2/named2.conf.in | 2 + .../system/filter-aaaa/ns3/named1.conf.in | 2 + .../system/filter-aaaa/ns3/named2.conf.in | 2 + bin/tests/system/filter-aaaa/ns4/sign.sh | 10 +- .../system/filter-aaaa/ns5/named.conf.in | 2 + bin/tests/system/filter-aaaa/tests.sh | 39 +++- lib/dns/adb.c | 2 +- lib/dns/include/dns/dyndb.h | 2 +- lib/isccfg/parser.c | 7 +- lib/ns/client.c | 1 + lib/ns/hooks.c | 182 ++++++++++-------- lib/ns/include/ns/client.h | 20 +- lib/ns/include/ns/hooks.h | 76 ++++++-- lib/ns/include/ns/query.h | 4 +- lib/ns/query.c | 91 ++++----- lib/ns/win32/libns.def | 2 +- 23 files changed, 340 insertions(+), 267 deletions(-) diff --git a/bin/hooks/Makefile.in b/bin/hooks/Makefile.in index 69e571d199..c6c8a915ad 100644 --- a/bin/hooks/Makefile.in +++ b/bin/hooks/Makefile.in @@ -11,16 +11,6 @@ srcdir = @srcdir@ VPATH = @srcdir@ top_srcdir = @top_srcdir@ -VERSION=@BIND9_VERSION@ - -@BIND9_PRODUCT@ - -@BIND9_DESCRIPTION@ - -@BIND9_SRCID@ - -@BIND9_CONFIGARGS@ - @BIND9_MAKE_INCLUDES@ CINCLUDES = -I${srcdir}/include -I${srcdir}/unix/include -I. \ @@ -40,8 +30,6 @@ TARGETS = @SO_TARGETS@ SO_OBJS = filter-aaaa.@O@ SO_SRCS = filter-aaaa.c -OBJS = - CFLAGS = @CFLAGS@ @SO_CFLAGS@ SO_LDFLAGS = @LDFLAGS@ @SO_LDFLAGS@ diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 174725eac2..e70c6c2bb9 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -13,29 +13,45 @@ #include +#include +#include +#include + +#include #include #include +#include #include +#include #include +#include #include #include +#include #include -#include - -#include -#include #include #include #include #include +#include -#define CHECK(r) \ - do { \ - result = (r); \ - if (result != ISC_R_SUCCESS) \ - goto cleanup; \ +#include +#include +#include +#include +#include +#include +#include +#include + +#define CHECK(op) \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + goto cleanup; \ + } \ } while (0) /* @@ -228,23 +244,20 @@ parse_parameters(const char *parameters, const void *cfg, } /** - ** Mandatory hook API functions. + ** Mandatory hook API functions: + ** + ** - hook_destroy + ** - hook_register + ** - hook_version **/ -/* - * Prototypes for the hook module API functions defined below. - */ -ns_hook_destroy_t hook_destroy; -ns_hook_register_t hook_register; -ns_hook_version_t hook_version; - /* * Called by ns_hookmodule_load() to register hook functions into * a hook table. */ isc_result_t hook_register(const unsigned int modid, const char *parameters, - const char *file, unsigned long line, + const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp) { @@ -254,20 +267,14 @@ hook_register(const unsigned int modid, const char *parameters, module_id = modid; - if (parameters != NULL) { - 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); + isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "loading 'filter-aaaa' " + "module from %s:%lu, %s parameters", + cfg_file, cfg_line, parameters != NULL ? "with" : "no"); + if (parameters != NULL) { CHECK(parse_parameters(parameters, cfg, actx, hctx)); - } else { - isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "loading 'filter-aaaa' " - "module from %s:%lu, no parameters", - file, line); } ns_hook_add(hooktable, NS_QUERY_QCTX_INITIALIZED, &filter_init); @@ -304,7 +311,7 @@ hook_register(const unsigned int modid, const char *parameters, } /* - * Called by ns_hookmodule_cleanup(); frees memory allocated by + * Called by ns_hookmodule_unload_all(); frees memory allocated by * the module when it was registered. */ void @@ -325,18 +332,16 @@ hook_destroy(void **instp) { * Returns hook module API version for compatibility checks. */ int -hook_version(unsigned int *flags) { - UNUSED(flags); - +hook_version(void) { return (NS_HOOK_VERSION); } /** - ** "filter-aaaa" feature implementation begins here + ** "filter-aaaa" feature implementation begins here. **/ /* - * Check whether this is a V4 client. + * Check whether this is an IPv4 client. */ static bool is_v4_client(ns_client_t *client) { @@ -352,7 +357,7 @@ is_v4_client(ns_client_t *client) { } /* - * Check whether this is a V6 client. + * Check whether this is an IPv6 client. */ static bool is_v6_client(ns_client_t *client) { @@ -389,7 +394,7 @@ filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp) { } /* - * Determine whether this client should have AAAA filtered nor not, + * Determine whether this client should have AAAA filtered or not, * based on the client address family and the settings of * filter-aaaa-on-v4 and filter-aaaa-on-v6. */ @@ -474,6 +479,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { * cached an A if it existed. */ if (result == ISC_R_SUCCESS) { + qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED; if (qctx->sigrdataset != NULL && dns_rdataset_isassociated(qctx->sigrdataset)) @@ -511,7 +517,6 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { ((qctx->client->hookflags[module_id] & FILTER_AAAA_RECURSING) != 0)) { - dns_rdataset_t *mrdataset = NULL; dns_rdataset_t *sigrdataset = NULL; @@ -520,6 +525,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { dns_rdatatype_aaaa, 0, NULL, &mrdataset); if (result == ISC_R_SUCCESS) { + qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; mrdataset->attributes |= DNS_RDATASETATTR_RENDERED; } @@ -529,6 +535,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { dns_rdatatype_aaaa, NULL, &sigrdataset); if (result == ISC_R_SUCCESS) { + qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; } @@ -593,6 +600,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || **mode == BREAK_DNSSEC)) { + qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; aaaa->attributes |= DNS_RDATASETATTR_RENDERED; if (aaaa_sig != NULL) { aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED; @@ -605,7 +613,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { /* * 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 + * and hide NS in the authority section if AAAA was filtered in the answer * section. */ static bool @@ -674,6 +682,8 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { result = dns_message_findtype(name, dns_rdatatype_ns, 0, &ns); if (result == ISC_R_SUCCESS) { + qctx->client->message->flags &= + ~DNS_MESSAGEFLAG_AD; ns->attributes |= DNS_RDATASETATTR_RENDERED; } diff --git a/bin/hooks/filter-aaaa.docbook b/bin/hooks/filter-aaaa.docbook index 3a0581e9cd..3a12e144c6 100644 --- a/bin/hooks/filter-aaaa.docbook +++ b/bin/hooks/filter-aaaa.docbook @@ -50,7 +50,7 @@ to omit some IPv6 addresses when responding to clients. - Until BIND 9.12, this feature was impleented natively in + Until BIND 9.12, this feature was implemented natively in named and enabled with the filter-aaaa ACL and the filter-aaaa-on-v4 and diff --git a/bin/named/server.c b/bin/named/server.c index 0fa0f7da31..cd9ceb55ae 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1544,6 +1544,7 @@ configure_hook(ns_hooktable_t *hooktable, const unsigned int modid, isc_result_t result = ISC_R_SUCCESS; const cfg_obj_t *obj; const char *type, *library; + const char *parameters = NULL; /* Get the path to the hook module. */ obj = cfg_tuple_get(hook, "type"); @@ -1560,22 +1561,12 @@ configure_hook(ns_hooktable_t *hooktable, const unsigned int modid, obj = cfg_tuple_get(hook, "parameters"); if (obj != NULL && cfg_obj_isstring(obj)) { - result = ns_hookmodule_load(library, modid, - cfg_obj_asstring(obj), - cfg_obj_file(obj), - cfg_obj_line(obj), - config, - named_g_aclconfctx, - hctx, hooktable); - } else { - result = ns_hookmodule_load(library, modid, NULL, - cfg_obj_file(hook), - cfg_obj_line(hook), - config, - named_g_aclconfctx, - hctx, hooktable); + parameters = cfg_obj_asstring(obj); } - + result = ns_hookmodule_load(library, modid, parameters, + cfg_obj_file(obj), cfg_obj_line(obj), + config, named_g_aclconfctx, + hctx, hooktable); if (result != ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, @@ -5318,6 +5309,16 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, } #ifdef HAVE_DLOPEN + if (hook_list != NULL) { + const void *hashinit = isc_hash_get_initializer(); + CHECK(ns_hook_createctx(mctx, hashinit, &hctx)); + + INSIST(view->hooktable == NULL); + CHECK(ns_hooktable_create(view->mctx, + (ns_hooktable_t **) &view->hooktable)); + view->hooktable_free = ns_hooktable_free; + } + for (element = cfg_list_first(hook_list); element != NULL; element = cfg_list_next(element)) @@ -5325,8 +5326,8 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, const cfg_obj_t *hook = cfg_listelt_value(element); if (view->hooktable == NULL) { - ns_hooktable_create(view->mctx, - (ns_hooktable_t **) &view->hooktable); + CHECK(ns_hooktable_create(view->mctx, + (ns_hooktable_t **) &view->hooktable)); view->hooktable_free = ns_hooktable_free; } @@ -8080,7 +8081,7 @@ load_configuration(const char *filename, named_server_t *server, * Shut down all dyndb and hook module instances. */ dns_dyndb_cleanup(false); - ns_hookmodule_cleanup(); + ns_hookmodule_unload_all(); /* * Parse the global default pseudo-config file. @@ -9565,7 +9566,7 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { * Shut down all dyndb and hook module instances. */ dns_dyndb_cleanup(true); - ns_hookmodule_cleanup(); + ns_hookmodule_unload_all(); while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { ISC_LIST_UNLINK(server->cachelist, nsc, link); diff --git a/bin/tests/system/filter-aaaa/clean.sh b/bin/tests/system/filter-aaaa/clean.sh index a282093ff2..852010f519 100644 --- a/bin/tests/system/filter-aaaa/clean.sh +++ b/bin/tests/system/filter-aaaa/clean.sh @@ -26,3 +26,6 @@ rm -f ns4/dsset-* rm -f dig.out.* rm -f ns*/named.lock rm -f ns*/managed-keys.bind* + +rm -f ns*/trusted.conf +rm -f ns*/keygen.out diff --git a/bin/tests/system/filter-aaaa/ns1/sign.sh b/bin/tests/system/filter-aaaa/ns1/sign.sh index 2b75296ec1..71da6a751e 100755 --- a/bin/tests/system/filter-aaaa/ns1/sign.sh +++ b/bin/tests/system/filter-aaaa/ns1/sign.sh @@ -21,10 +21,15 @@ infile=signed.db.in zonefile=signed.db.signed outfile=signed.db.signed -keyname1=`$KEYGEN -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null` -keyname2=`$KEYGEN -f KSK -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null` +$KEYGEN -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i +$KEYGEN -f KSK -a $DEFAULT_ALGORITHM $zone 2>&1 > keygen.out | cat_i +keyname=`cat keygen.out` +rm -f keygen.out -cat $infile $keyname1.key $keyname2.key >$zonefile +keyfile_to_trusted_keys $keyname > trusted.conf +cp trusted.conf ../ns2/trusted.conf +cp trusted.conf ../ns3/trusted.conf +cp trusted.conf ../ns5/trusted.conf -$SIGNER -o $zone -f $outfile $zonefile > /dev/null 2> signer.err || cat signer.err -echo_i "signed $zone" +$SIGNER -S -o $zone -f $outfile $infile > /dev/null 2> signer.err || cat signer.err +echo_i "signed zone '$zone'" diff --git a/bin/tests/system/filter-aaaa/ns2/named1.conf.in b/bin/tests/system/filter-aaaa/ns2/named1.conf.in index 5d9aeec8a4..0f48645932 100644 --- a/bin/tests/system/filter-aaaa/ns2/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named1.conf.in @@ -38,3 +38,5 @@ controls { }; zone "." { type hint; file "hints"; }; + +include "trusted.conf"; diff --git a/bin/tests/system/filter-aaaa/ns2/named2.conf.in b/bin/tests/system/filter-aaaa/ns2/named2.conf.in index a313403c98..18399cf08a 100644 --- a/bin/tests/system/filter-aaaa/ns2/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named2.conf.in @@ -38,3 +38,5 @@ controls { }; zone "." { type hint; file "hints"; }; + +include "trusted.conf"; diff --git a/bin/tests/system/filter-aaaa/ns3/named1.conf.in b/bin/tests/system/filter-aaaa/ns3/named1.conf.in index 7c24809a0c..2433c80d85 100644 --- a/bin/tests/system/filter-aaaa/ns3/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named1.conf.in @@ -38,3 +38,5 @@ controls { }; zone "." { type hint; file "hints"; }; + +include "trusted.conf"; diff --git a/bin/tests/system/filter-aaaa/ns3/named2.conf.in b/bin/tests/system/filter-aaaa/ns3/named2.conf.in index cd5df44938..479d437980 100644 --- a/bin/tests/system/filter-aaaa/ns3/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named2.conf.in @@ -38,3 +38,5 @@ controls { }; zone "." { type hint; file "hints"; }; + +include "trusted.conf"; diff --git a/bin/tests/system/filter-aaaa/ns4/sign.sh b/bin/tests/system/filter-aaaa/ns4/sign.sh index 2b75296ec1..20cc4a3f1b 100755 --- a/bin/tests/system/filter-aaaa/ns4/sign.sh +++ b/bin/tests/system/filter-aaaa/ns4/sign.sh @@ -21,10 +21,8 @@ infile=signed.db.in zonefile=signed.db.signed outfile=signed.db.signed -keyname1=`$KEYGEN -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null` -keyname2=`$KEYGEN -f KSK -a $DEFAULT_ALGORITHM -b $DEFAULT_BITS -n zone $zone 2> /dev/null` +$KEYGEN -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i +$KEYGEN -f KSK -a $DEFAULT_ALGORITHM $zone 2>&1 > /dev/null | cat_i -cat $infile $keyname1.key $keyname2.key >$zonefile - -$SIGNER -o $zone -f $outfile $zonefile > /dev/null 2> signer.err || cat signer.err -echo_i "signed $zone" +$SIGNER -S -o $zone -f $outfile $infile > /dev/null 2> signer.err || cat signer.err +echo_i "signed zone '$zone'" diff --git a/bin/tests/system/filter-aaaa/ns5/named.conf.in b/bin/tests/system/filter-aaaa/ns5/named.conf.in index df507b3016..b97ab1cafd 100644 --- a/bin/tests/system/filter-aaaa/ns5/named.conf.in +++ b/bin/tests/system/filter-aaaa/ns5/named.conf.in @@ -43,3 +43,5 @@ controls { }; zone "." { type hint; file "hints"; }; + +include "trusted.conf"; diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh index 86d0c7cb7b..4ff2ebe3a2 100644 --- a/bin/tests/system/filter-aaaa/tests.sh +++ b/bin/tests/system/filter-aaaa/tests.sh @@ -199,7 +199,6 @@ else echo_i "skipped." fi - # # Authoritative tests against: # filter-aaaa-on-v4 break-dnssec; @@ -380,6 +379,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)" ret=0 $DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 grep ::2 dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -397,6 +397,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -406,6 +407,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -414,6 +416,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)" ret=0 $DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 grep ::3 dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -423,6 +426,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -461,6 +465,7 @@ echo_i "checking that both A and AAAA are returned when both AAAA and A records ret=0 $DIG $DIGOPTS any dual.signed +dnssec -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 grep ::3 dig.out.ns2.test$n > /dev/null || ret=1 grep "1.0.0.3" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi @@ -509,7 +514,7 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` n=`expr $n + 1` -echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned ($n)" +echo_i "checking that AAAA is omitted from additional section, qtype=MX, unsigned, recursive ($n)" ret=0 $DIG $DIGOPTS +add +dnssec mx unsigned -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 grep "^mx.unsigned.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 && ret=1 @@ -517,15 +522,21 @@ if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` n=`expr $n + 1` -echo_i "checking that AAAA is included in additional section, qtype=MX, signed ($n)" +echo_i "checking that AAAA is included in additional section, qtype=MX, signed, recursive ($n)" ret=0 +# we need to prime the cache with addresses for the MX, since additional +# section data won't be included unless it's validated, and that doesn't +# necessarily happen otherwise. +$DIG $DIGOPTS +dnssec mx.signed @10.53.0.2 > /dev/null +$DIG $DIGOPTS +dnssec mx.signed aaaa @10.53.0.2 > /dev/null $DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.2 @10.53.0.2 > dig.out.ns2.test$n || ret=1 grep "^mx.signed.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` n=`expr $n + 1` -echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, over IPv6 ($n)" +echo_i "checking that AAAA is included in additional section, qtype=MX, unsigned, recursive, over IPv6 ($n)" if $TESTSOCK6 fd92:7065:b8e:ffff::2 then ret=0 @@ -537,7 +548,6 @@ else echo_i "skipped." fi - # # Recursive tests against: # filter-aaaa-on-v4 break-dnssec; @@ -547,6 +557,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)" ret=0 $DIG $DIGOPTS aaaa aaaa-only.signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1 grep ::2 dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -564,6 +575,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -573,6 +585,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -582,6 +595,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.signed +dnssec -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -590,6 +604,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned +dnssec -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -688,6 +703,7 @@ echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, ret=0 $DIG $DIGOPTS +add +dnssec mx signed -b 10.53.0.3 @10.53.0.3 > dig.out.ns3.test$n || ret=1 grep "^mx.signed.*AAAA" dig.out.ns3.test$n > /dev/null 2>&1 && ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1047,6 +1063,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive ($n)" ret=0 $DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 grep ::2 dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1064,6 +1081,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1073,6 +1091,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1081,6 +1100,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is returned when both AAAA and A records exist, signed and DO set, recursive ($n)" ret=0 $DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 grep ::3 dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1090,6 +1110,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 grep "ANSWER: 0" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1128,6 +1149,7 @@ echo_i "checking that both A and AAAA are returned when both AAAA and A records ret=0 $DIG $DIGOPTS any dual.signed +dnssec -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 grep "status: NOERROR" dig.out.ns2.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 grep ::3 dig.out.ns2.test$n > /dev/null || ret=1 grep "1.0.0.3" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi @@ -1183,6 +1205,7 @@ echo_i "checking that AAAA is included in additional section, qtype=MX, signed ( ret=0 $DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::2 @fd92:7065:b8e:ffff::2 > dig.out.ns2.test$n || ret=1 grep "^mx.signed.*AAAA" dig.out.ns2.test$n > /dev/null 2>&1 || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns2.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1204,6 +1227,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is returned when only AAAA record exists, signed, recursive with break-dnssec ($n)" ret=0 $DIG $DIGOPTS aaaa aaaa-only.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1 grep ::2 dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1221,6 +1245,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1230,6 +1255,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1239,6 +1265,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.signed +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1247,6 +1274,7 @@ echo_i "checking that NODATA/NOERROR is returned when both AAAA and A records ex ret=0 $DIG $DIGOPTS aaaa dual.unsigned +dnssec -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1 grep "ANSWER: 0" dig.out.ns3.test$n > /dev/null || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null && ret=1 grep "status: NOERROR" dig.out.ns3.test$n > /dev/null || ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` @@ -1339,6 +1367,7 @@ n=`expr $n + 1` echo_i "checking that AAAA is omitted from additional section, qtype=MX, signed, recursive with break-dnssec ($n)" ret=0 $DIG $DIGOPTS +add +dnssec mx signed -b fd92:7065:b8e:ffff::3 @fd92:7065:b8e:ffff::3 > dig.out.ns3.test$n || ret=1 +grep "flags:.*ad.*QUERY" dig.out.ns3.test$n > /dev/null || ret=1 grep "^mx.signed.*AAAA" dig.out.ns3.test$n > /dev/null 2>&1 && ret=1 if [ $ret != 0 ]; then echo_i "failed"; fi status=`expr $status + $ret` diff --git a/lib/dns/adb.c b/lib/dns/adb.c index ac0ab18fc5..b3a124fb03 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -2589,7 +2589,7 @@ dns_adb_create(isc_mem_t *mem, dns_view_t *view, isc_timermgr_t *timermgr, result = isc_taskmgr_excltask(adb->taskmgr, &adb->excl); if (result != ISC_R_SUCCESS) { DP(DEF_LEVEL, "adb: task-exclusive mode unavailable, " - "intializing table sizes to %u\n", + "initializing table sizes to %u\n", nbuckets[11]); adb->nentries = nbuckets[11]; adb->nnames = nbuckets[11]; diff --git a/lib/dns/include/dns/dyndb.h b/lib/dns/include/dns/dyndb.h index d5faf92069..015f8efab8 100644 --- a/lib/dns/include/dns/dyndb.h +++ b/lib/dns/include/dns/dyndb.h @@ -22,7 +22,7 @@ ISC_LANG_BEGINDECLS /*! * \brief - * Context for intializing a dyndb module. + * Context for initializing a dyndb module. * * This structure passes global server data to which a dyndb * module will need access -- the server memory context, hash diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index 5af9ae2228..eea80b2789 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -1326,10 +1326,6 @@ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_text = { &cfg_rep_string, NULL }; -/*% - * A bracketed address match list - */ - static cfg_type_t cfg_type_addrmatchelt; static cfg_type_t cfg_type_negated; @@ -1416,6 +1412,9 @@ static cfg_type_t cfg_type_addrmatchelt = { NULL, NULL }; +/*% + * A bracketed address match list + */ LIBISCCFG_EXTERNAL_DATA cfg_type_t cfg_type_bracketed_aml = { "bracketed_aml", cfg_parse_bracketed_list, cfg_print_bracketed_list, cfg_doc_bracketed_list, &cfg_rep_list, &cfg_type_addrmatchelt diff --git a/lib/ns/client.c b/lib/ns/client.c index 7739905d04..1c45094833 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -4044,6 +4044,7 @@ ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf) { REQUIRE((client->query.attributes & NS_QUERYATTR_NAMEBUFUSED) == 0); CTRACE("ns_client_newname"); + name = NULL; result = dns_message_gettempname(client->message, &name); if (result != ISC_R_SUCCESS) { diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 7f0ab4d4a2..d94cfdfdcd 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -21,33 +21,40 @@ #include #endif +#include +#include #include #include #include -#include +#include #include +#include #include #include +#include #define CHECK(op) \ - do { result = (op); \ - if (result != ISC_R_SUCCESS) goto cleanup; \ + do { \ + result = (op); \ + if (result != ISC_R_SUCCESS) { \ + goto cleanup; \ + } \ } while (0) typedef struct ns_hook_module ns_hook_module_t; struct ns_hook_module { isc_mem_t *mctx; void *handle; - char *filename; + char *modpath; ns_hook_register_t *register_func; ns_hook_destroy_t *destroy_func; void *inst; LINK(ns_hook_module_t) link; }; -static ns_hooklist_t hooktab[NS_QUERY_HOOKS_COUNT]; -LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &hooktab; +static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT]; +LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable; /* * List of hook modules. @@ -55,40 +62,40 @@ LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &hooktab; * These are stored here so they can be cleaned up on shutdown. * (The order in which they are stored is not important.) */ -static LIST(ns_hook_module_t) hook_modules; - -static isc_once_t once = ISC_ONCE_INIT; - -static void -init_modules(void) { - INIT_LIST(hook_modules); -} +static ISC_LIST(ns_hook_module_t) hook_modules; +static bool hook_modules_initialized = false; #if HAVE_DLFCN_H && HAVE_DLOPEN static isc_result_t -load_symbol(void *handle, const char *filename, +load_symbol(void *handle, const char *modpath, const char *symbol_name, void **symbolp) { - const char *errmsg; void *symbol; REQUIRE(handle != NULL); REQUIRE(symbolp != NULL && *symbolp == NULL); + /* + * Clear any pre-existing error conditions before running dlsym(). + * (In this case, we expect dlsym() to return non-NULL values + * and will always return an error if it returns NULL, but + * this ensures that we'll report the correct error condition + * if there is one.) + */ + dlerror(); symbol = dlsym(handle, symbol_name); if (symbol == NULL) { - errmsg = dlerror(); + const char *errmsg = dlerror(); if (errmsg == NULL) { errmsg = "returned function pointer is NULL"; } isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "failed to look upsymbol %s in " + "failed to look up symbol %s in " "hook module '%s': %s", - symbol_name, filename, errmsg); + symbol_name, modpath, errmsg); return (ISC_R_FAILURE); } - dlerror(); *symbolp = symbol; @@ -96,7 +103,7 @@ load_symbol(void *handle, const char *filename, } static isc_result_t -load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { +load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { isc_result_t result; void *handle = NULL; ns_hook_module_t *hmod = NULL; @@ -107,45 +114,50 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { REQUIRE(hmodp != NULL && *hmodp == NULL); - flags = RTLD_NOW|RTLD_LOCAL; + flags = RTLD_NOW | RTLD_LOCAL; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; #endif - handle = dlopen(filename, flags); + handle = dlopen(modpath, flags); if (handle == NULL) { - CHECK(ISC_R_FAILURE); + const char *errmsg = dlerror(); + if (errmsg == NULL) { + errmsg = "unknown error"; + } + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, + "failed to dlopen() hook module '%s': %s", + modpath, errmsg); + return (ISC_R_FAILURE); } - /* Clear dlerror */ - dlerror(); - - CHECK(load_symbol(handle, filename, "hook_version", + CHECK(load_symbol(handle, modpath, "hook_version", (void **)&version_func)); - version = version_func(NULL); + version = version_func(); if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || version > NS_HOOK_VERSION) { isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "driver API version mismatch: %d/%d", + "hook API version mismatch: %d/%d", version, NS_HOOK_VERSION); CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, filename, "hook_register", + CHECK(load_symbol(handle, modpath, "hook_register", (void **)®ister_func)); - CHECK(load_symbol(handle, filename, "hook_destroy", + CHECK(load_symbol(handle, modpath, "hook_destroy", (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); hmod->mctx = NULL; isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; + hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); hmod->register_func = register_func; hmod->destroy_func = destroy_func; - hmod->inst = NULL; ISC_LINK_INIT(hmod, link); @@ -158,16 +170,15 @@ cleanup: isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to dynamically load " - "module '%s': %s (%s)", filename, - dlerror(), isc_result_totext(result)); + "module '%s': %s", modpath, + isc_result_totext(result)); if (hmod != NULL) { - isc_mem_putanddetach(&hmod->mctx, hmod, - sizeof(*hmod)); + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); } if (handle != NULL) { - dlclose(handle); + (void) dlclose(handle); } } @@ -184,17 +195,17 @@ unload_library(ns_hook_module_t **hmodp) { *hmodp = NULL; if (hmod->handle != NULL) { - dlclose(hmod->handle); + (void) dlclose(hmod->handle); } - if (hmod->filename != NULL) { - isc_mem_free(hmod->mctx, hmod->filename); + if (hmod->modpath != NULL) { + isc_mem_free(hmod->mctx, hmod->modpath); } isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); } #elif _WIN32 static isc_result_t -load_symbol(HMODULE handle, const char *filename, +load_symbol(HMODULE handle, const char *modpath, const char *symbol_name, void **symbolp) { void *symbol; @@ -209,7 +220,7 @@ load_symbol(HMODULE handle, const char *filename, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to look up symbol %s in " "module '%s': %d", - symbol_name, filename, errstatus); + symbol_name, modpath, errstatus); return (ISC_R_FAILURE); } @@ -219,7 +230,7 @@ load_symbol(HMODULE handle, const char *filename, } static isc_result_t -load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { +load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { isc_result_t result; HMODULE handle; ns_hook_module_t *hmod = NULL; @@ -230,12 +241,12 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { REQUIRE(hmodp != NULL && *hmodp == NULL); - handle = LoadLibraryA(filename); + handle = LoadLibraryA(modpath); if (handle == NULL) { CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, filename, "hook_version", + CHECK(load_symbol(handle, modpath, "hook_version", (void **)&version_func)); version = version_func(NULL); @@ -244,23 +255,23 @@ load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { { isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "driver API version mismatch: %d/%d", + "hook API version mismatch: %d/%d", version, NS_HOOK_VERSION); CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, filename, "hook_register", + CHECK(load_symbol(handle, modpath, "hook_register", (void **)®ister_func)); - CHECK(load_symbol(handle, filename, "hook_destroy", + CHECK(load_symbol(handle, modpath, "hook_destroy", (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); hmod->mctx = NULL; isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; + hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); hmod->register_func = register_func; hmod->destroy_func = destroy_func; - hmod->inst = NULL; ISC_LINK_INIT(hmod, link); @@ -273,11 +284,11 @@ cleanup: isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to dynamically load " - "hook module '%s': %d (%s)", filename, + "hook module '%s': %d (%s)", modpath, GetLastError(), isc_result_totext(result)); + if (hmod != NULL) { - isc_mem_putanddetach(&hmod->mctx, hmod, - sizeof(*hmod)); + isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); } if (handle != NULL) { @@ -301,22 +312,22 @@ unload_library(ns_hook_module_t **hmodp) { FreeLibrary(hmod->handle); } - if (hmod->filename != NULL) { - isc_mem_free(hmod->mctx, hmod->filename); + if (hmod->modpath != NULL) { + isc_mem_free(hmod->mctx, hmod->modpath); } isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); } #else /* HAVE_DLFCN_H || _WIN32 */ static isc_result_t -load_library(isc_mem_t *mctx, const char *filename, ns_hook_module_t **hmodp) { +load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { UNUSED(mctx); - UNUSED(filename); + UNUSED(modpath); UNUSED(hmodp); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "hook module support is not hmodlemented"); + "hook module support is not implemented"); return (ISC_R_NOTIMPLEMENTED); } @@ -328,50 +339,53 @@ unload_library(ns_hook_module_t **hmodp) { #endif /* HAVE_DLFCN_H */ isc_result_t -ns_hookmodule_load(const char *libname, const unsigned int modid, +ns_hookmodule_load(const char *modpath, const unsigned int modid, const char *parameters, - const char *file, unsigned long line, + const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable) { isc_result_t result; - ns_hook_module_t *module = NULL; + ns_hook_module_t *hmod = NULL; + REQUIRE(hook_modules_initialized); REQUIRE(NS_HOOKCTX_VALID(hctx)); + REQUIRE(hooktable != NULL); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "loading module '%s'", libname); + "loading module '%s'", modpath); - CHECK(load_library(hctx->mctx, libname, &module)); - CHECK(module->register_func(modid, parameters, file, line, - cfg, actx, hctx, hooktable, - &module->inst)); + CHECK(load_library(hctx->mctx, modpath, &hmod)); + CHECK(hmod->register_func(modid, parameters, cfg_file, cfg_line, + cfg, actx, hctx, hooktable, + &hmod->inst)); - APPEND(hook_modules, module, link); - result = ISC_R_SUCCESS; + ISC_LIST_APPEND(hook_modules, hmod, link); cleanup: - if (result != ISC_R_SUCCESS && module != NULL) { - unload_library(&module); + if (result != ISC_R_SUCCESS && hmod != NULL) { + unload_library(&hmod); } return (result); } void -ns_hookmodule_cleanup(void) { +ns_hookmodule_unload_all(void) { ns_hook_module_t *hmod, *prev; - RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); + if (!hook_modules_initialized) { + return; + } hmod = ISC_LIST_TAIL(hook_modules); while (hmod != NULL) { - prev = PREV(hmod, link); - UNLINK(hook_modules, hmod, link); + prev = ISC_LIST_PREV(hmod, link); + ISC_LIST_UNLINK(hook_modules, hmod, link); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "unloading module '%s'", hmod->filename); + "unloading module '%s'", hmod->modpath); hmod->destroy_func(&hmod->inst); ENSURE(hmod->inst == NULL); unload_library(&hmod); @@ -408,8 +422,6 @@ ns_hook_destroyctx(ns_hookctx_t **hctxp) { hctx->magic = 0; - hctx->lctx = NULL; - isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx)); } @@ -417,9 +429,12 @@ void ns_hooktable_init(ns_hooktable_t *hooktable) { int i; - RUNTIME_CHECK(isc_once_do(&once, init_modules) == ISC_R_SUCCESS); + if (!hook_modules_initialized) { + ISC_LIST_INIT(hook_modules); + hook_modules_initialized = true; + } - for (i = 0; i < NS_QUERY_HOOKS_COUNT; i++) { + for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) { ISC_LIST_INIT((*hooktable)[i]); } } @@ -430,7 +445,7 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { REQUIRE(tablep != NULL && *tablep == NULL); - hooktable = isc_mem_get(mctx, sizeof(ns_hooktable_t)); + hooktable = isc_mem_get(mctx, sizeof(*hooktable)); ns_hooktable_init(hooktable); @@ -441,17 +456,20 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { void ns_hooktable_free(isc_mem_t *mctx, void **tablep) { + ns_hooktable_t *table; + REQUIRE(tablep != NULL && *tablep != NULL); - isc_mem_put(mctx, *tablep, sizeof(ns_hooktable_t)); + table = *tablep; *tablep = NULL; + isc_mem_put(mctx, table, sizeof(*table)); } void ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, ns_hook_t *hook) { - REQUIRE(hookpoint < NS_QUERY_HOOKS_COUNT); + REQUIRE(hookpoint < NS_HOOKPOINTS_COUNT); REQUIRE(hook != NULL); if (hooktable == NULL) { diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index ea209d6b5f..6d030c3180 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -191,7 +191,7 @@ typedef ISC_LIST(ns_client_t) client_list_t; #define NS_CLIENTATTR_WANTDNSSEC 0x00010 /*%< include dnssec records */ #define NS_CLIENTATTR_WANTNSID 0x00020 /*%< include nameserver ID */ /* Obsolete: NS_CLIENTATTR_FILTER_AAAA 0x00040 */ -/* Obsolete: define NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */ +/* Obsolete: NS_CLIENTATTR_FILTER_AAAA_RC 0x00080 */ #define NS_CLIENTATTR_WANTAD 0x00100 /*%< want AD in response if possible */ #define NS_CLIENTATTR_WANTCOOKIE 0x00200 /*%< return a COOKIE */ #define NS_CLIENTATTR_HAVECOOKIE 0x00400 /*%< has a valid COOKIE */ @@ -438,39 +438,39 @@ ns_client_newrdataset(ns_client_t *client); void ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp); -/*% +/*%< * Get and release temporary rdatasets in the client message; * used in query.c and in hook modules. */ isc_result_t ns_client_newnamebuf(ns_client_t *client); -/*% +/*%< * Allocate a name buffer for the client message. */ dns_name_t * ns_client_newname(ns_client_t *client, isc_buffer_t *dbuf, isc_buffer_t *nbuf); -/*% +/*%< * Get a temporary name for the client message. */ isc_buffer_t * ns_client_getnamebuf(ns_client_t *client); -/*% +/*%< * Get a name buffer from the pool, or allocate a new one if needed. */ void ns_client_keepname(ns_client_t *client, dns_name_t *name, isc_buffer_t *dbuf); -/*% +/*%< * Adjust buffer 'dbuf' to reflect that 'name' is using space in it, * and set client attributes appropriately. */ void ns_client_releasename(ns_client_t *client, dns_name_t **namep); -/*% +/*%< * Release 'name' back to the pool of temporary names for the client * message. If it is using a name buffer, relinquish its exclusive * rights on the buffer. @@ -478,20 +478,20 @@ ns_client_releasename(ns_client_t *client, dns_name_t **namep); isc_result_t ns_client_newdbversion(ns_client_t *client, unsigned int n); -/*% +/*%< * Allocate 'n' new database versions for use by client queries. */ ns_dbversion_t * ns_client_getdbversion(ns_client_t *client); -/*% +/*%< * Get a free database version for use by a client query, allocating * a new one if necessary. */ ns_dbversion_t * ns_client_findversion(ns_client_t *client, dns_db_t *db); -/*% +/*%< * Find the correct database version to use with a client query. * If we have already done a query related to the database 'db', * make sure subsequent queries are from the same version; diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 760292f0cc..10c68d2a95 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -162,7 +162,14 @@ * called this time and foo_bar() will return ISC_R_SUCCESS. */ +/*! + * Currently-defined hook points. So long as these are unique, + * the order in which they are declared is unimportant, but + * currently matches the order in which they are referenced in + * query.c. + */ typedef enum { + /* hookpoints from query.c */ NS_QUERY_QCTX_INITIALIZED, NS_QUERY_QCTX_DESTROYED, NS_QUERY_SETUP, @@ -186,7 +193,9 @@ typedef enum { NS_QUERY_DONE_BEGIN, NS_QUERY_DONE_SEND, - NS_QUERY_HOOKS_COUNT /* MUST BE LAST */ + /* XXX other files could be added later */ + + NS_HOOKPOINTS_COUNT /* MUST BE LAST */ } ns_hookpoint_t; typedef bool @@ -199,16 +208,16 @@ typedef struct ns_hook { } ns_hook_t; typedef ISC_LIST(ns_hook_t) ns_hooklist_t; -typedef ns_hooklist_t ns_hooktable_t[NS_QUERY_HOOKS_COUNT]; +typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT]; -/* +/*% * ns__hook_table is a global hook table, which is used if view->hooktable * is NULL. It's intended only for use by unit tests. */ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; /*! - * Context for intializing a hook module. + * Context for initializing a hook module. * * This structure passes data to which a hook module will need * access -- server memory context, hash initializer, log context, etc. @@ -223,7 +232,8 @@ typedef struct ns_hookctx { } 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) +#define NS_HOOKCTX_VALID(h) ISC_MAGIC_VALID(h, NS_HOOKCTX_MAGIC) + /* * API version * @@ -246,7 +256,7 @@ typedef isc_result_t ns_hook_register_t(const unsigned int modid, ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp); -/*% +/*%< * Called when registering a new module. * * 'parameters' contains the module configuration text. @@ -261,43 +271,68 @@ typedef isc_result_t ns_hook_register_t(const unsigned int modid, */ typedef void ns_hook_destroy_t(void **instp); -/*% +/*%< * Destroy a module instance. * * '*instp' must be set to NULL by the function before it returns. */ -typedef int ns_hook_version_t(unsigned int *flags); -/*% +typedef int ns_hook_version_t(void); +/*%< * Return the API version number a hook module was compiled with. * - * If the returned version number is no greater than than + * If the returned version number is no greater than * NS_HOOK_VERSION, and no less than NS_HOOK_VERSION - NS_HOOK_AGE, * then the module is API-compatible with named. - * - * 'flags' is currently unused and may be NULL, but could be used in - * the future to pass back driver capabilities or other information. */ +/*% + * Prototypes for API functions to be defined in each module. + */ +ns_hook_destroy_t hook_destroy; +ns_hook_register_t hook_register; +ns_hook_version_t hook_version; + isc_result_t ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp); void ns_hook_destroyctx(ns_hookctx_t **hctxp); +/*%< + * Create/destroy a hook module context. + */ isc_result_t -ns_hookmodule_load(const char *libname, const unsigned int modid, +ns_hookmodule_load(const char *modpath, const unsigned int modid, const char *parameters, - const char *file, unsigned long line, + const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable); +/*%< + * Load the hook module specified from the file 'modpath', using + * parameters 'parameters'. + * + * 'cfg_file' and 'cfg_line' specify the location of the hook module + * declaration in the configuration file. + * + * 'cfg' and 'actx' are the configuration context and ACL configuration + * context, respectively; they are passed as void * here in order to + * prevent this library from having a dependency on libisccfg). + * + * 'hctx' is the hook context and 'hooktable' is the hook table + * into which hook points should be registered. + */ + void -ns_hookmodule_cleanup(void); +ns_hookmodule_unload_all(void); +/*%< + * Unload all currently loaded hook modules. + */ void ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, ns_hook_t *hook); -/*% +/*%< * Append hook function 'hook' to the list of hooks at 'hookpoint' in * 'hooktable'. * @@ -310,21 +345,20 @@ ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, void ns_hooktable_init(ns_hooktable_t *hooktable); -/*% +/*%< * Initialize a hook table. */ isc_result_t ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep); -/*% +/*%< * Allocate and initialize a hook table. */ void ns_hooktable_free(isc_mem_t *mctx, void **tablep); -/*% +/*%< * Free a hook table. */ - #endif /* NS_HOOKS_H */ diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index 987dfe804d..b3fc3a742c 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -252,13 +252,13 @@ ns_query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qname, 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.) */ diff --git a/lib/ns/query.c b/lib/ns/query.c index 5de1f2b1f2..fd41929ba5 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -264,7 +264,7 @@ get_hooktab(query_ctx_t *qctx) { * is a macro instead of an inline function; it needs to be able to use * 'goto cleanup' regardless of the return value.) */ -#define PROCESS_HOOK(_id, _qctx) \ +#define CALL_HOOK(_id, _qctx) \ do { \ isc_result_t _res; \ ns_hooktable_t *_tab = get_hooktab(_qctx); \ @@ -290,9 +290,9 @@ get_hooktab(query_ctx_t *qctx) { * destruction calls which *must* run in every configured module. * * (This could be implemented as an inline void function, but is left as a - * macro for symmetry with PROCESS_HOOK above.) + * macro for symmetry with CALL_HOOK above.) */ -#define PROCESS_ALL_HOOKS(_id, _qctx) \ +#define CALL_HOOK_NORETURN(_id, _qctx) \ do { \ isc_result_t _res; \ ns_hooktable_t *_tab = get_hooktab(_qctx); \ @@ -1931,22 +1931,22 @@ query_addtoname(dns_name_t *name, dns_rdataset_t *rdataset) { static void query_setorder(query_ctx_t *qctx, dns_name_t *name, dns_rdataset_t *rdataset) { ns_client_t *client = qctx->client; + dns_order_t *order = client->view->order; CTRACE(ISC_LOG_DEBUG(3), "query_setorder"); UNUSED(client); - if (qctx->view->order != NULL) { - rdataset->attributes |= - dns_order_find(qctx->view->order, - name, rdataset->type, - rdataset->rdclass); + if (order != NULL) { + rdataset->attributes |= dns_order_find(order, name, + rdataset->type, + rdataset->rdclass); } rdataset->attributes |= DNS_RDATASETATTR_LOADORDER; }; /* - * Handle glue and fetch any other needed additional data for 'rdataset' + * Handle glue and fetch any other needed additional data for 'rdataset'. */ static void query_additional(query_ctx_t *qctx, dns_rdataset_t *rdataset) { @@ -4855,7 +4855,7 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, REQUIRE(qctx != NULL); REQUIRE(client != NULL); - memset(qctx, 0, sizeof(query_ctx_t)); + memset(qctx, 0, sizeof(*qctx)); /* Set this first so CCTRACE will work */ qctx->client = client; @@ -4866,32 +4866,9 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, qctx->event = event; qctx->qtype = qctx->type = qtype; qctx->result = ISC_R_SUCCESS; - qctx->fname = NULL; - qctx->zfname = NULL; - qctx->rdataset = NULL; - qctx->zrdataset = NULL; - qctx->sigrdataset = NULL; - qctx->zsigrdataset = NULL; - qctx->zversion = NULL; - qctx->node = NULL; - qctx->znode = NULL; - qctx->db = NULL; - qctx->zdb = NULL; - qctx->version = NULL; - qctx->zone = NULL; - qctx->need_wildcardproof = false; - qctx->redirected = false; - qctx->dns64_exclude = qctx->dns64 = qctx->rpz = false; - qctx->options = 0; - qctx->resuming = false; - qctx->is_zone = false; qctx->findcoveringnsec = qctx->view->synthfromdnssec; - qctx->is_staticstub_zone = false; - qctx->nxrewrite = false; - qctx->answer_has_ns = false; - qctx->authoritative = false; - PROCESS_ALL_HOOKS(NS_QUERY_QCTX_INITIALIZED, qctx); + CALL_HOOK_NORETURN(NS_QUERY_QCTX_INITIALIZED, qctx); } /*% @@ -4956,7 +4933,7 @@ qctx_freedata(query_ctx_t *qctx) { static void qctx_destroy(query_ctx_t *qctx) { - PROCESS_ALL_HOOKS(NS_QUERY_QCTX_DESTROYED, qctx); + CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx); dns_view_detach(&qctx->view); } @@ -5011,7 +4988,7 @@ query_setup(ns_client_t *client, dns_rdatatype_t qtype) { qctx_init(client, NULL, qtype, &qctx); query_trace(&qctx); - PROCESS_HOOK(NS_QUERY_SETUP, &qctx); + CALL_HOOK(NS_QUERY_SETUP, &qctx); /* * If it's a SIG query, we'll iterate the node. @@ -5118,7 +5095,7 @@ ns__query_start(query_ctx_t *qctx) { qctx->need_wildcardproof = false; qctx->rpz = false; - PROCESS_HOOK(NS_QUERY_START_BEGIN, qctx); + CALL_HOOK(NS_QUERY_START_BEGIN, qctx); /* * If we require a server cookie then send back BADCOOKIE @@ -5332,7 +5309,7 @@ query_lookup(query_ctx_t *qctx) { CCTRACE(ISC_LOG_DEBUG(3), "query_lookup"); - PROCESS_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx); + CALL_HOOK(NS_QUERY_LOOKUP_BEGIN, qctx); dns_clientinfomethods_init(&cm, ns_client_sourceip); dns_clientinfo_init(&ci, qctx->client, NULL); @@ -5512,7 +5489,7 @@ fetch_callback(isc_task_t *task, isc_event_t *event) { query_ctx_t qctx; /* - * Initalize a new qctx and use it to resume + * Initialize a new qctx and use it to resume * from recursion. */ qctx_init(client, devent, 0, &qctx); @@ -5753,7 +5730,7 @@ query_resume(query_ctx_t *qctx) { char tbuf[DNS_RDATATYPE_FORMATSIZE]; #endif - PROCESS_HOOK(NS_QUERY_RESUME_BEGIN, qctx); + CALL_HOOK(NS_QUERY_RESUME_BEGIN, qctx); qctx->want_restart = false; @@ -6587,7 +6564,7 @@ query_gotanswer(query_ctx_t *qctx, isc_result_t res) { CCTRACE(ISC_LOG_DEBUG(3), "query_gotanswer"); - PROCESS_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx); + CALL_HOOK(NS_QUERY_GOT_ANSWER_BEGIN, qctx); if (query_checkrrl(qctx, result) != ISC_R_SUCCESS) { return (ns_query_done(qctx)); @@ -6772,7 +6749,7 @@ query_respond_any(query_ctx_t *qctx) { isc_result_t result; dns_rdatatype_t onetype = 0; /* type to use for minimal-any */ - PROCESS_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); + CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); result = dns_db_allrdatasets(qctx->db, qctx->node, qctx->version, 0, &rdsiter); @@ -6925,14 +6902,14 @@ query_respond_any(query_ctx_t *qctx) { } if (found) { - PROCESS_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx); + CALL_HOOK(NS_QUERY_RESPOND_ANY_FOUND, qctx); if (qctx->fname != NULL) { dns_message_puttempname(qctx->client->message, &qctx->fname); } } else { - PROCESS_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx); + CALL_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx); if (qctx->fname != NULL) { dns_message_puttempname(qctx->client->message, @@ -7112,7 +7089,7 @@ query_respond(query_ctx_t *qctx) { * other way to prevent that assertion, since the order in * which hook modules are configured can't be enforced.) */ - PROCESS_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); + CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { sigrdatasetp = &qctx->sigrdataset; @@ -7555,7 +7532,7 @@ static isc_result_t query_notfound(query_ctx_t *qctx) { isc_result_t result; - PROCESS_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx); + CALL_HOOK(NS_QUERY_NOTFOUND_BEGIN, qctx); INSIST(!qctx->is_zone); @@ -7637,7 +7614,7 @@ query_prepare_delegation_response(query_ctx_t *qctx) { dns_rdataset_t **sigrdatasetp = NULL; bool detach = false; - PROCESS_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx); + CALL_HOOK(NS_QUERY_PREP_DELEGATION_BEGIN, qctx); /* * qctx->fname could be released in query_addrrset(), so save a copy of @@ -7691,7 +7668,7 @@ static isc_result_t query_zone_delegation(query_ctx_t *qctx) { isc_result_t result; - PROCESS_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx); + CALL_HOOK(NS_QUERY_ZONE_DELEGATION_BEGIN, qctx); /* * If the query type is DS, look to see if we are @@ -7789,7 +7766,7 @@ static isc_result_t query_delegation(query_ctx_t *qctx) { isc_result_t result; - PROCESS_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx); + CALL_HOOK(NS_QUERY_DELEGATION_BEGIN, qctx); qctx->authoritative = false; @@ -8046,7 +8023,7 @@ static isc_result_t query_nodata(query_ctx_t *qctx, isc_result_t res) { isc_result_t result = res; - PROCESS_HOOK(NS_QUERY_NODATA_BEGIN, qctx); + CALL_HOOK(NS_QUERY_NODATA_BEGIN, qctx); #ifdef dns64_bis_return_excluded_addresses if (qctx->dns64) @@ -8363,7 +8340,7 @@ query_nxdomain(query_ctx_t *qctx, bool empty_wild) { uint32_t ttl; isc_result_t result; - PROCESS_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx); + CALL_HOOK(NS_QUERY_NXDOMAIN_BEGIN, qctx); INSIST(qctx->is_zone || REDIRECT(qctx->client)); @@ -9259,7 +9236,7 @@ query_cname(query_ctx_t *qctx) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdata_cname_t cname; - PROCESS_HOOK(NS_QUERY_CNAME_BEGIN, qctx); + CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx); /* * If we have a zero ttl from the cache refetch it. @@ -9392,7 +9369,7 @@ query_dname(query_ctx_t *qctx) { isc_result_t result; unsigned int nlabels; - PROCESS_HOOK(NS_QUERY_DNAME_BEGIN, qctx); + CALL_HOOK(NS_QUERY_DNAME_BEGIN, qctx); /* * Compare the current qname to the found name. We need @@ -9605,9 +9582,9 @@ query_addcname(query_ctx_t *qctx, dns_trust_t trust, dns_ttl_t ttl) { */ static isc_result_t query_prepresponse(query_ctx_t *qctx) { - isc_result_t result = ISC_R_SUCCESS; + isc_result_t result; - PROCESS_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx); + CALL_HOOK(NS_QUERY_PREP_RESPONSE_BEGIN, qctx); if (WANTDNSSEC(qctx->client) && (qctx->fname->attributes & DNS_NAMEATTR_WILDCARD) != 0) @@ -10500,7 +10477,7 @@ ns_query_done(query_ctx_t *qctx) { CCTRACE(ISC_LOG_DEBUG(3), "ns_query_done"); - PROCESS_HOOK(NS_QUERY_DONE_BEGIN, qctx); + CALL_HOOK(NS_QUERY_DONE_BEGIN, qctx); /* * General cleanup. @@ -10595,7 +10572,7 @@ ns_query_done(query_ctx_t *qctx) { qctx->result = ISC_R_FAILURE; } - PROCESS_HOOK(NS_QUERY_DONE_SEND, qctx); + CALL_HOOK(NS_QUERY_DONE_SEND, qctx); query_send(qctx->client); diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index ab5efa25dd..e870f859f1 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -46,8 +46,8 @@ ns_clientmgr_destroy ns_hook_add ns_hook_createctx ns_hook_destroyctx -ns_hookmodule_cleanup ns_hookmodule_load +ns_hookmodule_unload_all ns_hooktable_create ns_hooktable_free ns_hooktable_init From 8725f573714b623ba2d22d36fc541853cbc1c19f Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 19 Sep 2018 12:19:58 -0700 Subject: [PATCH 13/26] refactor to remove dead code in query_respond_any() --- lib/ns/include/ns/hooks.h | 1 - lib/ns/query.c | 81 ++++++++++++++++----------------------- 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 10c68d2a95..f86364ac60 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -179,7 +179,6 @@ typedef enum { NS_QUERY_GOT_ANSWER_BEGIN, NS_QUERY_RESPOND_ANY_BEGIN, NS_QUERY_RESPOND_ANY_FOUND, - NS_QUERY_RESPOND_ANY_NOT_FOUND, NS_QUERY_RESPOND_BEGIN, NS_QUERY_NOTFOUND_BEGIN, NS_QUERY_PREP_DELEGATION_BEGIN, diff --git a/lib/ns/query.c b/lib/ns/query.c index fd41929ba5..3dcf23e7cc 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -6748,6 +6748,7 @@ query_respond_any(query_ctx_t *qctx) { dns_rdatasetiter_t *rdsiter = NULL; isc_result_t result; dns_rdatatype_t onetype = 0; /* type to use for minimal-any */ + isc_buffer_t b; CALL_HOOK(NS_QUERY_RESPOND_ANY_BEGIN, qctx); @@ -6908,58 +6909,42 @@ query_respond_any(query_ctx_t *qctx) { dns_message_puttempname(qctx->client->message, &qctx->fname); } - } else { - CALL_HOOK(NS_QUERY_RESPOND_ANY_NOT_FOUND, qctx); - if (qctx->fname != NULL) { - dns_message_puttempname(qctx->client->message, - &qctx->fname); - } - - /* - * No matching rdatasets found in cache. If we were - * searching for RRSIG/SIG, that's probably okay; - * otherwise this is an error condition. - */ - if (qctx->qtype == dns_rdatatype_rrsig || - qctx->qtype == dns_rdatatype_sig) - { - isc_buffer_t b; - if (!qctx->is_zone) { - qctx->authoritative = false; - qctx->client->attributes &= ~NS_CLIENTATTR_RA; - query_addauth(qctx); - return (ns_query_done(qctx)); - } - - if (qctx->qtype == dns_rdatatype_rrsig && - dns_db_issecure(qctx->db)) { - char namebuf[DNS_NAME_FORMATSIZE]; - dns_name_format(qctx->client->query.qname, - namebuf, - sizeof(namebuf)); - ns_client_log(qctx->client, - DNS_LOGCATEGORY_DNSSEC, - NS_LOGMODULE_QUERY, - ISC_LOG_WARNING, - "missing signature for %s", - namebuf); - } - - qctx->fname = ns_client_newname(qctx->client, - qctx->dbuf, &b); - return (query_sign_nodata(qctx)); - } else { - CCTRACE(ISC_LOG_ERROR, - "query_respond_any: " - "no matching rdatasets in cache"); - result = DNS_R_SERVFAIL; - } + query_addauth(qctx); + return (ns_query_done(qctx)); } - query_addauth(qctx); + /* + * If we're here, no matching rdatasets were found in + * cache. If we were searching for RRSIG/SIG, that + * may be okay, but otherwise something's gone wrong. + */ + INSIST(qctx->qtype == dns_rdatatype_rrsig || + qctx->qtype == dns_rdatatype_sig); - return (ns_query_done(qctx)); + if (qctx->fname != NULL) { + dns_message_puttempname(qctx->client->message, + &qctx->fname); + } + + if (!qctx->is_zone) { + qctx->authoritative = false; + qctx->client->attributes &= ~NS_CLIENTATTR_RA; + query_addauth(qctx); + return (ns_query_done(qctx)); + } + + if (qctx->qtype == dns_rdatatype_rrsig && dns_db_issecure(qctx->db)) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(qctx->client->query.qname, + namebuf, sizeof(namebuf)); + ns_client_log(qctx->client, DNS_LOGCATEGORY_DNSSEC, + NS_LOGMODULE_QUERY, ISC_LOG_WARNING, + "missing signature for %s", namebuf); + } + + qctx->fname = ns_client_newname(qctx->client, qctx->dbuf, &b); + return (query_sign_nodata(qctx)); cleanup: return (result); From 74683fbc3b82d815f110ee25b0eba2165852fd4b Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 19 Sep 2018 16:25:50 -0700 Subject: [PATCH 14/26] use entirely local persistent data in modules - eliminate qctx->hookdata and client->hookflags. - use a memory pool to allocate data blobs in the filter-aaaa module, and associate them with the client address in a hash table - instead of detaching the client in query_done(), mark it for deletion and then call ns_client_detach() from qctx_destroy(); this ensures that it will still exist when the QCTX_DESTROYED hook point is reached. --- bin/hooks/filter-aaaa.c | 229 ++++++++++++++++++++++++------------- bin/named/server.c | 24 +--- lib/ns/client.c | 1 - lib/ns/hooks.c | 8 +- lib/ns/include/ns/client.h | 6 - lib/ns/include/ns/hooks.h | 6 +- lib/ns/include/ns/query.h | 10 +- lib/ns/query.c | 13 ++- 8 files changed, 169 insertions(+), 128 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index e70c6c2bb9..ff4218a18b 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -55,15 +56,36 @@ } while (0) /* - * Set up in the register function. + * Possible values for the settings of filter-aaaa-on-v4 and + * filter-aaaa-on-v6: "no" is NONE, "yes" is FILTER, "break-dnssec" + * is BREAK_DNSSEC. */ -static int module_id; +typedef enum { + NONE = 0, + FILTER = 1, + BREAK_DNSSEC = 2 +} filter_aaaa_t; /* - * Hook data pool. + * Persistent data for use by this module. This will be associated + * with client object address in the hash table, and will remain + * accessible until the client object is detached. + */ +typedef struct filter_data { + filter_aaaa_t mode; + uint32_t flags; +} filter_data_t; + +/* + * Memory pool for use with persistent data. */ static isc_mempool_t *datapool = NULL; +/* + * Hash table associating a client object with its persistent data. + */ +static isc_ht_t *client_ht = NULL; + /* * Per-client flags set by this module */ @@ -82,56 +104,51 @@ static isc_mempool_t *datapool = NULL; * be added to a hook table when this module is registered. */ static bool -filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp); +filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); static ns_hook_t filter_init = { .action = filter_qctx_initialize, + .action_data = &client_ht, }; static bool -filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp); +filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp); static ns_hook_t filter_respbegin = { .action = filter_respond_begin, + .action_data = &client_ht, }; static bool -filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp); +filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp); static ns_hook_t filter_respanyfound = { .action = filter_respond_any_found, + .action_data = &client_ht, }; static bool -filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp); +filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp); static ns_hook_t filter_prepresp = { .action = filter_prep_response_begin, + .action_data = &client_ht, }; static bool -filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp); +filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp); static ns_hook_t filter_donesend = { .action = filter_query_done_send, + .action_data = &client_ht, }; static bool -filter_qctx_destroy(void *hookdata, void *cbdata, isc_result_t *resp); +filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); ns_hook_t filter_destroy = { .action = filter_qctx_destroy, + .action_data = &client_ht, }; /** ** Support for parsing of parameters and configuration of the module. **/ -/* - * Possible values for the settings of filter-aaaa-on-v4 and - * filter-aaaa-on-v6: "no" is NONE, "yes" is FILTER, "break-dnssec" - * is BREAK_DNSSEC. - */ -typedef enum { - NONE = 0, - FILTER = 1, - BREAK_DNSSEC = 2 -} filter_aaaa_t; - /* * Values configured when the module is loaded. */ @@ -256,7 +273,7 @@ parse_parameters(const char *parameters, const void *cfg, * a hook table. */ isc_result_t -hook_register(const unsigned int modid, const char *parameters, +hook_register(const char *parameters, const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp) @@ -265,8 +282,6 @@ hook_register(const unsigned int modid, const char *parameters, UNUSED(instp); - module_id = modid; - isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, "loading 'filter-aaaa' " @@ -285,9 +300,11 @@ hook_register(const unsigned int modid, const char *parameters, ns_hook_add(hooktable, NS_QUERY_DONE_SEND, &filter_donesend); ns_hook_add(hooktable, NS_QUERY_QCTX_DESTROYED, &filter_destroy); - CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_aaaa_t), + CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), &datapool)); + CHECK(isc_ht_init(&client_ht, hctx->mctx, 16)); + /* * Fill the mempool with 1K filter_aaaa state objects at * a time; ideally after a single allocation, the mempool will @@ -318,6 +335,9 @@ void hook_destroy(void **instp) { UNUSED(instp); + if (client_ht != NULL) { + isc_ht_destroy(&client_ht); + } if (datapool != NULL) { isc_mempool_destroy(&datapool); } @@ -369,25 +389,67 @@ is_v6_client(ns_client_t *client) { return (false); } -/* - * Shorthand to refer to the persistent data stored by this module in - * the query context structure. - */ -#define FILTER_MODE(qctx) ((filter_aaaa_t **) &qctx->hookdata[module_id]) +static filter_data_t * +client_state_get(const query_ctx_t *qctx, isc_ht_t **htp) { + filter_data_t *client_state = NULL; + isc_result_t result; + + result = isc_ht_find(*htp, (const unsigned char *)&qctx->client, + sizeof(qctx->client), (void **)&client_state); + + return (result == ISC_R_SUCCESS ? client_state : NULL); +} + +static void +client_state_create(const query_ctx_t *qctx, isc_ht_t **htp) { + filter_data_t *client_state; + isc_result_t result; + + client_state = isc_mempool_get(datapool); + if (client_state == NULL) { + return; + } + + client_state->mode = NONE; + client_state->flags = 0; + + result = isc_ht_add(*htp, (const unsigned char *)&qctx->client, + sizeof(qctx->client), client_state); + RUNTIME_CHECK(result == ISC_R_SUCCESS); +} + +static void +client_state_destroy(const query_ctx_t *qctx, isc_ht_t **htp) { + filter_data_t *client_state = client_state_get(qctx, htp); + isc_result_t result; + + if (client_state == NULL) { + return; + } + + result = isc_ht_delete(*htp, (const unsigned char *)&qctx->client, + sizeof(qctx->client)); + RUNTIME_CHECK(result == ISC_R_SUCCESS); + + isc_mempool_put(datapool, client_state); +} /* - * Initialize hook data in the query context, fetching from a memory - * pool. + * Initialize filter state, fetching it from a memory pool and storing it + * in a hash table keyed according to the client object; this enables + * us to retrieve persistent data related to a client query for as long + * as the object persists.. */ static bool -filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - filter_aaaa_t **mode = FILTER_MODE(qctx); +filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state; - UNUSED(cbdata); - - *mode = isc_mempool_get(datapool); - **mode = NONE; + client_state = client_state_get(qctx, htp); + if (client_state == NULL) { + client_state_create(qctx, htp); + } *resp = ISC_R_UNSET; return (false); @@ -399,12 +461,15 @@ filter_qctx_initialize(void *hookdata, void *cbdata, isc_result_t *resp) { * filter-aaaa-on-v4 and filter-aaaa-on-v6. */ static bool -filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - filter_aaaa_t **mode = FILTER_MODE(qctx); +filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); isc_result_t result; - UNUSED(cbdata); + if (client_state == NULL) { + return (false); + } if (v4_aaaa != NONE || v6_aaaa != NONE) { result = ns_client_checkaclsilent(qctx->client, NULL, @@ -413,12 +478,12 @@ filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { v4_aaaa != NONE && is_v4_client(qctx->client)) { - **mode = v4_aaaa; + client_state->mode = v4_aaaa; } else if (result == ISC_R_SUCCESS && v6_aaaa != NONE && is_v6_client(qctx->client)) { - **mode = v6_aaaa; + client_state->mode = v6_aaaa; } } @@ -434,15 +499,18 @@ filter_prep_response_begin(void *hookdata, void *cbdata, isc_result_t *resp) { * 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; - filter_aaaa_t **mode = FILTER_MODE(qctx); +filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); isc_result_t result = ISC_R_UNSET; - UNUSED(cbdata); + if (client_state == NULL) { + return (false); + } - if (**mode != BREAK_DNSSEC && - (**mode != FILTER || + if (client_state->mode != BREAK_DNSSEC && + (client_state->mode != FILTER || (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && dns_rdataset_isassociated(qctx->sigrdataset)))) { @@ -487,8 +555,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { qctx->sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; } - qctx->client->hookflags[module_id] |= - FILTER_AAAA_FILTERED; + client_state->flags |= FILTER_AAAA_FILTERED; } else if (!qctx->authoritative && RECURSIONOK(qctx->client) && (result == DNS_R_DELEGATION || @@ -507,15 +574,13 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { qctx->client->query.qname, NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { - qctx->client->hookflags[module_id] |= - FILTER_AAAA_RECURSING; + client_state->flags |= FILTER_AAAA_RECURSING; qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; } } } else if (qctx->qtype == dns_rdatatype_a && - ((qctx->client->hookflags[module_id] & - FILTER_AAAA_RECURSING) != 0)) + (client_state->flags & FILTER_AAAA_RECURSING) != 0) { dns_rdataset_t *mrdataset = NULL; dns_rdataset_t *sigrdataset = NULL; @@ -539,7 +604,7 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; } - qctx->client->hookflags[module_id] &= ~FILTER_AAAA_RECURSING; + client_state->flags &= ~FILTER_AAAA_RECURSING; result = ns_query_done(qctx); @@ -556,17 +621,20 @@ filter_respond_begin(void *hookdata, void *cbdata, isc_result_t *resp) { * When answering an ANY query, remove AAAA if A is present. */ static bool -filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - filter_aaaa_t **mode = FILTER_MODE(qctx); +filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); 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 (client_state == NULL) { + return (false); + } - if (**mode == NONE) { + if (client_state->mode == NONE) { *resp = ISC_R_UNSET; return (false); } @@ -598,7 +666,7 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { if (have_a && aaaa != NULL && (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || - **mode == BREAK_DNSSEC)) + client_state->mode == BREAK_DNSSEC)) { qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; aaaa->attributes |= DNS_RDATASETATTR_RENDERED; @@ -617,14 +685,17 @@ filter_respond_any_found(void *hookdata, void *cbdata, isc_result_t *resp) { * section. */ static bool -filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - filter_aaaa_t **mode = FILTER_MODE(qctx); +filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_data_t *client_state = client_state_get(qctx, htp); isc_result_t result; - UNUSED(cbdata); + if (client_state == NULL) { + return (false); + } - if (**mode == NONE) { + if (client_state->mode == NONE) { *resp = ISC_R_UNSET; return (false); } @@ -658,7 +729,7 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { dns_rdatatype_aaaa, &aaaa_sig); if (aaaa_sig == NULL || !WANTDNSSEC(qctx->client) || - **mode == BREAK_DNSSEC) + client_state->mode == BREAK_DNSSEC) { aaaa->attributes |= DNS_RDATASETATTR_RENDERED; if (aaaa_sig != NULL) { @@ -668,7 +739,7 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { } } - if ((qctx->client->hookflags[module_id] & FILTER_AAAA_FILTERED) != 0) { + if ((client_state->flags & FILTER_AAAA_FILTERED) != 0) { result = dns_message_firstname(qctx->client->message, DNS_SECTION_AUTHORITY); while (result == ISC_R_SUCCESS) { @@ -704,20 +775,20 @@ filter_query_done_send(void *hookdata, void *cbdata, isc_result_t *resp) { } /* - * Return hook data to the mempool. + * If the client is being detached, then we can delete our persistent + * data from hash table and return it to the memory pool. */ static bool -filter_qctx_destroy(void *hookdata, void *cbdata, isc_result_t *resp) { - query_ctx_t *qctx = (query_ctx_t *) hookdata; - filter_aaaa_t **mode = FILTER_MODE(qctx); +filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { + query_ctx_t *qctx = (query_ctx_t *) arg; + isc_ht_t **htp = (isc_ht_t **) cbdata; - UNUSED(cbdata); - - if (*mode != NULL) { - isc_mempool_put(datapool, *mode); - *mode = NULL; + if (!qctx->detach_client) { + return (false); } + client_state_destroy(qctx, htp); + *resp = ISC_R_UNSET; return (false); } diff --git a/bin/named/server.c b/bin/named/server.c index cd9ceb55ae..e4f1883edf 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1537,8 +1537,7 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, } static isc_result_t -configure_hook(ns_hooktable_t *hooktable, const unsigned int modid, - const cfg_obj_t *hook, +configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, const cfg_obj_t *config, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; @@ -1563,7 +1562,7 @@ configure_hook(ns_hooktable_t *hooktable, const unsigned int modid, if (obj != NULL && cfg_obj_isstring(obj)) { parameters = cfg_obj_asstring(obj); } - result = ns_hookmodule_load(library, modid, parameters, + result = ns_hookmodule_load(library, parameters, cfg_obj_file(obj), cfg_obj_line(obj), config, named_g_aclconfctx, hctx, hooktable); @@ -3760,7 +3759,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, unsigned int resolver_param; dns_ntatable_t *ntatable = NULL; const char *qminmode = NULL; - unsigned int module_counter = 0; REQUIRE(DNS_VIEW_VALID(view)); @@ -5310,8 +5308,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, #ifdef HAVE_DLOPEN if (hook_list != NULL) { - const void *hashinit = isc_hash_get_initializer(); - CHECK(ns_hook_createctx(mctx, hashinit, &hctx)); + CHECK(ns_hook_createctx(mctx, &hctx)); INSIST(view->hooktable == NULL); CHECK(ns_hooktable_create(view->mctx, @@ -5325,20 +5322,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, { const cfg_obj_t *hook = cfg_listelt_value(element); - if (view->hooktable == NULL) { - CHECK(ns_hooktable_create(view->mctx, - (ns_hooktable_t **) &view->hooktable)); - view->hooktable_free = ns_hooktable_free; - } - - if (hctx == NULL) { - CHECK(ns_hook_createctx(mctx, &hctx)); - } - - CHECK(configure_hook(view->hooktable, module_counter, - hook, config, hctx)); - - module_counter++; + CHECK(configure_hook(view->hooktable, hook, config, hctx)); } #endif diff --git a/lib/ns/client.c b/lib/ns/client.c index 1c45094833..36dbb1d2ab 100644 --- a/lib/ns/client.c +++ b/lib/ns/client.c @@ -3047,7 +3047,6 @@ client_create(ns_clientmgr_t *manager, ns_client_t **clientp) { ISC_QLINK_INIT(client, ilink); client->keytag = NULL; client->keytag_len = 0; - memset(client->hookflags, 0, sizeof(client->hookflags)); /* * We call the init routines for the various kinds of client here, diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index d94cfdfdcd..0f0abbf4ea 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -339,8 +339,7 @@ unload_library(ns_hook_module_t **hmodp) { #endif /* HAVE_DLFCN_H */ isc_result_t -ns_hookmodule_load(const char *modpath, const unsigned int modid, - const char *parameters, +ns_hookmodule_load(const char *modpath, const char *parameters, const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable) @@ -357,9 +356,8 @@ ns_hookmodule_load(const char *modpath, const unsigned int modid, "loading module '%s'", modpath); CHECK(load_library(hctx->mctx, modpath, &hmod)); - CHECK(hmod->register_func(modid, parameters, cfg_file, cfg_line, - cfg, actx, hctx, hooktable, - &hmod->inst)); + CHECK(hmod->register_func(parameters, cfg_file, cfg_line, + cfg, actx, hctx, hooktable, &hmod->inst)); ISC_LIST_APPEND(hook_modules, hmod, link); diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 6d030c3180..7d25eb9360 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -170,12 +170,6 @@ struct ns_client { uint32_t expire; unsigned char *keytag; uint16_t keytag_len; - - /*% - * Allows a hook module to set flags - * that persist across recursion. - */ - uint32_t hookflags[NS_MAX_MODULES]; }; typedef ISC_QUEUE(ns_client_t) client_queue_t; diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index f86364ac60..e0418051ad 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -246,8 +246,7 @@ typedef struct ns_hookctx { #define NS_HOOK_AGE 0 #endif -typedef isc_result_t ns_hook_register_t(const unsigned int modid, - const char *parameters, +typedef isc_result_t ns_hook_register_t(const char *parameters, const char *file, unsigned long line, const void *cfg, @@ -302,8 +301,7 @@ ns_hook_destroyctx(ns_hookctx_t **hctxp); */ isc_result_t -ns_hookmodule_load(const char *modpath, const unsigned int modid, - const char *parameters, +ns_hookmodule_load(const char *modpath, const char *parameters, const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx, ns_hooktable_t *hooktable); diff --git a/lib/ns/include/ns/query.h b/lib/ns/include/ns/query.h index b3fc3a742c..5e38d48fb2 100644 --- a/lib/ns/include/ns/query.h +++ b/lib/ns/include/ns/query.h @@ -27,12 +27,6 @@ #include -/* - * Maximum number of query hook modules that can be configured; - * more than this will overflow qctx->hookdata. - */ -#define NS_MAX_MODULES 16 - /*% nameserver database version structure */ typedef struct ns_dbversion { dns_db_t *db; @@ -156,6 +150,8 @@ struct query_ctx { dns_fixedname_t dsname; /* name needing DS */ ns_client_t *client; /* client object */ + bool detach_client; /* client needs detaching */ + dns_fetchevent_t *event; /* recursion event */ dns_db_t *db; /* zone or cache database */ @@ -174,8 +170,6 @@ struct query_ctx { dns_view_t *view; /* client view */ - void *hookdata[NS_MAX_MODULES]; /* data used by query hooks */ - isc_result_t result; /* query result */ int line; /* line to report error */ }; diff --git a/lib/ns/query.c b/lib/ns/query.c index 3dcf23e7cc..e9b703805d 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -4936,6 +4936,9 @@ qctx_destroy(query_ctx_t *qctx) { CALL_HOOK_NORETURN(NS_QUERY_QCTX_DESTROYED, qctx); dns_view_detach(&qctx->view); + if (qctx->detach_client) { + ns_client_detach(&qctx->client); + } } /*% @@ -6915,9 +6918,9 @@ query_respond_any(query_ctx_t *qctx) { } /* - * If we're here, no matching rdatasets were found in - * cache. If we were searching for RRSIG/SIG, that - * may be okay, but otherwise something's gone wrong. + * If we're here, no matching rdatasets were found. If we were + * searching for RRSIG/SIG, that may be okay, but otherwise + * something's gone wrong. */ INSIST(qctx->qtype == dns_rdatatype_rrsig || qctx->qtype == dns_rdatatype_sig); @@ -10517,7 +10520,7 @@ ns_query_done(query_ctx_t *qctx) { query_error(qctx->client, qctx->result, qctx->line); } - ns_client_detach(&qctx->client); + qctx->detach_client = true; return (qctx->result); } @@ -10561,7 +10564,7 @@ ns_query_done(query_ctx_t *qctx) { query_send(qctx->client); - ns_client_detach(&qctx->client); + qctx->detach_client = true; return (qctx->result); cleanup: From 0b988256c79e754cf3130cf78efb52aafdaa1878 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 19 Sep 2018 23:38:23 -0700 Subject: [PATCH 15/26] copy ns_hook objects before adding them to a hook table - this is necessary because adding the same hook to multiple views causes the ISC_LIST link value to become inconsistent; it isn't noticeable when only one hook action is ever registered at a given hook point, but it will break things when there are two. --- bin/hooks/filter-aaaa.c | 29 +++++++++++--------- lib/ns/hooks.c | 56 ++++++++++++++++++++++++++++----------- lib/ns/include/ns/hooks.h | 15 +++++++---- lib/ns/query.c | 2 +- lib/ns/tests/nstest.c | 11 ++++---- lib/ns/tests/query_test.c | 21 +++++++++------ 6 files changed, 87 insertions(+), 47 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index ff4218a18b..0fb64b9776 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -105,42 +105,42 @@ static isc_ht_t *client_ht = NULL; */ static bool filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t filter_init = { +static const ns_hook_t filter_init = { .action = filter_qctx_initialize, .action_data = &client_ht, }; static bool filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t filter_respbegin = { +static const ns_hook_t filter_respbegin = { .action = filter_respond_begin, .action_data = &client_ht, }; static bool filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t filter_respanyfound = { +static const ns_hook_t filter_respanyfound = { .action = filter_respond_any_found, .action_data = &client_ht, }; static bool filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t filter_prepresp = { +static const ns_hook_t filter_prepresp = { .action = filter_prep_response_begin, .action_data = &client_ht, }; static bool filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp); -static ns_hook_t filter_donesend = { +static const ns_hook_t filter_donesend = { .action = filter_query_done_send, .action_data = &client_ht, }; static bool filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); -ns_hook_t filter_destroy = { +static const ns_hook_t filter_destroy = { .action = filter_qctx_destroy, .action_data = &client_ht, }; @@ -292,13 +292,18 @@ hook_register(const char *parameters, CHECK(parse_parameters(parameters, cfg, actx, hctx)); } - ns_hook_add(hooktable, NS_QUERY_QCTX_INITIALIZED, &filter_init); - ns_hook_add(hooktable, NS_QUERY_RESPOND_BEGIN, &filter_respbegin); - ns_hook_add(hooktable, NS_QUERY_RESPOND_ANY_FOUND, + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_INITIALIZED, + &filter_init); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_BEGIN, + &filter_respbegin); + ns_hook_add(hooktable, hctx->mctx, 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); - ns_hook_add(hooktable, NS_QUERY_QCTX_DESTROYED, &filter_destroy); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_PREP_RESPONSE_BEGIN, + &filter_prepresp); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_DONE_SEND, + &filter_donesend); + ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_DESTROYED, + &filter_destroy); CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), &datapool)); diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 0f0abbf4ea..bc43f86abb 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -70,7 +70,7 @@ static isc_result_t load_symbol(void *handle, const char *modpath, const char *symbol_name, void **symbolp) { - void *symbol; + void *symbol = NULL; REQUIRE(handle != NULL); REQUIRE(symbolp != NULL && *symbolp == NULL); @@ -187,7 +187,7 @@ cleanup: static void unload_library(ns_hook_module_t **hmodp) { - ns_hook_module_t *hmod; + ns_hook_module_t *hmod = NULL; REQUIRE(hmodp != NULL && *hmodp != NULL); @@ -208,7 +208,7 @@ static isc_result_t load_symbol(HMODULE handle, const char *modpath, const char *symbol_name, void **symbolp) { - void *symbol; + void *symbol = NULL; REQUIRE(handle != NULL); REQUIRE(symbolp != NULL && *symbolp == NULL); @@ -301,7 +301,7 @@ cleanup: static void unload_library(ns_hook_module_t **hmodp) { - ns_hook_module_t *hmod; + ns_hook_module_t *hmod = NULL; REQUIRE(hmodp != NULL && *hmodp != NULL); @@ -371,7 +371,7 @@ cleanup: void ns_hookmodule_unload_all(void) { - ns_hook_module_t *hmod, *prev; + ns_hook_module_t *hmod = NULL, *prev = NULL; if (!hook_modules_initialized) { return; @@ -393,7 +393,7 @@ ns_hookmodule_unload_all(void) { isc_result_t ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { - ns_hookctx_t *hctx; + ns_hookctx_t *hctx = NULL; REQUIRE(hctxp != NULL && *hctxp == NULL); @@ -411,7 +411,7 @@ ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { void ns_hook_destroyctx(ns_hookctx_t **hctxp) { - ns_hookctx_t *hctx; + ns_hookctx_t *hctx = NULL; REQUIRE(hctxp != NULL && NS_HOOKCTX_VALID(*hctxp)); @@ -439,7 +439,7 @@ ns_hooktable_init(ns_hooktable_t *hooktable) { isc_result_t ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { - ns_hooktable_t *hooktable; + ns_hooktable_t *hooktable = NULL; REQUIRE(tablep != NULL && *tablep == NULL); @@ -454,26 +454,50 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { void ns_hooktable_free(isc_mem_t *mctx, void **tablep) { - ns_hooktable_t *table; + ns_hooktable_t *table = NULL; + ns_hook_t *hook = NULL, *next = NULL; + int i = 0; REQUIRE(tablep != NULL && *tablep != NULL); table = *tablep; *tablep = NULL; + + for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) { + for (hook = ISC_LIST_HEAD((*table)[i]); + hook != NULL; + hook = next) + { + next = ISC_LIST_NEXT(hook, link); + ISC_LIST_UNLINK((*table)[i], hook, link); + if (hook->mctx != NULL) { + isc_mem_putanddetach(&hook->mctx, + hook, sizeof(*hook)); + } + } + } + isc_mem_put(mctx, table, sizeof(*table)); } void -ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, - ns_hook_t *hook) +ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx, + ns_hookpoint_t hookpoint, const ns_hook_t *hook) { + ns_hook_t *copy = NULL; + + REQUIRE(hooktable != NULL); + REQUIRE(mctx != NULL); REQUIRE(hookpoint < NS_HOOKPOINTS_COUNT); REQUIRE(hook != NULL); - if (hooktable == NULL) { - hooktable = ns__hook_table; - } + copy = isc_mem_get(mctx, sizeof(*copy)); + memset(copy, 0, sizeof(*copy)); - ISC_LINK_INIT(hook, link); - ISC_LIST_APPEND((*hooktable)[hookpoint], hook, link); + copy->action = hook->action; + copy->action_data = hook->action_data; + isc_mem_attach(mctx, ©->mctx); + + ISC_LINK_INIT(copy, link); + ISC_LIST_APPEND((*hooktable)[hookpoint], copy, link); } diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index e0418051ad..e61d15db72 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -201,6 +201,7 @@ typedef bool (*ns_hook_action_t)(void *arg, void *data, isc_result_t *resultp); typedef struct ns_hook { + isc_mem_t *mctx; ns_hook_action_t action; void *action_data; ISC_LINK(struct ns_hook) link; @@ -327,17 +328,21 @@ ns_hookmodule_unload_all(void); */ void -ns_hook_add(ns_hooktable_t *hooktable, ns_hookpoint_t hookpoint, - ns_hook_t *hook); +ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx, + ns_hookpoint_t hookpoint, const ns_hook_t *hook); /*%< - * Append hook function 'hook' to the list of hooks at 'hookpoint' in - * 'hooktable'. + * Allocate (using memory context 'mctx') a copy of the 'hook' structure + * describing a hook callback and append it to the list of hooks at 'hookpoint' + * in 'hooktable'. * * Requires: - *\li 'hook' is not NULL + *\li 'hooktable' is not NULL + * + *\li 'mctx' is not NULL * *\li 'hookpoint' is less than NS_QUERY_HOOKS_COUNT * + *\li 'hook' is not NULL */ void diff --git a/lib/ns/query.c b/lib/ns/query.c index e9b703805d..6df013d295 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -485,7 +485,7 @@ query_addwildcardproof(query_ctx_t *qctx, bool ispositive, bool nodata); static void query_addauth(query_ctx_t *qctx); -/*% +/* * Increment query statistics counters. */ static inline void diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 2532042e82..9f24f6c4eb 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -672,8 +672,8 @@ extract_qctx(void *arg, void *data, isc_result_t *resultp) { */ static isc_result_t create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { - ns_hooktable_t *saved_hook_table, query_hooks; - ns_hook_t hook = { + ns_hooktable_t *saved_hook_table = NULL, *query_hooks = NULL; + const ns_hook_t hook = { .action = extract_qctx, .action_data = qctxp, }; @@ -690,15 +690,16 @@ create_qctx_for_client(ns_client_t *client, query_ctx_t **qctxp) { * set hooks. */ - ns_hooktable_init(&query_hooks); - ns_hook_add(&query_hooks, NS_QUERY_SETUP, &hook); + ns_hooktable_create(mctx, &query_hooks); + ns_hook_add(query_hooks, mctx, NS_QUERY_SETUP, &hook); saved_hook_table = ns__hook_table; - ns__hook_table = &query_hooks; + ns__hook_table = query_hooks; ns_query_start(client); ns__hook_table = saved_hook_table; + ns_hooktable_free(mctx, (void **)&query_hooks); if (*qctxp == NULL) { return (ISC_R_NOMEMORY); diff --git a/lib/ns/tests/query_test.c b/lib/ns/tests/query_test.c index 4b7002ae9c..e88a4bd4f1 100644 --- a/lib/ns/tests/query_test.c +++ b/lib/ns/tests/query_test.c @@ -82,9 +82,10 @@ typedef struct { */ static void run_sfcache_test(const ns__query_sfcache_test_params_t *test) { + ns_hooktable_t *query_hooks = NULL; query_ctx_t *qctx = NULL; isc_result_t result; - ns_hook_t hook = { + const ns_hook_t hook = { .action = ns_test_hook_catch_call, }; @@ -97,8 +98,9 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) { * Interrupt execution if ns_query_done() is called. */ - ns_hooktable_init(ns__hook_table); - ns_hook_add(ns__hook_table, NS_QUERY_DONE_BEGIN, &hook); + ns_hooktable_create(mctx, &query_hooks); + ns_hook_add(query_hooks, mctx, NS_QUERY_DONE_BEGIN, &hook); + ns__hook_table = query_hooks; /* * Construct a query context for a ./NS query with given flags. @@ -157,6 +159,7 @@ run_sfcache_test(const ns__query_sfcache_test_params_t *test) { * Clean up. */ ns_test_qctx_destroy(&qctx); + ns_hooktable_free(mctx, (void **)&query_hooks); } /* test ns__query_sfcache() */ @@ -279,9 +282,10 @@ typedef struct { */ static void run_start_test(const ns__query_start_test_params_t *test) { + ns_hooktable_t *query_hooks = NULL; query_ctx_t *qctx = NULL; isc_result_t result; - ns_hook_t hook = { + const ns_hook_t hook = { .action = ns_test_hook_catch_call, }; @@ -295,10 +299,10 @@ run_start_test(const ns__query_start_test_params_t *test) { /* * Interrupt execution if query_lookup() or ns_query_done() is called. */ - - ns_hooktable_init(ns__hook_table); - ns_hook_add(ns__hook_table, NS_QUERY_LOOKUP_BEGIN, &hook); - ns_hook_add(ns__hook_table, NS_QUERY_DONE_BEGIN, &hook); + ns_hooktable_create(mctx, &query_hooks); + ns_hook_add(query_hooks, mctx, NS_QUERY_LOOKUP_BEGIN, &hook); + ns_hook_add(query_hooks, mctx, NS_QUERY_DONE_BEGIN, &hook); + ns__hook_table = query_hooks; /* * Construct a query context using the supplied parameters. @@ -414,6 +418,7 @@ run_start_test(const ns__query_start_test_params_t *test) { ns_test_cleanup_zone(); } ns_test_qctx_destroy(&qctx); + ns_hooktable_free(mctx, (void **)&query_hooks); } /* test ns__query_start() */ From baa38d6e94e3b0b50ec663a8fe2fdaf3c9011357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 20 Sep 2018 15:07:33 +0200 Subject: [PATCH 16/26] refactor response filtering code in bin/hooks/filter-aaaa.c --- bin/hooks/filter-aaaa.c | 366 +++++++++++++++++++++------------------- 1 file changed, 193 insertions(+), 173 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 0fb64b9776..ccc161d7b0 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -365,6 +365,18 @@ hook_version(void) { ** "filter-aaaa" feature implementation begins here. **/ +/*% + * Structure describing the filtering to be applied by process_section(). + */ +typedef struct section_filter { + query_ctx_t * qctx; + filter_aaaa_t mode; + dns_section_t section; + const dns_name_t * name; + dns_rdatatype_t type; + bool only_if_a_exists; +} section_filter_t; + /* * Check whether this is an IPv4 client. */ @@ -439,11 +451,121 @@ client_state_destroy(const query_ctx_t *qctx, isc_ht_t **htp) { isc_mempool_put(datapool, client_state); } +/*% + * Mark 'rdataset' and 'sigrdataset' as rendered, gracefully handling NULL + * pointers and non-associated rdatasets. + */ +static void +mark_as_rendered(dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) { + if (rdataset != NULL && dns_rdataset_isassociated(rdataset)) { + rdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } + if (sigrdataset != NULL && dns_rdataset_isassociated(sigrdataset)) { + sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; + } +} + +/*% + * Check whether an RRset of given 'type' is present at given 'name'. If + * it is found and either it is not signed or the combination of query + * flags and configured processing 'mode' allows it, mark the RRset and its + * associated signatures as already rendered to prevent them from appearing + * in the response message stored in 'qctx'. If 'only_if_a_exists' is + * true, an RRset of type A must also exist at 'name' in order for the + * above processing to happen. + */ +static bool +process_name(query_ctx_t *qctx, filter_aaaa_t mode, const dns_name_t *name, + dns_rdatatype_t type, bool only_if_a_exists) +{ + dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + isc_result_t result; + bool modified = false; + + if (only_if_a_exists) { + CHECK(dns_message_findtype(name, dns_rdatatype_a, 0, NULL)); + } + + dns_message_findtype(name, type, 0, &rdataset); + dns_message_findtype(name, dns_rdatatype_rrsig, type, &sigrdataset); + + if (rdataset != NULL && + (sigrdataset == NULL || !WANTDNSSEC(qctx->client) || + mode == BREAK_DNSSEC)) + { + /* + * An RRset of given 'type' was found at 'name' and at least + * one of the following is true: + * + * - the RRset is not signed, + * - the client did not set the DO bit in its request, + * - configuration allows us to tamper with signed responses. + * + * This means it is okay to filter out this RRset and its + * signatures, if any, from the response. + */ + mark_as_rendered(rdataset, sigrdataset); + modified = true; + } + + cleanup: + return (modified); +} + +/*% + * Apply the requested section filter, i.e. prevent (when possible, as + * determined by process_name()) RRsets of given 'type' from being rendered + * in the given 'section' of the response message stored in 'qctx'. Clear + * the AD bit if the answer and/or authority section was modified. If + * 'name' is NULL, all names in the given 'section' are processed; + * otherwise, only 'name' is. 'only_if_a_exists' is passed through to + * process_name(). + */ +static void +process_section(const section_filter_t *filter) { + query_ctx_t *qctx = filter->qctx; + filter_aaaa_t mode = filter->mode; + dns_section_t section = filter->section; + const dns_name_t *name = filter->name; + dns_rdatatype_t type = filter->type; + bool only_if_a_exists = filter->only_if_a_exists; + + dns_message_t *message = qctx->client->message; + isc_result_t result; + + for (result = dns_message_firstname(message, section); + result == ISC_R_SUCCESS; + result = dns_message_nextname(message, section)) + { + dns_name_t *cur = NULL; + dns_message_currentname(message, section, &cur); + if (name != NULL && !dns_name_equal(name, cur)) { + /* + * We only want to process 'name' and this is not it. + */ + continue; + } + + if (!process_name(qctx, mode, cur, type, only_if_a_exists)) { + /* + * Response was not modified, do not touch the AD bit. + */ + continue; + } + + if (section == DNS_SECTION_ANSWER || + section == DNS_SECTION_AUTHORITY) + { + message->flags &= ~DNS_MESSAGEFLAG_AD; + } + } +} + /* * Initialize filter state, fetching it from a memory pool and storing it - * in a hash table keyed according to the client object; this enables - * us to retrieve persistent data related to a client query for as long - * as the object persists.. + * in a hash table keyed according to the client object; this enables us to + * retrieve persistent data related to a client query for as long as the + * object persists. */ static bool filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { @@ -451,19 +573,20 @@ filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { isc_ht_t **htp = (isc_ht_t **) cbdata; filter_data_t *client_state; + *resp = ISC_R_UNSET; + client_state = client_state_get(qctx, htp); if (client_state == NULL) { client_state_create(qctx, htp); } - *resp = ISC_R_UNSET; return (false); } /* - * Determine whether this client should have AAAA filtered or not, - * based on the client address family and the settings of - * filter-aaaa-on-v4 and filter-aaaa-on-v6. + * Determine whether this client should have AAAA filtered or not, based on + * the client address family and the settings of filter-aaaa-on-v4 and + * filter-aaaa-on-v6. */ static bool filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { @@ -472,6 +595,8 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { filter_data_t *client_state = client_state_get(qctx, htp); isc_result_t result; + *resp = ISC_R_UNSET; + if (client_state == NULL) { return (false); } @@ -492,7 +617,6 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { } } - *resp = ISC_R_UNSET; return (false); } @@ -500,8 +624,8 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { * Hide AAAA rrsets if there is a matching A. Trigger recursion if * necessary to find out whether an A exists. * - * (This version is for processing answers to explicit AAAA - * queries; ANY queries are handled in query_filter_aaaa_any().) + * (This version is for processing answers to explicit AAAA queries; ANY + * queries are handled in filter_respond_any_found().) */ static bool filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { @@ -510,6 +634,8 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { filter_data_t *client_state = client_state_get(qctx, htp); isc_result_t result = ISC_R_UNSET; + *resp = ISC_R_UNSET; + if (client_state == NULL) { return (false); } @@ -519,7 +645,6 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && dns_rdataset_isassociated(qctx->sigrdataset)))) { - *resp = result; return (false); } @@ -552,14 +677,8 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { * cached an A if it existed. */ if (result == ISC_R_SUCCESS) { + mark_as_rendered(qctx->rdataset, qctx->sigrdataset); qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; - qctx->rdataset->attributes |= DNS_RDATASETATTR_RENDERED; - if (qctx->sigrdataset != NULL && - dns_rdataset_isassociated(qctx->sigrdataset)) - { - qctx->sigrdataset->attributes |= - DNS_RDATASETATTR_RENDERED; - } client_state->flags |= FILTER_AAAA_FILTERED; } else if (!qctx->authoritative && RECURSIONOK(qctx->client) && @@ -587,27 +706,14 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { } else if (qctx->qtype == dns_rdatatype_a && (client_state->flags & 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) { - qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; - 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) { - qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; - sigrdataset->attributes |= DNS_RDATASETATTR_RENDERED; - } + const section_filter_t filter_answer = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_ANSWER, + .name = qctx->fname, + .type = dns_rdatatype_aaaa, + }; + process_section(&filter_answer); client_state->flags &= ~FILTER_AAAA_RECURSING; @@ -630,63 +736,34 @@ filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; isc_ht_t **htp = (isc_ht_t **) cbdata; filter_data_t *client_state = client_state_get(qctx, htp); - dns_name_t *name = NULL; - dns_rdataset_t *aaaa = NULL, *aaaa_sig = NULL; - dns_rdataset_t *a = NULL; - bool have_a = true; - - if (client_state == NULL) { - return (false); - } - - if (client_state->mode == NONE) { - *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) || - client_state->mode == BREAK_DNSSEC)) - { - qctx->client->message->flags &= ~DNS_MESSAGEFLAG_AD; - aaaa->attributes |= DNS_RDATASETATTR_RENDERED; - if (aaaa_sig != NULL) { - aaaa_sig->attributes |= DNS_RDATASETATTR_RENDERED; - } - } *resp = ISC_R_UNSET; + + if (client_state != NULL && client_state->mode != NONE) { + /* + * If we are authoritative, require an A record to be + * present before filtering out AAAA records; otherwise, + * just assume an A record exists even if it was not in the + * cache (and therefore is not in the response message), + * thus proceeding with filtering out AAAA records. + */ + const section_filter_t filter_answer = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_ANSWER, + .name = qctx->tname, + .type = dns_rdatatype_aaaa, + .only_if_a_exists = qctx->authoritative, + }; + process_section(&filter_answer); + } + return (false); } /* - * Hide AAAA rrsets in the additional section if there is a matching A, - * and hide NS in the authority section if AAAA was filtered in the answer + * Hide AAAA rrsets in the additional section if there is a matching A, and + * hide NS in the authority section if AAAA was filtered in the answer * section. */ static bool @@ -694,106 +771,49 @@ filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; isc_ht_t **htp = (isc_ht_t **) cbdata; filter_data_t *client_state = client_state_get(qctx, htp); - isc_result_t result; - - if (client_state == NULL) { - return (false); - } - - if (client_state->mode == NONE) { - *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) || - client_state->mode == BREAK_DNSSEC) - { - aaaa->attributes |= DNS_RDATASETATTR_RENDERED; - if (aaaa_sig != NULL) { - aaaa_sig->attributes |= - DNS_RDATASETATTR_RENDERED; - } - } - } - - if ((client_state->flags & 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) { - qctx->client->message->flags &= - ~DNS_MESSAGEFLAG_AD; - 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; + + if (client_state != NULL && client_state->mode != NONE) { + const section_filter_t filter_additional = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_ADDITIONAL, + .type = dns_rdatatype_aaaa, + .only_if_a_exists = true, + }; + process_section(&filter_additional); + + if ((client_state->flags & FILTER_AAAA_FILTERED) != 0) { + const section_filter_t filter_authority = { + .qctx = qctx, + .mode = client_state->mode, + .section = DNS_SECTION_AUTHORITY, + .type = dns_rdatatype_ns, + }; + process_section(&filter_authority); + } + } + return (false); } /* - * If the client is being detached, then we can delete our persistent - * data from hash table and return it to the memory pool. + * If the client is being detached, then we can delete our persistent data + * from hash table and return it to the memory pool. */ static bool filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; isc_ht_t **htp = (isc_ht_t **) cbdata; + *resp = ISC_R_UNSET; + if (!qctx->detach_client) { return (false); } client_state_destroy(qctx, htp); - *resp = ISC_R_UNSET; return (false); } From 9df0bdc99c154a917bbfb20c1fed47c1818e769d Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Thu, 22 Nov 2018 09:15:13 +0000 Subject: [PATCH 17/26] add additional hook points, plus some minor refactoring - added some hook points that will be needed for a dns64 module later - moved some code from the beginning of query_respond() to the end of query_prepresponse(); this has no effect on functionality but means we can have a hook point at the top of query_respond(), which seems nicer - compressed duplicated code into query_zerottl_refetch() function - added a qctx->answered flag so that a module can prevent query_addrrset() from being called from query_respond() when it's already been called from the module. --- lib/ns/include/ns/hooks.h | 6 + lib/ns/query.c | 370 +++++++++++++++++++++----------------- 2 files changed, 215 insertions(+), 161 deletions(-) diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index e61d15db72..fe710c30c3 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -176,16 +176,22 @@ typedef enum { NS_QUERY_START_BEGIN, NS_QUERY_LOOKUP_BEGIN, NS_QUERY_RESUME_BEGIN, + NS_QUERY_RESUME_RESTORED, NS_QUERY_GOT_ANSWER_BEGIN, NS_QUERY_RESPOND_ANY_BEGIN, NS_QUERY_RESPOND_ANY_FOUND, + NS_QUERY_ADDANSWER_BEGIN, NS_QUERY_RESPOND_BEGIN, NS_QUERY_NOTFOUND_BEGIN, + NS_QUERY_NOTFOUND_RECURSE, NS_QUERY_PREP_DELEGATION_BEGIN, NS_QUERY_ZONE_DELEGATION_BEGIN, NS_QUERY_DELEGATION_BEGIN, + NS_QUERY_DELEGATION_RECURSE_BEGIN, NS_QUERY_NODATA_BEGIN, NS_QUERY_NXDOMAIN_BEGIN, + NS_QUERY_NCACHE_BEGIN, + NS_QUERY_ZEROTTL_RECURSE, NS_QUERY_CNAME_BEGIN, NS_QUERY_DNAME_BEGIN, NS_QUERY_PREP_RESPONSE_BEGIN, diff --git a/lib/ns/query.c b/lib/ns/query.c index 6df013d295..32c0847b78 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -343,9 +343,9 @@ get_hooktab(query_ctx_t *qctx) { * 8. The answer was not found in the database (query_notfound(). * Set up a referral and go to 9. * - * 9. Handle a delegation response (query_delegation()). If we are - * allowed to recurse, go to 5, otherwise go to 15 to clean up and - * return the delegation to the client. + * 9. Handle a delegation response (query_delegation()). If we need + * to and are allowed to recurse (query_delegation_recurse()), go to 5, + * otherwise go to 15 to clean up and return the delegation to the client. * * 10. No such domain (query_nxdomain()). Attempt redirection; if * unsuccessful, add authority section records (query_addsoa(), @@ -433,6 +433,9 @@ query_zone_delegation(query_ctx_t *qctx); static isc_result_t query_delegation(query_ctx_t *qctx); +static isc_result_t +query_delegation_recurse(query_ctx_t *qctx); + static void query_addds(query_ctx_t *qctx); @@ -457,6 +460,9 @@ query_ncache(query_ctx_t *qctx, isc_result_t result); static isc_result_t query_coveringnsec(query_ctx_t *qctx); +static isc_result_t +query_zerottl_refetch(query_ctx_t *qctx); + static isc_result_t query_cname(query_ctx_t *qctx); @@ -5840,6 +5846,8 @@ query_resume(query_ctx_t *qctx) { qctx->type = qctx->qtype; } + CALL_HOOK(NS_QUERY_RESUME_RESTORED, qctx); + if (DNS64(qctx->client)) { qctx->client->query.attributes &= ~NS_QUERYATTR_DNS64; qctx->dns64 = true; @@ -7007,43 +7015,74 @@ query_getexpire(query_ctx_t *qctx) { } } +/*% + * Fill the ANSWER section of a positive response. + */ +static isc_result_t +query_addanswer(query_ctx_t *qctx) { + dns_rdataset_t **sigrdatasetp = NULL; + isc_result_t result; + + CALL_HOOK(NS_QUERY_ADDANSWER_BEGIN, qctx); + + if (qctx->dns64) { + result = query_dns64(qctx); + qctx->noqname = NULL; + dns_rdataset_disassociate(qctx->rdataset); + dns_message_puttemprdataset(qctx->client->message, + &qctx->rdataset); + if (result == ISC_R_NOMORE) { +#ifndef dns64_bis_return_excluded_addresses + if (qctx->dns64_exclude) { + if (!qctx->is_zone) + return (ns_query_done(qctx)); + /* + * Add a fake SOA record. + */ + (void)query_addsoa(qctx, 600, + DNS_SECTION_AUTHORITY); + return (ns_query_done(qctx)); + } +#endif + if (qctx->is_zone) { + return (query_nodata(qctx, DNS_R_NXDOMAIN)); + } else { + return (query_ncache(qctx, DNS_R_NXDOMAIN)); + } + } else if (result != ISC_R_SUCCESS) { + qctx->result = result; + return (ns_query_done(qctx)); + } + } else if (qctx->client->query.dns64_aaaaok != NULL) { + query_filter64(qctx); + ns_client_putrdataset(qctx->client, &qctx->rdataset); + } else { + if (!qctx->is_zone && RECURSIONOK(qctx->client)) { + query_prefetch(qctx->client, qctx->fname, + qctx->rdataset); + } + if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { + sigrdatasetp = &qctx->sigrdataset; + } + query_addrrset(qctx, &qctx->fname, + &qctx->rdataset, sigrdatasetp, + qctx->dbuf, DNS_SECTION_ANSWER); + } + + return (ISC_R_COMPLETE); + + cleanup: + return (result); +} + /*% * Build a repsonse for a "normal" query, for a type other than ANY, * for which we have an answer (either positive or negative). */ static isc_result_t query_respond(query_ctx_t *qctx) { - dns_rdataset_t **sigrdatasetp = NULL; isc_result_t result; - /* - * If we have a zero ttl from the cache, refetch. - */ - if (!qctx->is_zone && !qctx->resuming && !STALE(qctx->rdataset) && - qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client)) - { - qctx_clean(qctx); - - INSIST(!REDIRECT(qctx->client)); - result = ns_query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - if (qctx->dns64) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } else { - QUERY_ERROR(qctx, result); - } - - return (ns_query_done(qctx)); - } - /* * Check to see if the AAAA RRset has non-excluded addresses * in it. If not look for a A RRset. @@ -7079,10 +7118,6 @@ query_respond(query_ctx_t *qctx) { */ CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); - if (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL) { - sigrdatasetp = &qctx->sigrdataset; - } - if (NOQNAME(qctx->rdataset) && WANTDNSSEC(qctx->client)) { qctx->noqname = qctx->rdataset; } else { @@ -7117,44 +7152,9 @@ query_respond(query_ctx_t *qctx) { */ query_getexpire(qctx); - if (qctx->dns64) { - result = query_dns64(qctx); - qctx->noqname = NULL; - dns_rdataset_disassociate(qctx->rdataset); - dns_message_puttemprdataset(qctx->client->message, - &qctx->rdataset); - if (result == ISC_R_NOMORE) { -#ifndef dns64_bis_return_excluded_addresses - if (qctx->dns64_exclude) { - if (!qctx->is_zone) - return (ns_query_done(qctx)); - /* - * Add a fake SOA record. - */ - (void)query_addsoa(qctx, 600, - DNS_SECTION_AUTHORITY); - return (ns_query_done(qctx)); - } -#endif - if (qctx->is_zone) { - return (query_nodata(qctx, DNS_R_NXDOMAIN)); - } else { - return (query_ncache(qctx, DNS_R_NXDOMAIN)); - } - } else if (result != ISC_R_SUCCESS) { - qctx->result = result; - return (ns_query_done(qctx)); - } - } else if (qctx->client->query.dns64_aaaaok != NULL) { - query_filter64(qctx); - ns_client_putrdataset(qctx->client, &qctx->rdataset); - } else { - if (!qctx->is_zone && RECURSIONOK(qctx->client)) - query_prefetch(qctx->client, qctx->fname, - qctx->rdataset); - query_addrrset(qctx, &qctx->fname, - &qctx->rdataset, sigrdatasetp, - qctx->dbuf, DNS_SECTION_ANSWER); + result = query_addanswer(qctx); + if (result != ISC_R_COMPLETE) { + return (result); } query_addnoqnameproof(qctx); @@ -7441,7 +7441,8 @@ query_filter64(query_ctx_t *qctx) { i = 0; for (result = dns_rdataset_first(qctx->rdataset); result == ISC_R_SUCCESS; - result = dns_rdataset_next(qctx->rdataset)) { + result = dns_rdataset_next(qctx->rdataset)) + { if (!client->query.dns64_aaaaok[i++]) continue; dns_rdataset_current(qctx->rdataset, &rdata); @@ -7565,14 +7566,18 @@ query_notfound(query_ctx_t *qctx) { qctx->client->query.qname, NULL, NULL, qctx->resuming); if (result == ISC_R_SUCCESS) { + CALL_HOOK(NS_QUERY_NOTFOUND_RECURSE, qctx); qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; - if (qctx->dns64) + + if (qctx->dns64) { qctx->client->query.attributes |= NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) + } + if (qctx->dns64_exclude) { qctx->client->query.attributes |= NS_QUERYATTR_DNS64EXCLUDE; + } } else { QUERY_ERROR(qctx, result); } @@ -7808,60 +7813,9 @@ query_delegation(query_ctx_t *qctx) { RESTORE(qctx->sigrdataset, qctx->zsigrdataset); } - if (RECURSIONOK(qctx->client)) { - /* - * We have a delegation and recursion is allowed, - * so we call ns_query_recurse() to follow it. - * This phase of the query processing is done; - * we'll resume via fetch_callback() and - * query_resume() when the recursion is complete. - */ - dns_name_t *qname = qctx->client->query.qname; - - INSIST(!REDIRECT(qctx->client)); - - if (dns_rdatatype_atparent(qctx->type)) { - /* - * Parent is recursive for this rdata - * type (i.e., DS). - */ - result = ns_query_recurse(qctx->client, - qctx->qtype, qname, - NULL, NULL, - qctx->resuming); - } else if (qctx->dns64) { - /* - * Look up an A record so we can - * synthesize DNS64. - */ - result = ns_query_recurse(qctx->client, - dns_rdatatype_a, qname, - NULL, NULL, - qctx->resuming); - } else { - /* - * Any other recursion. - */ - result = ns_query_recurse(qctx->client, - qctx->qtype, qname, - qctx->fname, - qctx->rdataset, - qctx->resuming); - } - if (result == ISC_R_SUCCESS) { - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - if (qctx->dns64) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } else { - QUERY_ERROR(qctx, result); - } - - return (ns_query_done(qctx)); + result = query_delegation_recurse(qctx); + if (result != ISC_R_COMPLETE) { + return (result); } return (query_prepare_delegation_response(qctx)); @@ -7870,6 +7824,71 @@ query_delegation(query_ctx_t *qctx) { return (result); } +/*% + * Handle recursive queries that are triggered as part of the + * delegation process. + */ +static isc_result_t +query_delegation_recurse(query_ctx_t *qctx) { + isc_result_t result; + dns_name_t *qname = qctx->client->query.qname; + + if (!RECURSIONOK(qctx->client)) { + return (ISC_R_COMPLETE); + } + + CALL_HOOK(NS_QUERY_DELEGATION_RECURSE_BEGIN, qctx); + + /* + * We have a delegation and recursion is allowed, + * so we call ns_query_recurse() to follow it. + * This phase of the query processing is done; + * we'll resume via fetch_callback() and + * query_resume() when the recursion is complete. + */ + + INSIST(!REDIRECT(qctx->client)); + + if (dns_rdatatype_atparent(qctx->type)) { + /* + * Parent is authoritative for this RDATA type (i.e. DS). + */ + result = ns_query_recurse(qctx->client, qctx->qtype, qname, + NULL, NULL, qctx->resuming); + } else if (qctx->dns64) { + /* + * Look up an A record so we can synthesize DNS64. + */ + result = ns_query_recurse(qctx->client, dns_rdatatype_a, qname, + NULL, NULL, qctx->resuming); + } else { + /* + * Any other recursion. + */ + result = ns_query_recurse(qctx->client, qctx->qtype, qname, + qctx->fname, qctx->rdataset, + qctx->resuming); + } + + if (result == ISC_R_SUCCESS) { + qctx->client->query.attributes |= NS_QUERYATTR_RECURSING; + if (qctx->dns64) { + qctx->client->query.attributes |= NS_QUERYATTR_DNS64; + } + if (qctx->dns64_exclude) { + qctx->client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } + } else { + QUERY_ERROR(qctx, result); + } + + return (ns_query_done(qctx)); + + cleanup: + return (result); +} + /*% * Add a DS record if needed. */ @@ -9029,9 +9048,9 @@ query_coveringnsec(query_ctx_t *qctx) { /* * Zero TTL handling of wildcard record. * - * We don't yet have code to handle synthesis and type ANY, - * AAAA filtering or dns64 processing so we abort the - * synthesis here if there would be a interaction. + * We don't yet have code to handle synthesis and type ANY or dns64 + * processing so we abort the synthesis here if there would be a + * interaction. */ switch (result) { case ISC_R_SUCCESS: @@ -9189,6 +9208,8 @@ query_ncache(query_ctx_t *qctx, isc_result_t result) { result == DNS_R_NCACHENXRRSET || result == DNS_R_NXDOMAIN); + CALL_HOOK(NS_QUERY_NCACHE_BEGIN, qctx); + qctx->authoritative = false; if (result == DNS_R_NCACHENXDOMAIN) { @@ -9210,6 +9231,52 @@ query_ncache(query_ctx_t *qctx, isc_result_t result) { } return (query_nodata(qctx, result)); + + cleanup: + return (result); +} + +/* + * If we have a zero ttl from the cache, refetch. + */ +static isc_result_t +query_zerottl_refetch(query_ctx_t *qctx) { + isc_result_t result; + + if (qctx->is_zone || qctx->resuming || STALE(qctx->rdataset) || + qctx->rdataset->ttl != 0 || !RECURSIONOK(qctx->client)) + { + return (ISC_R_COMPLETE); + } + + qctx_clean(qctx); + + INSIST(!REDIRECT(qctx->client)); + + result = ns_query_recurse(qctx->client, qctx->qtype, + qctx->client->query.qname, + NULL, NULL, qctx->resuming); + if (result == ISC_R_SUCCESS) { + CALL_HOOK(NS_QUERY_ZEROTTL_RECURSE, qctx); + qctx->client->query.attributes |= + NS_QUERYATTR_RECURSING; + + if (qctx->dns64) { + qctx->client->query.attributes |= + NS_QUERYATTR_DNS64; + } + if (qctx->dns64_exclude) { + qctx->client->query.attributes |= + NS_QUERYATTR_DNS64EXCLUDE; + } + } else { + QUERY_ERROR(qctx, result); + } + + return (ns_query_done(qctx)); + + cleanup: + return (result); } /* @@ -9226,33 +9293,9 @@ query_cname(query_ctx_t *qctx) { CALL_HOOK(NS_QUERY_CNAME_BEGIN, qctx); - /* - * If we have a zero ttl from the cache refetch it. - */ - if (!qctx->is_zone && !qctx->resuming && !STALE(qctx->rdataset) && - qctx->rdataset->ttl == 0 && RECURSIONOK(qctx->client)) - { - qctx_clean(qctx); - - INSIST(!REDIRECT(qctx->client)); - - result = ns_query_recurse(qctx->client, qctx->qtype, - qctx->client->query.qname, - NULL, NULL, qctx->resuming); - if (result == ISC_R_SUCCESS) { - qctx->client->query.attributes |= - NS_QUERYATTR_RECURSING; - if (qctx->dns64) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64; - if (qctx->dns64_exclude) - qctx->client->query.attributes |= - NS_QUERYATTR_DNS64EXCLUDE; - } else { - QUERY_ERROR(qctx, result); - } - - return (ns_query_done(qctx)); + result = query_zerottl_refetch(qctx); + if (result != ISC_R_COMPLETE) { + return (result); } /* @@ -9587,6 +9630,11 @@ query_prepresponse(query_ctx_t *qctx) { return (query_respond_any(qctx)); } + result = query_zerottl_refetch(qctx); + if (result != ISC_R_COMPLETE) { + return (result); + } + return (query_respond(qctx)); cleanup: From b94945e60663fb2a3d6641ea41d720500fb39fb4 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Wed, 31 Oct 2018 19:02:29 -0700 Subject: [PATCH 18/26] refactor to support multiple module instances - use a per-view module list instead of global hook_modules - create an 'instance' pointer when registering modules, store it in the module structure, and use it as action_data when calling hook functions - this enables multiple module instances to be set up in parallel - also some nomenclature changes and cleanup --- bin/hooks/filter-aaaa.c | 267 ++++++++++++++++++++----------------- bin/named/server.c | 23 ++-- lib/dns/include/dns/view.h | 6 + lib/dns/view.c | 5 + lib/ns/hooks.c | 143 +++++++++++--------- lib/ns/include/ns/hooks.h | 51 +++---- lib/ns/include/ns/types.h | 2 + lib/ns/win32/libns.def | 5 +- 8 files changed, 283 insertions(+), 219 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index ccc161d7b0..0084645262 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -46,6 +46,7 @@ #include #include #include +#include #define CHECK(op) \ do { \ @@ -76,15 +77,27 @@ typedef struct filter_data { uint32_t flags; } filter_data_t; -/* - * Memory pool for use with persistent data. - */ -static isc_mempool_t *datapool = NULL; +typedef struct filter_instance { + ns_module_t *module; + isc_mem_t *mctx; -/* - * Hash table associating a client object with its persistent data. - */ -static isc_ht_t *client_ht = NULL; + /* + * Memory pool for use with persistent data. + */ + isc_mempool_t *datapool; + + /* + * Hash table associating a client object with its persistent data. + */ + isc_ht_t *ht; + + /* + * Values configured when the module is loaded. + */ + filter_aaaa_t v4_aaaa; + filter_aaaa_t v6_aaaa; + dns_acl_t *aaaa_acl; +} filter_instance_t; /* * Per-client flags set by this module @@ -100,62 +113,79 @@ static isc_ht_t *client_ht = NULL; NS_QUERYATTR_RECURSIONOK) != 0) /* - * Hook registration structures: pointers to these structures will - * be added to a hook table when this module is registered. + * Forward declarations of functions referenced in install_hooks(). */ static bool filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); -static const ns_hook_t filter_init = { - .action = filter_qctx_initialize, - .action_data = &client_ht, -}; - static bool filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp); -static const ns_hook_t filter_respbegin = { - .action = filter_respond_begin, - .action_data = &client_ht, -}; - static bool filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp); -static const ns_hook_t filter_respanyfound = { - .action = filter_respond_any_found, - .action_data = &client_ht, -}; - static bool filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp); -static const ns_hook_t filter_prepresp = { - .action = filter_prep_response_begin, - .action_data = &client_ht, -}; - static bool filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp); -static const ns_hook_t filter_donesend = { - .action = filter_query_done_send, - .action_data = &client_ht, -}; - static bool filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); -static const ns_hook_t filter_destroy = { - .action = filter_qctx_destroy, - .action_data = &client_ht, -}; + +/*% + * Register the functions to be called at each hook point in 'hooktable', using + * memory context 'mctx' for allocating copies of stack-allocated structures + * passed to ns_hook_add(). Make sure 'inst' will be passed as the 'cbdata' + * argument to every callback. + */ +static void +install_hooks(ns_hooktable_t *hooktable, isc_mem_t *mctx, + filter_instance_t *inst) +{ + const ns_hook_t filter_init = { + .action = filter_qctx_initialize, + .action_data = inst, + }; + + const ns_hook_t filter_respbegin = { + .action = filter_respond_begin, + .action_data = inst, + }; + + const ns_hook_t filter_respanyfound = { + .action = filter_respond_any_found, + .action_data = inst, + }; + + const ns_hook_t filter_prepresp = { + .action = filter_prep_response_begin, + .action_data = inst, + }; + + const ns_hook_t filter_donesend = { + .action = filter_query_done_send, + .action_data = inst, + }; + + const ns_hook_t filter_destroy = { + .action = filter_qctx_destroy, + .action_data = inst, + }; + + ns_hook_add(hooktable, mctx, - + NS_QUERY_QCTX_INITIALIZED, &filter_init); + ns_hook_add(hooktable, mctx, + NS_QUERY_RESPOND_BEGIN, &filter_respbegin); + ns_hook_add(hooktable, mctx, + NS_QUERY_RESPOND_ANY_FOUND, &filter_respanyfound); + ns_hook_add(hooktable, mctx, + NS_QUERY_PREP_RESPONSE_BEGIN, &filter_prepresp); + ns_hook_add(hooktable, mctx, + NS_QUERY_DONE_SEND, &filter_donesend); + ns_hook_add(hooktable, mctx, + NS_QUERY_QCTX_DESTROYED, &filter_destroy); +} /** ** Support for parsing of parameters and configuration of the module. **/ -/* - * Values configured when the module is loaded. - */ -static filter_aaaa_t v4_aaaa = NONE; -static filter_aaaa_t v6_aaaa = NONE; -static dns_acl_t *aaaa_acl = NULL; - /* * Support for parsing of parameters. */ @@ -220,8 +250,8 @@ parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, } static isc_result_t -parse_parameters(const char *parameters, const void *cfg, - void *actx, ns_hookctx_t *hctx) +parse_parameters(filter_instance_t *inst, const char *parameters, + const void *cfg, void *actx, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; cfg_parser_t *parser = NULL; @@ -236,18 +266,18 @@ parse_parameters(const char *parameters, const void *cfg, CHECK(cfg_parse_buffer(parser, &b, &cfg_type_parameters, ¶m_obj)); - CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &v4_aaaa)); - CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6", &v6_aaaa)); + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", + &inst->v4_aaaa)); + CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v6", + &inst->v6_aaaa)); - obj = NULL; result = cfg_map_get(param_obj, "filter-aaaa", &obj); if (result == ISC_R_SUCCESS) { CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *) cfg, - hctx->lctx, - (cfg_aclconfctx_t *) actx, - hctx->mctx, 0, &aaaa_acl)); + hctx->lctx, (cfg_aclconfctx_t *) actx, + hctx->mctx, 0, &inst->aaaa_acl)); } else { - CHECK(dns_acl_any(hctx->mctx, &aaaa_acl)); + CHECK(dns_acl_any(hctx->mctx, &inst->aaaa_acl)); } cleanup: @@ -269,46 +299,36 @@ parse_parameters(const char *parameters, const void *cfg, **/ /* - * Called by ns_hookmodule_load() to register hook functions into + * Called by ns_module_load() to register hook functions into * a hook table. */ isc_result_t hook_register(const char *parameters, const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, - ns_hookctx_t *hctx, ns_hooktable_t *hooktable, void **instp) + const void *cfg, void *actx, ns_hookctx_t *hctx, + ns_hooktable_t *hooktable, void **instp) { + filter_instance_t *inst = NULL; isc_result_t result; - UNUSED(instp); isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "loading 'filter-aaaa' " + "registering 'filter-aaaa' " "module from %s:%lu, %s parameters", cfg_file, cfg_line, parameters != NULL ? "with" : "no"); + inst = isc_mem_get(hctx->mctx, sizeof(*inst)); + memset(inst, 0, sizeof(*inst)); + isc_mem_attach(hctx->mctx, &inst->mctx); + if (parameters != NULL) { - CHECK(parse_parameters(parameters, cfg, actx, hctx)); + CHECK(parse_parameters(inst, parameters, cfg, actx, hctx)); } - ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_INITIALIZED, - &filter_init); - ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_BEGIN, - &filter_respbegin); - ns_hook_add(hooktable, hctx->mctx, NS_QUERY_RESPOND_ANY_FOUND, - &filter_respanyfound); - ns_hook_add(hooktable, hctx->mctx, NS_QUERY_PREP_RESPONSE_BEGIN, - &filter_prepresp); - ns_hook_add(hooktable, hctx->mctx, NS_QUERY_DONE_SEND, - &filter_donesend); - ns_hook_add(hooktable, hctx->mctx, NS_QUERY_QCTX_DESTROYED, - &filter_destroy); - CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), - &datapool)); - - CHECK(isc_ht_init(&client_ht, hctx->mctx, 16)); + &inst->datapool)); + CHECK(isc_ht_init(&inst->ht, hctx->mctx, 16)); /* * Fill the mempool with 1K filter_aaaa state objects at @@ -320,36 +340,45 @@ hook_register(const char *parameters, * so that they'll always be returned to the pool and not * freed until the pool is destroyed on shutdown. */ - isc_mempool_setfillcount(datapool, 1024); - isc_mempool_setfreemax(datapool, UINT_MAX); + isc_mempool_setfillcount(inst->datapool, 1024); + isc_mempool_setfreemax(inst->datapool, UINT_MAX); + + /* + * Set hook points in the view's hooktable. + */ + install_hooks(hooktable, hctx->mctx, inst); + + *instp = inst; cleanup: - if (result != ISC_R_SUCCESS) { - if (datapool != NULL) { - isc_mempool_destroy(&datapool); - } + if (result != ISC_R_SUCCESS && inst != NULL) { + hook_destroy((void **) &inst); } + return (result); } /* - * Called by ns_hookmodule_unload_all(); frees memory allocated by + * Called by ns_module_unload(); frees memory allocated by * the module when it was registered. */ void hook_destroy(void **instp) { - UNUSED(instp); + filter_instance_t *inst = (filter_instance_t *) *instp; - if (client_ht != NULL) { - isc_ht_destroy(&client_ht); + if (inst->ht != NULL) { + isc_ht_destroy(&inst->ht); } - if (datapool != NULL) { - isc_mempool_destroy(&datapool); + if (inst->datapool != NULL) { + isc_mempool_destroy(&inst->datapool); } - if (aaaa_acl != NULL) { - dns_acl_detach(&aaaa_acl); + if (inst->aaaa_acl != NULL) { + dns_acl_detach(&inst->aaaa_acl); } + isc_mem_putanddetach(&inst->mctx, inst, sizeof(*inst)); + *instp = NULL; + return; } @@ -407,22 +436,22 @@ is_v6_client(ns_client_t *client) { } static filter_data_t * -client_state_get(const query_ctx_t *qctx, isc_ht_t **htp) { +client_state_get(const query_ctx_t *qctx, filter_instance_t *inst) { filter_data_t *client_state = NULL; isc_result_t result; - result = isc_ht_find(*htp, (const unsigned char *)&qctx->client, + result = isc_ht_find(inst->ht, (const unsigned char *)&qctx->client, sizeof(qctx->client), (void **)&client_state); return (result == ISC_R_SUCCESS ? client_state : NULL); } static void -client_state_create(const query_ctx_t *qctx, isc_ht_t **htp) { +client_state_create(const query_ctx_t *qctx, filter_instance_t *inst) { filter_data_t *client_state; isc_result_t result; - client_state = isc_mempool_get(datapool); + client_state = isc_mempool_get(inst->datapool); if (client_state == NULL) { return; } @@ -430,25 +459,25 @@ client_state_create(const query_ctx_t *qctx, isc_ht_t **htp) { client_state->mode = NONE; client_state->flags = 0; - result = isc_ht_add(*htp, (const unsigned char *)&qctx->client, + result = isc_ht_add(inst->ht, (const unsigned char *)&qctx->client, sizeof(qctx->client), client_state); RUNTIME_CHECK(result == ISC_R_SUCCESS); } static void -client_state_destroy(const query_ctx_t *qctx, isc_ht_t **htp) { - filter_data_t *client_state = client_state_get(qctx, htp); +client_state_destroy(const query_ctx_t *qctx, filter_instance_t *inst) { + filter_data_t *client_state = client_state_get(qctx, inst); isc_result_t result; if (client_state == NULL) { return; } - result = isc_ht_delete(*htp, (const unsigned char *)&qctx->client, + result = isc_ht_delete(inst->ht, (const unsigned char *)&qctx->client, sizeof(qctx->client)); RUNTIME_CHECK(result == ISC_R_SUCCESS); - isc_mempool_put(datapool, client_state); + isc_mempool_put(inst->datapool, client_state); } /*% @@ -570,14 +599,14 @@ process_section(const section_filter_t *filter) { static bool filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; - isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_instance_t *inst = (filter_instance_t *) cbdata; filter_data_t *client_state; *resp = ISC_R_UNSET; - client_state = client_state_get(qctx, htp); + client_state = client_state_get(qctx, inst); if (client_state == NULL) { - client_state_create(qctx, htp); + client_state_create(qctx, inst); } return (false); @@ -591,8 +620,8 @@ filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { static bool filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; - isc_ht_t **htp = (isc_ht_t **) cbdata; - filter_data_t *client_state = client_state_get(qctx, htp); + filter_instance_t *inst = (filter_instance_t *) cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); isc_result_t result; *resp = ISC_R_UNSET; @@ -601,19 +630,19 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { return (false); } - if (v4_aaaa != NONE || v6_aaaa != NONE) { + if (inst->v4_aaaa != NONE || inst->v6_aaaa != NONE) { result = ns_client_checkaclsilent(qctx->client, NULL, - aaaa_acl, true); + inst->aaaa_acl, true); if (result == ISC_R_SUCCESS && - v4_aaaa != NONE && + inst->v4_aaaa != NONE && is_v4_client(qctx->client)) { - client_state->mode = v4_aaaa; + client_state->mode = inst->v4_aaaa; } else if (result == ISC_R_SUCCESS && - v6_aaaa != NONE && + inst->v6_aaaa != NONE && is_v6_client(qctx->client)) { - client_state->mode = v6_aaaa; + client_state->mode = inst->v6_aaaa; } } @@ -630,8 +659,8 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { static bool filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; - isc_ht_t **htp = (isc_ht_t **) cbdata; - filter_data_t *client_state = client_state_get(qctx, htp); + filter_instance_t *inst = (filter_instance_t *) cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); isc_result_t result = ISC_R_UNSET; *resp = ISC_R_UNSET; @@ -734,8 +763,8 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { static bool filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; - isc_ht_t **htp = (isc_ht_t **) cbdata; - filter_data_t *client_state = client_state_get(qctx, htp); + filter_instance_t *inst = (filter_instance_t *) cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); *resp = ISC_R_UNSET; @@ -769,8 +798,8 @@ filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { static bool filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; - isc_ht_t **htp = (isc_ht_t **) cbdata; - filter_data_t *client_state = client_state_get(qctx, htp); + filter_instance_t *inst = (filter_instance_t *) cbdata; + filter_data_t *client_state = client_state_get(qctx, inst); *resp = ISC_R_UNSET; @@ -805,7 +834,7 @@ filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { static bool filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; - isc_ht_t **htp = (isc_ht_t **) cbdata; + filter_instance_t *inst = (filter_instance_t *) cbdata; *resp = ISC_R_UNSET; @@ -813,7 +842,7 @@ filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { return (false); } - client_state_destroy(qctx, htp); + client_state_destroy(qctx, inst); return (false); } diff --git a/bin/named/server.c b/bin/named/server.c index e4f1883edf..b6a43df85d 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1537,7 +1537,7 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, } static isc_result_t -configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, +configure_hook(dns_view_t *view, const cfg_obj_t *hook, const cfg_obj_t *config, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; @@ -1562,14 +1562,14 @@ configure_hook(ns_hooktable_t *hooktable, const cfg_obj_t *hook, if (obj != NULL && cfg_obj_isstring(obj)) { parameters = cfg_obj_asstring(obj); } - result = ns_hookmodule_load(library, parameters, - cfg_obj_file(obj), cfg_obj_line(obj), - config, named_g_aclconfctx, - hctx, hooktable); + result = ns_module_load(library, parameters, + cfg_obj_file(obj), cfg_obj_line(obj), + config, named_g_aclconfctx, + hctx, view->modlist, view->hooktable); if (result != ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, - "%s: hook module configuration failed: %s", + "%s: module configuration failed: %s", library, isc_result_totext(result)); } return (result); @@ -5314,6 +5314,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, CHECK(ns_hooktable_create(view->mctx, (ns_hooktable_t **) &view->hooktable)); view->hooktable_free = ns_hooktable_free; + + ns_modlist_create(view->mctx, (ns_modlist_t **)&view->modlist); + view->modlist_free = ns_modlist_free; } for (element = cfg_list_first(hook_list); @@ -5322,7 +5325,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, { const cfg_obj_t *hook = cfg_listelt_value(element); - CHECK(configure_hook(view->hooktable, hook, config, hctx)); + CHECK(configure_hook(view, hook, config, hctx)); } #endif @@ -8062,10 +8065,9 @@ load_configuration(const char *filename, named_server_t *server, CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx)); /* - * Shut down all dyndb and hook module instances. + * Shut down all dyndb instances. */ dns_dyndb_cleanup(false); - ns_hookmodule_unload_all(); /* * Parse the global default pseudo-config file. @@ -9547,10 +9549,9 @@ shutdown_server(isc_task_t *task, isc_event_t *event) { } /* - * Shut down all dyndb and hook module instances. + * Shut down all dyndb instances. */ dns_dyndb_cleanup(true); - ns_hookmodule_unload_all(); while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) { ISC_LIST_UNLINK(server->cachelist, nsc, link); diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index c80dc5da5e..0fedb5d67f 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -236,8 +236,14 @@ struct dns_view { dns_dtmsgtype_t dttypes; /* Dnstap message types to log */ + /* Registered module instances */ + void *modlist; + void (*modlist_free)(isc_mem_t *, void **); + + /* Hook table */ void *hooktable; /* ns_hooktable */ void (*hooktable_free)(isc_mem_t *, void **); + }; #define DNS_VIEW_MAGIC ISC_MAGIC('V','i','e','w') diff --git a/lib/dns/view.c b/lib/dns/view.c index 357f102625..ca5900b3d2 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -256,6 +256,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->dtenv = NULL; view->dttypes = 0; + view->modlist = NULL; + view->modlist_free = NULL; view->hooktable = NULL; view->hooktable_free = NULL; @@ -551,6 +553,9 @@ destroy(dns_view_t *view) { if (view->hooktable != NULL && view->hooktable_free != NULL) { view->hooktable_free(view->mctx, &view->hooktable); } + if (view->modlist != NULL && view->modlist_free != NULL) { + view->modlist_free(view->mctx, &view->modlist); + } isc_mem_putanddetach(&view->mctx, view, sizeof(*view)); } diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index bc43f86abb..4573f6fc1e 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -42,29 +42,19 @@ } \ } while (0) -typedef struct ns_hook_module ns_hook_module_t; -struct ns_hook_module { - isc_mem_t *mctx; - void *handle; - char *modpath; - ns_hook_register_t *register_func; - ns_hook_destroy_t *destroy_func; - void *inst; - LINK(ns_hook_module_t) link; +struct ns_module { + isc_mem_t *mctx; + void *handle; + void *inst; + char *modpath; + ns_hook_register_t *register_func; + ns_hook_destroy_t *destroy_func; + LINK(ns_module_t) link; }; static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT]; LIBNS_EXTERNAL_DATA ns_hooktable_t *ns__hook_table = &default_hooktable; -/* - * List of hook modules. - * - * These are stored here so they can be cleaned up on shutdown. - * (The order in which they are stored is not important.) - */ -static ISC_LIST(ns_hook_module_t) hook_modules; -static bool hook_modules_initialized = false; - #if HAVE_DLFCN_H && HAVE_DLOPEN static isc_result_t load_symbol(void *handle, const char *modpath, @@ -103,10 +93,10 @@ load_symbol(void *handle, const char *modpath, } static isc_result_t -load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { +load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { isc_result_t result; void *handle = NULL; - ns_hook_module_t *hmod = NULL; + ns_module_t *hmod = NULL; ns_hook_register_t *register_func = NULL; ns_hook_destroy_t *destroy_func = NULL; ns_hook_version_t *version_func = NULL; @@ -158,7 +148,6 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); hmod->register_func = register_func; hmod->destroy_func = destroy_func; - hmod->inst = NULL; ISC_LINK_INIT(hmod, link); @@ -186,14 +175,21 @@ cleanup: } static void -unload_library(ns_hook_module_t **hmodp) { - ns_hook_module_t *hmod = NULL; +unload_library(ns_module_t **hmodp) { + ns_module_t *hmod = NULL; REQUIRE(hmodp != NULL && *hmodp != NULL); hmod = *hmodp; *hmodp = NULL; + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "unloading module '%s'", hmod->modpath); + + if (hmod->inst != NULL) { + hmod->destroy_func(&hmod->inst); + } if (hmod->handle != NULL) { (void) dlclose(hmod->handle); } @@ -230,10 +226,10 @@ load_symbol(HMODULE handle, const char *modpath, } static isc_result_t -load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { +load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { isc_result_t result; HMODULE handle; - ns_hook_module_t *hmod = NULL; + ns_module_t *hmod = NULL; ns_hook_register_t *register_func = NULL; ns_hook_destroy_t *destroy_func = NULL; ns_hook_version_t *version_func = NULL; @@ -272,7 +268,6 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); hmod->register_func = register_func; hmod->destroy_func = destroy_func; - hmod->inst = NULL; ISC_LINK_INIT(hmod, link); @@ -300,14 +295,21 @@ cleanup: } static void -unload_library(ns_hook_module_t **hmodp) { - ns_hook_module_t *hmod = NULL; +unload_library(ns_module_t **hmodp) { + ns_module_t *hmod = NULL; REQUIRE(hmodp != NULL && *hmodp != NULL); hmod = *hmodp; *hmodp = NULL; + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "unloading module '%s'", hmod->modpath); + + if (hmod->inst != NULL) { + hmod->destroy_func(&hmod->inst); + } if (hmod->handle != NULL) { FreeLibrary(hmod->handle); } @@ -320,7 +322,7 @@ unload_library(ns_hook_module_t **hmodp) { } #else /* HAVE_DLFCN_H || _WIN32 */ static isc_result_t -load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { +load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { UNUSED(mctx); UNUSED(modpath); UNUSED(hmodp); @@ -333,22 +335,22 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_hook_module_t **hmodp) { } static void -unload_library(ns_hook_module_t **hmodp) { +unload_library(ns_module_t **hmodp) { UNUSED(hmodp); } #endif /* HAVE_DLFCN_H */ isc_result_t -ns_hookmodule_load(const char *modpath, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, - ns_hookctx_t *hctx, ns_hooktable_t *hooktable) +ns_module_load(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, void *actx, ns_hookctx_t *hctx, + ns_modlist_t *modlist, ns_hooktable_t *hooktable) { isc_result_t result; - ns_hook_module_t *hmod = NULL; + ns_module_t *hmod = NULL; - REQUIRE(hook_modules_initialized); REQUIRE(NS_HOOKCTX_VALID(hctx)); + REQUIRE(modlist != NULL); REQUIRE(hooktable != NULL); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, @@ -356,10 +358,15 @@ ns_hookmodule_load(const char *modpath, const char *parameters, "loading module '%s'", modpath); CHECK(load_library(hctx->mctx, modpath, &hmod)); + + isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, + NS_LOGMODULE_HOOKS, ISC_LOG_INFO, + "registering module '%s'", modpath); + CHECK(hmod->register_func(parameters, cfg_file, cfg_line, cfg, actx, hctx, hooktable, &hmod->inst)); - ISC_LIST_APPEND(hook_modules, hmod, link); + ISC_LIST_APPEND(*modlist, hmod, link); cleanup: if (result != ISC_R_SUCCESS && hmod != NULL) { @@ -369,28 +376,6 @@ cleanup: return (result); } -void -ns_hookmodule_unload_all(void) { - ns_hook_module_t *hmod = NULL, *prev = NULL; - - if (!hook_modules_initialized) { - return; - } - - hmod = ISC_LIST_TAIL(hook_modules); - while (hmod != NULL) { - prev = ISC_LIST_PREV(hmod, link); - ISC_LIST_UNLINK(hook_modules, hmod, link); - isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, - NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "unloading module '%s'", hmod->modpath); - hmod->destroy_func(&hmod->inst); - ENSURE(hmod->inst == NULL); - unload_library(&hmod); - hmod = prev; - } -} - isc_result_t ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { ns_hookctx_t *hctx = NULL; @@ -427,11 +412,6 @@ void ns_hooktable_init(ns_hooktable_t *hooktable) { int i; - if (!hook_modules_initialized) { - ISC_LIST_INIT(hook_modules); - hook_modules_initialized = true; - } - for (i = 0; i < NS_HOOKPOINTS_COUNT; i++) { ISC_LIST_INIT((*hooktable)[i]); } @@ -501,3 +481,38 @@ ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx, ISC_LINK_INIT(copy, link); ISC_LIST_APPEND((*hooktable)[hookpoint], copy, link); } + +void +ns_modlist_create(isc_mem_t *mctx, ns_modlist_t **listp) { + ns_modlist_t *modlist = NULL; + + REQUIRE(listp != NULL && *listp == NULL); + + modlist = isc_mem_get(mctx, sizeof(*modlist)); + memset(modlist, 0, sizeof(*modlist)); + ISC_LIST_INIT(*modlist); + + *listp = modlist; +} + +void +ns_modlist_free(isc_mem_t *mctx, void **listp) { + ns_modlist_t *list = NULL; + ns_module_t *hmod = NULL, *next = NULL; + + REQUIRE(listp != NULL && *listp != NULL); + + list = *listp; + *listp = NULL; + + for (hmod = ISC_LIST_HEAD(*list); + hmod != NULL; + hmod = next) + { + next = ISC_LIST_NEXT(hmod, link); + ISC_LIST_UNLINK(*list, hmod, link); + unload_library(&hmod); + } + + isc_mem_put(mctx, list, sizeof(*list)); +} diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index fe710c30c3..14af15d695 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -253,14 +253,11 @@ typedef struct ns_hookctx { #define NS_HOOK_AGE 0 #endif -typedef isc_result_t ns_hook_register_t(const char *parameters, - const char *file, - unsigned long line, - const void *cfg, - void *actx, - ns_hookctx_t *hctx, - ns_hooktable_t *hooktable, - void **instp); +typedef isc_result_t +ns_hook_register_t(const char *parameters, + const char *file, unsigned long line, + const void *cfg, void *actx, ns_hookctx_t *hctx, + ns_hooktable_t *hooktable, void **instp); /*%< * Called when registering a new module. * @@ -308,13 +305,13 @@ ns_hook_destroyctx(ns_hookctx_t **hctxp); */ isc_result_t -ns_hookmodule_load(const char *modpath, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, - ns_hookctx_t *hctx, ns_hooktable_t *hooktable); +ns_module_load(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, void *actx, ns_hookctx_t *hctx, + ns_modlist_t *modlist, ns_hooktable_t *hooktable); /*%< - * Load the hook module specified from the file 'modpath', using - * parameters 'parameters'. + * Load the module specified from the file 'modpath', and + * register an instance using 'parameters'. * * 'cfg_file' and 'cfg_line' specify the location of the hook module * declaration in the configuration file. @@ -325,12 +322,27 @@ ns_hookmodule_load(const char *modpath, const char *parameters, * * 'hctx' is the hook context and 'hooktable' is the hook table * into which hook points should be registered. + * + * 'instp' will be left pointing to the instance of the module + * created by the module's hook_register function. */ void -ns_hookmodule_unload_all(void); +ns_modlist_create(isc_mem_t *mctx, ns_modlist_t **listp); /*%< - * Unload all currently loaded hook modules. + * Create and initialize a module list. + */ + +void +ns_modlist_free(isc_mem_t *mctx, void **listp); +/*%< + * Close each module in a module list, then free the list object. + */ + +void +ns_hooktable_free(isc_mem_t *mctx, void **tablep); +/*%< + * Free a hook table. */ void @@ -362,11 +374,4 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep); /*%< * Allocate and initialize a hook table. */ - -void -ns_hooktable_free(isc_mem_t *mctx, void **tablep); -/*%< - * Free a hook table. - */ - #endif /* NS_HOOKS_H */ diff --git a/lib/ns/include/ns/types.h b/lib/ns/include/ns/types.h index 06066e2942..189c46bc79 100644 --- a/lib/ns/include/ns/types.h +++ b/lib/ns/include/ns/types.h @@ -18,6 +18,8 @@ typedef struct ns_altsecret ns_altsecret_t; typedef ISC_LIST(ns_altsecret_t) ns_altsecretlist_t; typedef struct ns_client ns_client_t; typedef struct ns_clientmgr ns_clientmgr_t; +typedef struct ns_module ns_module_t; +typedef ISC_LIST(ns_module_t) ns_modlist_t; typedef struct ns_interface ns_interface_t; typedef struct ns_interfacemgr ns_interfacemgr_t; typedef struct ns_query ns_query_t; diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index e870f859f1..f5be0ac290 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -46,8 +46,6 @@ ns_clientmgr_destroy ns_hook_add ns_hook_createctx ns_hook_destroyctx -ns_hookmodule_load -ns_hookmodule_unload_all ns_hooktable_create ns_hooktable_free ns_hooktable_init @@ -79,6 +77,9 @@ ns_listenlist_default ns_listenlist_detach ns_log_init ns_log_setcontext +ns_modlist_create +ns_modlist_free +ns_module_load ns_notify_start ns_query_cancel ns_query_done From 7a47e4d85f5db3140c80cc258786205d835c4a01 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 2 Nov 2018 23:28:25 -0700 Subject: [PATCH 19/26] restore filter-aaaa syntax checking - added functionality to check hook parameters in named-checkconf, and restored the checkconf tests that were removed from the filter-aaaa test. --- bin/check/Makefile.in | 2 +- bin/check/named-checkconf.c | 13 +++- bin/check/named-checkconf.docbook | 13 +++- bin/hooks/filter-aaaa.c | 82 +++++++++++++++++++- bin/named/server.c | 8 +- bin/tests/system/filter-aaaa/conf/bad1.conf | 15 ++++ bin/tests/system/filter-aaaa/conf/bad2.conf | 24 ++++++ bin/tests/system/filter-aaaa/conf/bad3.conf | 17 ++++ bin/tests/system/filter-aaaa/conf/bad4.conf | 17 ++++ bin/tests/system/filter-aaaa/conf/bad5.conf | 19 +++++ bin/tests/system/filter-aaaa/conf/good1.conf | 14 ++++ bin/tests/system/filter-aaaa/conf/good2.conf | 14 ++++ bin/tests/system/filter-aaaa/conf/good3.conf | 15 ++++ bin/tests/system/filter-aaaa/conf/good4.conf | 15 ++++ bin/tests/system/filter-aaaa/conf/good5.conf | 17 ++++ bin/tests/system/filter-aaaa/tests.sh | 20 +++++ lib/bind9/Makefile.in | 7 +- lib/bind9/check.c | 78 +++++++++++++++++-- lib/bind9/include/bind9/check.h | 7 +- lib/ns/hooks.c | 39 +++++++++- lib/ns/include/ns/hooks.h | 28 ++++++- lib/ns/win32/libns.def | 1 + 22 files changed, 435 insertions(+), 30 deletions(-) create mode 100644 bin/tests/system/filter-aaaa/conf/bad1.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad2.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad3.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad4.conf create mode 100644 bin/tests/system/filter-aaaa/conf/bad5.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good1.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good2.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good3.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good4.conf create mode 100644 bin/tests/system/filter-aaaa/conf/good5.conf diff --git a/bin/check/Makefile.in b/bin/check/Makefile.in index b15cd90a70..8f009a4b81 100644 --- a/bin/check/Makefile.in +++ b/bin/check/Makefile.in @@ -66,7 +66,7 @@ named-checkzone.@O@: named-checkzone.c named-checkconf@EXEEXT@: named-checkconf.@O@ check-tool.@O@ ${ISCDEPLIBS} \ ${NSDEPENDLIBS} ${DNSDEPLIBS} ${ISCCFGDEPLIBS} ${BIND9DEPLIBS} export BASEOBJS="named-checkconf.@O@ check-tool.@O@"; \ - export LIBS0="${NSLIBS} ${BIND9LIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ + export LIBS0="${BIND9LIBS} ${NSLIBS} ${ISCCFGLIBS} ${DNSLIBS}"; \ ${FINALBUILDCMD} named-checkzone@EXEEXT@: named-checkzone.@O@ check-tool.@O@ ${ISCDEPLIBS} \ diff --git a/bin/check/named-checkconf.c b/bin/check/named-checkconf.c index 753f5ba69c..d5599ea133 100644 --- a/bin/check/named-checkconf.c +++ b/bin/check/named-checkconf.c @@ -46,6 +46,8 @@ static const char *program = "named-checkconf"; +static bool loadhooks = true; + isc_log_t *logc = NULL; #define CHECK(r)\ @@ -562,7 +564,7 @@ main(int argc, char **argv) { /* * Process memory debugging argument first. */ -#define CMDLINE_FLAGS "dhjlm:t:pvxz" +#define CMDLINE_FLAGS "cdhjlm:t:pvxz" while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != -1) { switch (c) { case 'm': @@ -587,6 +589,10 @@ main(int argc, char **argv) { while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) { switch (c) { + case 'c': + loadhooks = false; + break; + case 'd': debug++; break; @@ -677,9 +683,10 @@ main(int argc, char **argv) { ISC_R_SUCCESS) exit(1); - result = bind9_check_namedconf(config, logc, mctx); - if (result != ISC_R_SUCCESS) + result = bind9_check_namedconf(config, loadhooks, logc, mctx); + if (result != ISC_R_SUCCESS) { exit_status = 1; + } if (result == ISC_R_SUCCESS && (load_zones || list_zones)) { result = load_zones_fromconfig(config, mctx, list_zones); diff --git a/bin/check/named-checkconf.docbook b/bin/check/named-checkconf.docbook index dea38896ce..69f322c4d8 100644 --- a/bin/check/named-checkconf.docbook +++ b/bin/check/named-checkconf.docbook @@ -52,7 +52,7 @@ named-checkconf - + @@ -114,6 +114,17 @@
+ + -c + + + Check "core" configuration only. This suppresses the loading + of hook modules, and causes all parameters to + hook statements to be ignored. + + + + -p diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 0084645262..50e5d473ac 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -249,8 +249,52 @@ parse_filter_aaaa_on(const cfg_obj_t *param_obj, const char *param_name, return (result); } +static isc_result_t +check_syntax(cfg_obj_t *fmap, const void *cfg, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *aclobj = NULL; + dns_acl_t *acl = NULL; + filter_aaaa_t f4 = NONE, f6 = NONE; + + cfg_map_get(fmap, "filter-aaaa", &aclobj); + if (aclobj == NULL) { + return (result); + } + + CHECK(cfg_acl_fromconfig(aclobj, (const cfg_obj_t *) cfg, + lctx, (cfg_aclconfctx_t *) actx, + mctx, 0, &acl)); + + CHECK(parse_filter_aaaa_on(fmap, "filter-aaaa-on-v4", &f4)); + CHECK(parse_filter_aaaa_on(fmap, "filter-aaaa-on-v6", &f6)); + + if ((f4 != NONE || f6 != NONE) && dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, lctx, ISC_LOG_WARNING, + "\"filter-aaaa\" is 'none;' but " + "either filter-aaaa-on-v4 or filter-aaaa-on-v6 " + "is enabled"); + result = ISC_R_FAILURE; + } else if (f4 == NONE && f6 == NONE && !dns_acl_isnone(acl)) { + cfg_obj_log(aclobj, lctx, ISC_LOG_WARNING, + "\"filter-aaaa\" is set but " + "neither filter-aaaa-on-v4 or filter-aaaa-on-v6 " + "is enabled"); + result = ISC_R_FAILURE; + } + + cleanup: + if (acl != NULL) { + dns_acl_detach(&acl); + } + + return (result); +} + static isc_result_t parse_parameters(filter_instance_t *inst, const char *parameters, + const char *cfg_file, unsigned long cfg_line, const void *cfg, void *actx, ns_hookctx_t *hctx) { isc_result_t result = ISC_R_SUCCESS; @@ -263,8 +307,10 @@ parse_parameters(filter_instance_t *inst, const char *parameters, isc_buffer_constinit(&b, parameters, strlen(parameters)); isc_buffer_add(&b, strlen(parameters)); - CHECK(cfg_parse_buffer(parser, &b, &cfg_type_parameters, - ¶m_obj)); + CHECK(cfg_parse_buffer4(parser, &b, cfg_file, cfg_line, + &cfg_type_parameters, 0, ¶m_obj)); + + CHECK(check_syntax(param_obj, cfg, hctx->mctx, hctx->lctx, actx)); CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &inst->v4_aaaa)); @@ -323,7 +369,9 @@ hook_register(const char *parameters, isc_mem_attach(hctx->mctx, &inst->mctx); if (parameters != NULL) { - CHECK(parse_parameters(inst, parameters, cfg, actx, hctx)); + CHECK(parse_parameters(inst, parameters, + cfg_file, cfg_line, + cfg, actx, hctx)); } CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), @@ -358,6 +406,34 @@ hook_register(const char *parameters, return (result); } +isc_result_t +hook_check(const char *parameters, const char *cfg_file, unsigned long cfg_line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + isc_result_t result = ISC_R_SUCCESS; + cfg_parser_t *parser = NULL; + cfg_obj_t *param_obj = NULL; + isc_buffer_t b; + + CHECK(cfg_parser_create(mctx, lctx, &parser)); + + isc_buffer_constinit(&b, parameters, strlen(parameters)); + isc_buffer_add(&b, strlen(parameters)); + CHECK(cfg_parse_buffer4(parser, &b, cfg_file, cfg_line, + &cfg_type_parameters, 0, ¶m_obj)); + + CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx)); + + cleanup: + if (param_obj != NULL) { + cfg_obj_destroy(parser, ¶m_obj); + } + if (parser != NULL) { + cfg_parser_destroy(&parser); + } + return (result); +} + /* * Called by ns_module_unload(); frees memory allocated by * the module when it was registered. diff --git a/bin/named/server.c b/bin/named/server.c index b6a43df85d..8204db5451 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -5308,7 +5308,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, #ifdef HAVE_DLOPEN if (hook_list != NULL) { - CHECK(ns_hook_createctx(mctx, &hctx)); + CHECK(ns_hook_createctx(mctx, view, &hctx)); INSIST(view->hooktable == NULL); CHECK(ns_hooktable_create(view->mctx, @@ -8102,8 +8102,12 @@ load_configuration(const char *filename, named_server_t *server, /* * Check the validity of the configuration. + * + * (Ignore hook module parameters for now; they will be + * checked later when the modules are actually loaded and + * registered.) */ - CHECK(bind9_check_namedconf(config, named_g_lctx, named_g_mctx)); + CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx)); /* * Fill in the maps array, used for resolving defaults. diff --git a/bin/tests/system/filter-aaaa/conf/bad1.conf b/bin/tests/system/filter-aaaa/conf/bad1.conf new file mode 100644 index 0000000000..0107435c2f --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad1.conf @@ -0,0 +1,15 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { none; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad2.conf b/bin/tests/system/filter-aaaa/conf/bad2.conf new file mode 100644 index 0000000000..0db0bb81c1 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad2.conf @@ -0,0 +1,24 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + /* + * While this matches the defaults, it is not a good configuration + * to have in named.conf as the two options contradict each other + * indicating a error on behalf of the operator. + * + * The default is to have filter-aaaa-on-v4 off, but if it is turned + * on then it applies to all IPv4 queries. This results in + * contradictory defaults. + */ + filter-aaaa-on-v4 no; + filter-aaaa { any; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad3.conf b/bin/tests/system/filter-aaaa/conf/bad3.conf new file mode 100644 index 0000000000..418c548186 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad3.conf @@ -0,0 +1,17 @@ +/* + * 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. + */ + +view myview { + hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 no; + filter-aaaa { any; }; + }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad4.conf b/bin/tests/system/filter-aaaa/conf/bad4.conf new file mode 100644 index 0000000000..0357956123 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad4.conf @@ -0,0 +1,17 @@ +/* + * 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. + */ + +view myview { + hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { none; }; + }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/bad5.conf b/bin/tests/system/filter-aaaa/conf/bad5.conf new file mode 100644 index 0000000000..ea807d3fbd --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/bad5.conf @@ -0,0 +1,19 @@ +/* + * 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. + */ + +plugin query "../../../plugins/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 1.0.0.0/8; }; +}; + +view myview { + match-clients { any; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good1.conf b/bin/tests/system/filter-aaaa/conf/good1.conf new file mode 100644 index 0000000000..e5136a9c77 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good1.conf @@ -0,0 +1,14 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good2.conf b/bin/tests/system/filter-aaaa/conf/good2.conf new file mode 100644 index 0000000000..935e1f1211 --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good2.conf @@ -0,0 +1,14 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good3.conf b/bin/tests/system/filter-aaaa/conf/good3.conf new file mode 100644 index 0000000000..f92ad6b38b --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good3.conf @@ -0,0 +1,15 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 break-dnssec; + filter-aaaa { 1.0.0.0/8; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good4.conf b/bin/tests/system/filter-aaaa/conf/good4.conf new file mode 100644 index 0000000000..ea4756093c --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good4.conf @@ -0,0 +1,15 @@ +/* + * 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. + */ + +hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 1.0.0.0/8; }; +}; diff --git a/bin/tests/system/filter-aaaa/conf/good5.conf b/bin/tests/system/filter-aaaa/conf/good5.conf new file mode 100644 index 0000000000..131c5524dd --- /dev/null +++ b/bin/tests/system/filter-aaaa/conf/good5.conf @@ -0,0 +1,17 @@ +/* + * 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. + */ + +view myview { + hook query "../../../hooks/lib/filter-aaaa.so" { + filter-aaaa-on-v4 yes; + filter-aaaa { 1.0.0.0/8; }; + }; +}; diff --git a/bin/tests/system/filter-aaaa/tests.sh b/bin/tests/system/filter-aaaa/tests.sh index 4ff2ebe3a2..f9b4d882b9 100644 --- a/bin/tests/system/filter-aaaa/tests.sh +++ b/bin/tests/system/filter-aaaa/tests.sh @@ -20,6 +20,26 @@ rm -f dig.out.* DIGOPTS="+tcp +noadd +nosea +nostat +nocmd -p ${PORT}" RNDCCMD="$RNDC -c $SYSTEMTESTTOP/common/rndc.conf -p ${CONTROLPORT} -s" +for conf in conf/good*.conf +do + n=`expr $n + 1` + echo_i "checking that $conf is accepted ($n)" + ret=0 + $CHECKCONF "$conf" || ret=1 + if [ $ret != 0 ]; then echo_i "failed"; fi + status=`expr $status + $ret` +done + +for conf in conf/bad*.conf +do + n=`expr $n + 1` + echo_i "checking that $conf is rejected ($n)" + ret=0 + $CHECKCONF "$conf" >/dev/null && ret=1 + if [ $ret != 0 ]; then echo_i "failed"; fi + status=`expr $status + $ret` +done + # # Authoritative tests against: # filter-aaaa-on-v4 yes; diff --git a/lib/bind9/Makefile.in b/lib/bind9/Makefile.in index 5a9760c0e0..b2441fb925 100644 --- a/lib/bind9/Makefile.in +++ b/lib/bind9/Makefile.in @@ -18,7 +18,7 @@ VERSION=@BIND9_VERSION@ @BIND9_MAKE_INCLUDES@ CINCLUDES = -I. ${BIND9_INCLUDES} ${DNS_INCLUDES} ${ISC_INCLUDES} \ - ${ISCCFG_INCLUDES} @OPENSSL_INCLUDES@ + ${ISCCFG_INCLUDES} ${NS_INCLUDES} @OPENSSL_INCLUDES@ CDEFINES = CWARNINGS = @@ -26,6 +26,7 @@ CWARNINGS = ISCLIBS = ../../lib/isc/libisc.@A@ @OPENSSL_LIBS@ ISCCFGLIBS = ../../lib/isccfg/libisccfg.@A@ DNSLIBS = ../../lib/dns/libdns.@A@ @DNS_CRYPTO_LIBS@ +NSLIBS = ../../lib/ns/libns.@A@ ISCDEPLIBS = ../../lib/isc/libisc.@A@ ISCCFGDEPLIBS = ../../lib/isccfg/libisccfg.@A@ @@ -61,8 +62,8 @@ libbind9.la: ${OBJS} ${ISCCFGDEPLIBS} ${ISCDEPLIBS} ${DNSDEPLIBS} ${LIBTOOL_MODE_LINK} \ ${CC} ${ALL_CFLAGS} ${LDFLAGS} -o libbind9.la -rpath ${libdir} \ -version-info ${LIBINTERFACE}:${LIBREVISION}:${LIBAGE} \ - ${OBJS} ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} @DNS_CRYPTO_LIBS@ \ - ${LIBS} + ${OBJS} ${NSLIBS} ${DNSLIBS} ${ISCCFGLIBS} ${ISCLIBS} \ + @DNS_CRYPTO_LIBS@ ${LIBS} timestamp: libbind9.@A@ touch timestamp diff --git a/lib/bind9/check.c b/lib/bind9/check.c index 4fac8e9b85..efef37f00d 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -54,6 +54,8 @@ #include #include +#include + #include static unsigned char dlviscorg_ndata[] = "\003dlv\003isc\003org"; @@ -3349,7 +3351,7 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj, static isc_result_t check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const char *viewname, dns_rdataclass_t vclass, - isc_symtab_t *files, isc_symtab_t *inview, + isc_symtab_t *files, bool checkhooks, isc_symtab_t *inview, isc_log_t *logctx, isc_mem_t *mctx) { const cfg_obj_t *zones = NULL; @@ -3365,6 +3367,7 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const cfg_obj_t *obj; const cfg_obj_t *options = NULL; const cfg_obj_t *opts = NULL; + const cfg_obj_t *hook_list = NULL; bool enablednssec, enablevalidation; const char *valstr = "no"; unsigned int tflags, mflags; @@ -3662,6 +3665,56 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, if (tresult != ISC_R_SUCCESS) result = tresult; + /* + * Load hook modules. + */ + if (checkhooks) { + if (voptions != NULL) { + (void)cfg_map_get(voptions, "hook", &hook_list); + } else { + (void)cfg_map_get(config, "hook", &hook_list); + } + } + +#ifdef HAVE_DLOPEN + for (element = cfg_list_first(hook_list); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *hook = cfg_listelt_value(element); + + const char *type, *library; + const char *parameters = NULL; + + /* Get the path to the hook module. */ + obj = cfg_tuple_get(hook, "type"); + type = cfg_obj_asstring(obj); + + /* Only query hooks are supported currently. */ + if (strcasecmp(type, "query") != 0) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "unsupported hook type"); + return (ISC_R_FAILURE); + } + + library = cfg_obj_asstring(cfg_tuple_get(hook, "library")); + + obj = cfg_tuple_get(hook, "parameters"); + if (obj != NULL && cfg_obj_isstring(obj)) { + parameters = cfg_obj_asstring(obj); + } + tresult = ns_module_check(library, parameters, + cfg_obj_file(obj), cfg_obj_line(obj), + config, mctx, logctx, actx); + if (tresult != ISC_R_SUCCESS) { + cfg_obj_log(obj, logctx, ISC_LOG_ERROR, + "%s: module check failed: %s", + library, isc_result_totext(tresult)); + result = tresult; + } + } +#endif /* HAVE_DLOPEN */ + cleanup: if (symtab != NULL) isc_symtab_destroy(&symtab); @@ -3916,8 +3969,8 @@ bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx, } isc_result_t -bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, - isc_mem_t *mctx) +bind9_check_namedconf(const cfg_obj_t *config, bool hooks, + isc_log_t *logctx, isc_mem_t *mctx) { const cfg_obj_t *options = NULL; const cfg_obj_t *views = NULL; @@ -3973,13 +4026,15 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, } if (views == NULL) { - tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in, - files, inview, logctx, mctx); + tresult = check_viewconf(config, NULL, NULL, + dns_rdataclass_in, files, + hooks, inview, logctx, mctx); if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { result = ISC_R_FAILURE; } } else { const cfg_obj_t *zones = NULL; + const cfg_obj_t *hooks = NULL; (void)cfg_map_get(config, "zone", &zones); if (zones != NULL) { @@ -3988,6 +4043,14 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, "all zones must be in views"); result = ISC_R_FAILURE; } + + (void)cfg_map_get(config, "hook", &hooks); + if (hooks != NULL) { + cfg_obj_log(hooks, logctx, ISC_LOG_ERROR, + "when using 'view' statements, " + "all hooks must be defined in views"); + result = ISC_R_FAILURE; + } } tresult = isc_symtab_create(mctx, 100, NULL, NULL, true, &symtab); @@ -4051,8 +4114,9 @@ bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, } } if (tresult == ISC_R_SUCCESS) - tresult = check_viewconf(config, voptions, key, vclass, - files, inview, logctx, mctx); + tresult = check_viewconf(config, voptions, key, + vclass, files, hooks, + inview, logctx, mctx); if (tresult != ISC_R_SUCCESS) result = ISC_R_FAILURE; } diff --git a/lib/bind9/include/bind9/check.h b/lib/bind9/include/bind9/check.h index 92d4bdda71..4d483fcfd4 100644 --- a/lib/bind9/include/bind9/check.h +++ b/lib/bind9/include/bind9/check.h @@ -35,12 +35,15 @@ ISC_LANG_BEGINDECLS isc_result_t -bind9_check_namedconf(const cfg_obj_t *config, isc_log_t *logctx, - isc_mem_t *mctx); +bind9_check_namedconf(const cfg_obj_t *config, bool check_hooks, + isc_log_t *logctx, isc_mem_t *mctx); /*%< * Check the syntactic validity of a configuration parse tree generated from * a named.conf file. * + * If 'check_hooks' is true, load hook modules and check the validity of their + * parameters as well. + * * Requires: *\li config is a valid parse tree * diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 4573f6fc1e..885b7fa25f 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -30,6 +30,8 @@ #include #include +#include + #include #include #include @@ -47,6 +49,7 @@ struct ns_module { void *handle; void *inst; char *modpath; + ns_hook_check_t *check_func; ns_hook_register_t *register_func; ns_hook_destroy_t *destroy_func; LINK(ns_module_t) link; @@ -97,6 +100,7 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { isc_result_t result; void *handle = NULL; ns_module_t *hmod = NULL; + ns_hook_check_t *check_func = NULL; ns_hook_register_t *register_func = NULL; ns_hook_destroy_t *destroy_func = NULL; ns_hook_version_t *version_func = NULL; @@ -104,7 +108,7 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { REQUIRE(hmodp != NULL && *hmodp == NULL); - flags = RTLD_NOW | RTLD_LOCAL; + flags = RTLD_LAZY | RTLD_LOCAL; #ifdef RTLD_DEEPBIND flags |= RTLD_DEEPBIND; #endif @@ -136,16 +140,19 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { CHECK(ISC_R_FAILURE); } + CHECK(load_symbol(handle, modpath, "hook_check", + (void **)&check_func)); CHECK(load_symbol(handle, modpath, "hook_register", (void **)®ister_func)); CHECK(load_symbol(handle, modpath, "hook_destroy", (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); - hmod->mctx = NULL; + memset(hmod, 0, sizeof(*hmod)); isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); + hmod->check_func = check_func; hmod->register_func = register_func; hmod->destroy_func = destroy_func; @@ -262,7 +269,7 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { (void **)&destroy_func)); hmod = isc_mem_get(mctx, sizeof(*hmod)); - hmod->mctx = NULL; + memset(hmod, 0, sizeof(*hmod)); isc_mem_attach(mctx, &hmod->mctx); hmod->handle = handle; hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); @@ -377,7 +384,28 @@ cleanup: } isc_result_t -ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { +ns_module_check(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx) +{ + isc_result_t result; + ns_module_t *hmod = NULL; + + CHECK(load_library(mctx, modpath, &hmod)); + + result = hmod->check_func(parameters, cfg_file, cfg_line, + cfg, mctx, lctx, actx); + +cleanup: + if (hmod != NULL) { + unload_library(&hmod); + } + + return (result); +} + +isc_result_t +ns_hook_createctx(isc_mem_t *mctx, dns_view_t *view, ns_hookctx_t **hctxp) { ns_hookctx_t *hctx = NULL; REQUIRE(hctxp != NULL && *hctxp == NULL); @@ -386,6 +414,8 @@ ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp) { memset(hctx, 0, sizeof(*hctx)); hctx->lctx = ns_lctx; + dns_view_attach(view, &hctx->view); + isc_mem_attach(mctx, &hctx->mctx); hctx->magic = NS_HOOKCTX_MAGIC; @@ -405,6 +435,7 @@ ns_hook_destroyctx(ns_hookctx_t **hctxp) { hctx->magic = 0; + dns_view_detach(&hctx->view); isc_mem_putanddetach(&hctx->mctx, hctx, sizeof(*hctx)); } diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 14af15d695..64f944a4f1 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -233,6 +233,7 @@ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; */ typedef struct ns_hookctx { unsigned int magic; + dns_view_t *view; isc_mem_t *mctx; isc_log_t *lctx; } ns_hookctx_t; @@ -272,14 +273,23 @@ ns_hook_register_t(const char *parameters, *\li Other errors are possible */ -typedef void ns_hook_destroy_t(void **instp); +typedef void +ns_hook_destroy_t(void **instp); /*%< * Destroy a module instance. * * '*instp' must be set to NULL by the function before it returns. */ -typedef int ns_hook_version_t(void); +typedef isc_result_t +ns_hook_check_t(const char *parameters, const char *file, unsigned long line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx); +/*%< + * Check the validity of 'parameters'. + */ + +typedef int +ns_hook_version_t(void); /*%< * Return the API version number a hook module was compiled with. * @@ -291,13 +301,13 @@ typedef int ns_hook_version_t(void); /*% * Prototypes for API functions to be defined in each module. */ +ns_hook_check_t hook_check; ns_hook_destroy_t hook_destroy; ns_hook_register_t hook_register; ns_hook_version_t hook_version; isc_result_t -ns_hook_createctx(isc_mem_t *mctx, ns_hookctx_t **hctxp); - +ns_hook_createctx(isc_mem_t *mctx, dns_view_t *view, ns_hookctx_t **hctxp); void ns_hook_destroyctx(ns_hookctx_t **hctxp); /*%< @@ -327,6 +337,16 @@ ns_module_load(const char *modpath, const char *parameters, * created by the module's hook_register function. */ +isc_result_t +ns_module_check(const char *modpath, const char *parameters, + const char *cfg_file, unsigned long cfg_line, + const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx); +/*%< + * Open the module at 'modpath' and check the validity of + * 'parameters', logging any errors or warnings found, then + * close it without configuring it. + */ + void ns_modlist_create(isc_mem_t *mctx, ns_modlist_t **listp); /*%< diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index f5be0ac290..c7192933a6 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -79,6 +79,7 @@ ns_log_init ns_log_setcontext ns_modlist_create ns_modlist_free +ns_module_check ns_module_load ns_notify_start ns_query_cancel From 8da0c0e7d553011b7f5870e98e811389440fa8a1 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 30 Nov 2018 10:12:04 -0800 Subject: [PATCH 20/26] eliminate ns_hookctx structure, pass mctx/lctx/view directly --- bin/hooks/filter-aaaa.c | 40 ++++++++++++------------ bin/named/server.c | 16 +++------- lib/bind9/check.c | 4 +-- lib/ns/hooks.c | 65 +++++++++------------------------------ lib/ns/include/ns/hooks.h | 49 ++++++----------------------- lib/ns/win32/libns.def | 2 -- 6 files changed, 52 insertions(+), 124 deletions(-) diff --git a/bin/hooks/filter-aaaa.c b/bin/hooks/filter-aaaa.c index 50e5d473ac..2fedc6301c 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/hooks/filter-aaaa.c @@ -294,8 +294,8 @@ check_syntax(cfg_obj_t *fmap, const void *cfg, static isc_result_t parse_parameters(filter_instance_t *inst, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, ns_hookctx_t *hctx) + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) { isc_result_t result = ISC_R_SUCCESS; cfg_parser_t *parser = NULL; @@ -303,14 +303,14 @@ parse_parameters(filter_instance_t *inst, const char *parameters, const cfg_obj_t *obj = NULL; isc_buffer_t b; - CHECK(cfg_parser_create(hctx->mctx, hctx->lctx, &parser)); + CHECK(cfg_parser_create(mctx, lctx, &parser)); isc_buffer_constinit(&b, parameters, strlen(parameters)); isc_buffer_add(&b, strlen(parameters)); CHECK(cfg_parse_buffer4(parser, &b, cfg_file, cfg_line, &cfg_type_parameters, 0, ¶m_obj)); - CHECK(check_syntax(param_obj, cfg, hctx->mctx, hctx->lctx, actx)); + CHECK(check_syntax(param_obj, cfg, mctx, lctx, actx)); CHECK(parse_filter_aaaa_on(param_obj, "filter-aaaa-on-v4", &inst->v4_aaaa)); @@ -320,10 +320,10 @@ parse_parameters(filter_instance_t *inst, const char *parameters, result = cfg_map_get(param_obj, "filter-aaaa", &obj); if (result == ISC_R_SUCCESS) { CHECK(cfg_acl_fromconfig(obj, (const cfg_obj_t *) cfg, - hctx->lctx, (cfg_aclconfctx_t *) actx, - hctx->mctx, 0, &inst->aaaa_acl)); + lctx, (cfg_aclconfctx_t *) actx, + mctx, 0, &inst->aaaa_acl)); } else { - CHECK(dns_acl_any(hctx->mctx, &inst->aaaa_acl)); + CHECK(dns_acl_any(mctx, &inst->aaaa_acl)); } cleanup: @@ -350,33 +350,32 @@ parse_parameters(filter_instance_t *inst, const char *parameters, */ isc_result_t hook_register(const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, ns_hookctx_t *hctx, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, ns_hooktable_t *hooktable, void **instp) { filter_instance_t *inst = NULL; isc_result_t result; - isc_log_write(hctx->lctx, NS_LOGCATEGORY_GENERAL, + isc_log_write(lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, "registering 'filter-aaaa' " "module from %s:%lu, %s parameters", cfg_file, cfg_line, parameters != NULL ? "with" : "no"); - inst = isc_mem_get(hctx->mctx, sizeof(*inst)); + inst = isc_mem_get(mctx, sizeof(*inst)); memset(inst, 0, sizeof(*inst)); - isc_mem_attach(hctx->mctx, &inst->mctx); + isc_mem_attach(mctx, &inst->mctx); if (parameters != NULL) { - CHECK(parse_parameters(inst, parameters, - cfg_file, cfg_line, - cfg, actx, hctx)); + CHECK(parse_parameters(inst, parameters, cfg, cfg_file, + cfg_line, mctx, lctx, actx)); } - CHECK(isc_mempool_create(hctx->mctx, sizeof(filter_data_t), + CHECK(isc_mempool_create(mctx, sizeof(filter_data_t), &inst->datapool)); - CHECK(isc_ht_init(&inst->ht, hctx->mctx, 16)); + CHECK(isc_ht_init(&inst->ht, mctx, 16)); /* * Fill the mempool with 1K filter_aaaa state objects at @@ -394,7 +393,7 @@ hook_register(const char *parameters, /* * Set hook points in the view's hooktable. */ - install_hooks(hooktable, hctx->mctx, inst); + install_hooks(hooktable, mctx, inst); *instp = inst; @@ -407,8 +406,9 @@ hook_register(const char *parameters, } isc_result_t -hook_check(const char *parameters, const char *cfg_file, unsigned long cfg_line, - const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx) +hook_check(const char *parameters, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) { isc_result_t result = ISC_R_SUCCESS; cfg_parser_t *parser = NULL; diff --git a/bin/named/server.c b/bin/named/server.c index 8204db5451..1a1c443da3 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1538,7 +1538,7 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, static isc_result_t configure_hook(dns_view_t *view, const cfg_obj_t *hook, - const cfg_obj_t *config, ns_hookctx_t *hctx) + const cfg_obj_t *config) { isc_result_t result = ISC_R_SUCCESS; const cfg_obj_t *obj; @@ -1563,9 +1563,9 @@ configure_hook(dns_view_t *view, const cfg_obj_t *hook, parameters = cfg_obj_asstring(obj); } result = ns_module_load(library, parameters, - cfg_obj_file(obj), cfg_obj_line(obj), - config, named_g_aclconfctx, - hctx, view->modlist, view->hooktable); + config, cfg_obj_file(obj), cfg_obj_line(obj), + named_g_mctx, named_g_lctx, named_g_aclconfctx, + view); if (result != ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, @@ -3755,7 +3755,6 @@ 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; @@ -5308,8 +5307,6 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, #ifdef HAVE_DLOPEN if (hook_list != NULL) { - CHECK(ns_hook_createctx(mctx, view, &hctx)); - INSIST(view->hooktable == NULL); CHECK(ns_hooktable_create(view->mctx, (ns_hooktable_t **) &view->hooktable)); @@ -5325,7 +5322,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, { const cfg_obj_t *hook = cfg_listelt_value(element); - CHECK(configure_hook(view, hook, config, hctx)); + CHECK(configure_hook(view, hook, config)); } #endif @@ -5580,9 +5577,6 @@ 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); } diff --git a/lib/bind9/check.c b/lib/bind9/check.c index efef37f00d..af43a1d04d 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -3703,9 +3703,9 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, if (obj != NULL && cfg_obj_isstring(obj)) { parameters = cfg_obj_asstring(obj); } - tresult = ns_module_check(library, parameters, + tresult = ns_module_check(library, parameters, config, cfg_obj_file(obj), cfg_obj_line(obj), - config, mctx, logctx, actx); + mctx, logctx, actx); if (tresult != ISC_R_SUCCESS) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, "%s: module check failed: %s", diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 885b7fa25f..5ce67292f4 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -348,32 +348,32 @@ unload_library(ns_module_t **hmodp) { #endif /* HAVE_DLFCN_H */ isc_result_t -ns_module_load(const char *modpath, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, ns_hookctx_t *hctx, - ns_modlist_t *modlist, ns_hooktable_t *hooktable) +ns_module_load(const char *modpath, const char *parameters, const void *cfg, + const char *cfg_file, unsigned long cfg_line, isc_mem_t *mctx, + isc_log_t *lctx, void *actx, dns_view_t *view) { isc_result_t result; ns_module_t *hmod = NULL; - REQUIRE(NS_HOOKCTX_VALID(hctx)); - REQUIRE(modlist != NULL); - REQUIRE(hooktable != NULL); + REQUIRE(mctx != NULL); + REQUIRE(lctx != NULL); + REQUIRE(view != NULL); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, "loading module '%s'", modpath); - CHECK(load_library(hctx->mctx, modpath, &hmod)); + CHECK(load_library(mctx, modpath, &hmod)); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, "registering module '%s'", modpath); - CHECK(hmod->register_func(parameters, cfg_file, cfg_line, - cfg, actx, hctx, hooktable, &hmod->inst)); + CHECK(hmod->register_func(parameters, cfg, cfg_file, cfg_line, + mctx, lctx, actx, view->hooktable, + &hmod->inst)); - ISC_LIST_APPEND(*modlist, hmod, link); + ISC_LIST_APPEND(*(ns_modlist_t *)view->modlist, hmod, link); cleanup: if (result != ISC_R_SUCCESS && hmod != NULL) { @@ -385,16 +385,16 @@ cleanup: isc_result_t ns_module_check(const char *modpath, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx) + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) { isc_result_t result; ns_module_t *hmod = NULL; CHECK(load_library(mctx, modpath, &hmod)); - result = hmod->check_func(parameters, cfg_file, cfg_line, - cfg, mctx, lctx, actx); + result = hmod->check_func(parameters, cfg, cfg_file, cfg_line, + mctx, lctx, actx); cleanup: if (hmod != NULL) { @@ -404,41 +404,6 @@ cleanup: return (result); } -isc_result_t -ns_hook_createctx(isc_mem_t *mctx, dns_view_t *view, ns_hookctx_t **hctxp) { - ns_hookctx_t *hctx = NULL; - - REQUIRE(hctxp != NULL && *hctxp == NULL); - - hctx = isc_mem_get(mctx, sizeof(*hctx)); - memset(hctx, 0, sizeof(*hctx)); - hctx->lctx = ns_lctx; - - dns_view_attach(view, &hctx->view); - - 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 = NULL; - - REQUIRE(hctxp != NULL && NS_HOOKCTX_VALID(*hctxp)); - - hctx = *hctxp; - *hctxp = NULL; - - hctx->magic = 0; - - dns_view_detach(&hctx->view); - 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 64f944a4f1..a25a336508 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -222,25 +222,6 @@ typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT]; */ LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; -/*! - * Context for initializing 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; - dns_view_t *view; - 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(h) ISC_MAGIC_VALID(h, NS_HOOKCTX_MAGIC) - /* * API version * @@ -256,8 +237,8 @@ typedef struct ns_hookctx { typedef isc_result_t ns_hook_register_t(const char *parameters, - const char *file, unsigned long line, - const void *cfg, void *actx, ns_hookctx_t *hctx, + const void *cfg, const char *file, unsigned long line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, ns_hooktable_t *hooktable, void **instp); /*%< * Called when registering a new module. @@ -282,8 +263,9 @@ ns_hook_destroy_t(void **instp); */ typedef isc_result_t -ns_hook_check_t(const char *parameters, const char *file, unsigned long line, - const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx); +ns_hook_check_t(const char *parameters, + const void *cfg, const char *file, unsigned long line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx); /*%< * Check the validity of 'parameters'. */ @@ -306,19 +288,11 @@ ns_hook_destroy_t hook_destroy; ns_hook_register_t hook_register; ns_hook_version_t hook_version; -isc_result_t -ns_hook_createctx(isc_mem_t *mctx, dns_view_t *view, ns_hookctx_t **hctxp); -void -ns_hook_destroyctx(ns_hookctx_t **hctxp); -/*%< - * Create/destroy a hook module context. - */ - isc_result_t ns_module_load(const char *modpath, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, void *actx, ns_hookctx_t *hctx, - ns_modlist_t *modlist, ns_hooktable_t *hooktable); + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, + dns_view_t *view); /*%< * Load the module specified from the file 'modpath', and * register an instance using 'parameters'. @@ -330,17 +304,14 @@ ns_module_load(const char *modpath, const char *parameters, * context, respectively; they are passed as void * here in order to * prevent this library from having a dependency on libisccfg). * - * 'hctx' is the hook context and 'hooktable' is the hook table - * into which hook points should be registered. - * * 'instp' will be left pointing to the instance of the module * created by the module's hook_register function. */ isc_result_t ns_module_check(const char *modpath, const char *parameters, - const char *cfg_file, unsigned long cfg_line, - const void *cfg, isc_mem_t *mctx, isc_log_t *lctx, void *actx); + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx); /*%< * Open the module at 'modpath' and check the validity of * 'parameters', logging any errors or warnings found, then diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index c7192933a6..d95f7980ba 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -44,8 +44,6 @@ ns_clientmgr_create ns_clientmgr_createclients ns_clientmgr_destroy ns_hook_add -ns_hook_createctx -ns_hook_destroyctx ns_hooktable_create ns_hooktable_free ns_hooktable_init From fd20f10d52913e2e39cbbc9f2f5f75cc6498147b Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 30 Nov 2018 15:32:03 -0800 Subject: [PATCH 21/26] name change from "hook modules" to "plugins" - "hook" is now used only for hook points and hook actions - the "hook" statement in named.conf is now "plugin" - ns_module and ns_modlist are now ns_plugin and ns_plugins - ns_module_load is renamed ns_plugin_register - the mandatory functions in plugin modules (hook_register, hook_check, hook_version, hook_destroy) have been renamed --- bin/Makefile.in | 2 +- bin/check/named-checkconf.c | 6 +- bin/check/named-checkconf.docbook | 4 +- bin/named/server.c | 48 ++-- bin/{hooks => plugins}/Makefile.in | 0 bin/{hooks => plugins}/filter-aaaa.8 | 0 bin/{hooks => plugins}/filter-aaaa.c | 39 +-- bin/{hooks => plugins}/filter-aaaa.docbook | 8 +- bin/{hooks => plugins}/filter-aaaa.html | 0 bin/tests/system/filter-aaaa/conf/bad1.conf | 2 +- bin/tests/system/filter-aaaa/conf/bad2.conf | 2 +- bin/tests/system/filter-aaaa/conf/bad3.conf | 2 +- bin/tests/system/filter-aaaa/conf/bad4.conf | 2 +- bin/tests/system/filter-aaaa/conf/good1.conf | 2 +- bin/tests/system/filter-aaaa/conf/good2.conf | 2 +- bin/tests/system/filter-aaaa/conf/good3.conf | 2 +- bin/tests/system/filter-aaaa/conf/good4.conf | 2 +- bin/tests/system/filter-aaaa/conf/good5.conf | 2 +- .../system/filter-aaaa/ns1/named1.conf.in | 2 +- .../system/filter-aaaa/ns1/named2.conf.in | 2 +- .../system/filter-aaaa/ns2/named1.conf.in | 2 +- .../system/filter-aaaa/ns2/named2.conf.in | 2 +- .../system/filter-aaaa/ns3/named1.conf.in | 2 +- .../system/filter-aaaa/ns3/named2.conf.in | 2 +- .../system/filter-aaaa/ns4/named1.conf.in | 2 +- .../system/filter-aaaa/ns4/named2.conf.in | 2 +- .../system/filter-aaaa/ns5/named.conf.in | 2 +- configure | 4 +- configure.ac | 2 +- doc/arm/Bv9ARM-book.xml | 2 +- lib/bind9/check.c | 46 ++-- lib/bind9/include/bind9/check.h | 4 +- lib/dns/include/dns/view.h | 4 +- lib/dns/view.c | 8 +- lib/isccfg/namedconf.c | 26 +- lib/ns/hooks.c | 260 +++++++++--------- lib/ns/include/ns/client.h | 2 +- lib/ns/include/ns/hooks.h | 79 +++--- lib/ns/include/ns/types.h | 4 +- lib/ns/query.c | 6 +- lib/ns/win32/libns.def | 8 +- util/copyrights | 7 + 42 files changed, 309 insertions(+), 296 deletions(-) rename bin/{hooks => plugins}/Makefile.in (100%) rename bin/{hooks => plugins}/filter-aaaa.8 (100%) rename bin/{hooks => plugins}/filter-aaaa.c (96%) rename bin/{hooks => plugins}/filter-aaaa.docbook (96%) rename bin/{hooks => plugins}/filter-aaaa.html (100%) diff --git a/bin/Makefile.in b/bin/Makefile.in index 8e55b450dc..9ad7f626b8 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -12,7 +12,7 @@ VPATH = @srcdir@ top_srcdir = @top_srcdir@ SUBDIRS = named rndc dig delv dnssec tools nsupdate check confgen \ - @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ hooks tests + @NZD_TOOLS@ @PYTHON_TOOLS@ @PKCS11_TOOLS@ plugins tests TARGETS = @BIND9_MAKE_RULES@ diff --git a/bin/check/named-checkconf.c b/bin/check/named-checkconf.c index d5599ea133..e4e55faad7 100644 --- a/bin/check/named-checkconf.c +++ b/bin/check/named-checkconf.c @@ -46,7 +46,7 @@ static const char *program = "named-checkconf"; -static bool loadhooks = true; +static bool loadplugins = true; isc_log_t *logc = NULL; @@ -590,7 +590,7 @@ main(int argc, char **argv) { while ((c = isc_commandline_parse(argc, argv, CMDLINE_FLAGS)) != EOF) { switch (c) { case 'c': - loadhooks = false; + loadplugins = false; break; case 'd': @@ -683,7 +683,7 @@ main(int argc, char **argv) { ISC_R_SUCCESS) exit(1); - result = bind9_check_namedconf(config, loadhooks, logc, mctx); + result = bind9_check_namedconf(config, loadplugins, logc, mctx); if (result != ISC_R_SUCCESS) { exit_status = 1; } diff --git a/bin/check/named-checkconf.docbook b/bin/check/named-checkconf.docbook index 69f322c4d8..97ed3ebf69 100644 --- a/bin/check/named-checkconf.docbook +++ b/bin/check/named-checkconf.docbook @@ -119,8 +119,8 @@ Check "core" configuration only. This suppresses the loading - of hook modules, and causes all parameters to - hook statements to be ignored. + of plugin modules, and causes all parameters to + plugin statements to be ignored. diff --git a/bin/named/server.c b/bin/named/server.c index 1a1c443da3..19f67aeec5 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1537,35 +1537,35 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, } static isc_result_t -configure_hook(dns_view_t *view, const cfg_obj_t *hook, - const cfg_obj_t *config) +configure_plugin(dns_view_t *view, const cfg_obj_t *plugin, + const cfg_obj_t *config) { isc_result_t result = ISC_R_SUCCESS; const cfg_obj_t *obj; const char *type, *library; const char *parameters = NULL; - /* Get the path to the hook module. */ - obj = cfg_tuple_get(hook, "type"); + /* Get the path to the plugin module. */ + obj = cfg_tuple_get(plugin, "type"); type = cfg_obj_asstring(obj); - /* Only query hooks are supported currently. */ + /* Only query plugins are supported currently. */ if (strcasecmp(type, "query") != 0) { cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, - "unsupported hook type"); + "unsupported plugin type"); return (ISC_R_FAILURE); } - library = cfg_obj_asstring(cfg_tuple_get(hook, "library")); + library = cfg_obj_asstring(cfg_tuple_get(plugin, "library")); - obj = cfg_tuple_get(hook, "parameters"); + obj = cfg_tuple_get(plugin, "parameters"); if (obj != NULL && cfg_obj_isstring(obj)) { parameters = cfg_obj_asstring(obj); } - result = ns_module_load(library, parameters, - config, cfg_obj_file(obj), cfg_obj_line(obj), - named_g_mctx, named_g_lctx, named_g_aclconfctx, - view); + result = ns_plugin_register(library, parameters, config, + cfg_obj_file(obj), cfg_obj_line(obj), + named_g_mctx, named_g_lctx, + named_g_aclconfctx, view); if (result != ISC_R_SUCCESS) { isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, @@ -3714,7 +3714,7 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, const cfg_obj_t *dlvobj = NULL; unsigned int dlzargc; char **dlzargv; - const cfg_obj_t *dyndb_list, *hook_list; + const cfg_obj_t *dyndb_list, *plugin_list; const cfg_obj_t *disabled; const cfg_obj_t *obj, *obj2; const cfg_listelt_t *element; @@ -5296,33 +5296,33 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, #endif /* - * Load hook modules. + * Load plugins. */ - hook_list = NULL; + plugin_list = NULL; if (voptions != NULL) { - (void)cfg_map_get(voptions, "hook", &hook_list); + (void)cfg_map_get(voptions, "plugin", &plugin_list); } else { - (void)cfg_map_get(config, "hook", &hook_list); + (void)cfg_map_get(config, "plugin", &plugin_list); } #ifdef HAVE_DLOPEN - if (hook_list != NULL) { + if (plugin_list != NULL) { INSIST(view->hooktable == NULL); CHECK(ns_hooktable_create(view->mctx, (ns_hooktable_t **) &view->hooktable)); view->hooktable_free = ns_hooktable_free; - ns_modlist_create(view->mctx, (ns_modlist_t **)&view->modlist); - view->modlist_free = ns_modlist_free; + ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins); + view->plugins_free = ns_plugins_free; } - for (element = cfg_list_first(hook_list); + for (element = cfg_list_first(plugin_list); element != NULL; element = cfg_list_next(element)) { - const cfg_obj_t *hook = cfg_listelt_value(element); + const cfg_obj_t *plugin = cfg_listelt_value(element); - CHECK(configure_hook(view, hook, config)); + CHECK(configure_plugin(view, plugin, config)); } #endif @@ -8097,7 +8097,7 @@ load_configuration(const char *filename, named_server_t *server, /* * Check the validity of the configuration. * - * (Ignore hook module parameters for now; they will be + * (Ignore plugin parameters for now; they will be * checked later when the modules are actually loaded and * registered.) */ diff --git a/bin/hooks/Makefile.in b/bin/plugins/Makefile.in similarity index 100% rename from bin/hooks/Makefile.in rename to bin/plugins/Makefile.in diff --git a/bin/hooks/filter-aaaa.8 b/bin/plugins/filter-aaaa.8 similarity index 100% rename from bin/hooks/filter-aaaa.8 rename to bin/plugins/filter-aaaa.8 diff --git a/bin/hooks/filter-aaaa.c b/bin/plugins/filter-aaaa.c similarity index 96% rename from bin/hooks/filter-aaaa.c rename to bin/plugins/filter-aaaa.c index 2fedc6301c..18c1b962b2 100644 --- a/bin/hooks/filter-aaaa.c +++ b/bin/plugins/filter-aaaa.c @@ -78,7 +78,7 @@ typedef struct filter_data { } filter_data_t; typedef struct filter_instance { - ns_module_t *module; + ns_plugin_t *module; isc_mem_t *mctx; /* @@ -337,22 +337,23 @@ parse_parameters(filter_instance_t *inst, const char *parameters, } /** - ** Mandatory hook API functions: + ** Mandatory plugin API functions: ** - ** - hook_destroy - ** - hook_register - ** - hook_version + ** - plugin_destroy + ** - plugin_register + ** - plugin_version + ** - plugin_check **/ /* - * Called by ns_module_load() to register hook functions into - * a hook table. + * Called by ns_plugin_register() to initialize the plugin and + * register hook functions into the view hook table. */ isc_result_t -hook_register(const char *parameters, - const void *cfg, const char *cfg_file, unsigned long cfg_line, - isc_mem_t *mctx, isc_log_t *lctx, void *actx, - ns_hooktable_t *hooktable, void **instp) +plugin_register(const char *parameters, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, + ns_hooktable_t *hooktable, void **instp) { filter_instance_t *inst = NULL; isc_result_t result; @@ -399,16 +400,16 @@ hook_register(const char *parameters, cleanup: if (result != ISC_R_SUCCESS && inst != NULL) { - hook_destroy((void **) &inst); + plugin_destroy((void **) &inst); } return (result); } isc_result_t -hook_check(const char *parameters, - const void *cfg, const char *cfg_file, unsigned long cfg_line, - isc_mem_t *mctx, isc_log_t *lctx, void *actx) +plugin_check(const char *parameters, + const void *cfg, const char *cfg_file, unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx) { isc_result_t result = ISC_R_SUCCESS; cfg_parser_t *parser = NULL; @@ -435,11 +436,11 @@ hook_check(const char *parameters, } /* - * Called by ns_module_unload(); frees memory allocated by + * Called by ns_plugins_free(); frees memory allocated by * the module when it was registered. */ void -hook_destroy(void **instp) { +plugin_destroy(void **instp) { filter_instance_t *inst = (filter_instance_t *) *instp; if (inst->ht != NULL) { @@ -462,8 +463,8 @@ hook_destroy(void **instp) { * Returns hook module API version for compatibility checks. */ int -hook_version(void) { - return (NS_HOOK_VERSION); +plugin_version(void) { + return (NS_PLUGIN_VERSION); } /** diff --git a/bin/hooks/filter-aaaa.docbook b/bin/plugins/filter-aaaa.docbook similarity index 96% rename from bin/hooks/filter-aaaa.docbook rename to bin/plugins/filter-aaaa.docbook index 3a12e144c6..ae34d7baf1 100644 --- a/bin/hooks/filter-aaaa.docbook +++ b/bin/plugins/filter-aaaa.docbook @@ -38,14 +38,14 @@ - hook query "filter-aaaa.so" + plugin query "filter-aaaa.so" { parameters }; DESCRIPTION - filter-aaaa.so is a query hook module for + filter-aaaa.so is a query plugin module for named, enabling named to omit some IPv6 addresses when responding to clients. @@ -57,10 +57,10 @@ filter-aaaa-on-v6 options. These options are now deprecated in named.conf, but can be passed as parameters to the filter-aaaa.so - hook module, for example: + plugin, for example: -hook query "/usr/local/lib/filter-aaaa.so" { +plugin query "/usr/local/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa-on-v6 yes; filter-aaaa { 192.0.2.1; 2001:db8:2::1; }; diff --git a/bin/hooks/filter-aaaa.html b/bin/plugins/filter-aaaa.html similarity index 100% rename from bin/hooks/filter-aaaa.html rename to bin/plugins/filter-aaaa.html diff --git a/bin/tests/system/filter-aaaa/conf/bad1.conf b/bin/tests/system/filter-aaaa/conf/bad1.conf index 0107435c2f..3e117325e2 100644 --- a/bin/tests/system/filter-aaaa/conf/bad1.conf +++ b/bin/tests/system/filter-aaaa/conf/bad1.conf @@ -9,7 +9,7 @@ * information regarding copyright ownership. */ -hook query "../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa { none; }; }; diff --git a/bin/tests/system/filter-aaaa/conf/bad2.conf b/bin/tests/system/filter-aaaa/conf/bad2.conf index 0db0bb81c1..3298bd3232 100644 --- a/bin/tests/system/filter-aaaa/conf/bad2.conf +++ b/bin/tests/system/filter-aaaa/conf/bad2.conf @@ -9,7 +9,7 @@ * information regarding copyright ownership. */ -hook query "../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../plugins/lib/filter-aaaa.so" { /* * While this matches the defaults, it is not a good configuration * to have in named.conf as the two options contradict each other diff --git a/bin/tests/system/filter-aaaa/conf/bad3.conf b/bin/tests/system/filter-aaaa/conf/bad3.conf index 418c548186..202091fe6a 100644 --- a/bin/tests/system/filter-aaaa/conf/bad3.conf +++ b/bin/tests/system/filter-aaaa/conf/bad3.conf @@ -10,7 +10,7 @@ */ view myview { - hook query "../../../hooks/lib/filter-aaaa.so" { + plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 no; filter-aaaa { any; }; }; diff --git a/bin/tests/system/filter-aaaa/conf/bad4.conf b/bin/tests/system/filter-aaaa/conf/bad4.conf index 0357956123..759fbf7c5e 100644 --- a/bin/tests/system/filter-aaaa/conf/bad4.conf +++ b/bin/tests/system/filter-aaaa/conf/bad4.conf @@ -10,7 +10,7 @@ */ view myview { - hook query "../../../hooks/lib/filter-aaaa.so" { + plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa { none; }; }; diff --git a/bin/tests/system/filter-aaaa/conf/good1.conf b/bin/tests/system/filter-aaaa/conf/good1.conf index e5136a9c77..953e975825 100644 --- a/bin/tests/system/filter-aaaa/conf/good1.conf +++ b/bin/tests/system/filter-aaaa/conf/good1.conf @@ -9,6 +9,6 @@ * information regarding copyright ownership. */ -hook query "../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; }; diff --git a/bin/tests/system/filter-aaaa/conf/good2.conf b/bin/tests/system/filter-aaaa/conf/good2.conf index 935e1f1211..997d5e9fcb 100644 --- a/bin/tests/system/filter-aaaa/conf/good2.conf +++ b/bin/tests/system/filter-aaaa/conf/good2.conf @@ -9,6 +9,6 @@ * information regarding copyright ownership. */ -hook query "../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 break-dnssec; }; diff --git a/bin/tests/system/filter-aaaa/conf/good3.conf b/bin/tests/system/filter-aaaa/conf/good3.conf index f92ad6b38b..2fa677fa10 100644 --- a/bin/tests/system/filter-aaaa/conf/good3.conf +++ b/bin/tests/system/filter-aaaa/conf/good3.conf @@ -9,7 +9,7 @@ * information regarding copyright ownership. */ -hook query "../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 break-dnssec; filter-aaaa { 1.0.0.0/8; }; }; diff --git a/bin/tests/system/filter-aaaa/conf/good4.conf b/bin/tests/system/filter-aaaa/conf/good4.conf index ea4756093c..92c7be6288 100644 --- a/bin/tests/system/filter-aaaa/conf/good4.conf +++ b/bin/tests/system/filter-aaaa/conf/good4.conf @@ -9,7 +9,7 @@ * information regarding copyright ownership. */ -hook query "../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa { 1.0.0.0/8; }; }; diff --git a/bin/tests/system/filter-aaaa/conf/good5.conf b/bin/tests/system/filter-aaaa/conf/good5.conf index 131c5524dd..e88c515789 100644 --- a/bin/tests/system/filter-aaaa/conf/good5.conf +++ b/bin/tests/system/filter-aaaa/conf/good5.conf @@ -10,7 +10,7 @@ */ view myview { - hook query "../../../hooks/lib/filter-aaaa.so" { + plugin query "../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa { 1.0.0.0/8; }; }; diff --git a/bin/tests/system/filter-aaaa/ns1/named1.conf.in b/bin/tests/system/filter-aaaa/ns1/named1.conf.in index cd05abc9e9..3941dd67cd 100644 --- a/bin/tests/system/filter-aaaa/ns1/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named1.conf.in @@ -25,7 +25,7 @@ options { acl filterees { 10.53.0.1; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa { filterees; }; }; diff --git a/bin/tests/system/filter-aaaa/ns1/named2.conf.in b/bin/tests/system/filter-aaaa/ns1/named2.conf.in index 3201f7c9b3..cd28f03056 100644 --- a/bin/tests/system/filter-aaaa/ns1/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns1/named2.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v6 yes; filter-aaaa { fd92:7065:b8e:ffff::1; }; }; diff --git a/bin/tests/system/filter-aaaa/ns2/named1.conf.in b/bin/tests/system/filter-aaaa/ns2/named1.conf.in index 0f48645932..446279fba5 100644 --- a/bin/tests/system/filter-aaaa/ns2/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named1.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 yes; filter-aaaa { 10.53.0.2; }; }; diff --git a/bin/tests/system/filter-aaaa/ns2/named2.conf.in b/bin/tests/system/filter-aaaa/ns2/named2.conf.in index 18399cf08a..4fc0cab29a 100644 --- a/bin/tests/system/filter-aaaa/ns2/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns2/named2.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v6 yes; filter-aaaa { fd92:7065:b8e:ffff::2; }; }; diff --git a/bin/tests/system/filter-aaaa/ns3/named1.conf.in b/bin/tests/system/filter-aaaa/ns3/named1.conf.in index 2433c80d85..e757e8878b 100644 --- a/bin/tests/system/filter-aaaa/ns3/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named1.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 break-dnssec; filter-aaaa { 10.53.0.3; }; }; diff --git a/bin/tests/system/filter-aaaa/ns3/named2.conf.in b/bin/tests/system/filter-aaaa/ns3/named2.conf.in index 479d437980..216a85aef6 100644 --- a/bin/tests/system/filter-aaaa/ns3/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns3/named2.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v6 break-dnssec; filter-aaaa { fd92:7065:b8e:ffff::3; }; }; diff --git a/bin/tests/system/filter-aaaa/ns4/named1.conf.in b/bin/tests/system/filter-aaaa/ns4/named1.conf.in index 87e2eadcf5..804ed0ae3b 100644 --- a/bin/tests/system/filter-aaaa/ns4/named1.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named1.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 break-dnssec; filter-aaaa { 10.53.0.4; }; }; diff --git a/bin/tests/system/filter-aaaa/ns4/named2.conf.in b/bin/tests/system/filter-aaaa/ns4/named2.conf.in index 79b5ce8eff..87874d1375 100644 --- a/bin/tests/system/filter-aaaa/ns4/named2.conf.in +++ b/bin/tests/system/filter-aaaa/ns4/named2.conf.in @@ -23,7 +23,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v6 break-dnssec; filter-aaaa { fd92:7065:b8e:ffff::4; }; }; diff --git a/bin/tests/system/filter-aaaa/ns5/named.conf.in b/bin/tests/system/filter-aaaa/ns5/named.conf.in index b97ab1cafd..88bdf805b9 100644 --- a/bin/tests/system/filter-aaaa/ns5/named.conf.in +++ b/bin/tests/system/filter-aaaa/ns5/named.conf.in @@ -28,7 +28,7 @@ options { minimal-responses no; }; -hook query "../../../../hooks/lib/filter-aaaa.so" { +plugin query "../../../../plugins/lib/filter-aaaa.so" { filter-aaaa-on-v4 break-dnssec; filter-aaaa { any; }; }; diff --git a/configure b/configure index 4839c207dc..1eccd82ae3 100755 --- a/configure +++ b/configure @@ -21548,7 +21548,7 @@ ac_config_commands="$ac_config_commands chmod" # elsewhere if there's a good reason for doing so. # -ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/hooks/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile" +ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/plugins/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py bin/python/isc/tests/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/python/dnssec-keymgr.py bin/python/isc/__init__.py bin/python/isc/checkds.py bin/python/isc/coverage.py bin/python/isc/dnskey.py bin/python/isc/eventlist.py bin/python/isc/keydict.py bin/python/isc/keyevent.py bin/python/isc/keymgr.py bin/python/isc/keyseries.py bin/python/isc/keyzone.py bin/python/isc/policy.py bin/python/isc/rndc.py bin/python/isc/tests/dnskey_test.py bin/python/isc/tests/policy_test.py bin/rndc/Makefile bin/tests/Makefile bin/tests/headerdep_test.sh bin/tests/optional/Makefile bin/tests/pkcs11/Makefile bin/tests/pkcs11/benchmarks/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/dlzs.conf bin/tests/system/dyndb/Makefile bin/tests/system/dyndb/driver/Makefile bin/tests/system/pipelined/Makefile bin/tests/system/rndc/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/scripts/check-secure-delegation.pl contrib/scripts/zone-edit.sh doc/Makefile doc/arm/Makefile doc/arm/noteversion.xml doc/arm/pkgversion.xml doc/arm/releaseinfo.xml doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/tex/Makefile doc/tex/armstyle.sty doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-manpage.xsl doc/xsl/isc-notes-html.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/irs/tests/Makefile lib/isc/pthreads/Makefile lib/isc/pthreads/include/Makefile lib/isc/pthreads/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/include/pk11/Makefile lib/isc/include/pkcs11/Makefile lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isc/unix/include/pkcs11/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccc/tests/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/isccfg/tests/Makefile lib/ns/Makefile lib/ns/include/Makefile lib/ns/include/ns/Makefile lib/ns/tests/Makefile lib/samples/Makefile lib/samples/Makefile-postinstall unit/unittest.sh fuzz/Makefile" # @@ -22558,11 +22558,11 @@ do "bin/delv/Makefile") CONFIG_FILES="$CONFIG_FILES bin/delv/Makefile" ;; "bin/dig/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dig/Makefile" ;; "bin/dnssec/Makefile") CONFIG_FILES="$CONFIG_FILES bin/dnssec/Makefile" ;; - "bin/hooks/Makefile") CONFIG_FILES="$CONFIG_FILES bin/hooks/Makefile" ;; "bin/named/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/Makefile" ;; "bin/named/unix/Makefile") CONFIG_FILES="$CONFIG_FILES bin/named/unix/Makefile" ;; "bin/nsupdate/Makefile") CONFIG_FILES="$CONFIG_FILES bin/nsupdate/Makefile" ;; "bin/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/pkcs11/Makefile" ;; + "bin/plugins/Makefile") CONFIG_FILES="$CONFIG_FILES bin/plugins/Makefile" ;; "bin/python/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/Makefile" ;; "bin/python/isc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/isc/Makefile" ;; "bin/python/isc/utils.py") CONFIG_FILES="$CONFIG_FILES bin/python/isc/utils.py" ;; diff --git a/configure.ac b/configure.ac index b7f1037712..55610d843a 100644 --- a/configure.ac +++ b/configure.ac @@ -2957,11 +2957,11 @@ AC_CONFIG_FILES([ bin/delv/Makefile bin/dig/Makefile bin/dnssec/Makefile - bin/hooks/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile + bin/plugins/Makefile bin/python/Makefile bin/python/isc/Makefile bin/python/isc/utils.py diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index 00e5142d41..b81f8384e3 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -18276,7 +18276,7 @@ allow-query { !{ !10/8; any; }; key example; }; - + diff --git a/lib/bind9/check.c b/lib/bind9/check.c index af43a1d04d..ada1e257db 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -3351,7 +3351,7 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj, static isc_result_t check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const char *viewname, dns_rdataclass_t vclass, - isc_symtab_t *files, bool checkhooks, isc_symtab_t *inview, + isc_symtab_t *files, bool check_plugins, isc_symtab_t *inview, isc_log_t *logctx, isc_mem_t *mctx) { const cfg_obj_t *zones = NULL; @@ -3367,7 +3367,7 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const cfg_obj_t *obj; const cfg_obj_t *options = NULL; const cfg_obj_t *opts = NULL; - const cfg_obj_t *hook_list = NULL; + const cfg_obj_t *plugin_list = NULL; bool enablednssec, enablevalidation; const char *valstr = "no"; unsigned int tflags, mflags; @@ -3666,44 +3666,44 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, result = tresult; /* - * Load hook modules. + * Load plugins. */ - if (checkhooks) { + if (check_plugins) { if (voptions != NULL) { - (void)cfg_map_get(voptions, "hook", &hook_list); + (void)cfg_map_get(voptions, "plugin", &plugin_list); } else { - (void)cfg_map_get(config, "hook", &hook_list); + (void)cfg_map_get(config, "plugin", &plugin_list); } } #ifdef HAVE_DLOPEN - for (element = cfg_list_first(hook_list); + for (element = cfg_list_first(plugin_list); element != NULL; element = cfg_list_next(element)) { - const cfg_obj_t *hook = cfg_listelt_value(element); + const cfg_obj_t *plugin = cfg_listelt_value(element); const char *type, *library; const char *parameters = NULL; - /* Get the path to the hook module. */ - obj = cfg_tuple_get(hook, "type"); + /* Get the path to the plugin module. */ + obj = cfg_tuple_get(plugin, "type"); type = cfg_obj_asstring(obj); - /* Only query hooks are supported currently. */ + /* Only query plugins are supported currently. */ if (strcasecmp(type, "query") != 0) { cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "unsupported hook type"); + "unsupported plugin type"); return (ISC_R_FAILURE); } - library = cfg_obj_asstring(cfg_tuple_get(hook, "library")); + library = cfg_obj_asstring(cfg_tuple_get(plugin, "library")); - obj = cfg_tuple_get(hook, "parameters"); + obj = cfg_tuple_get(plugin, "parameters"); if (obj != NULL && cfg_obj_isstring(obj)) { parameters = cfg_obj_asstring(obj); } - tresult = ns_module_check(library, parameters, config, + tresult = ns_plugin_check(library, parameters, config, cfg_obj_file(obj), cfg_obj_line(obj), mctx, logctx, actx); if (tresult != ISC_R_SUCCESS) { @@ -3969,7 +3969,7 @@ bind9_check_controls(const cfg_obj_t *config, isc_log_t *logctx, } isc_result_t -bind9_check_namedconf(const cfg_obj_t *config, bool hooks, +bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins, isc_log_t *logctx, isc_mem_t *mctx) { const cfg_obj_t *options = NULL; @@ -4028,13 +4028,13 @@ bind9_check_namedconf(const cfg_obj_t *config, bool hooks, if (views == NULL) { tresult = check_viewconf(config, NULL, NULL, dns_rdataclass_in, files, - hooks, inview, logctx, mctx); + check_plugins, inview, logctx, mctx); if (result == ISC_R_SUCCESS && tresult != ISC_R_SUCCESS) { result = ISC_R_FAILURE; } } else { const cfg_obj_t *zones = NULL; - const cfg_obj_t *hooks = NULL; + const cfg_obj_t *plugins = NULL; (void)cfg_map_get(config, "zone", &zones); if (zones != NULL) { @@ -4044,11 +4044,11 @@ bind9_check_namedconf(const cfg_obj_t *config, bool hooks, result = ISC_R_FAILURE; } - (void)cfg_map_get(config, "hook", &hooks); - if (hooks != NULL) { - cfg_obj_log(hooks, logctx, ISC_LOG_ERROR, + (void)cfg_map_get(config, "plugin", &plugins); + if (plugins != NULL) { + cfg_obj_log(plugins, logctx, ISC_LOG_ERROR, "when using 'view' statements, " - "all hooks must be defined in views"); + "all plugins must be defined in views"); result = ISC_R_FAILURE; } } @@ -4115,7 +4115,7 @@ bind9_check_namedconf(const cfg_obj_t *config, bool hooks, } if (tresult == ISC_R_SUCCESS) tresult = check_viewconf(config, voptions, key, - vclass, files, hooks, + vclass, files, check_plugins, inview, logctx, mctx); if (tresult != ISC_R_SUCCESS) result = ISC_R_FAILURE; diff --git a/lib/bind9/include/bind9/check.h b/lib/bind9/include/bind9/check.h index 4d483fcfd4..0cac2e189c 100644 --- a/lib/bind9/include/bind9/check.h +++ b/lib/bind9/include/bind9/check.h @@ -35,13 +35,13 @@ ISC_LANG_BEGINDECLS isc_result_t -bind9_check_namedconf(const cfg_obj_t *config, bool check_hooks, +bind9_check_namedconf(const cfg_obj_t *config, bool check_plugins, isc_log_t *logctx, isc_mem_t *mctx); /*%< * Check the syntactic validity of a configuration parse tree generated from * a named.conf file. * - * If 'check_hooks' is true, load hook modules and check the validity of their + * If 'check_plugins' is true, load plugins and check the validity of their * parameters as well. * * Requires: diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h index 0fedb5d67f..43a3e9e016 100644 --- a/lib/dns/include/dns/view.h +++ b/lib/dns/include/dns/view.h @@ -237,8 +237,8 @@ struct dns_view { to log */ /* Registered module instances */ - void *modlist; - void (*modlist_free)(isc_mem_t *, void **); + void *plugins; + void (*plugins_free)(isc_mem_t *, void **); /* Hook table */ void *hooktable; /* ns_hooktable */ diff --git a/lib/dns/view.c b/lib/dns/view.c index ca5900b3d2..ca907cd5c1 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -256,8 +256,8 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, view->dtenv = NULL; view->dttypes = 0; - view->modlist = NULL; - view->modlist_free = NULL; + view->plugins = NULL; + view->plugins_free = NULL; view->hooktable = NULL; view->hooktable_free = NULL; @@ -553,8 +553,8 @@ destroy(dns_view_t *view) { if (view->hooktable != NULL && view->hooktable_free != NULL) { view->hooktable_free(view->mctx, &view->hooktable); } - if (view->modlist != NULL && view->modlist_free != NULL) { - view->modlist_free(view->mctx, &view->modlist); + if (view->plugins != NULL && view->plugins_free != NULL) { + view->plugins_free(view->mctx, &view->plugins); } isc_mem_putanddetach(&view->mctx, view, sizeof(*view)); } diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 9ac2235b0a..e94b0178e3 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -98,7 +98,7 @@ static cfg_type_t cfg_type_dlz; static cfg_type_t cfg_type_dnstap; static cfg_type_t cfg_type_dnstapoutput; static cfg_type_t cfg_type_dyndb; -static cfg_type_t cfg_type_hook; +static cfg_type_t cfg_type_plugin; static cfg_type_t cfg_type_ixfrdifftype; static cfg_type_t cfg_type_key; static cfg_type_t cfg_type_logfile; @@ -996,7 +996,7 @@ namedconf_or_view_clauses[] = { { "dyndb", &cfg_type_dyndb, CFG_CLAUSEFLAG_MULTI }, { "key", &cfg_type_key, CFG_CLAUSEFLAG_MULTI }, { "managed-keys", &cfg_type_managedkeys, CFG_CLAUSEFLAG_MULTI }, - { "hook", &cfg_type_hook, CFG_CLAUSEFLAG_MULTI }, + { "plugin", &cfg_type_plugin, CFG_CLAUSEFLAG_MULTI }, { "server", &cfg_type_server, CFG_CLAUSEFLAG_MULTI }, { "trusted-keys", &cfg_type_dnsseckeys, CFG_CLAUSEFLAG_MULTI }, { "zone", &cfg_type_zone, CFG_CLAUSEFLAG_MULTI }, @@ -2385,26 +2385,26 @@ static cfg_type_t cfg_type_dyndb = { }; /*% - * The "hook" statement syntax. - * Currently only one hook type is supported: query. + * The "plugin" statement syntax. + * Currently only one plugin type is supported: query. */ -static const char *hook_enums[] = { +static const char *plugin_enums[] = { "query", NULL }; -static cfg_type_t cfg_type_hooktype = { - "hooktype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, - &cfg_rep_string, hook_enums +static cfg_type_t cfg_type_plugintype = { + "plugintype", cfg_parse_enum, cfg_print_ustring, cfg_doc_enum, + &cfg_rep_string, plugin_enums }; -static cfg_tuplefielddef_t hook_fields[] = { - { "type", &cfg_type_hooktype, 0 }, +static cfg_tuplefielddef_t plugin_fields[] = { + { "type", &cfg_type_plugintype, 0 }, { "library", &cfg_type_astring, 0 }, { "parameters", &cfg_type_optional_bracketed_text, 0 }, { NULL, NULL, 0 } }; -static cfg_type_t cfg_type_hook = { - "hook", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, - &cfg_rep_tuple, hook_fields +static cfg_type_t cfg_type_plugin = { + "plugin", cfg_parse_tuple, cfg_print_tuple, cfg_doc_tuple, + &cfg_rep_tuple, plugin_fields }; /*% diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 5ce67292f4..d79c29f355 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -44,15 +44,15 @@ } \ } while (0) -struct ns_module { +struct ns_plugin { isc_mem_t *mctx; void *handle; void *inst; char *modpath; - ns_hook_check_t *check_func; - ns_hook_register_t *register_func; - ns_hook_destroy_t *destroy_func; - LINK(ns_module_t) link; + ns_plugin_check_t *check_func; + ns_plugin_register_t *register_func; + ns_plugin_destroy_t *destroy_func; + LINK(ns_plugin_t) link; }; static ns_hooklist_t default_hooktable[NS_HOOKPOINTS_COUNT]; @@ -85,7 +85,7 @@ load_symbol(void *handle, const char *modpath, isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to look up symbol %s in " - "hook module '%s': %s", + "plugin '%s': %s", symbol_name, modpath, errmsg); return (ISC_R_FAILURE); } @@ -96,17 +96,17 @@ load_symbol(void *handle, const char *modpath, } static isc_result_t -load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { +load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) { isc_result_t result; void *handle = NULL; - ns_module_t *hmod = NULL; - ns_hook_check_t *check_func = NULL; - ns_hook_register_t *register_func = NULL; - ns_hook_destroy_t *destroy_func = NULL; - ns_hook_version_t *version_func = NULL; + ns_plugin_t *plugin = NULL; + ns_plugin_check_t *check_func = NULL; + ns_plugin_register_t *register_func = NULL; + ns_plugin_destroy_t *destroy_func = NULL; + ns_plugin_version_t *version_func = NULL; int version, flags; - REQUIRE(hmodp != NULL && *hmodp == NULL); + REQUIRE(pluginp != NULL && *pluginp == NULL); flags = RTLD_LAZY | RTLD_LOCAL; #ifdef RTLD_DEEPBIND @@ -121,56 +121,57 @@ load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { } isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "failed to dlopen() hook module '%s': %s", + "failed to dlopen() plugin '%s': %s", modpath, errmsg); return (ISC_R_FAILURE); } - CHECK(load_symbol(handle, modpath, "hook_version", + CHECK(load_symbol(handle, modpath, "plugin_version", (void **)&version_func)); version = version_func(); - if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || - version > NS_HOOK_VERSION) + if (version < (NS_PLUGIN_VERSION - NS_PLUGIN_AGE) || + version > NS_PLUGIN_VERSION) { isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "hook API version mismatch: %d/%d", - version, NS_HOOK_VERSION); + "plugin API version mismatch: %d/%d", + version, NS_PLUGIN_VERSION); CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, modpath, "hook_check", + CHECK(load_symbol(handle, modpath, "plugin_check", (void **)&check_func)); - CHECK(load_symbol(handle, modpath, "hook_register", + CHECK(load_symbol(handle, modpath, "plugin_register", (void **)®ister_func)); - CHECK(load_symbol(handle, modpath, "hook_destroy", + CHECK(load_symbol(handle, modpath, "plugin_destroy", (void **)&destroy_func)); - hmod = isc_mem_get(mctx, sizeof(*hmod)); - memset(hmod, 0, sizeof(*hmod)); - isc_mem_attach(mctx, &hmod->mctx); - hmod->handle = handle; - hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); - hmod->check_func = check_func; - hmod->register_func = register_func; - hmod->destroy_func = destroy_func; + plugin = isc_mem_get(mctx, sizeof(*plugin)); + memset(plugin, 0, sizeof(*plugin)); + isc_mem_attach(mctx, &plugin->mctx); + plugin->handle = handle; + plugin->modpath = isc_mem_strdup(plugin->mctx, modpath); + plugin->check_func = check_func; + plugin->register_func = register_func; + plugin->destroy_func = destroy_func; - ISC_LINK_INIT(hmod, link); + ISC_LINK_INIT(plugin, link); - *hmodp = hmod; - hmod = NULL; + *pluginp = plugin; + plugin = NULL; cleanup: if (result != ISC_R_SUCCESS) { isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to dynamically load " - "module '%s': %s", modpath, + "plugin '%s': %s", modpath, isc_result_totext(result)); - if (hmod != NULL) { - isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); + if (plugin != NULL) { + isc_mem_putanddetach(&plugin->mctx, plugin, + sizeof(*plugin)); } if (handle != NULL) { @@ -182,29 +183,29 @@ cleanup: } static void -unload_library(ns_module_t **hmodp) { - ns_module_t *hmod = NULL; +unload_plugin(ns_plugin_t **pluginp) { + ns_plugin_t *plugin = NULL; - REQUIRE(hmodp != NULL && *hmodp != NULL); + REQUIRE(pluginp != NULL && *pluginp != NULL); - hmod = *hmodp; - *hmodp = NULL; + plugin = *pluginp; + *pluginp = NULL; isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "unloading module '%s'", hmod->modpath); + "unloading plugin '%s'", plugin->modpath); - if (hmod->inst != NULL) { - hmod->destroy_func(&hmod->inst); + if (plugin->inst != NULL) { + plugin->destroy_func(&plugin->inst); } - if (hmod->handle != NULL) { - (void) dlclose(hmod->handle); + if (plugin->handle != NULL) { + (void) dlclose(plugin->handle); } - if (hmod->modpath != NULL) { - isc_mem_free(hmod->mctx, hmod->modpath); + if (plugin->modpath != NULL) { + isc_mem_free(plugin->mctx, plugin->modpath); } - isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); + isc_mem_putanddetach(&plugin->mctx, plugin, sizeof(*plugin)); } #elif _WIN32 static isc_result_t @@ -222,7 +223,7 @@ load_symbol(HMODULE handle, const char *modpath, isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to look up symbol %s in " - "module '%s': %d", + "plugin '%s': %d", symbol_name, modpath, errstatus); return (ISC_R_FAILURE); } @@ -233,64 +234,65 @@ load_symbol(HMODULE handle, const char *modpath, } static isc_result_t -load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { +load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) { isc_result_t result; HMODULE handle; - ns_module_t *hmod = NULL; - ns_hook_register_t *register_func = NULL; - ns_hook_destroy_t *destroy_func = NULL; - ns_hook_version_t *version_func = NULL; + ns_plugin_t *plugin = NULL; + ns_plugin_register_t *register_func = NULL; + ns_plugin_destroy_t *destroy_func = NULL; + ns_plugin_version_t *version_func = NULL; int version; - REQUIRE(hmodp != NULL && *hmodp == NULL); + REQUIRE(pluginp != NULL && *pluginp == NULL); handle = LoadLibraryA(modpath); if (handle == NULL) { CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, modpath, "hook_version", + CHECK(load_symbol(handle, modpath, "plugin_version", (void **)&version_func)); version = version_func(NULL); - if (version < (NS_HOOK_VERSION - NS_HOOK_AGE) || - version > NS_HOOK_VERSION) + if (version < (NS_PLUGIN_VERSION - NS_PLUGIN_AGE) || + version > NS_PLUGIN_VERSION) { isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "hook API version mismatch: %d/%d", - version, NS_HOOK_VERSION); + "plugin API version mismatch: %d/%d", + version, NS_PLUGIN_VERSION); CHECK(ISC_R_FAILURE); } - CHECK(load_symbol(handle, modpath, "hook_register", + CHECK(load_symbol(handle, modpath, "plugin_register", (void **)®ister_func)); - CHECK(load_symbol(handle, modpath, "hook_destroy", + CHECK(load_symbol(handle, modpath, "plugin_destroy", (void **)&destroy_func)); - hmod = isc_mem_get(mctx, sizeof(*hmod)); - memset(hmod, 0, sizeof(*hmod)); - isc_mem_attach(mctx, &hmod->mctx); - hmod->handle = handle; - hmod->modpath = isc_mem_strdup(hmod->mctx, modpath); - hmod->register_func = register_func; - hmod->destroy_func = destroy_func; + plugin = isc_mem_get(mctx, sizeof(*plugin)); + memset(plugin, 0, sizeof(*plugin)); + isc_mem_attach(mctx, &plugin->mctx); + plugin->handle = handle; + plugin->modpath = isc_mem_strdup(plugin->mctx, modpath); + plugin->register_func = register_func; + plugin->destroy_func = destroy_func; - ISC_LINK_INIT(hmod, link); + ISC_LINK_INIT(plugin, link); - *hmodp = hmod; - hmod = NULL; + *pluginp = plugin; + plugin = NULL; cleanup: if (result != ISC_R_SUCCESS) { isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, "failed to dynamically load " - "hook module '%s': %d (%s)", modpath, + "plugin '%s': %d (%s)", modpath, GetLastError(), isc_result_totext(result)); - if (hmod != NULL) { - isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); + if (plugin != NULL) { + isc_mem_putanddetach(&plugin->mctx, plugin, + sizeof(*plugin)); } if (handle != NULL) { @@ -302,58 +304,60 @@ cleanup: } static void -unload_library(ns_module_t **hmodp) { - ns_module_t *hmod = NULL; +unload_plugin(ns_plugin_t **pluginp) { + ns_plugin_t *plugin = NULL; - REQUIRE(hmodp != NULL && *hmodp != NULL); + REQUIRE(pluginp != NULL && *pluginp != NULL); - hmod = *hmodp; - *hmodp = NULL; + plugin = *pluginp; + *pluginp = NULL; isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "unloading module '%s'", hmod->modpath); + "unloading plugin '%s'", plugin->modpath); - if (hmod->inst != NULL) { - hmod->destroy_func(&hmod->inst); + if (plugin->inst != NULL) { + plugin->destroy_func(&plugin->inst); } - if (hmod->handle != NULL) { - FreeLibrary(hmod->handle); + if (plugin->handle != NULL) { + FreeLibrary(plugin->handle); } - if (hmod->modpath != NULL) { - isc_mem_free(hmod->mctx, hmod->modpath); + if (plugin->modpath != NULL) { + isc_mem_free(plugin->mctx, plugin->modpath); } - isc_mem_putanddetach(&hmod->mctx, hmod, sizeof(*hmod)); + isc_mem_putanddetach(&plugin->mctx, plugin, sizeof(*plugin)); } #else /* HAVE_DLFCN_H || _WIN32 */ static isc_result_t -load_library(isc_mem_t *mctx, const char *modpath, ns_module_t **hmodp) { +load_plugin(isc_mem_t *mctx, const char *modpath, ns_plugin_t **pluginp) { UNUSED(mctx); UNUSED(modpath); - UNUSED(hmodp); + UNUSED(pluginp); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_ERROR, - "hook module support is not implemented"); + "plugin support is not implemented"); return (ISC_R_NOTIMPLEMENTED); } static void -unload_library(ns_module_t **hmodp) { - UNUSED(hmodp); +unload_plugin(ns_plugin_t **pluginp) { + UNUSED(pluginp); } #endif /* HAVE_DLFCN_H */ isc_result_t -ns_module_load(const char *modpath, const char *parameters, const void *cfg, - const char *cfg_file, unsigned long cfg_line, isc_mem_t *mctx, - isc_log_t *lctx, void *actx, dns_view_t *view) +ns_plugin_register(const char *modpath, const char *parameters, + const void *cfg, const char *cfg_file, + unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, + dns_view_t *view) { isc_result_t result; - ns_module_t *hmod = NULL; + ns_plugin_t *plugin = NULL; REQUIRE(mctx != NULL); REQUIRE(lctx != NULL); @@ -361,44 +365,44 @@ ns_module_load(const char *modpath, const char *parameters, const void *cfg, isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "loading module '%s'", modpath); + "loading plugin '%s'", modpath); - CHECK(load_library(mctx, modpath, &hmod)); + CHECK(load_plugin(mctx, modpath, &plugin)); isc_log_write(ns_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, - "registering module '%s'", modpath); + "registering plugin '%s'", modpath); - CHECK(hmod->register_func(parameters, cfg, cfg_file, cfg_line, - mctx, lctx, actx, view->hooktable, - &hmod->inst)); + CHECK(plugin->register_func(parameters, cfg, cfg_file, cfg_line, + mctx, lctx, actx, view->hooktable, + &plugin->inst)); - ISC_LIST_APPEND(*(ns_modlist_t *)view->modlist, hmod, link); + ISC_LIST_APPEND(*(ns_plugins_t *)view->plugins, plugin, link); cleanup: - if (result != ISC_R_SUCCESS && hmod != NULL) { - unload_library(&hmod); + if (result != ISC_R_SUCCESS && plugin != NULL) { + unload_plugin(&plugin); } return (result); } isc_result_t -ns_module_check(const char *modpath, const char *parameters, +ns_plugin_check(const char *modpath, const char *parameters, const void *cfg, const char *cfg_file, unsigned long cfg_line, isc_mem_t *mctx, isc_log_t *lctx, void *actx) { isc_result_t result; - ns_module_t *hmod = NULL; + ns_plugin_t *plugin = NULL; - CHECK(load_library(mctx, modpath, &hmod)); + CHECK(load_plugin(mctx, modpath, &plugin)); - result = hmod->check_func(parameters, cfg, cfg_file, cfg_line, + result = plugin->check_func(parameters, cfg, cfg_file, cfg_line, mctx, lctx, actx); cleanup: - if (hmod != NULL) { - unload_library(&hmod); + if (plugin != NULL) { + unload_plugin(&plugin); } return (result); @@ -479,35 +483,35 @@ ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx, } void -ns_modlist_create(isc_mem_t *mctx, ns_modlist_t **listp) { - ns_modlist_t *modlist = NULL; +ns_plugins_create(isc_mem_t *mctx, ns_plugins_t **listp) { + ns_plugins_t *plugins = NULL; REQUIRE(listp != NULL && *listp == NULL); - modlist = isc_mem_get(mctx, sizeof(*modlist)); - memset(modlist, 0, sizeof(*modlist)); - ISC_LIST_INIT(*modlist); + plugins = isc_mem_get(mctx, sizeof(*plugins)); + memset(plugins, 0, sizeof(*plugins)); + ISC_LIST_INIT(*plugins); - *listp = modlist; + *listp = plugins; } void -ns_modlist_free(isc_mem_t *mctx, void **listp) { - ns_modlist_t *list = NULL; - ns_module_t *hmod = NULL, *next = NULL; +ns_plugins_free(isc_mem_t *mctx, void **listp) { + ns_plugins_t *list = NULL; + ns_plugin_t *plugin = NULL, *next = NULL; REQUIRE(listp != NULL && *listp != NULL); list = *listp; *listp = NULL; - for (hmod = ISC_LIST_HEAD(*list); - hmod != NULL; - hmod = next) + for (plugin = ISC_LIST_HEAD(*list); + plugin != NULL; + plugin = next) { - next = ISC_LIST_NEXT(hmod, link); - ISC_LIST_UNLINK(*list, hmod, link); - unload_library(&hmod); + next = ISC_LIST_NEXT(plugin, link); + ISC_LIST_UNLINK(*list, plugin, link); + unload_plugin(&plugin); } isc_mem_put(mctx, list, sizeof(*list)); diff --git a/lib/ns/include/ns/client.h b/lib/ns/include/ns/client.h index 7d25eb9360..f78abc2149 100644 --- a/lib/ns/include/ns/client.h +++ b/lib/ns/include/ns/client.h @@ -434,7 +434,7 @@ void ns_client_putrdataset(ns_client_t *client, dns_rdataset_t **rdatasetp); /*%< * Get and release temporary rdatasets in the client message; - * used in query.c and in hook modules. + * used in query.c and in plugins. */ isc_result_t diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index a25a336508..1a7dfe26bb 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -223,27 +223,27 @@ typedef ns_hooklist_t ns_hooktable_t[NS_HOOKPOINTS_COUNT]; LIBNS_EXTERNAL_DATA extern ns_hooktable_t *ns__hook_table; /* - * API version + * Plugin API version * - * When the API changes, increment NS_HOOK_VERSION. If the + * When the API changes, increment NS_PLUGIN_VERSION. If the * change is backward-compatible (e.g., adding a new function call - * but not changing or removing an old one), increment NS_HOOK_AGE - * as well; if not, set NS_HOOK_AGE to 0. + * but not changing or removing an old one), increment NS_PLUGIN_AGE + * as well; if not, set NS_PLUGIN_AGE to 0. */ -#ifndef NS_HOOK_VERSION -#define NS_HOOK_VERSION 1 -#define NS_HOOK_AGE 0 +#ifndef NS_PLUGIN_VERSION +#define NS_PLUGIN_VERSION 1 +#define NS_PLUGIN_AGE 0 #endif typedef isc_result_t -ns_hook_register_t(const char *parameters, - const void *cfg, const char *file, unsigned long line, - isc_mem_t *mctx, isc_log_t *lctx, void *actx, - ns_hooktable_t *hooktable, void **instp); +ns_plugin_register_t(const char *parameters, + const void *cfg, const char *file, unsigned long line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, + ns_hooktable_t *hooktable, void **instp); /*%< - * Called when registering a new module. + * Called when registering a new plugin. * - * 'parameters' contains the module configuration text. + * 'parameters' contains the plugin configuration text. * * '*instp' will be set to the module instance handle if the function * is successful. @@ -255,79 +255,80 @@ ns_hook_register_t(const char *parameters, */ typedef void -ns_hook_destroy_t(void **instp); +ns_plugin_destroy_t(void **instp); /*%< - * Destroy a module instance. + * Destroy a plugin instance. * * '*instp' must be set to NULL by the function before it returns. */ typedef isc_result_t -ns_hook_check_t(const char *parameters, - const void *cfg, const char *file, unsigned long line, - isc_mem_t *mctx, isc_log_t *lctx, void *actx); +ns_plugin_check_t(const char *parameters, + const void *cfg, const char *file, unsigned long line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx); /*%< * Check the validity of 'parameters'. */ typedef int -ns_hook_version_t(void); +ns_plugin_version_t(void); /*%< - * Return the API version number a hook module was compiled with. + * Return the API version number a plugin was compiled with. * * If the returned version number is no greater than - * NS_HOOK_VERSION, and no less than NS_HOOK_VERSION - NS_HOOK_AGE, + * NS_PLUGIN_VERSION, and no less than NS_PLUGIN_VERSION - NS_PLUGIN_AGE, * then the module is API-compatible with named. */ /*% * Prototypes for API functions to be defined in each module. */ -ns_hook_check_t hook_check; -ns_hook_destroy_t hook_destroy; -ns_hook_register_t hook_register; -ns_hook_version_t hook_version; +ns_plugin_check_t plugin_check; +ns_plugin_destroy_t plugin_destroy; +ns_plugin_register_t plugin_register; +ns_plugin_version_t plugin_version; isc_result_t -ns_module_load(const char *modpath, const char *parameters, - const void *cfg, const char *cfg_file, unsigned long cfg_line, - isc_mem_t *mctx, isc_log_t *lctx, void *actx, - dns_view_t *view); +ns_plugin_register(const char *modpath, const char *parameters, + const void *cfg, const char *cfg_file, + unsigned long cfg_line, + isc_mem_t *mctx, isc_log_t *lctx, void *actx, + dns_view_t *view); /*%< - * Load the module specified from the file 'modpath', and + * Load the plugin module specified from the file 'modpath', and * register an instance using 'parameters'. * - * 'cfg_file' and 'cfg_line' specify the location of the hook module + * 'cfg_file' and 'cfg_line' specify the location of the plugin * declaration in the configuration file. * * 'cfg' and 'actx' are the configuration context and ACL configuration * context, respectively; they are passed as void * here in order to * prevent this library from having a dependency on libisccfg). * - * 'instp' will be left pointing to the instance of the module - * created by the module's hook_register function. + * 'instp' will be left pointing to the instance of the plugin + * created by the module's plugin_register function. */ isc_result_t -ns_module_check(const char *modpath, const char *parameters, +ns_plugin_check(const char *modpath, const char *parameters, const void *cfg, const char *cfg_file, unsigned long cfg_line, isc_mem_t *mctx, isc_log_t *lctx, void *actx); /*%< - * Open the module at 'modpath' and check the validity of + * Open the plugin module at 'modpath' and check the validity of * 'parameters', logging any errors or warnings found, then * close it without configuring it. */ void -ns_modlist_create(isc_mem_t *mctx, ns_modlist_t **listp); +ns_plugins_create(isc_mem_t *mctx, ns_plugins_t **listp); /*%< - * Create and initialize a module list. + * Create and initialize a plugin list. */ void -ns_modlist_free(isc_mem_t *mctx, void **listp); +ns_plugins_free(isc_mem_t *mctx, void **listp); /*%< - * Close each module in a module list, then free the list object. + * Close each plugin module in a plugin list, then free the list object. */ void diff --git a/lib/ns/include/ns/types.h b/lib/ns/include/ns/types.h index 189c46bc79..0c70332966 100644 --- a/lib/ns/include/ns/types.h +++ b/lib/ns/include/ns/types.h @@ -18,8 +18,8 @@ typedef struct ns_altsecret ns_altsecret_t; typedef ISC_LIST(ns_altsecret_t) ns_altsecretlist_t; typedef struct ns_client ns_client_t; typedef struct ns_clientmgr ns_clientmgr_t; -typedef struct ns_module ns_module_t; -typedef ISC_LIST(ns_module_t) ns_modlist_t; +typedef struct ns_plugin ns_plugin_t; +typedef ISC_LIST(ns_plugin_t) ns_plugins_t; typedef struct ns_interface ns_interface_t; typedef struct ns_interfacemgr ns_interfacemgr_t; typedef struct ns_query ns_query_t; diff --git a/lib/ns/query.c b/lib/ns/query.c index 32c0847b78..191e0dc35a 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -371,7 +371,7 @@ get_hooktab(query_ctx_t *qctx) { * * (XXX: This description omits several special cases including * DNS64, RPZ, RRL, and the SERVFAIL cache. It also doesn't discuss - * query hook modules.) + * plugins.) */ static void @@ -7112,9 +7112,9 @@ query_respond(query_ctx_t *qctx) { * XXX: This hook is meant to be at the top of this function, * but is postponed until after DNS64 in order to avoid an * assertion if the hook causes recursion. (When DNS64 also - * becomes a hook module, it will be necessary to find some + * becomes a plugin, it will be necessary to find some * other way to prevent that assertion, since the order in - * which hook modules are configured can't be enforced.) + * which plugins are configured can't be enforced.) */ CALL_HOOK(NS_QUERY_RESPOND_BEGIN, qctx); diff --git a/lib/ns/win32/libns.def b/lib/ns/win32/libns.def index d95f7980ba..95532062d1 100644 --- a/lib/ns/win32/libns.def +++ b/lib/ns/win32/libns.def @@ -75,11 +75,11 @@ ns_listenlist_default ns_listenlist_detach ns_log_init ns_log_setcontext -ns_modlist_create -ns_modlist_free -ns_module_check -ns_module_load ns_notify_start +ns_plugin_check +ns_plugin_register +ns_plugins_create +ns_plugins_free ns_query_cancel ns_query_done ns_query_free diff --git a/util/copyrights b/util/copyrights index 3845fe4f59..648b7dd2aa 100644 --- a/util/copyrights +++ b/util/copyrights @@ -153,6 +153,7 @@ ./bin/dnssec/win32/verify.vcxproj.filters.in X 2013,2015,2018 ./bin/dnssec/win32/verify.vcxproj.in X 2013,2014,2015,2016,2017,2018 ./bin/dnssec/win32/verify.vcxproj.user X 2013,2018 +./bin/named/Makefile.in MAKE 1998,1999,2000,2001,2002,2004,2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 ./bin/named/bind9.xsl SGML 2006,2007,2008,2009,2012,2013,2014,2015,2016,2017,2018 ./bin/named/bind9.xsl.h X 2007,2008,2009,2011,2012,2013,2014,2015,2016,2017,2018 ./bin/named/builtin.c C 2001,2002,2003,2004,2005,2007,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 @@ -239,6 +240,10 @@ ./bin/pkcs11/win32/pk11tokens.vcxproj.filters.in X 2014,2015,2018 ./bin/pkcs11/win32/pk11tokens.vcxproj.in X 2014,2015,2016,2017,2018 ./bin/pkcs11/win32/pk11tokens.vcxproj.user X 2014,2018 +./bin/plugins/filter-aaaa.8 MAN DOCBOOK +./bin/plugins/filter-aaaa.c C 2018 +./bin/plugins/filter-aaaa.docbook SGML 2018 +./bin/plugins/filter-aaaa.html HTML DOCBOOK ./bin/python/dnssec-checkds.8 MAN DOCBOOK ./bin/python/dnssec-checkds.docbook SGML 2012,2013,2014,2015,2016,2017,2018 ./bin/python/dnssec-checkds.html HTML DOCBOOK @@ -622,6 +627,7 @@ ./bin/tests/system/filter-aaaa/clean.sh SH 2010,2012,2014,2016,2018 ./bin/tests/system/filter-aaaa/ns1/sign.sh SH 2010,2012,2014,2016,2018 ./bin/tests/system/filter-aaaa/ns4/sign.sh SH 2010,2012,2014,2016,2018 +./bin/tests/system/filter-aaaa/prereq.sh SH 2018 ./bin/tests/system/filter-aaaa/setup.sh SH 2010,2012,2014,2016,2017,2018 ./bin/tests/system/filter-aaaa/tests.sh SH 2010,2012,2015,2016,2018 ./bin/tests/system/formerr/clean.sh SH 2013,2014,2015,2016,2018 @@ -1469,6 +1475,7 @@ ./doc/arm/man.dnssec-signzone.html X 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 ./doc/arm/man.dnssec-verify.html X 2012,2013,2014,2015,2016,2017,2018 ./doc/arm/man.dnstap-read.html X 2015,2016,2017,2018 +./doc/arm/man.filter-aaaa.html X 2018 ./doc/arm/man.host.html X 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 ./doc/arm/man.mdig.html X 2016,2017,2018 ./doc/arm/man.named-checkconf.html X 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018 From 423496879855ebf23ae0198899c8b5ad8724ad56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Mon, 3 Dec 2018 15:30:02 +0100 Subject: [PATCH 22/26] add a function for processing a list of configured plugins Add a new libisccfg function, cfg_pluginlist_foreach(), which allows an arbitrary callback to be invoked for every "plugin" stanza present in a configuration object. Use this function for both loading plugins and checking their configuration in order to reduce duplication of configuration processing code present in bin/named/server.c and lib/bind9/check.c. --- bin/named/server.c | 78 +++++++++++++------------------- lib/bind9/check.c | 79 ++++++++++++++++++++------------- lib/isccfg/include/isccfg/cfg.h | 41 +++++++++++++++++ lib/isccfg/parser.c | 48 ++++++++++++++++++++ 4 files changed, 169 insertions(+), 77 deletions(-) diff --git a/bin/named/server.c b/bin/named/server.c index 19f67aeec5..b44fd1e281 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -1535,45 +1535,6 @@ configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx, name, isc_result_totext(result)); return (result); } - -static isc_result_t -configure_plugin(dns_view_t *view, const cfg_obj_t *plugin, - const cfg_obj_t *config) -{ - isc_result_t result = ISC_R_SUCCESS; - const cfg_obj_t *obj; - const char *type, *library; - const char *parameters = NULL; - - /* Get the path to the plugin module. */ - obj = cfg_tuple_get(plugin, "type"); - type = cfg_obj_asstring(obj); - - /* Only query plugins are supported currently. */ - if (strcasecmp(type, "query") != 0) { - cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, - "unsupported plugin type"); - return (ISC_R_FAILURE); - } - - library = cfg_obj_asstring(cfg_tuple_get(plugin, "library")); - - obj = cfg_tuple_get(plugin, "parameters"); - if (obj != NULL && cfg_obj_isstring(obj)) { - parameters = cfg_obj_asstring(obj); - } - result = ns_plugin_register(library, parameters, config, - cfg_obj_file(obj), cfg_obj_line(obj), - named_g_mctx, named_g_lctx, - named_g_aclconfctx, view); - if (result != ISC_R_SUCCESS) { - isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, - NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, - "%s: module configuration failed: %s", - library, isc_result_totext(result)); - } - return (result); -} #endif @@ -3686,6 +3647,35 @@ create_mapped_acl(void) { return (result); } +#ifdef HAVE_DLOPEN +/*% + * A callback for the cfg_pluginlist_foreach() call in configure_view() below. + * If registering any plugin fails, registering subsequent ones is not + * attempted. + */ +static isc_result_t +register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, + const char *plugin_path, const char *parameters, + void *callback_data) +{ + dns_view_t *view = callback_data; + isc_result_t result; + + result = ns_plugin_register(plugin_path, parameters, config, + cfg_obj_file(obj), cfg_obj_line(obj), + named_g_mctx, named_g_lctx, + named_g_aclconfctx, view); + if (result != ISC_R_SUCCESS) { + isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL, + NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, + "%s: plugin configuration failed: %s", + plugin_path, isc_result_totext(result)); + } + + return (result); +} +#endif + /* * Configure 'view' according to 'vconfig', taking defaults from 'config' * where values are missing in 'vconfig'. @@ -5314,15 +5304,9 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins); view->plugins_free = ns_plugins_free; - } - for (element = cfg_list_first(plugin_list); - element != NULL; - element = cfg_list_next(element)) - { - const cfg_obj_t *plugin = cfg_listelt_value(element); - - CHECK(configure_plugin(view, plugin, config)); + CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx, + register_one_plugin, view)); } #endif diff --git a/lib/bind9/check.c b/lib/bind9/check.c index ada1e257db..e07c3d0d0c 100644 --- a/lib/bind9/check.c +++ b/lib/bind9/check.c @@ -3348,6 +3348,46 @@ check_rpz_catz(const char *rpz_catz, const cfg_obj_t *rpz_obj, return (result); } +#ifdef HAVE_DLOPEN +/*% + * Data structure used for the 'callback_data' argument to check_one_plugin(). + */ +struct check_one_plugin_data { + isc_mem_t *mctx; + isc_log_t *lctx; + cfg_aclconfctx_t *actx; + isc_result_t *check_result; +}; + +/*% + * A callback for the cfg_pluginlist_foreach() call in check_viewconf() below. + * Since the point is to check configuration of all plugins even when + * processing some of them fails, always return ISC_R_SUCCESS and indicate any + * check failures through the 'check_result' variable passed in via the + * 'callback_data' structure. + */ +static isc_result_t +check_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, + const char *plugin_path, const char *parameters, + void *callback_data) +{ + struct check_one_plugin_data *data = callback_data; + isc_result_t result; + + result = ns_plugin_check(plugin_path, parameters, config, + cfg_obj_file(obj), cfg_obj_line(obj), + data->mctx, data->lctx, data->actx); + if (result != ISC_R_SUCCESS) { + cfg_obj_log(obj, data->lctx, ISC_LOG_ERROR, + "%s: plugin check failed: %s", + plugin_path, isc_result_totext(result)); + *data->check_result = result; + } + + return (ISC_R_SUCCESS); +} +#endif + static isc_result_t check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, const char *viewname, dns_rdataclass_t vclass, @@ -3677,39 +3717,18 @@ check_viewconf(const cfg_obj_t *config, const cfg_obj_t *voptions, } #ifdef HAVE_DLOPEN - for (element = cfg_list_first(plugin_list); - element != NULL; - element = cfg_list_next(element)) { - const cfg_obj_t *plugin = cfg_listelt_value(element); + struct check_one_plugin_data check_one_plugin_data = { + .mctx = mctx, + .lctx = logctx, + .actx = actx, + .check_result = &tresult, + }; - const char *type, *library; - const char *parameters = NULL; - - /* Get the path to the plugin module. */ - obj = cfg_tuple_get(plugin, "type"); - type = cfg_obj_asstring(obj); - - /* Only query plugins are supported currently. */ - if (strcasecmp(type, "query") != 0) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "unsupported plugin type"); - return (ISC_R_FAILURE); - } - - library = cfg_obj_asstring(cfg_tuple_get(plugin, "library")); - - obj = cfg_tuple_get(plugin, "parameters"); - if (obj != NULL && cfg_obj_isstring(obj)) { - parameters = cfg_obj_asstring(obj); - } - tresult = ns_plugin_check(library, parameters, config, - cfg_obj_file(obj), cfg_obj_line(obj), - mctx, logctx, actx); + (void)cfg_pluginlist_foreach(config, plugin_list, logctx, + check_one_plugin, + &check_one_plugin_data); if (tresult != ISC_R_SUCCESS) { - cfg_obj_log(obj, logctx, ISC_LOG_ERROR, - "%s: module check failed: %s", - library, isc_result_totext(tresult)); result = tresult; } } diff --git a/lib/isccfg/include/isccfg/cfg.h b/lib/isccfg/include/isccfg/cfg.h index 8f8ca55e43..03d340bd81 100644 --- a/lib/isccfg/include/isccfg/cfg.h +++ b/lib/isccfg/include/isccfg/cfg.h @@ -555,6 +555,47 @@ const char * cfg_map_nextclause(const cfg_type_t *map, const void **clauses, unsigned int *idx); +typedef isc_result_t +(pluginlist_cb_t)(const cfg_obj_t *config, const cfg_obj_t *obj, + const char *plugin_path, const char *parameters, + void *callback_data); +/*%< + * Function prototype for the callback used with cfg_pluginlist_foreach(). + * Called once for each element of the list passed to cfg_pluginlist_foreach(). + * If this callback returns anything else than #ISC_R_SUCCESS, no further list + * elements will be processed. + * + * \li 'config' - the 'config' object passed to cfg_pluginlist_foreach() + * \li 'obj' - object representing the specific "plugin" stanza to be processed + * \li 'plugin_path' - path to the shared object with plugin code + * \li 'parameters' - configuration text for the plugin + * \li 'callback_data' - the pointer passed to cfg_pluginlist_foreach() + */ + +isc_result_t +cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list, + isc_log_t *lctx, pluginlist_cb_t callback, + void *callback_data); +/*%< + * For every "plugin" stanza present in 'list' (which in turn is a part of + * 'config'), invoke the given 'callback', passing 'callback_data' to it along + * with a fixed set of arguments (see the definition of the #pluginlist_cb_t + * type). Use logging context 'lctx' for logging error messages. Interrupt + * processing if 'callback' returns something else than #ISC_R_SUCCESS for any + * element of 'list'. + * + * Requires: + * + * \li 'config' is not NULL + * \li 'callback' is not NULL + * + * Returns: + * + * \li #ISC_R_SUCCESS if 'callback' returned #ISC_R_SUCCESS for all elements of + * 'list' + * \li first 'callback' return value which was not #ISC_R_SUCCESS otherwise + */ + ISC_LANG_ENDDECLS #endif /* ISCCFG_CFG_H */ diff --git a/lib/isccfg/parser.c b/lib/isccfg/parser.c index eea80b2789..07341bf725 100644 --- a/lib/isccfg/parser.c +++ b/lib/isccfg/parser.c @@ -3457,3 +3457,51 @@ cfg_parser_mapadd(cfg_parser_t *pctx, cfg_obj_t *mapobj, return (result); } + +isc_result_t +cfg_pluginlist_foreach(const cfg_obj_t *config, const cfg_obj_t *list, + isc_log_t *lctx, pluginlist_cb_t *callback, + void *callback_data) +{ + isc_result_t result = ISC_R_SUCCESS; + const cfg_listelt_t *element; + + REQUIRE(config != NULL); + REQUIRE(callback != NULL); + + for (element = cfg_list_first(list); + element != NULL; + element = cfg_list_next(element)) + { + const cfg_obj_t *plugin = cfg_listelt_value(element); + const cfg_obj_t *obj; + const char *type, *library; + const char *parameters = NULL; + + /* Get the path to the plugin module. */ + obj = cfg_tuple_get(plugin, "type"); + type = cfg_obj_asstring(obj); + + /* Only query plugins are supported currently. */ + if (strcasecmp(type, "query") != 0) { + cfg_obj_log(obj, lctx, ISC_LOG_ERROR, + "unsupported plugin type"); + return (ISC_R_FAILURE); + } + + library = cfg_obj_asstring(cfg_tuple_get(plugin, "library")); + + obj = cfg_tuple_get(plugin, "parameters"); + if (obj != NULL && cfg_obj_isstring(obj)) { + parameters = cfg_obj_asstring(obj); + } + + result = callback(config, obj, library, parameters, + callback_data); + if (result != ISC_R_SUCCESS) { + break; + } + } + + return (result); +} From c63ead9d9620ff4be6426f49ac84b7d79bde955a Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 30 Nov 2018 18:01:47 -0800 Subject: [PATCH 23/26] add basic plugins documentation --- doc/arm/Bv9ARM-book.xml | 3 ++ doc/arm/plugins.xml | 95 +++++++++++++++++++++++++++++++++++++++++ util/copyrights | 1 + 3 files changed, 99 insertions(+) create mode 100644 doc/arm/plugins.xml diff --git a/doc/arm/Bv9ARM-book.xml b/doc/arm/Bv9ARM-book.xml index b81f8384e3..3c90ae3958 100644 --- a/doc/arm/Bv9ARM-book.xml +++ b/doc/arm/Bv9ARM-book.xml @@ -1325,6 +1325,9 @@ controls { + + + Advanced DNS Features diff --git a/doc/arm/plugins.xml b/doc/arm/plugins.xml new file mode 100644 index 0000000000..507970b85d --- /dev/null +++ b/doc/arm/plugins.xml @@ -0,0 +1,95 @@ + + + +
Plugins + + + Plugins are a mechanism to extend the functionality of + named using dynamically loadable libraries. + By using plugins, core server functionality can be kept simple + for the majority of users; more complex code implementing optional + features need only be installed by users that need those features. + + + The plugin interface is a work in progress, and is expected to evolve + as more plugins are added. Currently, only "query plugins" are supported; + these modify the name server query logic. Other plugin types may be added + in the future. + + + The only plugin currently included in BIND is + filter-aaaa.so, which replaces the + filter-aaaa feature that previously existed natively + as part of named. + The code for this feature has been removed from named, + and can no longer be configured using standard + named.conf syntax, but linking in the + filter-aaaa.so plugin provides identical + functionality. + + +
Configuring Plugins + + A plugin is configured with the plugin + statement in named.conf: + + + plugin query "library.so" { + parameters + }; + + + In this example, file library.so is the plugin + library. query indicates that this is a query + plugin. + + + Multiple plugin statements can be specified, to load + different plugins or multiple instances of the same plugin. + + + parameters are passed as an opaque + string to the plugin's initialization routine. Configuration + syntax will differ depending on the module. + +
+ +
Developing Plugins + + Each plugin implements four functions: + + plugin_register to allocate memory, + configure a plugin instance, and attach to hook points within + named, + plugin_destroy to tear down the plugin + instance and free memory, + plugin_version to check that the plugin + is compatible with the current version of the plugin API, + plugin_check to test syntactic + correctness of the plugin parameters. + + + + At various locations within the named source code, + there are "hook points" at which a plugin may register itself. + When a hook point is reached while named is + running, it is checked to see whether any plugins have registered + themselves there; if so, the associated "hook action" is called - + this is a function within the plugin library. Hook actions may + examine the runtime state and make changes - for example, modifying + the answers to be sent back to a client or forcing a query to be + aborted. More details can be found in the file + lib/ns/include/ns/hooks.h. + +
+ +
diff --git a/util/copyrights b/util/copyrights index 648b7dd2aa..45bf7c0e99 100644 --- a/util/copyrights +++ b/util/copyrights @@ -1510,6 +1510,7 @@ ./doc/arm/options.grammar.xml SGML 2018 ./doc/arm/pkcs11.xml SGML 2010,2012,2013,2014,2015,2016,2018 ./doc/arm/pkgversion.xml.in SGML 2015,2016,2018 +./doc/arm/plugins.xml SGML 2018 ./doc/arm/redirect.zoneopt.xml SGML 2018 ./doc/arm/releaseinfo.xml.in SGML 2015,2016,2018 ./doc/arm/server.grammar.xml SGML 2018 From f70a84537d8afd532ae9ee5d7a5d7e17b94937a2 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Tue, 4 Dec 2018 20:06:03 -0800 Subject: [PATCH 24/26] revise hooks.h comments --- lib/ns/include/ns/hooks.h | 214 ++++++++++++++++++++------------------ 1 file changed, 111 insertions(+), 103 deletions(-) diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 1a7dfe26bb..0570d225a6 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -25,141 +25,149 @@ #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: + * "Hooks" are a mechanism to call a defined function or set of functions once + * a certain place in code is reached. Hook actions can inspect and alter the + * state of an ongoing process, allowing processing to continue afterward or + * triggering an early return. * - * - hook-related types and macros are not placed in libns header files, - * - hook-related code is compiled away unless --with-atf is used, - * - hook-related macro names are prefixed with "NS_". + * Currently hooks are used in two ways: in plugins, which use them to + * add functionality to query processing, and in the unit tests for libns, + * where they are used to inspect state before and after certain functions have + * run. * - * However, the implementation is pretty generic and could be repurposed for - * general use, e.g. as part of libisc, after some further customization. + * Both of these uses are limited to libns, so hooks are currently defined in + * the ns/hooks.h header file, and hook-related macro and function names are + * prefixed with `NS_` and `ns_`. However, the design is fairly generic and + * could be repurposed for general use, e.g. as part of libisc, after some + * further customization. * - * Hooks are created by inserting a macro into any function returning - * isc_result_t (NS_PROCESS_HOOK()) or void (NS_PROCESS_HOOK_VOID()). As both - * of these macros contain a return statement which is inlined into the - * function into which the hook is inserted, a hook callback is able to cause - * that function to return at hook insertion point. For functions returning - * isc_result_t, if a hook callback intends to cause a return at hook insertion - * point, it also has to set the value to be returned by the function. + * Hooks are created by defining a hook point identifier in the ns_hookpoint_t + * enum below, and placing a special call at a corresponding location in the + * code which invokes the action(s) for that hook; there are two such special + * calls currently implemented, namely the CALL_HOOK() and CALL_HOOK_NORETURN() + * macros in query.c. The former macro contains a "goto cleanup" statement + * which is inlined into the function into which the hook has been inserted; + * this enables the hook action to cause the calling function to return from + * the hook insertion point. For functions returning isc_result_t, if a hook + * action intends to cause a return at hook insertion point, it also has to set + * the value to be returned by the calling function. * - * Hook callbacks are functions which: + * A hook table is an array (indexed by the value of the hook point identifier) + * in which each cell contains a linked list of structures, each of which + * contains a function pointer to a hook action and a pointer to data which is + * to be passed to the action function when it is called. * - * - return a boolean value; if true is returned by the callback, the - * function into which the hook is inserted will return at hook insertion - * point; if false is returned by the callback, execution of the - * function into which the hook is inserted continues normally, + * Each view has its own separate hook table, populated by loading plugin + * modules specified in the "plugin" statements in named.conf. There is also a + * special, global hook table (ns__hook_table) that is only used by libns unit + * tests and whose existence can be safely ignored by plugin modules. + * + * Hook actions are functions which: + * + * - return a boolean value: if true is returned by the hook action, the + * function into which the hook is inserted will return and no further hook + * actions at the same hook point will be invoked; if false is returned by + * the hook action and there are further hook actions set up at the same + * hook point, they will be processed; if false is returned and there are + * no further hook actions set up at the same hook point, execution of the + * function into which the hook has been inserted will be resumed, * * - accept three pointers as arguments: + * - a pointer specified by the special call at the hook insertion point, + * - a pointer specified upon inserting the action into the hook table, + * - a pointer to an isc_result_t value which will be returned by the + * function into which the hook is inserted if the action returns true. * - * - a pointer specified by the hook itself, - * - a pointer specified upon inserting the callback into the hook table, - * - a pointer to isc_result_t which will be returned by the function - * into which the hook is inserted if the callback returns true. + * In order for a hook action to be called for a given hook, a pointer to that + * action function (along with an optional pointer to action-specific data) has + * to be inserted into the relevant hook table entry for that hook using an + * ns_hook_add() call. If multiple actions are set up at a single hook point, + * they are processed in FIFO order. * - * Hook tables are arrays which consist of a number of tuples (one tuple per - * hook identifier), each of which determines the callback to be invoked when a - * given hook is processed and the data to be passed to that callback. In an - * attempt to keep things as simple as possible, current implementation uses - * hook tables which are statically-sized arrays only allowing a single - * callback to be invoked for each hook identifier. - * - * In order for a hook callback to be called for a given hook, a pointer to - * that callback (along with an optional pointer to callback-specific data) has - * to be inserted into the relevant hook table entry for that hook. Replacing - * whole hook tables is also possible. - * - * Consider the following sample code: + * As an example, consider the following hypothetical function in query.c: * * ---------------------------------------------------------------------------- - * ns_hook_t *foo_hook_table = NULL; + * static isc_result_t + * query_foo(query_ctx_t *qctx) { + * isc_result_t result; * - * isc_result_t - * foo_bar(void) { - * int val = 42; + * CALL_HOOK(NS_QUERY_FOO_BEGIN, qctx); * - * ... + * ns_client_log(qctx->client, NS_LOGCATEGORY_CLIENT, NS_LOGMODULE_QUERY, + * ISC_LOG_DEBUG(99), "Lorem ipsum dolor sit amet..."); * - * NS_PROCESS_HOOK(foo_hook_table, FOO_EXTRACT_VAL, &val); + * result = ISC_R_COMPLETE; * - * ... - * - * printf("This message may not be printed due to use of hooks."); - * - * return (ISC_R_SUCCESS); + * cleanup: + * return (result); * } + * ---------------------------------------------------------------------------- * - * bool - * cause_failure(void *hook_data, void *callback_data, isc_result_t *resultp) { - * int *valp = (int *)hook_data; - * bool *calledp = (bool *)callback_data; + * and the following hook action: * - * ... + * ---------------------------------------------------------------------------- + * static bool + * cause_failure(void *hook_data, void *action_data, isc_result_t *resultp) { + * UNUSED(hook_data); + * UNUSED(action_data); * * *resultp = ISC_R_FAILURE; * * return (true); * } + * ---------------------------------------------------------------------------- * - * bool - * examine_val(void *hook_data, void *callback_data, isc_result_t *resultp) { - * int *valp = (int *)hook_data; - * int *valcopyp = (int *)callback_data; + * If this hook action was installed in the hook table using: + * + * ---------------------------------------------------------------------------- + * const ns_hook_t foo_fail = { + * .action = cause_failure, + * }; + * + * ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_fail); + * ---------------------------------------------------------------------------- + * + * then query_foo() would return ISC_R_FAILURE every time it is called due to + * the cause_failure() hook action returning true and setting '*resultp' to + * ISC_R_FAILURE. query_foo() would also never log the "Lorem ipsum dolor sit + * amet..." message. + * + * Consider a different hook action: + * + * ---------------------------------------------------------------------------- + * static bool + * log_qtype(void *hook_data, void *action_data, isc_result_t *resultp) { + * query_ctx_t *qctx = (query_ctx_t *)hook_data; + * FILE *stream = (FILE *)action_data; * * UNUSED(resultp); * - * ... + * fprintf(stream, "QTYPE=%u\n", qctx->qtype); * * return (false); * } - * - * void - * test_foo_bar(void) { - * bool called = false; - * int valcopy; - * - * ns_hook_t my_hooks[FOO_HOOKS_COUNT] = { - * [FOO_EXTRACT_VAL] = { - * .callback = cause_failure, - * .callback_data = &called, - * }, - * }; - * - * foo_hook_table = my_hooks; - * foo_bar(); - * - * { - * const ns_hook_t examine_hook = { - * .callback = examine_val, - * .callback_data = &valcopy, - * }; - * - * my_hooks[FOO_EXTRACT_VAL] = examine_hook; - * } - * foo_bar(); - * - * } * ---------------------------------------------------------------------------- * - * When test_foo_bar() is called, "foo_hook_table" is set to "my_hooks". Then - * foo_bar() gets invoked. Once execution reaches the insertion point for hook - * FOO_EXTRACT_VAL, cause_failure() will be called with &val as "hook_data" and - * &called as "callback_data". It can do whatever it pleases with these two - * values. Eventually, cause_failure() sets *resultp to ISC_R_FAILURE and - * returns true, which causes foo_bar() to return ISC_R_FAILURE and never - * execute the printf() call below hook insertion point. + * If this hook action was installed in the hook table instead of + * cause_failure(), using: * - * Execution then returns to test_foo_bar(). Unlike before the first call to - * foo_bar(), this time only a single hook ("examine_hook") is defined instead - * of a complete hook table. This hook is then subsequently inserted at index - * FOO_EXTRACT_VAL into the "my_hook" hook table. This causes the hook - * previously set at that index (the one calling cause_failure()) to be - * replaced with "examine_hook". Thus, when the second call to foo_bar() is - * subsequently made, examine_val() will be called with &val as "hook_data" and - * &valcopy as "callback_data". Contrary to cause_failure(), extract_val() - * returns false, which means it does not access "resultp" and does not - * cause foo_bar() to return at hook insertion point. Thus, printf() will be - * called this time and foo_bar() will return ISC_R_SUCCESS. + * ---------------------------------------------------------------------------- + * const ns_hook_t foo_log_qtype = { + * .action = log_qtype, + * .action_data = stderr, + * }; + * + * ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_log_qtype); + * ---------------------------------------------------------------------------- + * + * then the QTYPE stored in the query context passed to query_foo() would be + * logged to stderr upon each call to that function; 'qctx' would be passed to + * the hook action in 'hook_data' since it is specified in the CALL_HOOK() call + * inside query_foo() while stderr would be passed to the hook action in + * 'action_data' since it is specified in the ns_hook_t structure passed to + * ns_hook_add(). As the hook action returns false, query_foo() would also be + * logging the "Lorem ipsum dolor sit amet..." message before returning + * ISC_R_COMPLETE. */ /*! @@ -342,7 +350,7 @@ ns_hook_add(ns_hooktable_t *hooktable, isc_mem_t *mctx, ns_hookpoint_t hookpoint, const ns_hook_t *hook); /*%< * Allocate (using memory context 'mctx') a copy of the 'hook' structure - * describing a hook callback and append it to the list of hooks at 'hookpoint' + * describing a hook action and append it to the list of hooks at 'hookpoint' * in 'hooktable'. * * Requires: From 0e12988dd62dfdfdbefb0aa967620e46acba2b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 6 Dec 2018 11:36:30 +0100 Subject: [PATCH 25/26] make hook actions return an enum instead of a bool Use an enum instead of a bool for the return type of hook actions in order to facilitate adding further hook processing models in the future. --- bin/plugins/filter-aaaa.c | 46 ++++++++++++++++----------------- lib/ns/include/ns/hooks.h | 53 ++++++++++++++++++++++++--------------- lib/ns/query.c | 18 +++++++------ lib/ns/tests/nstest.c | 8 +++--- lib/ns/tests/nstest.h | 3 ++- 5 files changed, 73 insertions(+), 55 deletions(-) diff --git a/bin/plugins/filter-aaaa.c b/bin/plugins/filter-aaaa.c index 18c1b962b2..131f412c23 100644 --- a/bin/plugins/filter-aaaa.c +++ b/bin/plugins/filter-aaaa.c @@ -115,17 +115,17 @@ typedef struct filter_instance { /* * Forward declarations of functions referenced in install_hooks(). */ -static bool +static ns_hookresult_t filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp); -static bool +static ns_hookresult_t filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp); -static bool +static ns_hookresult_t filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp); -static bool +static ns_hookresult_t filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp); -static bool +static ns_hookresult_t filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp); -static bool +static ns_hookresult_t filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp); /*% @@ -673,7 +673,7 @@ process_section(const section_filter_t *filter) { * retrieve persistent data related to a client query for as long as the * object persists. */ -static bool +static ns_hookresult_t filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; filter_instance_t *inst = (filter_instance_t *) cbdata; @@ -686,7 +686,7 @@ filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { client_state_create(qctx, inst); } - return (false); + return (NS_HOOK_CONTINUE); } /* @@ -694,7 +694,7 @@ filter_qctx_initialize(void *arg, void *cbdata, isc_result_t *resp) { * the client address family and the settings of filter-aaaa-on-v4 and * filter-aaaa-on-v6. */ -static bool +static ns_hookresult_t filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; filter_instance_t *inst = (filter_instance_t *) cbdata; @@ -704,7 +704,7 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { *resp = ISC_R_UNSET; if (client_state == NULL) { - return (false); + return (NS_HOOK_CONTINUE); } if (inst->v4_aaaa != NONE || inst->v6_aaaa != NONE) { @@ -723,7 +723,7 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { } } - return (false); + return (NS_HOOK_CONTINUE); } /* @@ -733,7 +733,7 @@ filter_prep_response_begin(void *arg, void *cbdata, isc_result_t *resp) { * (This version is for processing answers to explicit AAAA queries; ANY * queries are handled in filter_respond_any_found().) */ -static bool +static ns_hookresult_t filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; filter_instance_t *inst = (filter_instance_t *) cbdata; @@ -743,7 +743,7 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { *resp = ISC_R_UNSET; if (client_state == NULL) { - return (false); + return (NS_HOOK_CONTINUE); } if (client_state->mode != BREAK_DNSSEC && @@ -751,7 +751,7 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { (WANTDNSSEC(qctx->client) && qctx->sigrdataset != NULL && dns_rdataset_isassociated(qctx->sigrdataset)))) { - return (false); + return (NS_HOOK_CONTINUE); } if (qctx->qtype == dns_rdatatype_aaaa) { @@ -827,17 +827,17 @@ filter_respond_begin(void *arg, void *cbdata, isc_result_t *resp) { *resp = result; - return (true); + return (NS_HOOK_RETURN); } *resp = result; - return (false); + return (NS_HOOK_CONTINUE); } /* * When answering an ANY query, remove AAAA if A is present. */ -static bool +static ns_hookresult_t filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; filter_instance_t *inst = (filter_instance_t *) cbdata; @@ -864,7 +864,7 @@ filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { process_section(&filter_answer); } - return (false); + return (NS_HOOK_CONTINUE); } /* @@ -872,7 +872,7 @@ filter_respond_any_found(void *arg, void *cbdata, isc_result_t *resp) { * hide NS in the authority section if AAAA was filtered in the answer * section. */ -static bool +static ns_hookresult_t filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; filter_instance_t *inst = (filter_instance_t *) cbdata; @@ -901,14 +901,14 @@ filter_query_done_send(void *arg, void *cbdata, isc_result_t *resp) { } } - return (false); + return (NS_HOOK_CONTINUE); } /* * If the client is being detached, then we can delete our persistent data * from hash table and return it to the memory pool. */ -static bool +static ns_hookresult_t filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { query_ctx_t *qctx = (query_ctx_t *) arg; filter_instance_t *inst = (filter_instance_t *) cbdata; @@ -916,10 +916,10 @@ filter_qctx_destroy(void *arg, void *cbdata, isc_result_t *resp) { *resp = ISC_R_UNSET; if (!qctx->detach_client) { - return (false); + return (NS_HOOK_CONTINUE); } client_state_destroy(qctx, inst); - return (false); + return (NS_HOOK_CONTINUE); } diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index 0570d225a6..0f6ff88c4c 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -64,19 +64,23 @@ * * Hook actions are functions which: * - * - return a boolean value: if true is returned by the hook action, the - * function into which the hook is inserted will return and no further hook - * actions at the same hook point will be invoked; if false is returned by - * the hook action and there are further hook actions set up at the same - * hook point, they will be processed; if false is returned and there are - * no further hook actions set up at the same hook point, execution of the - * function into which the hook has been inserted will be resumed, + * - return an ns_hookresult_t value: + * - if NS_HOOK_RETURN is returned by the hook action, the function + * into which the hook is inserted will return and no further hook + * actions at the same hook point will be invoked, + * - if NS_HOOK_CONTINUE is returned by the hook action and there are + * further hook actions set up at the same hook point, they will be + * processed; if NS_HOOK_CONTINUE is returned and there are no + * further hook actions set up at the same hook point, execution of + * the function into which the hook has been inserted will be + * resumed. * * - accept three pointers as arguments: * - a pointer specified by the special call at the hook insertion point, * - a pointer specified upon inserting the action into the hook table, * - a pointer to an isc_result_t value which will be returned by the - * function into which the hook is inserted if the action returns true. + * function into which the hook is inserted if the action returns + * NS_HOOK_RETURN. * * In order for a hook action to be called for a given hook, a pointer to that * action function (along with an optional pointer to action-specific data) has @@ -106,14 +110,14 @@ * and the following hook action: * * ---------------------------------------------------------------------------- - * static bool + * static ns_hookresult_t * cause_failure(void *hook_data, void *action_data, isc_result_t *resultp) { * UNUSED(hook_data); * UNUSED(action_data); * * *resultp = ISC_R_FAILURE; * - * return (true); + * return (NS_HOOK_RETURN); * } * ---------------------------------------------------------------------------- * @@ -127,15 +131,15 @@ * ns_hook_add(..., NS_QUERY_FOO_BEGIN, &foo_fail); * ---------------------------------------------------------------------------- * - * then query_foo() would return ISC_R_FAILURE every time it is called due to - * the cause_failure() hook action returning true and setting '*resultp' to - * ISC_R_FAILURE. query_foo() would also never log the "Lorem ipsum dolor sit - * amet..." message. + * then query_foo() would return ISC_R_FAILURE every time it is called due + * to the cause_failure() hook action returning NS_HOOK_RETURN and setting + * '*resultp' to ISC_R_FAILURE. query_foo() would also never log the + * "Lorem ipsum dolor sit amet..." message. * * Consider a different hook action: * * ---------------------------------------------------------------------------- - * static bool + * static ns_hookresult_t * log_qtype(void *hook_data, void *action_data, isc_result_t *resultp) { * query_ctx_t *qctx = (query_ctx_t *)hook_data; * FILE *stream = (FILE *)action_data; @@ -144,7 +148,7 @@ * * fprintf(stream, "QTYPE=%u\n", qctx->qtype); * - * return (false); + * return (NS_HOOK_CONTINUE); * } * ---------------------------------------------------------------------------- * @@ -165,9 +169,9 @@ * the hook action in 'hook_data' since it is specified in the CALL_HOOK() call * inside query_foo() while stderr would be passed to the hook action in * 'action_data' since it is specified in the ns_hook_t structure passed to - * ns_hook_add(). As the hook action returns false, query_foo() would also be - * logging the "Lorem ipsum dolor sit amet..." message before returning - * ISC_R_COMPLETE. + * ns_hook_add(). As the hook action returns NS_HOOK_CONTINUE, + * query_foo() would also be logging the "Lorem ipsum dolor sit amet..." + * message before returning ISC_R_COMPLETE. */ /*! @@ -211,7 +215,16 @@ typedef enum { NS_HOOKPOINTS_COUNT /* MUST BE LAST */ } ns_hookpoint_t; -typedef bool +/* + * Returned by a hook action to indicate how to proceed after it has + * been called: continue processing, or return immediately. + */ +typedef enum { + NS_HOOK_CONTINUE, + NS_HOOK_RETURN, +} ns_hookresult_t; + +typedef ns_hookresult_t (*ns_hook_action_t)(void *arg, void *data, isc_result_t *resultp); typedef struct ns_hook { diff --git a/lib/ns/query.c b/lib/ns/query.c index 191e0dc35a..3608b7d40e 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -255,16 +255,16 @@ get_hooktab(query_ctx_t *qctx) { } /* - * Call the specified hook function in every configured module that - * implements that function. If any hook function returns 'true', we set - * 'result' and terminate processing by jumping to the 'cleanup' tag. + * Call the specified hook function in every configured module that implements + * that function. If any hook function returns NS_HOOK_RETURN, we + * set 'result' and terminate processing by jumping to the 'cleanup' tag. * * (Note that a hook function may set the 'result' to ISC_R_SUCCESS but * still terminate processing within the calling function. That's why this * is a macro instead of an inline function; it needs to be able to use * 'goto cleanup' regardless of the return value.) */ -#define CALL_HOOK(_id, _qctx) \ +#define CALL_HOOK(_id, _qctx) \ do { \ isc_result_t _res; \ ns_hooktable_t *_tab = get_hooktab(_qctx); \ @@ -274,11 +274,15 @@ get_hooktab(query_ctx_t *qctx) { ns_hook_action_t _func = _hook->action; \ void *_data = _hook->action_data; \ INSIST(_func != NULL); \ - if (_func(_qctx, _data, &_res)) { \ + switch (_func(_qctx, _data, &_res)) { \ + case NS_HOOK_CONTINUE: \ + _hook = ISC_LIST_NEXT(_hook, link); \ + break; \ + case NS_HOOK_RETURN: \ result = _res; \ goto cleanup; \ - } else { \ - _hook = ISC_LIST_NEXT(_hook, link); \ + default: \ + INSIST(0); \ } \ } \ } while (false) diff --git a/lib/ns/tests/nstest.c b/lib/ns/tests/nstest.c index 9f24f6c4eb..b5e13c6ee1 100644 --- a/lib/ns/tests/nstest.c +++ b/lib/ns/tests/nstest.c @@ -633,7 +633,7 @@ destroy_message: * "data". Causes execution to be interrupted at hook insertion * point. */ -static bool +static ns_hookresult_t extract_qctx(void *arg, void *data, isc_result_t *resultp) { query_ctx_t **qctxp; query_ctx_t *qctx; @@ -660,7 +660,7 @@ extract_qctx(void *arg, void *data, isc_result_t *resultp) { *qctxp = qctx; *resultp = ISC_R_UNSET; - return (true); + return (NS_HOOK_RETURN); } /*% @@ -801,7 +801,7 @@ ns_test_qctx_destroy(query_ctx_t **qctxp) { *qctxp = NULL; } -bool +ns_hookresult_t ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp) { UNUSED(arg); @@ -809,7 +809,7 @@ ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp) *resultp = ISC_R_UNSET; - return (true); + return (NS_HOOK_RETURN); } /* diff --git a/lib/ns/tests/nstest.h b/lib/ns/tests/nstest.h index fc69befdc6..6777149ab5 100644 --- a/lib/ns/tests/nstest.h +++ b/lib/ns/tests/nstest.h @@ -30,6 +30,7 @@ #include #include +#include typedef struct ns_test_id { const char *description; @@ -150,5 +151,5 @@ ns_test_qctx_destroy(query_ctx_t **qctxp); /*% * A hook callback interrupting execution at given hook's insertion point. */ -bool +ns_hookresult_t ns_test_hook_catch_call(void *arg, void *data, isc_result_t *resultp); From fa666f5d88c27ba712c87c71e683290071f24ad2 Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 30 Nov 2018 18:59:30 -0800 Subject: [PATCH 26/26] CHANGES, release notes --- CHANGES | 17 +++++++++++++++++ doc/arm/notes.xml | 25 +++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/CHANGES b/CHANGES index 33e6f91b4c..a043f8630e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,20 @@ +5106. [experimental] A new "plugin" mechanism has been added to allow + extension of query processing functionality through + the use of dynamically loadable libraries. A + "filter-aaaa.so" plugin has been implemented, + replacing the filter-aaaa feature that was formerly + implemented as a native part of BIND. + + The "filter-aaaa", "filter-aaaa-on-v4" and + "filter-aaaa-on-v6" options can no longer be + configured using native named.conf syntax. However, + loading the filter-aaaa.so plugin and setting its + parameters provides identical functionality. + + Note that the plugin API is a work in progress and + is likely to evolve as further plugins are + implemented. [GL #15] + 5105. [bug] Fix a race between process_fd and socketclose in unix socket code. [GL #744] diff --git a/doc/arm/notes.xml b/doc/arm/notes.xml index 1b46a0a852..8d707fb2e0 100644 --- a/doc/arm/notes.xml +++ b/doc/arm/notes.xml @@ -153,6 +153,19 @@ as described in RFC 7706. [GL #33] + + + A new plugin mechanism has been added to allow + extension of query processing functionality through the use of + external libraries. The new filter-aaaa.so + plugin replaces the filter-aaaa feature that + was formerly implemented as a native part of BIND. + + + The plugin API is a work in progress and is likely to evolve + as further plugins are implemented. [GL #15] + + BIND now can be compiled against the libidn2 @@ -289,6 +302,18 @@ the operating system, and it cannot be built without threads. + + + The filter-aaaa, + filter-aaaa-on-v4, and + filter-aaaa-on-v6 options have been removed + from named, and can no longer be + configured using native named.conf syntax. + However, loading the new filter-aaaa.so + plugin and setting its parameters provides identical + functionality. + + named can no longer use the EDNS CLIENT-SUBNET