]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
Add dynamic library support
authorPMunch <peterme@peterme.net>
Thu, 17 Oct 2019 13:10:33 +0000 (15:10 +0200)
committerPMunch <peterme@peterme.net>
Mon, 21 Oct 2019 07:34:51 +0000 (09:34 +0200)
13 files changed:
Makefile.in
config.h.in
configure
configure.ac
dynlibmod/dynlibmod.c [new file with mode: 0644]
dynlibmod/dynlibmod.h [new file with mode: 0644]
dynlibmod/examples/helloworld.c [new file with mode: 0644]
services/modstack.c
util/config_file.c
util/config_file.h
util/configlexer.lex
util/configparser.y
util/fptr_wlist.c

index d9d4fe7ad6d1c60d35157f63ee9dc48d5bff224b..21367eec334312cef0d9aa6baed92c1fe742b8a6 100644 (file)
@@ -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 \
index d8ec50a6d7669cd5a275b95f9642278e9ec967d6..a07b970bc109c89d6f915b3f856f9b27db4b86fc 100644 (file)
 /* 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
 
index 4e222879ee94c65fe8d7473f8daf3fcae970b454..41984f6527424a89c7d807c45ee5e7281c4c7828 100755 (executable)
--- 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.
index 216a78c65fa526d289657c54cb614d9947d4cf9e..7d108d002cc9c30da4b8560e6e8d6e956ccb1399 100644 (file)
@@ -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 (file)
index 0000000..47d3153
--- /dev/null
@@ -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 <windows.h>
+#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 <dlfcn.h>
+#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 (file)
index 0000000..ac5d737
--- /dev/null
@@ -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 (file)
index 0000000..76c1df2
--- /dev/null
@@ -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;
+}
index 68e5928146dd5a6d71255e55982b667f8a775bb6..a600549b16c30fc707ea1fe549b468233d09795b 100644 (file)
@@ -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
index 119b222384430ca694289b04ca08dc2af129c62f..7a8fb0bbc667de4d64458b66cb2f799acaf79f20 100644 (file)
@@ -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);
index b3ef930a0f161cd6c3727acc533ac44b74f35b86..6706ab08bacb33f80c4298c2deaef04ff53835c4 100644 (file)
@@ -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;
 
index a86ddf55d9beb5f9e9957537e3a2549e419089f9..1010dcda9c7bc3b2c9647f40d2f6014010c33231 100644 (file)
@@ -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) }
index 10227a2ff7ff674898e978e3892d389b1aa12803..5f58d75b3ac4715dac5b6a106c58a473963390ef 100644 (file)
@@ -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));
index f5da501de19be48cc09e211ff7d36619b3885caf..20eaeb13704e30d7689fa032f973c4d95321e1ef 100644 (file)
@@ -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