From d2f4644388121c640cc2ef78be7cfe0befc7c66e Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Sun, 12 Aug 2018 11:19:36 -0700 Subject: [PATCH] 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.