From: PMunch Date: Thu, 17 Oct 2019 13:10:33 +0000 (+0200) Subject: Add dynamic library support X-Git-Tag: release-1.11.0~45^2^2~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1762437121c91c6972d3fb8c22266d0c8d837f0c;p=thirdparty%2Funbound.git Add dynamic library support --- diff --git a/Makefile.in b/Makefile.in index d9d4fe7ad..21367eec3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -25,6 +25,7 @@ DNSTAP_SRC=@DNSTAP_SRC@ DNSTAP_OBJ=@DNSTAP_OBJ@ DNSCRYPT_SRC=@DNSCRYPT_SRC@ DNSCRYPT_OBJ=@DNSCRYPT_OBJ@ +WITH_DYNLIBMODULE=@WITH_DYNLIBMODULE@ WITH_PYTHONMODULE=@WITH_PYTHONMODULE@ WITH_PYUNBOUND=@WITH_PYUNBOUND@ PY_MAJOR_VERSION=@PY_MAJOR_VERSION@ @@ -87,6 +88,12 @@ LINTFLAGS+="-D__uint16_t=uint16_t" "-DEVP_PKEY_ASN1_METHOD=int" "-D_RuneLocale=i INSTALL=$(SHELL) $(srcdir)/install-sh +DYNLIBMOD_SRC=dynlibmod/dynlibmod.c +DYNLIBMOD_OBJ=@DYNLIBMOD_OBJ@ +DYNLIBMOD_HEADER=@DYNLIBMOD_HEADER@ +DYNLIBMOD_EXTRALIBS=@DYNLIBMOD_EXTRALIBS@ + + #pythonmod.c is not here, it is mentioned by itself in its own rules, #makedepend fails on missing interface.h otherwise. PYTHONMOD_SRC=pythonmod/pythonmod_utils.c @@ -139,7 +146,7 @@ autotrust.lo val_anchor.lo \ validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \ val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo cachedb.lo redis.lo authzone.lo \ $(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \ -$(IPSECMOD_OBJ) $(IPSET_OBJ) respip.lo +$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \ outside_network.lo COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo @@ -326,7 +333,7 @@ libunbound.la: $(LIBUNBOUND_OBJ_LINK) $(LINK_LIB) $(UBSYMS) -o $@ $(LIBUNBOUND_OBJ_LINK) -rpath $(libdir) $(SSLLIB) $(LIBS) unbound$(EXEEXT): $(DAEMON_OBJ_LINK) libunbound.la - $(LINK) -o $@ $(DAEMON_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) + $(LINK) -o $@ $(DAEMON_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) $(DYNLIBMOD_EXTRALIBS) unbound-checkconf$(EXEEXT): $(CHECKCONF_OBJ_LINK) libunbound.la $(LINK) -o $@ $(CHECKCONF_OBJ_LINK) $(EXTRALINK) $(SSLLIB) $(LIBS) @@ -453,6 +460,7 @@ clean: rm -f unbound$(EXEEXT) unbound-checkconf$(EXEEXT) unbound-host$(EXEEXT) unbound-control$(EXEEXT) unbound-anchor$(EXEEXT) unbound-control-setup libunbound.la unbound.h rm -f $(ALL_SRC:.c=.lint) rm -f _unbound.la libunbound/python/libunbound_wrap.c libunbound/python/unbound.py pythonmod/interface.h pythonmod/unboundmodule.py + rm -f libunbound.a rm -rf autom4te.cache .libs build doc/html doc/xml realclean: clean @@ -622,6 +630,7 @@ depend: -e 's?$$(srcdir)/pythonmod/pythonmod.h?$$(PYTHONMOD_HEADER)?g' \ -e 's?$$(srcdir)/edns-subnet/subnetmod.h $$(srcdir)/edns-subnet/subnet-whitelist.h $$(srcdir)/edns-subnet/edns-subnet.h $$(srcdir)/edns-subnet/addrtree.h?$$(SUBNET_HEADER)?g' \ -e 's?$$(srcdir)/ipsecmod/ipsecmod.h $$(srcdir)/ipsecmod/ipsecmod-whitelist.h?$$(IPSECMOD_HEADER)?g' \ + -e 's?$$(srcdir)/dynlibmod/dynlibmod.h?$$(DYNLIBMOD_HEADER)?g' \ -e 's!\(.*\)\.o[ :]*!\1.lo \1.o: !g' \ > $(DEPEND_TMP) cp $(DEPEND_TARGET) $(DEPEND_TMP2) @@ -783,7 +792,7 @@ modstack.lo modstack.o: $(srcdir)/services/modstack.c config.h $(srcdir)/service $(srcdir)/services/view.h $(PYTHONMOD_HEADER) $(srcdir)/ipsecmod/ipsecmod.h \ $(srcdir)/edns-subnet/subnetmod.h $(srcdir)/util/alloc.h $(srcdir)/util/net_help.h \ $(srcdir)/util/storage/slabhash.h $(srcdir)/edns-subnet/addrtree.h $(srcdir)/edns-subnet/edns-subnet.h \ - $(srcdir)/ipset/ipset.h + $(srcdir)/ipset/ipset.h $(srcdir)/dynlibmod/dynlibmod.h view.lo view.o: $(srcdir)/services/view.c config.h $(srcdir)/services/view.h $(srcdir)/util/rbtree.h \ $(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/services/localzone.h $(srcdir)/util/storage/dnstree.h \ $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/data/msgreply.h \ @@ -865,7 +874,8 @@ fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/ $(srcdir)/libunbound/unbound-event.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \ $(srcdir)/util/config_file.h $(srcdir)/respip/respip.h $(PYTHONMOD_HEADER) \ $(srcdir)/ipsecmod/ipsecmod.h $(srcdir)/edns-subnet/subnetmod.h $(srcdir)/util/net_help.h \ - $(srcdir)/edns-subnet/addrtree.h $(srcdir)/edns-subnet/edns-subnet.h $(srcdir)/ipset/ipset.h + $(srcdir)/edns-subnet/addrtree.h $(srcdir)/edns-subnet/edns-subnet.h $(srcdir)/ipset/ipset.h \ + $(srcdir)/dynlibmod/dynlibmod.h locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h log.lo log.o: $(srcdir)/util/log.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/sldns/sbuffer.h mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h @@ -1072,6 +1082,14 @@ dnstap.lo dnstap.o: $(srcdir)/dnstap/dnstap.c config.h $(srcdir)/sldns/sbuffer. dnstap/dnstap.pb-c.h dnstap.pb-c.lo dnstap.pb-c.o: dnstap/dnstap.pb-c.c dnstap/dnstap.pb-c.h \ +dynlibmod.lo dynlibmod.o: $(srcdir)/dynlibmod/dynlibmod.c config.h $(srcdir)/dynlibmod/dynlibmod.h \ + $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ + $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \ + $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/rbtree.h\ + $(srcdir)/util/storage/dnstree.h $(srcdir)/util/fptr_wlist.h $(srcdir)/util/netevent.h \ + $(srcdir)/dnscrypt/dnscrypt.h $(srcdir)/util/tube.h \ + $(srcdir)/services/mesh.h $(srcdir)/services/modstack.h $(srcdir)/util/regional.h $(srcdir)/util/net_help.h \ + $(srcdir)/util/config_file.h $(srcdir)/services/cache/dns.h $(srcdir)/sldns/wire2str.h ipsecmod.lo ipsecmod.o: $(srcdir)/ipsecmod/ipsecmod.c config.h $(srcdir)/ipsecmod/ipsecmod.h \ $(srcdir)/util/module.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ $(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \ diff --git a/config.h.in b/config.h.in index d8ec50a6d..a07b970bc 100644 --- a/config.h.in +++ b/config.h.in @@ -836,6 +836,9 @@ /* Define if you want Python module. */ #undef WITH_PYTHONMODULE +/* Define if you want dynamic library module. */ +#undef WITH_DYNLIBMODULE + /* Define if you want PyUnbound. */ #undef WITH_PYUNBOUND diff --git a/configure b/configure index 4e222879e..41984f652 100755 --- a/configure +++ b/configure @@ -697,6 +697,10 @@ PYTHON_LDFLAGS PYTHON_CPPFLAGS PYTHON PYTHON_VERSION +DYNLIBMOD_EXTRALIBS +DYNLIBMOD_HEADER +DYNLIBMOD_OBJ +WITH_DYNLIBMODULE PTHREAD_CFLAGS_ONLY PTHREAD_CFLAGS PTHREAD_LIBS @@ -851,6 +855,7 @@ enable_alloc_nonregional with_pthreads with_solaris_threads with_syslog_facility +with_dynlibmodule with_pyunbound with_pythonmodule enable_swig_version_check @@ -1607,6 +1612,8 @@ Optional Packages: --with-solaris-threads use solaris native thread library. --with-syslog-facility=LOCAL0 - LOCAL7 set SYSLOG_FACILITY, default DAEMON + --with-dynlibmodule build dynamic library module, or + --without-dynlibmodule to disable it. (default=no) --with-pyunbound build PyUnbound, or --without-pyunbound to skip it. (default=no) --with-pythonmodule build Python module, or --without-pythonmodule to @@ -17123,6 +17130,34 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# Check for dynamic library module + +# Check whether --with-dynlibmodule was given. +if test "${with_dynlibmodule+set}" = set; then : + withval=$with_dynlibmodule; +else + withval="no" +fi + + +if test x_$withval != x_no; then + +$as_echo "#define WITH_DYNLIBMODULE 1" >>confdefs.h + + WITH_DYNLIBMODULE=yes + + DYNLIBMOD_OBJ="dynlibmod.lo" + + DYNLIBMOD_HEADER='$(srcdir)/dynlibmod/dynlibmod.h' + + if test $on_mingw = "no"; then + DYNLIBMOD_EXTRALIBS="-ldl -export-dynamic" + else + DYNLIBMOD_EXTRALIBS="-Wl,--export-all-symbols,--out-implib,libunbound.a" + fi + +fi + # Check for PyUnbound # Check whether --with-pyunbound was given. diff --git a/configure.ac b/configure.ac index 216a78c65..7d108d002 100644 --- a/configure.ac +++ b/configure.ac @@ -616,6 +616,28 @@ case "${UNBOUND_SYSLOG_FACILITY}" in esac AC_DEFINE_UNQUOTED(UB_SYSLOG_FACILITY,${UNBOUND_SYSLOG_FACILITY},[the SYSLOG_FACILITY to use, default LOG_DAEMON]) +# Check for dynamic library module +AC_ARG_WITH(dynlibmodule, + AC_HELP_STRING([--with-dynlibmodule], + [build dynamic library module, or --without-dynlibmodule to disable it. (default=no)]), + [], [ withval="no" ]) + +if test x_$withval != x_no; then + AC_DEFINE(WITH_DYNLIBMODULE, 1, [Define if you want dynlib module.]) + WITH_DYNLIBMODULE=yes + AC_SUBST(WITH_DYNLIBMODULE) + DYNLIBMOD_OBJ="dynlibmod.lo" + AC_SUBST(DYNLIBMOD_OBJ) + DYNLIBMOD_HEADER='$(srcdir)/dynlibmod/dynlibmod.h' + AC_SUBST(DYNLIBMOD_HEADER) + if test $on_mingw = "no"; then + DYNLIBMOD_EXTRALIBS="-ldl -export-dynamic" + else + DYNLIBMOD_EXTRALIBS="-Wl,--export-all-symbols,--out-implib,libunbound.a" + fi + AC_SUBST(DYNLIBMOD_EXTRALIBS) +fi + # Check for PyUnbound AC_ARG_WITH(pyunbound, AC_HELP_STRING([--with-pyunbound], diff --git a/dynlibmod/dynlibmod.c b/dynlibmod/dynlibmod.c new file mode 100644 index 000000000..47d315306 --- /dev/null +++ b/dynlibmod/dynlibmod.c @@ -0,0 +1,236 @@ +#include "config.h" +#include "util/module.h" +#include "util/config_file.h" +#include "dynlibmod/dynlibmod.h" + +#if HAVE_WINDOWS_H +#include +#define __DYNSYM FARPROC +#define __LOADSYM GetProcAddress +void log_dlerror() { + DWORD dwLastError = GetLastError(); + LPSTR MessageBuffer; + DWORD dwBufferLength; + DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM ; + if(dwBufferLength = FormatMessageA( + dwFormatFlags, + NULL, // module to get message from (NULL == system) + dwLastError, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language + (LPSTR) &MessageBuffer, + 0, + NULL + )) + { + 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. + // + LocalFree(MessageBuffer); + } + +} +#else +#include +#define __DYNSYM void* +#define __LOADSYM dlsym +void log_dlerror() { + log_err("dynlibmod: %s", dlerror()); +} +#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*); +struct dynlibmod_env { + + /** Dynamic library filename. */ + const char* fname; + + /** Module init function */ + func_init_t func_init; + /** Module deinit function */ + func_deinit_t func_deinit; + /** Module operate function */ + func_operate_t func_operate; + /** Module super_inform function */ + func_inform_t func_inform; + + /** 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)); + if (!de) + { + log_err("dynlibmod: malloc failure"); + return 0; + } + + env->modinfo[id] = (void*) de; + + de->fname = env->cfg->dynlib_file; + if (de->fname == NULL || de->fname[0] == 0) { + 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 + if (dynamic_library == NULL) { + log_dlerror(); + log_err("dynlibmod: unable to load dynamic library."); + 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 + 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 + 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 + 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 + return 0; + } else { + de->func_inform = (func_inform_t) inform; + } + } + de->func_init(id, env->cfg); + return 1; +} + +/** dynlib module deinit */ +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->fname = NULL; + free(de); +} + +/** dynlib module operate on a query */ +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; + } +} + +/** 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; + } +} + +/** dynlib module cleanup query state */ +void dynlibmod_clear(struct module_qstate* qstate, int id) { + struct dynlibmod_qstate* dq; + if (qstate == NULL) + return; + + 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; +} + +/** dynlib module alloc size routine */ +size_t dynlibmod_get_mem(struct module_env* env, int id) { + struct dynlibmod_env* de = (struct dynlibmod_env*)env->modinfo[id]; + verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de); + if(!de) + return 0; + return sizeof(*de); +} + +/** + * The module function block + */ +static struct module_func_block dynlibmod_block = { + "dynlib", + &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate, &dynlibmod_inform_super, + &dynlibmod_clear, &dynlibmod_get_mem +}; + +struct module_func_block* dynlibmod_get_funcblock(void) +{ + return &dynlibmod_block; +} diff --git a/dynlibmod/dynlibmod.h b/dynlibmod/dynlibmod.h new file mode 100644 index 000000000..ac5d737b4 --- /dev/null +++ b/dynlibmod/dynlibmod.h @@ -0,0 +1,71 @@ +/* + * dynlibmod.h: module header file + * + * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz) + * Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz) + * + * This software is open source. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the organization nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * \file + * Dynamic loading module for unbound. Loads dynamic library. + */ +#ifndef DYNLIBMOD_H +#define DYNLIBMOD_H +#include "util/module.h" +#include "services/outbound_list.h" + +/** + * Get the module function block. + * @return: function block with function pointers to module methods. + */ +struct module_func_block* dynlibmod_get_funcblock(void); + +/** dynlib module init */ +int dynlibmod_init(struct module_env* env, int id); + +/** dynlib module deinit */ +void dynlibmod_deinit(struct module_env* env, int id); + +/** dynlib module operate on a query */ +void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event, + int id, struct outbound_entry* outbound); + +/** dynlib module */ +void dynlibmod_inform_super(struct module_qstate* qstate, int id, + struct module_qstate* super); + +/** dynlib module cleanup query state */ +void dynlibmod_clear(struct module_qstate* qstate, int id); + +/** dynlib module alloc size routine */ +size_t dynlibmod_get_mem(struct module_env* env, int id); + +#endif /* DYNLIBMOD_H */ diff --git a/dynlibmod/examples/helloworld.c b/dynlibmod/examples/helloworld.c new file mode 100644 index 000000000..76c1df215 --- /dev/null +++ b/dynlibmod/examples/helloworld.c @@ -0,0 +1,45 @@ +/* + * This is an example to show how dynamic libraries can be made to work with + * unbound. To build a .so file simply run: + * gcc -I../.. -shared -Wall -Werror -fpic -o helloworld.so helloworld.c + * And to build for windows, first make unbound with the --with-dynlibmod + * switch, then use this command: + * x86_64-w64-mingw32-gcc -m64 -I../.. -shared -Wall -Werror -fpic -o helloworld.dll helloworld.c -L../.. -l:libunbound.a + * to cross-compile a 64-bit Windows DLL. + */ + +#include "../../config.h" +#include "../../util/module.h" + +#ifdef HAVE_WINDOWS_H +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +EXPORT int init(int id, struct config_file* cfg) { + log_info("Hello world from init"); + return 1; +} + +EXPORT int deinit(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) { + log_info("Hello world from operate"); + if (event == module_event_new || event == module_event_pass) { + qstate->ext_state[id] = module_wait_module; + } else if (event == module_event_moddone) { + qstate->ext_state[id] = module_finished; + } 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) { + log_info("Hello world from inform_super"); + return 1; +} diff --git a/services/modstack.c b/services/modstack.c index 68e592814..a600549b1 100644 --- a/services/modstack.c +++ b/services/modstack.c @@ -51,6 +51,9 @@ #ifdef WITH_PYTHONMODULE #include "pythonmod/pythonmod.h" #endif +#ifdef WITH_DYNLIBMODULE +#include "dynlibmod/dynlibmod.h" +#endif #ifdef USE_CACHEDB #include "cachedb/cachedb.h" #endif @@ -140,6 +143,9 @@ module_list_avail(void) #ifdef WITH_PYTHONMODULE "python", #endif +#ifdef WITH_DYNLIBMODULE + "dynlib", +#endif #ifdef USE_CACHEDB "cachedb", #endif @@ -171,6 +177,9 @@ module_funcs_avail(void) #ifdef WITH_PYTHONMODULE &pythonmod_get_funcblock, #endif +#ifdef WITH_DYNLIBMODULE + &dynlibmod_get_funcblock, +#endif #ifdef USE_CACHEDB &cachedb_get_funcblock, #endif diff --git a/util/config_file.c b/util/config_file.c index 119b22238..7a8fb0bbc 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -264,6 +264,7 @@ config_create(void) cfg->unblock_lan_zones = 0; cfg->insecure_lan_zones = 0; cfg->python_script = NULL; + cfg->dynlib_file = NULL; cfg->remote_control_enable = 0; cfg->control_ifs.first = NULL; cfg->control_ifs.last = NULL; @@ -610,6 +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("module-config:", module_conf) else S_STRLIST("python-script:", python_script) + else S_STR("dynlib-file:", dynlib_file) else S_YNO("disable-dnssec-lame-check:", disable_dnssec_lame_check) #ifdef CLIENT_SUBNET /* Can't set max subnet prefix here, since that value is used when @@ -1062,6 +1064,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_YNO(opt, "insecure-lan-zones", insecure_lan_zones) else O_DEC(opt, "max-udp-size", max_udp_size) else O_LST(opt, "python-script", python_script) + else O_STR(opt, "dynlib-file", dynlib_file) else O_YNO(opt, "disable-dnssec-lame-check", disable_dnssec_lame_check) else O_DEC(opt, "ip-ratelimit", ip_ratelimit) else O_DEC(opt, "ratelimit", ratelimit) @@ -1398,6 +1401,7 @@ config_delete(struct config_file* cfg) free(cfg->version); free(cfg->module_conf); free(cfg->outgoing_avail_ports); + free(cfg->dynlib_file); config_delstrlist(cfg->caps_whitelist); config_delstrlist(cfg->private_address); config_delstrlist(cfg->private_domain); diff --git a/util/config_file.h b/util/config_file.h index b3ef930a0..6706ab08b 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -439,6 +439,9 @@ struct config_file { /** Python script file */ struct config_strlist* python_script; + /** Dynamic library file */ + char* dynlib_file; + /** Use systemd socket activation. */ int use_systemd; diff --git a/util/configlexer.lex b/util/configlexer.lex index a86ddf55d..1010dcda9 100644 --- a/util/configlexer.lex +++ b/util/configlexer.lex @@ -404,6 +404,8 @@ control-key-file{COLON} { YDVAR(1, VAR_CONTROL_KEY_FILE) } control-cert-file{COLON} { YDVAR(1, VAR_CONTROL_CERT_FILE) } python-script{COLON} { YDVAR(1, VAR_PYTHON_SCRIPT) } python{COLON} { YDVAR(0, VAR_PYTHON) } +dynlib-file{COLON} { YDVAR(1, VAR_DYNLIB_FILE) } +dynlib{COLON} { YDVAR(0, VAR_DYNLIB) } domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) } minimal-responses{COLON} { YDVAR(1, VAR_MINIMAL_RESPONSES) } rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) } diff --git a/util/configparser.y b/util/configparser.y index 10227a2ff..5f58d75b3 100644 --- a/util/configparser.y +++ b/util/configparser.y @@ -168,6 +168,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES %token VAR_TLS_SESSION_TICKET_KEYS %token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6 +%token VAR_DYNLIB VAR_DYNLIB_FILE %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -175,7 +176,7 @@ toplevelvar: serverstart contents_server | stubstart contents_stub | forwardstart contents_forward | pythonstart contents_py | rcstart contents_rc | dtstart contents_dt | viewstart contents_view | dnscstart contents_dnsc | cachedbstart contents_cachedb | - ipsetstart contents_ipset | authstart contents_auth + ipsetstart contents_ipset | authstart contents_auth | dynlibstart contents_dl ; /* server: declaration */ @@ -2741,6 +2742,21 @@ py_script: VAR_PYTHON_SCRIPT STRING_ARG if(!cfg_strlist_append_ex(&cfg_parser->cfg->python_script, $2)) yyerror("out of memory"); } +dynlibstart: VAR_DYNLIB + { + OUTYY(("\nP(dynlib:)\n")); + } + ; +contents_dl: contents_dl content_dl + | ; +content_dl: dl_file + ; +dl_file: VAR_DYNLIB_FILE STRING_ARG + { + OUTYY(("P(dynlib-file:%s)\n", $2)); + free(cfg_parser->cfg->dynlib_file); + cfg_parser->cfg->dynlib_file = $2; + } server_disable_dnssec_lame_check: VAR_DISABLE_DNSSEC_LAME_CHECK STRING_ARG { OUTYY(("P(disable_dnssec_lame_check:%s)\n", $2)); diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index f5da501de..20eaeb137 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -81,6 +81,9 @@ #ifdef WITH_PYTHONMODULE #include "pythonmod/pythonmod.h" #endif +#ifdef WITH_DYNLIBMODULE +#include "dynlibmod/dynlibmod.h" +#endif #ifdef USE_CACHEDB #include "cachedb/cachedb.h" #endif @@ -379,6 +382,9 @@ fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id)) #ifdef WITH_PYTHONMODULE else if(fptr == &pythonmod_init) return 1; #endif +#ifdef WITH_DYNLIBMODULE + else if(fptr == &dynlibmod_init) return 1; +#endif #ifdef USE_CACHEDB else if(fptr == &cachedb_init) return 1; #endif @@ -404,6 +410,9 @@ fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id)) #ifdef WITH_PYTHONMODULE else if(fptr == &pythonmod_deinit) return 1; #endif +#ifdef WITH_DYNLIBMODULE + else if(fptr == &dynlibmod_deinit) return 1; +#endif #ifdef USE_CACHEDB else if(fptr == &cachedb_deinit) return 1; #endif @@ -430,6 +439,9 @@ fptr_whitelist_mod_operate(void (*fptr)(struct module_qstate* qstate, #ifdef WITH_PYTHONMODULE else if(fptr == &pythonmod_operate) return 1; #endif +#ifdef WITH_DYNLIBMODULE + else if(fptr == &dynlibmod_operate) return 1; +#endif #ifdef USE_CACHEDB else if(fptr == &cachedb_operate) return 1; #endif @@ -456,6 +468,9 @@ fptr_whitelist_mod_inform_super(void (*fptr)( #ifdef WITH_PYTHONMODULE else if(fptr == &pythonmod_inform_super) return 1; #endif +#ifdef WITH_DYNLIBMODULE + else if(fptr == &dynlibmod_inform_super) return 1; +#endif #ifdef USE_CACHEDB else if(fptr == &cachedb_inform_super) return 1; #endif @@ -482,6 +497,9 @@ fptr_whitelist_mod_clear(void (*fptr)(struct module_qstate* qstate, #ifdef WITH_PYTHONMODULE else if(fptr == &pythonmod_clear) return 1; #endif +#ifdef WITH_DYNLIBMODULE + else if(fptr == &dynlibmod_clear) return 1; +#endif #ifdef USE_CACHEDB else if(fptr == &cachedb_clear) return 1; #endif @@ -507,6 +525,9 @@ fptr_whitelist_mod_get_mem(size_t (*fptr)(struct module_env* env, int id)) #ifdef WITH_PYTHONMODULE else if(fptr == &pythonmod_get_mem) return 1; #endif +#ifdef WITH_DYNLIBMODULE + else if(fptr == &dynlibmod_get_mem) return 1; +#endif #ifdef USE_CACHEDB else if(fptr == &cachedb_get_mem) return 1; #endif