Add support for multiple dynamic modules

Allows the use of multiple dynamic modules. Simply add more "dynlib"
entries to the "modules-config" and the same amount of "dynlib-file"
entries in the dynlib configuration block.
This commit is contained in:
PMunch 2019-10-21 15:02:03 +02:00
parent 8eeb910e3d
commit f177dc974c
6 changed files with 38 additions and 21 deletions

View file

@ -842,7 +842,8 @@ python:
# o list dynlib in the module-config string (above) to enable. # o list dynlib in the module-config string (above) to enable.
# It can be placed anywhere, the dynlib module is only a very thin wrapper # It can be placed anywhere, the dynlib module is only a very thin wrapper
# to load modules dynamically. # to load modules dynamically.
# o and give a dynlib-file to run. # o and give a dynlib-file to run. If more than one dynlib entry is listed in
# the module-config then you need one dynlib-file per instance.
dynlib: dynlib:
# Script file to load # Script file to load
# dynlib-file: "@UNBOUND_SHARE_DIR@/dynlib.so" # dynlib-file: "@UNBOUND_SHARE_DIR@/dynlib.so"

View file

@ -1792,14 +1792,16 @@ clause gives the settings for the \fIdynlib\fR(1) module. This module is only
a very small wrapper that allows dynamic modules to be loaded on runtime a very small wrapper that allows dynamic modules to be loaded on runtime
instead of being compiled into the application. To enable the dynlib module it instead of being compiled into the application. To enable the dynlib module it
has to be compiled into the daemon, and the word "dynlib" has to be put in the has to be compiled into the daemon, and the word "dynlib" has to be put in the
\fBmodule\-config:\fR option. \fBmodule\-config:\fR option. Multiple instances of dynamic libraries are
supported by adding the word "dynlib" more than once.
.LP .LP
The \fBdynlib\-file:\fR path should be specified as an absolute path relative The \fBdynlib\-file:\fR path should be specified as an absolute path relative
to the new path set by \fBchroot:\fR option, or as a relative path to the to the new path set by \fBchroot:\fR option, or as a relative path to the
working directory. working directory.
.TP .TP
.B dynlib\-file: \fI<dynlib file>\fR .B dynlib\-file: \fI<dynlib file>\fR
The dynamic library file to load. The dynamic library file to load. Repeat this option for every dynlib module
instance added to the \fBmodule\-config:\fR option.
.SS "DNS64 Module Options" .SS "DNS64 Module Options"
.LP .LP
The dns64 module must be configured in the \fBmodule\-config:\fR "dns64 The dns64 module must be configured in the \fBmodule\-config:\fR "dns64

View file

