mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
Improve dynlib module and add documentation
Dynamic library module is now only a thin wrapper that loads dynamic libraries and forwards all function calls directly to the loaded module. This meant adding get_mem and clear, and get_mem calls have been added in the expected places. Documentation has also been added to the example.conf and the unbound.conf manpage.
This commit is contained in:
parent
1762437121
commit
8eeb910e3d
9 changed files with 119 additions and 88 deletions
|
|
@ -803,6 +803,9 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
|
|||
size_t dnscrypt_shared_secret = 0;
|
||||
size_t dnscrypt_nonce = 0;
|
||||
#endif /* USE_DNSCRYPT */
|
||||
#ifdef WITH_DYNLIBMODULE
|
||||
size_t dynlib = 0;
|
||||
#endif /* WITH_DYNLIBMODULE */
|
||||
msg = slabhash_get_mem(daemon->env->msg_cache);
|
||||
rrset = slabhash_get_mem(&daemon->env->rrset_cache->table);
|
||||
val = mod_get_mem(&worker->env, "validator");
|
||||
|
|
@ -821,6 +824,9 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
|
|||
dnscrypt_nonce = slabhash_get_mem(daemon->dnscenv->nonces_cache);
|
||||
}
|
||||
#endif /* USE_DNSCRYPT */
|
||||
#ifdef WITH_DYNLIBMODULE
|
||||
dynlib = mod_get_mem(&worker->env, "dynlib");
|
||||
#endif /* WITH_DYNLIBMODULE */
|
||||
|
||||
if(!print_longnum(ssl, "mem.cache.rrset"SQ, rrset))
|
||||
return 0;
|
||||
|
|
@ -848,6 +854,10 @@ print_mem(RES* ssl, struct worker* worker, struct daemon* daemon,
|
|||
dnscrypt_nonce))
|
||||
return 0;
|
||||
#endif /* USE_DNSCRYPT */
|
||||
#ifdef WITH_DYNLIBMODULE
|
||||
if(!print_longnum(ssl, "mem.mod.dynlibmod"SQ, dynlib))
|
||||
return 0;
|
||||
#endif /* WITH_DYNLIBMODULE */
|
||||
if(!print_longnum(ssl, "mem.streamwait"SQ,
|
||||
(size_t)s->svr.mem_stream_wait))
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -837,6 +837,16 @@ python:
|
|||
# Script file to load
|
||||
# python-script: "@UNBOUND_SHARE_DIR@/ubmodule-tst.py"
|
||||
|
||||
# Dynamic library config section. To enable:
|
||||
# o use --with-dynlibmodule to configure before compiling.
|
||||
# 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
|
||||
# to load modules dynamically.
|
||||
# o and give a dynlib-file to run.
|
||||
dynlib:
|
||||
# Script file to load
|
||||
# dynlib-file: "@UNBOUND_SHARE_DIR@/dynlib.so"
|
||||
|
||||
# Remote control config section.
|
||||
remote-control:
|
||||
# Enable remote control with unbound-control(8) here.
|
||||
|
|
|
|||
|
|
@ -940,7 +940,9 @@ EDNS client subnet support the default is "subnetcache validator iterator".
|
|||
Most modules that need to be listed here have to be listed at the beginning
|
||||
of the line. The cachedb module has to be listed just before the iterator.
|
||||
The python module can be listed in different places, it then processes the
|
||||
output of the module it is just before.
|
||||
output of the module it is just before. The dynlib module can be listed pretty
|
||||
much anywhere, it is only a very thin wrapper that allows dynamic libraries to
|
||||
run in its place.
|
||||
.TP
|
||||
.B trust\-anchor\-file: \fI<filename>
|
||||
File with trusted keys for validation. Both DS and DNSKEY entries can appear
|
||||
|
|
@ -1782,6 +1784,22 @@ directory.
|
|||
.B python\-script: \fI<python file>\fR
|
||||
The script file to load. Repeat this option for every python module instance
|
||||
added to the \fBmodule\-config:\fR option.
|
||||
.SS "Dynamic Library Module Options"
|
||||
.LP
|
||||
The
|
||||
.B dynlib:
|
||||
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
|
||||
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
|
||||
\fBmodule\-config:\fR option.
|
||||
.LP
|
||||
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
|
||||
working directory.
|
||||
.TP
|
||||
.B dynlib\-file: \fI<dynlib file>\fR
|
||||
The dynamic library file to load.
|
||||
.SS "DNS64 Module Options"
|
||||
.LP
|
||||
The dns64 module must be configured in the \fBmodule\-config:\fR "dns64
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#if HAVE_WINDOWS_H
|
||||
#include <windows.h>
|
||||
#define __DYNMOD HMODULE
|
||||
#define __DYNSYM FARPROC
|
||||
#define __LOADSYM GetProcAddress
|
||||
void log_dlerror() {
|
||||
|
|
@ -25,43 +26,39 @@ void log_dlerror() {
|
|||
))
|
||||
{
|
||||
DWORD dwBytesWritten;
|
||||
|
||||
//
|
||||
// Output message string on stderr.
|
||||
//
|
||||
log_info("dynlibmod: %s (%ld)", MessageBuffer, dwLastError);
|
||||
//WriteFile(
|
||||
// GetStdHandle(STD_ERROR_HANDLE),
|
||||
// MessageBuffer,
|
||||
// dwBufferLength,
|
||||
// &dwBytesWritten,
|
||||
// NULL
|
||||
// );
|
||||
|
||||
//
|
||||
// Free the buffer allocated by the system.
|
||||
//
|
||||
log_err("dynlibmod: %s (%ld)", MessageBuffer, dwLastError);
|
||||
LocalFree(MessageBuffer);
|
||||
}
|
||||
|
||||
}
|
||||
HMODULE open_library(const char* fname) {
|
||||
return LoadLibrary(fname);
|
||||
}
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#define __DYNMOD void*
|
||||
#define __DYNSYM void*
|
||||
#define __LOADSYM dlsym
|
||||
void log_dlerror() {
|
||||
log_err("dynlibmod: %s", dlerror());
|
||||
}
|
||||
void* open_library(const char* fname) {
|
||||
return dlopen(fname, RTLD_LAZY | RTLD_GLOBAL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Global state for the module.
|
||||
*/
|
||||
|
||||
typedef int (*func_init_t)(int, struct config_file*);
|
||||
typedef int (*func_deinit_t)(int);
|
||||
typedef int (*func_operate_t)(int, enum module_ev event, struct module_qstate* qstate, void*);
|
||||
typedef int (*func_inform_t)(int, struct module_qstate* qstate, struct module_qstate* super, void*);
|
||||
typedef void (*func_init_t)(struct module_env*, int);
|
||||
typedef void (*func_deinit_t)(struct module_env*, int);
|
||||
typedef void (*func_operate_t)(struct module_qstate*, enum module_ev, int, struct outbound_entry*);
|
||||
typedef void (*func_inform_t)(struct module_qstate*, int, struct module_qstate*);
|
||||
typedef void (*func_clear_t)(struct module_qstate*, int);
|
||||
typedef size_t (*func_get_mem_t)(struct module_env*, int);
|
||||
|
||||
struct dynlibmod_env {
|
||||
|
||||
/** Dynamic library filename. */
|
||||
|
|
@ -75,20 +72,19 @@ struct dynlibmod_env {
|
|||
func_operate_t func_operate;
|
||||
/** Module super_inform function */
|
||||
func_inform_t func_inform;
|
||||
/** Module clear function */
|
||||
func_clear_t func_clear;
|
||||
/** Module get_mem function */
|
||||
func_get_mem_t func_get_mem;
|
||||
|
||||
/** Module qstate. */
|
||||
struct module_qstate* qstate;
|
||||
};
|
||||
|
||||
struct dynlibmod_qstate {
|
||||
|
||||
/** Module per query data. */
|
||||
void* data;
|
||||
};
|
||||
|
||||
/** dynlib module init */
|
||||
int dynlibmod_init(struct module_env* env, int id) {
|
||||
struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
|
||||
__DYNMOD dynamic_library;
|
||||
if (!de)
|
||||
{
|
||||
log_err("dynlibmod: malloc failure");
|
||||
|
|
@ -102,59 +98,63 @@ int dynlibmod_init(struct module_env* env, int id) {
|
|||
log_err("dynlibmod: no dynamic library given.");
|
||||
return 0;
|
||||
}
|
||||
log_info("Trying to load library %s", de->fname);
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
void* dynamic_library = dlopen(de->fname, RTLD_LAZY | RTLD_GLOBAL);
|
||||
#else
|
||||
HMODULE dynamic_library = LoadLibrary(de->fname);
|
||||
#endif
|
||||
verbose(VERB_ALGO, "dynlibmod: Trying to load library %s", de->fname);
|
||||
dynamic_library = open_library(de->fname);
|
||||
if (dynamic_library == NULL) {
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load dynamic library.");
|
||||
log_err("dynlibmod: unable to load dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
__DYNSYM initializer = __LOADSYM(dynamic_library,"init");
|
||||
if (initializer == NULL) {
|
||||
log_err("dynlibmod: unable to load init procedure from dynamic library.");
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
log_err("dynlibmod: %s", dlerror());
|
||||
#endif
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load init procedure from dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
de->func_init = (func_init_t) initializer;
|
||||
}
|
||||
__DYNSYM deinitializer = __LOADSYM(dynamic_library,"deinit");
|
||||
if (deinitializer == NULL) {
|
||||
log_err("dynlibmod: unable to load deinit procedure from dynamic library.");
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
log_err("dynlibmod: %s", dlerror());
|
||||
#endif
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load deinit procedure from dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
de->func_deinit = (func_deinit_t) deinitializer;
|
||||
}
|
||||
__DYNSYM operate = __LOADSYM(dynamic_library,"operate");
|
||||
if (operate == NULL) {
|
||||
log_err("dynlibmod: unable to load operate procedure from dynamic library.");
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
log_err("dynlibmod: %s", dlerror());
|
||||
#endif
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load operate procedure from dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
de->func_operate = (func_operate_t) operate;
|
||||
}
|
||||
__DYNSYM inform = __LOADSYM(dynamic_library,"inform_super");
|
||||
if (inform == NULL) {
|
||||
log_err("dynlibmod: unable to load inform_super procedure from dynamic library.");
|
||||
#ifndef HAVE_WINDOWS_H
|
||||
log_err("dynlibmod: %s", dlerror());
|
||||
#endif
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load inform_super procedure from dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
de->func_inform = (func_inform_t) inform;
|
||||
}
|
||||
__DYNSYM clear = __LOADSYM(dynamic_library,"clear");
|
||||
if (clear == NULL) {
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load clear procedure from dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
de->func_clear = (func_clear_t) clear;
|
||||
}
|
||||
de->func_init(id, env->cfg);
|
||||
__DYNSYM get_mem = __LOADSYM(dynamic_library,"get_mem");
|
||||
if (get_mem == NULL) {
|
||||
log_dlerror();
|
||||
log_err("dynlibmod: unable to load get_mem procedure from dynamic library \"%s\".", de->fname);
|
||||
return 0;
|
||||
} else {
|
||||
de->func_get_mem = (func_get_mem_t) get_mem;
|
||||
}
|
||||
}
|
||||
de->func_init(env, id);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +163,7 @@ void dynlibmod_deinit(struct module_env* env, int id) {
|
|||
struct dynlibmod_env* de = env->modinfo[id];
|
||||
if(de == NULL)
|
||||
return;
|
||||
de->func_deinit(id);
|
||||
de->func_deinit(env, id);
|
||||
de->fname = NULL;
|
||||
free(de);
|
||||
}
|
||||
|
|
@ -172,44 +172,23 @@ void dynlibmod_deinit(struct module_env* env, int id) {
|
|||
void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event,
|
||||
int id, struct outbound_entry* outbound) {
|
||||
struct dynlibmod_env* de = qstate->env->modinfo[id];
|
||||
struct dynlibmod_qstate* dq = (struct dynlibmod_qstate*)qstate->minfo[id];
|
||||
|
||||
void * data = dq == NULL ? NULL : dq->data;
|
||||
int ret = de->func_operate(id, event, qstate, data);
|
||||
if (ret != 1) {
|
||||
log_err("dynlibmod: dynamic library returned bad code from operate %d.", ret);
|
||||
qstate->ext_state[id] = module_error;
|
||||
}
|
||||
de->func_operate(qstate, event, id, outbound);
|
||||
}
|
||||
|
||||
/** dynlib module */
|
||||
void dynlibmod_inform_super(struct module_qstate* qstate, int id,
|
||||
struct module_qstate* super) {
|
||||
struct dynlibmod_env* de = qstate->env->modinfo[id];
|
||||
struct dynlibmod_qstate* dq = (struct dynlibmod_qstate*)qstate->minfo[id];
|
||||
|
||||
void * data = dq == NULL ? NULL : dq->data;
|
||||
int ret = de->func_inform(id, qstate, super, data);
|
||||
if (ret != 1) {
|
||||
log_err("dynlibmod: dynamic library returned bad code from inform_super %d.", ret);
|
||||
qstate->ext_state[id] = module_error;
|
||||
}
|
||||
de->func_inform(qstate, id, super);
|
||||
}
|
||||
|
||||
/** dynlib module cleanup query state */
|
||||
void dynlibmod_clear(struct module_qstate* qstate, int id) {
|
||||
struct dynlibmod_qstate* dq;
|
||||
if (qstate == NULL)
|
||||
return;
|
||||
struct dynlibmod_env* de = qstate->env->modinfo[id];
|
||||
|
||||
dq = (struct dynlibmod_qstate*)qstate->minfo[id];
|
||||
verbose(VERB_ALGO, "dynlibmod: clear, id: %d, dq:%p", id, dq);
|
||||
if(dq != NULL) {
|
||||
/* Free qstate */
|
||||
free(dq);
|
||||
}
|
||||
|
||||
qstate->minfo[id] = NULL;
|
||||
de->func_clear(qstate, id);
|
||||
}
|
||||
|
||||
/** dynlib module alloc size routine */
|
||||
|
|
@ -218,7 +197,9 @@ size_t dynlibmod_get_mem(struct module_env* env, int id) {
|
|||
verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de);
|
||||
if(!de)
|
||||
return 0;
|
||||
return sizeof(*de);
|
||||
|
||||
size_t size = de->func_get_mem(env, id);
|
||||
return size + sizeof(*de);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
/*
|
||||
* dynlibmod.h: module header file
|
||||
*
|
||||
* Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
|
||||
* Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
|
||||
* Copyright (c) 2019, Peter Munch-Ellingsen (peterme AT peterme.net)
|
||||
*
|
||||
* This software is open source.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -17,17 +17,15 @@
|
|||
#define EXPORT
|
||||
#endif
|
||||
|
||||
EXPORT int init(int id, struct config_file* cfg) {
|
||||
EXPORT void init(struct module_env* env, int id) {
|
||||
log_info("Hello world from init");
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT int deinit(int id) {
|
||||
EXPORT void deinit(struct module_env* env, int id) {
|
||||
log_info("Hello world from deinit");
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT int operate(int id, enum module_ev event, struct module_qstate* qstate, void* data) {
|
||||
EXPORT void operate(struct module_qstate* qstate, enum module_ev event, int id, struct outbound_entry* entry) {
|
||||
log_info("Hello world from operate");
|
||||
if (event == module_event_new || event == module_event_pass) {
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
|
|
@ -36,10 +34,17 @@ EXPORT int operate(int id, enum module_ev event, struct module_qstate* qstate, v
|
|||
} else {
|
||||
qstate->ext_state[id] = module_error;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT int inform_super(int id, struct module_qstate* qstate, struct module_qstate* super, void* data) {
|
||||
EXPORT void inform_super(struct module_qstate* qstate, int id, struct module_qstate* super) {
|
||||
log_info("Hello world from inform_super");
|
||||
return 1;
|
||||
}
|
||||
|
||||
EXPORT void clear(struct module_qstate* qstate, int id) {
|
||||
log_info("Hello world from clear");
|
||||
}
|
||||
|
||||
EXPORT size_t get_mem(struct module_env* env, int id) {
|
||||
log_info("Hello world from get_mem");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -641,6 +641,7 @@ struct ub_shm_stat_info {
|
|||
long long respip;
|
||||
long long dnscrypt_shared_secret;
|
||||
long long dnscrypt_nonce;
|
||||
long long dynlib;
|
||||
} mem;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -261,6 +261,9 @@ static void print_mem(struct ub_shm_stat_info* shm_stat,
|
|||
#ifdef USE_IPSECMOD
|
||||
PR_LL("mem.mod.ipsecmod", shm_stat->mem.ipsecmod);
|
||||
#endif
|
||||
#ifdef WITH_DYNLIBMODULE
|
||||
PR_LL("mem.mod.dynlib", shm_stat->mem.dynlib);
|
||||
#endif
|
||||
#ifdef USE_DNSCRYPT
|
||||
PR_LL("mem.cache.dnscrypt_shared_secret",
|
||||
shm_stat->mem.dnscrypt_shared_secret);
|
||||
|
|
|
|||
|
|
@ -280,6 +280,10 @@ void shm_main_run(struct worker *worker)
|
|||
#ifdef USE_IPSECMOD
|
||||
shm_stat->mem.ipsecmod = (long long)mod_get_mem(&worker->env,
|
||||
"ipsecmod");
|
||||
#endif
|
||||
#ifdef WITH_DYNLIBMODULE
|
||||
shm_stat->mem.dynlib = (long long)mod_get_mem(&worker->env,
|
||||
"dynlib");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue