From: Colin Vidal Date: Tue, 27 May 2025 09:46:21 +0000 (+0200) Subject: add zone-specific plugin instance X-Git-Tag: v9.21.14~56^2~13 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5893770cd9ad15fa7caf383dc7793685268012a7;p=thirdparty%2Fbind9.git add zone-specific plugin instance The zone object now has its own hooktable and plugins, which are initialized during zone initialization. --- diff --git a/bin/named/include/named/server.h b/bin/named/include/named/server.h index 7be62eecc70..7d0713b78da 100644 --- a/bin/named/include/named/server.h +++ b/bin/named/include/named/server.h @@ -31,6 +31,8 @@ #include #include +#include + #include #include #include @@ -407,3 +409,13 @@ named_server_togglememprof(isc_lex_t *lex); */ const char * named_server_getmemprof(void); + +/*% + * Helper callback function to register a plugin, called via + * cfg_pluginlist_foreach(). Note: if registration of any + * plugin fails, subsequent ones will not be attempted. + */ +isc_result_t +named_register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, + const char *plugin_path, const char *parameters, + void *callback_data); diff --git a/bin/named/include/named/zoneconf.h b/bin/named/include/named/zoneconf.h index ed0735ec516..ff5a326832e 100644 --- a/bin/named/include/named/zoneconf.h +++ b/bin/named/include/named/zoneconf.h @@ -81,3 +81,16 @@ named_zone_templateopts(const cfg_obj_t *config, const cfg_obj_t *zoptions); * the template options and return them. If no such template is found, * return NULL. */ + +isc_result_t +named_zone_loadplugins(dns_zone_t *zone, const cfg_obj_t *config, + const cfg_obj_t *zoptions); +/*%< + * Load plugins that should run for this specific zone. Take care of cleaning + * up any pre-existing plugins first, if the zone is re-used. + * + * Require: + * \li 'zone' to be a valid zone + * \li 'config' to be a valid named.conf configuration tree + * \li 'zoptions' to be a valid zone configuration tree + */ diff --git a/bin/named/server.c b/bin/named/server.c index 5629508a486..0a4f60beea1 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -3712,18 +3712,13 @@ create_mapped_acl(void) { return result; } -/*% - * 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 +named_register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, + const char *plugin_path, const char *parameters, + void *callback_data) { char full_path[PATH_MAX]; isc_result_t result; + ns_hook_data_t *hookdata = callback_data; result = ns_plugin_expandpath(plugin_path, full_path, sizeof(full_path)); @@ -3738,7 +3733,7 @@ register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj, result = ns_plugin_register(full_path, parameters, config, cfg_obj_file(obj), cfg_obj_line(obj), - isc_g_mctx, named_g_aclconfctx, view); + isc_g_mctx, named_g_aclconfctx, hookdata); if (result != ISC_R_SUCCESS) { isc_log_write(NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR, @@ -5422,16 +5417,20 @@ configure_view(dns_view_t *view, dns_viewlist_t *viewlist, cfg_obj_t *config, } if (plugin_list != NULL) { + ns_hook_data_t hookdata = {}; + INSIST(view->hooktable == NULL); - CHECK(ns_hooktable_create(view->mctx, - (ns_hooktable_t **)&view->hooktable)); + ns_hooktable_create(view->mctx, &hookdata.hooktable); + view->hooktable = hookdata.hooktable; view->hooktable_free = ns_hooktable_free; - ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins); + ns_plugins_create(view->mctx, &hookdata.plugins); + view->plugins = hookdata.plugins; view->plugins_free = ns_plugins_free; CHECK(cfg_pluginlist_foreach(config, plugin_list, - register_one_plugin, view)); + named_register_one_plugin, + &hookdata)); } /* @@ -6661,6 +6660,8 @@ configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig, dns_zone_rekey(zone, fullsign, false); } + result = named_zone_loadplugins(zone, config, zoptions); + cleanup: if (zone != NULL) { dns_zone_detach(&zone); diff --git a/bin/named/zoneconf.c b/bin/named/zoneconf.c index 2ebbb94843e..ab7dad50d89 100644 --- a/bin/named/zoneconf.c +++ b/bin/named/zoneconf.c @@ -43,6 +43,7 @@ #include #include +#include #include #include @@ -2097,3 +2098,42 @@ named_zone_templateopts(const cfg_obj_t *config, const cfg_obj_t *zoptions) { return NULL; } + +isc_result_t +named_zone_loadplugins(dns_zone_t *zone, const cfg_obj_t *config, + const cfg_obj_t *zoptions) { + isc_result_t result = ISC_R_SUCCESS; + const cfg_obj_t *pluginlist = NULL; + + /* + * If the zone previously had any loaded plugins, unload them: + * they might not be needed anymore, or they might hold state + * that's now obsolete. + */ + dns_zone_unloadplugins(zone); + + /* + * Load zone-specific plugin instances. + */ + if (zoptions != NULL) { + (void)cfg_map_get(zoptions, "plugin", &pluginlist); + } + + if (pluginlist != NULL) { + ns_hook_data_t hookdata = {}; + isc_mem_t *zmctx = dns_zone_getmctx(zone); + + ns_hooktable_create(zmctx, &hookdata.hooktable); + dns_zone_sethooktable(zone, hookdata.hooktable, + ns_hooktable_free); + + ns_plugins_create(zmctx, &hookdata.plugins); + dns_zone_setplugins(zone, hookdata.plugins, ns_plugins_free); + + result = cfg_pluginlist_foreach(config, pluginlist, + named_register_one_plugin, + &hookdata); + } + + return result; +} diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h index a7ce4559649..88127095483 100644 --- a/lib/dns/include/dns/zone.h +++ b/lib/dns/include/dns/zone.h @@ -2754,6 +2754,49 @@ dns_zone_getkeystores(dns_zone_t *zone); * initialized. */ +void * +dns_zone_gethooktable(dns_zone_t *zone); +/**< + * Returns the zone hooktable + * + * Requires: + * \li 'zone' to be a valid zone. + */ + +void +dns_zone_sethooktable(dns_zone_t *zone, void *hooktable, + void (*hooktable_free)(isc_mem_t *, void **)); +/**< + * Initialize zone hooktable and free callback + * + * Requires: + * \li 'zone' to be a valid zone. + * \li 'hooktable' to be initialized. + * \li 'hooktable_free' to be valid. + */ + +void +dns_zone_setplugins(dns_zone_t *zone, void *plugins, + void (*plugins_free)(isc_mem_t *, void **)); +/**< + * Initialize zone plugins owning list and free callback + * + * Requires: + * \li 'zone' to be a valid zone. + * \li 'plugins' to be initialized. + * \li 'plugins_free' to be valid. + */ + +void +dns_zone_unloadplugins(dns_zone_t *zone); +/**< + * Unload all plugins attached to this zone, and free the hooktable as well as + * the plugins list. + * + * Requires: + * \li 'zone' to be a valid zone. + */ + #if DNS_ZONE_TRACE #define dns_zone_ref(ptr) dns_zone__ref(ptr, __func__, __FILE__, __LINE__) #define dns_zone_unref(ptr) dns_zone__unref(ptr, __func__, __FILE__, __LINE__) diff --git a/lib/dns/zone.c b/lib/dns/zone.c index b7350b9c2a6..dd16e4ce6e2 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -530,6 +530,14 @@ struct dns_zone { */ dns_skr_t *skr; dns_skrbundle_t *skrbundle; + + /* + * Plugin-related data structures + */ + void *plugins; + void (*plugins_free)(isc_mem_t *, void **); + void *hooktable; + void (*hooktable_free)(isc_mem_t *, void **); }; #define zonediff_init(z, d) \ @@ -1376,6 +1384,7 @@ zone_free(dns_zone_t *zone) { if (zone->gluecachestats != NULL) { isc_stats_detach(&zone->gluecachestats); } + dns_zone_unloadplugins(zone); /* last stuff */ ZONEDB_DESTROYLOCK(&zone->dblock); @@ -24864,3 +24873,48 @@ dns_zone_setrad(dns_zone_t *zone, dns_name_t *name) { } rcu_read_unlock(); } + +void * +dns_zone_gethooktable(dns_zone_t *zone) { + REQUIRE(DNS_ZONE_VALID(zone)); + return zone->hooktable; +} + +void +dns_zone_sethooktable(dns_zone_t *zone, void *hooktable, + void (*hooktable_free)(isc_mem_t *, void **)) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->hooktable == NULL); + REQUIRE(zone->hooktable_free == NULL); + + zone->hooktable = hooktable; + zone->hooktable_free = hooktable_free; +} + +void +dns_zone_setplugins(dns_zone_t *zone, void *plugins, + void (*plugins_free)(isc_mem_t *, void **)) { + REQUIRE(DNS_ZONE_VALID(zone)); + REQUIRE(zone->plugins == NULL); + REQUIRE(zone->plugins_free == NULL); + + zone->plugins = plugins; + zone->plugins_free = plugins_free; +} + +void +dns_zone_unloadplugins(dns_zone_t *zone) { + if (zone->hooktable != NULL) { + INSIST(zone->hooktable_free); + zone->hooktable_free(zone->mctx, &zone->hooktable); + INSIST(zone->hooktable == NULL); + zone->hooktable_free = NULL; + } + + if (zone->plugins != NULL) { + INSIST(zone->plugins_free); + zone->plugins_free(zone->mctx, &zone->plugins); + INSIST(zone->plugins == NULL); + zone->plugins_free = NULL; + } +} diff --git a/lib/ns/hooks.c b/lib/ns/hooks.c index 4fd2aae6bbe..9c7957e8189 100644 --- a/lib/ns/hooks.c +++ b/lib/ns/hooks.c @@ -224,12 +224,12 @@ unload_plugin(ns_plugin_t **pluginp) { isc_result_t ns_plugin_register(const char *modpath, const char *parameters, const void *cfg, const char *cfg_file, unsigned long cfg_line, - isc_mem_t *mctx, void *actx, dns_view_t *view) { + isc_mem_t *mctx, void *actx, ns_hook_data_t *hookdata) { isc_result_t result; ns_plugin_t *plugin = NULL; REQUIRE(mctx != NULL); - REQUIRE(view != NULL); + REQUIRE(hookdata != NULL); isc_log_write(NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_HOOKS, ISC_LOG_INFO, "loading plugin '%s'", modpath); @@ -240,9 +240,9 @@ ns_plugin_register(const char *modpath, const char *parameters, const void *cfg, "registering plugin '%s'", modpath); CHECK(plugin->register_func(parameters, cfg, cfg_file, cfg_line, mctx, - actx, view->hooktable, &plugin->inst)); + actx, hookdata->hooktable, &plugin->inst)); - ISC_LIST_APPEND(*(ns_plugins_t *)view->plugins, plugin, link); + ISC_LIST_APPEND(*hookdata->plugins, plugin, link); cleanup: if (result != ISC_R_SUCCESS && plugin != NULL) { @@ -281,7 +281,7 @@ ns_hooktable_init(ns_hooktable_t *hooktable) { } } -isc_result_t +void ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { ns_hooktable_t *hooktable = NULL; @@ -292,8 +292,6 @@ ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep) { ns_hooktable_init(hooktable); *tablep = hooktable; - - return ISC_R_SUCCESS; } void diff --git a/lib/ns/include/ns/hooks.h b/lib/ns/include/ns/hooks.h index c5addf2c829..ee371dfdc10 100644 --- a/lib/ns/include/ns/hooks.h +++ b/lib/ns/include/ns/hooks.h @@ -447,6 +447,15 @@ typedef struct ns_hook_resume { void *arg; /* argument to pass to the callback */ } ns_hook_resume_t; +/* + * Wrapper struct holding hook/plugins owning data structures used and owned by + * zones and views having registered plugins. + */ +typedef struct ns_hook_data { + ns_hooktable_t *hooktable; + ns_plugins_t *plugins; +} ns_hook_data_t; + /* * Plugin API version * @@ -535,7 +544,7 @@ ns_plugin_expandpath(const char *src, char *dst, size_t dstsize); isc_result_t ns_plugin_register(const char *modpath, const char *parameters, const void *cfg, const char *cfg_file, unsigned long cfg_line, - isc_mem_t *mctx, void *actx, dns_view_t *view); + isc_mem_t *mctx, void *actx, ns_hook_data_t *hookdata); /*%< * Load the plugin module specified from the file 'modpath', and * register an instance using 'parameters'. @@ -603,7 +612,7 @@ ns_hooktable_init(ns_hooktable_t *hooktable); * Initialize a hook table. */ -isc_result_t +void ns_hooktable_create(isc_mem_t *mctx, ns_hooktable_t **tablep); /*%< * Allocate and initialize a hook table. diff --git a/lib/ns/query.c b/lib/ns/query.c index 99f742a2929..ede3245be1e 100644 --- a/lib/ns/query.c +++ b/lib/ns/query.c @@ -259,18 +259,80 @@ acquire_recursionquota(ns_client_t *client); static void release_recursionquota(ns_client_t *client); -/* - * Return the hooktable in use with 'qctx', or if there isn't one - * set, return the default hooktable. - */ +static ns_hookresult_t +ns__query_callhook(uint8_t id, query_ctx_t *qctx, isc_result_t *result, + ns_hooktable_t *hooktab) { + isc_result_t hookresult = *result; + ns_hook_t *hook; + + if (hooktab == NULL) { + return NS_HOOK_CONTINUE; + } + + hook = ISC_LIST_HEAD((*hooktab)[id]); + while (hook != NULL) { + ns_hook_action_t func = hook->action; + void *data = hook->action_data; + + INSIST(func != NULL); + + switch (func(qctx, data, &hookresult)) { + case NS_HOOK_CONTINUE: + hook = ISC_LIST_NEXT(hook, link); + break; + case NS_HOOK_RETURN: + *result = hookresult; + return NS_HOOK_RETURN; + default: + UNREACHABLE(); + } + } + + return NS_HOOK_CONTINUE; +} + +static void +ns__query_callhook_noreturn(uint8_t id, query_ctx_t *qctx, + ns_hooktable_t *hooktab) { + ns_hook_t *hook; + isc_result_t dummyres; + + if (hooktab == NULL) { + return; + } + + hook = ISC_LIST_HEAD((*hooktab)[id]); + while (hook != NULL) { + ns_hook_action_t func = hook->action; + void *data = hook->action_data; + + INSIST(func != NULL); + + func(qctx, data, &dummyres); + hook = ISC_LIST_NEXT(hook, link); + } +} + static ns_hooktable_t * -get_hooktab(query_ctx_t *qctx) { - if (qctx == NULL || qctx->view == NULL || qctx->view->hooktable == NULL) - { - return ns__hook_table; +ns__zone_hooktab(query_ctx_t *qctx) { + ns_hooktable_t *hooktab = NULL; + + if (qctx && qctx->zone) { + hooktab = dns_zone_gethooktable(qctx->zone); + } + + return hooktab; +} + +static ns_hooktable_t * +ns__view_hooktab(query_ctx_t *qctx) { + ns_hooktable_t *hooktab = NULL; + + if (qctx && qctx->view) { + hooktab = qctx->view->hooktable; } - return qctx->view->hooktable; + return hooktab; } /* @@ -283,28 +345,22 @@ get_hooktab(query_ctx_t *qctx) { * is a macro instead of a static function; it needs to be able to use * 'goto cleanup' regardless of the return value.) */ -#define CALL_HOOK(_id, _qctx) \ - do { \ - isc_result_t _res = result; \ - 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); \ - switch (_func(_qctx, _data, &_res)) { \ - case NS_HOOK_CONTINUE: \ - _hook = ISC_LIST_NEXT(_hook, link); \ - break; \ - case NS_HOOK_RETURN: \ - result = _res; \ - goto cleanup; \ - default: \ - UNREACHABLE(); \ - } \ - } \ - } while (false) +#define CALL_HOOK(_id, _qctx) \ + if (ns__query_callhook(_id, _qctx, &result, \ + ns__zone_hooktab(_qctx)) == NS_HOOK_RETURN) \ + { \ + goto cleanup; \ + } \ + if (ns__query_callhook(_id, _qctx, &result, \ + ns__view_hooktab(_qctx)) == NS_HOOK_RETURN) \ + { \ + goto cleanup; \ + } \ + if (ns__query_callhook(_id, _qctx, &result, ns__hook_table) == \ + NS_HOOK_RETURN) \ + { \ + goto cleanup; \ + } /* * Call the specified hook function in every configured module that @@ -315,20 +371,10 @@ get_hooktab(query_ctx_t *qctx) { * (This could be implemented as a static void function, but is left as a * macro for symmetry with CALL_HOOK above.) */ -#define CALL_HOOK_NORETURN(_id, _qctx) \ - do { \ - 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); \ - } \ - } while (false) +#define CALL_HOOK_NORETURN(_id, _qctx) \ + ns__query_callhook_noreturn(_id, _qctx, ns__zone_hooktab(_qctx)); \ + ns__query_callhook_noreturn(_id, _qctx, ns__view_hooktab(_qctx)); \ + ns__query_callhook_noreturn(_id, _qctx, ns__hook_table); /* * The functions defined below implement the query logic that previously lived