@ -81,34 +81,48 @@ struct dynlibmod_env {
struct module_qstate* qstate; struct module_qstate* qstate;
}; };
/**
* counter for dynamic library module instances
* incremeted by dynlibmod_init
*/
int dynlib_mod_count = 0;
/** dynlib module init */ /** dynlib module init */
int dynlibmod_init(struct module_env* env, int id) { int dynlibmod_init(struct module_env* env, int id) {
int dynlib_mod_idx = dynlib_mod_count++;
struct config_strlist* cfg_item = env->cfg->dynlib_file;
struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env)); struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
__DYNMOD dynamic_library; __DYNMOD dynamic_library;
if (!de) if (!de)
{ {
log_err("dynlibmod: malloc failure"); log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx);
return 0; return 0;
} }
env->modinfo[id] = (void*) de; env->modinfo[id] = (void*) de;
de->fname = env->cfg->dynlib_file; de->fname = NULL;
if (de->fname == NULL || de->fname[0] == 0) { for(int i = dynlib_mod_idx;
log_err("dynlibmod: no dynamic library given."); i != 0 && cfg_item != NULL;
i--, cfg_item = cfg_item->next) {}
if (cfg_item == NULL || cfg_item->str == NULL || cfg_item->str[0] == 0) {
log_err("dynlibmod[%d]: no dynamic library given.", dynlib_mod_idx);
return 0; return 0;
} else {
de->fname = cfg_item->str;
} }
verbose(VERB_ALGO, "dynlibmod: Trying to load library %s", de->fname); verbose(VERB_ALGO, "dynlibmod[%d]: Trying to load library %s", dynlib_mod_idx, de->fname);
dynamic_library = open_library(de->fname); dynamic_library = open_library(de->fname);
if (dynamic_library == NULL) { if (dynamic_library == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
__DYNSYM initializer = __LOADSYM(dynamic_library,"init"); __DYNSYM initializer = __LOADSYM(dynamic_library,"init");
if (initializer == NULL) { if (initializer == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load init procedure from dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load init procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
de->func_init = (func_init_t) initializer; de->func_init = (func_init_t) initializer;
@ -116,7 +130,7 @@ int dynlibmod_init(struct module_env* env, int id) {
__DYNSYM deinitializer = __LOADSYM(dynamic_library,"deinit"); __DYNSYM deinitializer = __LOADSYM(dynamic_library,"deinit");
if (deinitializer == NULL) { if (deinitializer == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load deinit procedure from dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load deinit procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
de->func_deinit = (func_deinit_t) deinitializer; de->func_deinit = (func_deinit_t) deinitializer;
@ -124,7 +138,7 @@ int dynlibmod_init(struct module_env* env, int id) {
__DYNSYM operate = __LOADSYM(dynamic_library,"operate"); __DYNSYM operate = __LOADSYM(dynamic_library,"operate");
if (operate == NULL) { if (operate == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load operate procedure from dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load operate procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
de->func_operate = (func_operate_t) operate; de->func_operate = (func_operate_t) operate;
@ -132,7 +146,7 @@ int dynlibmod_init(struct module_env* env, int id) {
__DYNSYM inform = __LOADSYM(dynamic_library,"inform_super"); __DYNSYM inform = __LOADSYM(dynamic_library,"inform_super");
if (inform == NULL) { if (inform == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load inform_super procedure from dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load inform_super procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
de->func_inform = (func_inform_t) inform; de->func_inform = (func_inform_t) inform;
@ -140,7 +154,7 @@ int dynlibmod_init(struct module_env* env, int id) {
__DYNSYM clear = __LOADSYM(dynamic_library,"clear"); __DYNSYM clear = __LOADSYM(dynamic_library,"clear");
if (clear == NULL) { if (clear == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load clear procedure from dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load clear procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
de->func_clear = (func_clear_t) clear; de->func_clear = (func_clear_t) clear;
@ -148,7 +162,7 @@ int dynlibmod_init(struct module_env* env, int id) {
__DYNSYM get_mem = __LOADSYM(dynamic_library,"get_mem"); __DYNSYM get_mem = __LOADSYM(dynamic_library,"get_mem");
if (get_mem == NULL) { if (get_mem == NULL) {
log_dlerror(); log_dlerror();
log_err("dynlibmod: unable to load get_mem procedure from dynamic library \"%s\".", de->fname); log_err("dynlibmod[%d]: unable to load get_mem procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
return 0; return 0;
} else { } else {
de->func_get_mem = (func_get_mem_t) get_mem; de->func_get_mem = (func_get_mem_t) get_mem;

View file

@ -611,7 +611,7 @@ int config_set_option(struct config_file* cfg, const char* opt,
else S_STR("control-cert-file:", control_cert_file) else S_STR("control-cert-file:", control_cert_file)
else S_STR("module-config:", module_conf) else S_STR("module-config:", module_conf)
else S_STRLIST("python-script:", python_script) else S_STRLIST("python-script:", python_script)
else S_STR("dynlib-file:", dynlib_file) else S_STRLIST("dynlib-file:", dynlib_file)
else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check) else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check)
#ifdef CLIENT_SUBNET #ifdef CLIENT_SUBNET
/* Can't set max subnet prefix here, since that value is used when /* Can't set max subnet prefix here, since that value is used when
@ -1064,7 +1064,7 @@ config_get_option(struct config_file* cfg, const char* opt,
else O_YNO(opt, "insecure-lan-zones", insecure_lan_zones) else O_YNO(opt, "insecure-lan-zones", insecure_lan_zones)
else O_DEC(opt, "max-udp-size", max_udp_size) else O_DEC(opt, "max-udp-size", max_udp_size)
else O_LST(opt, "python-script", python_script) else O_LST(opt, "python-script", python_script)
else O_STR(opt, "dynlib-file", dynlib_file) else O_LST(opt, "dynlib-file", dynlib_file)
else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check) else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check)
else O_DEC(opt, "ip-ratelimit", ip_ratelimit) else O_DEC(opt, "ip-ratelimit", ip_ratelimit)
else O_DEC(opt, "ratelimit", ratelimit) else O_DEC(opt, "ratelimit", ratelimit)
@ -1401,7 +1401,6 @@ config_delete(struct config_file* cfg)
free(cfg->version); free(cfg->version);
free(cfg->module_conf); free(cfg->module_conf);
free(cfg->outgoing_avail_ports); free(cfg->outgoing_avail_ports);
free(cfg->dynlib_file);
config_delstrlist(cfg->caps_whitelist); config_delstrlist(cfg->caps_whitelist);
config_delstrlist(cfg->private_address); config_delstrlist(cfg->private_address);
config_delstrlist(cfg->private_domain); config_delstrlist(cfg->private_domain);
@ -1441,6 +1440,7 @@ config_delete(struct config_file* cfg)
config_deldblstrlist(cfg->ratelimit_for_domain); config_deldblstrlist(cfg->ratelimit_for_domain);
config_deldblstrlist(cfg->ratelimit_below_domain); config_deldblstrlist(cfg->ratelimit_below_domain);
config_delstrlist(cfg->python_script); config_delstrlist(cfg->python_script);
config_delstrlist(cfg->dynlib_file);
#ifdef USE_IPSECMOD #ifdef USE_IPSECMOD
free(cfg->ipsecmod_hook); free(cfg->ipsecmod_hook);
config_delstrlist(cfg->ipsecmod_whitelist); config_delstrlist(cfg->ipsecmod_whitelist);

View file

@ -440,7 +440,7 @@ struct config_file {
struct config_strlist* python_script; struct config_strlist* python_script;
/** Dynamic library file */ /** Dynamic library file */
char* dynlib_file; struct config_strlist* dynlib_file;
/** Use systemd socket activation. */ /** Use systemd socket activation. */
int use_systemd; int use_systemd;

View file

@ -2754,8 +2754,8 @@ content_dl: dl_file
dl_file: VAR_DYNLIB_FILE STRING_ARG dl_file: VAR_DYNLIB_FILE STRING_ARG
{ {
OUTYY(("P(dynlib-file:%s)\n", $2)); OUTYY(("P(dynlib-file:%s)\n", $2));
free(cfg_parser->cfg->dynlib_file); if(!cfg_strlist_append_ex(&cfg_parser->cfg->dynlib_file, $2))
cfg_parser->cfg->dynlib_file = $2; yyerror("out of memory");
} }
server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG
{ {