mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-28 04:34:54 -04:00
add zone-specific plugin instance
The zone object now has its own hooktable and plugins, which are initialized during zone initialization.
This commit is contained in:
parent
0247506ddc
commit
5893770cd9
9 changed files with 286 additions and 70 deletions
|
|
@ -31,6 +31,8 @@
|
|||
#include <dns/stats.h>
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <isccfg/cfg.h>
|
||||
|
||||
#include <ns/interfacemgr.h>
|
||||
#include <ns/server.h>
|
||||
#include <ns/stats.h>
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
#include <dns/zone.h>
|
||||
|
||||
#include <ns/client.h>
|
||||
#include <ns/hooks.h>
|
||||
|
||||
#include <named/config.h>
|
||||
#include <named/globals.h>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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__)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
138
lib/ns/query.c
138
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_hooktable_t *
|
||||
get_hooktab(query_ctx_t *qctx) {
|
||||
if (qctx == NULL || qctx->view == NULL || qctx->view->hooktable == NULL)
|
||||
{
|
||||
return ns__hook_table;
|
||||
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;
|
||||
}
|
||||
|
||||
return qctx->view->hooktable;
|
||||
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 *
|
||||
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 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
|
||||
|
|
|
|||
Loading…
Reference in a new issue