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:
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
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;
* 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);
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", "", "<none>", 0,
- hctx, NULL);
#endif
/*
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
minimal-responses no;
};
+hook query "../../../../hooks/lib/filter-aaaa.so";
+
key rndc_key {
secret "1234abcd8765";
algorithm hmac-sha256;
--- /dev/null
+#!/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
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')
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);
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));
}
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;
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;
{ "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 },
&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.
*/
cfg_print_cstr(pctx, "{ <unspecified-text> }");
}
-
bool
cfg_is_enum(const char *s, const char *const *enums) {
const char * const *p;
&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, "[ { <unspecified-text> } ]");
+}
+
+cfg_type_t cfg_type_optional_bracketed_text = {
+ "optional_btext", parse_optional_btext, print_optional_btext,
+ doc_optional_btext, NULL, NULL
+};
+
/*
* Booleans
*/
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;
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,
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
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;
/*!
* 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; \
\
} \
}
-#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
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
*
*/
-ns_hooktable_t *
-ns_hooktable_save(void);
+void
+ns_hooktable_init(ns_hooktable_t *hooktable);
/*%
- * Returns a pointer to the current global hook table so it can
- * be restored after replacing it.
+ * Initialize a hook table.
*/
-void
-ns_hooktable_reset(ns_hooktable_t *hooktable);
+isc_result_t
+ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep);
/*%
- * Set the global hooks table pointer to 'hooktable'.
- *
- * If 'hooktable' is NULL, restores the default global hook table.
+ * Allocate and initialize a hook table.
*/
void
-ns_hooktable_init(ns_hooktable_t *hooktable);
+ns_hooktable_free(isc_mem_t *mctx, void **tablep);
/*%
- * Initialize a hook table. If 'hooktable' is NULL, initialize
- * the global hooktable ns__hook_table.
+ * Free a hook table.
*/
+
#endif /* NS_HOOKS_H */
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
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);
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);
/*
* 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.
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);
/*
* 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.