125039b37SCy Schubert /**
225039b37SCy Schubert  * \file
325039b37SCy Schubert  * This file contains the dynamic library module for Unbound.
425039b37SCy Schubert  * This loads a dynamic library (.dll, .so) and calls that for the
525039b37SCy Schubert  * module actions.
625039b37SCy Schubert  */
725039b37SCy Schubert #include "config.h"
8f44e67d1SCy Schubert #include "dynlibmod/dynlibmod.h"
925039b37SCy Schubert #include "util/module.h"
1025039b37SCy Schubert #include "util/config_file.h"
1125039b37SCy Schubert 
1225039b37SCy Schubert #if HAVE_WINDOWS_H
1325039b37SCy Schubert #include <windows.h>
1425039b37SCy Schubert #define __DYNMOD HMODULE
1525039b37SCy Schubert #define __DYNSYM FARPROC
1625039b37SCy Schubert #define __LOADSYM GetProcAddress
log_dlerror()17f44e67d1SCy Schubert static void log_dlerror() {
1825039b37SCy Schubert     DWORD dwLastError = GetLastError();
1925039b37SCy Schubert     LPSTR MessageBuffer;
2025039b37SCy Schubert     DWORD dwBufferLength;
2125039b37SCy Schubert     DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
2225039b37SCy Schubert         FORMAT_MESSAGE_IGNORE_INSERTS |
2325039b37SCy Schubert         FORMAT_MESSAGE_FROM_SYSTEM ;
2425039b37SCy Schubert     if((dwBufferLength = FormatMessageA(
2525039b37SCy Schubert         dwFormatFlags,
2625039b37SCy Schubert         NULL, // module to get message from (NULL == system)
2725039b37SCy Schubert         dwLastError,
2825039b37SCy Schubert         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
2925039b37SCy Schubert         (LPSTR) &MessageBuffer,
3025039b37SCy Schubert         0,
3125039b37SCy Schubert         NULL
3225039b37SCy Schubert         )))
3325039b37SCy Schubert     {
3425039b37SCy Schubert         log_err("dynlibmod: %s (%ld)", MessageBuffer, dwLastError);
3525039b37SCy Schubert         LocalFree(MessageBuffer);
3625039b37SCy Schubert     }
3725039b37SCy Schubert 
3825039b37SCy Schubert }
3925039b37SCy Schubert 
open_library(const char * fname)40f44e67d1SCy Schubert static HMODULE open_library(const char* fname) {
4125039b37SCy Schubert     return LoadLibrary(fname);
4225039b37SCy Schubert }
4325039b37SCy Schubert 
close_library(const char * fname,__DYNMOD handle)44f44e67d1SCy Schubert static void close_library(const char* fname, __DYNMOD handle) {
4525039b37SCy Schubert 	(void)fname;
4625039b37SCy Schubert 	(void)handle;
4725039b37SCy Schubert }
4825039b37SCy Schubert #else
4925039b37SCy Schubert #include <dlfcn.h>
5025039b37SCy Schubert #define __DYNMOD void*
5125039b37SCy Schubert #define __DYNSYM void*
5225039b37SCy Schubert #define __LOADSYM dlsym
log_dlerror()53f44e67d1SCy Schubert static void log_dlerror() {
5425039b37SCy Schubert     log_err("dynlibmod: %s", dlerror());
5525039b37SCy Schubert }
5625039b37SCy Schubert 
open_library(const char * fname)57f44e67d1SCy Schubert static void* open_library(const char* fname) {
5825039b37SCy Schubert     return dlopen(fname, RTLD_LAZY | RTLD_GLOBAL);
5925039b37SCy Schubert }
6025039b37SCy Schubert 
close_library(const char * fname,__DYNMOD handle)61f44e67d1SCy Schubert static void close_library(const char* fname, __DYNMOD handle) {
6225039b37SCy Schubert 	if(!handle) return;
6325039b37SCy Schubert 	if(dlclose(handle) != 0) {
6425039b37SCy Schubert 		log_err("dlclose %s: %s", fname, strerror(errno));
6525039b37SCy Schubert 	}
6625039b37SCy Schubert }
6725039b37SCy Schubert #endif
6825039b37SCy Schubert 
6925039b37SCy Schubert /** module counter for multiple dynlib modules */
7025039b37SCy Schubert static int dynlib_mod_count = 0;
7125039b37SCy Schubert 
7225039b37SCy Schubert /** dynlib module init */
dynlibmod_init(struct module_env * env,int id)7325039b37SCy Schubert int dynlibmod_init(struct module_env* env, int id) {
7425039b37SCy Schubert     int dynlib_mod_idx = dynlib_mod_count++;
7525039b37SCy Schubert     struct config_strlist* cfg_item = env->cfg->dynlib_file;
7625039b37SCy Schubert     struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
7725039b37SCy Schubert     __DYNMOD dynamic_library;
78*103ba509SCy Schubert     int i;
7925039b37SCy Schubert     if (!de)
8025039b37SCy Schubert     {
8125039b37SCy Schubert         log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx);
8225039b37SCy Schubert         return 0;
8325039b37SCy Schubert     }
8425039b37SCy Schubert 
8525039b37SCy Schubert     env->modinfo[id] = (void*) de;
8625039b37SCy Schubert 
8725039b37SCy Schubert     de->fname = NULL;
88*103ba509SCy Schubert     for(i = dynlib_mod_idx;
8925039b37SCy Schubert         i != 0 && cfg_item != NULL;
9025039b37SCy Schubert         i--, cfg_item = cfg_item->next) {}
9125039b37SCy Schubert 
9225039b37SCy Schubert     if (cfg_item == NULL || cfg_item->str == NULL || cfg_item->str[0] == 0) {
9325039b37SCy Schubert         log_err("dynlibmod[%d]: no dynamic library given.", dynlib_mod_idx);
9425039b37SCy Schubert         return 0;
9525039b37SCy Schubert     } else {
9625039b37SCy Schubert         de->fname = cfg_item->str;
9725039b37SCy Schubert     }
9825039b37SCy Schubert     verbose(VERB_ALGO, "dynlibmod[%d]: Trying to load library %s", dynlib_mod_idx, de->fname);
9925039b37SCy Schubert     dynamic_library = open_library(de->fname);
10025039b37SCy Schubert     de->dynamic_library = (void*)dynamic_library;
10125039b37SCy Schubert     if (dynamic_library == NULL) {
10225039b37SCy Schubert         log_dlerror();
10325039b37SCy Schubert         log_err("dynlibmod[%d]: unable to load dynamic library \"%s\".", dynlib_mod_idx, de->fname);
10425039b37SCy Schubert         return 0;
10525039b37SCy Schubert     } else {
10625039b37SCy Schubert 	__DYNSYM initializer;
10725039b37SCy Schubert 	__DYNSYM deinitializer;
10825039b37SCy Schubert 	__DYNSYM operate;
10925039b37SCy Schubert 	__DYNSYM inform;
11025039b37SCy Schubert 	__DYNSYM clear;
11125039b37SCy Schubert 	__DYNSYM get_mem;
11225039b37SCy Schubert         initializer = __LOADSYM(dynamic_library,"init");
11325039b37SCy Schubert         if (initializer == NULL) {
11425039b37SCy Schubert             log_dlerror();
11525039b37SCy Schubert             log_err("dynlibmod[%d]: unable to load init procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
11625039b37SCy Schubert             return 0;
11725039b37SCy Schubert         } else {
11825039b37SCy Schubert             de->func_init = (func_init_t)(void*)initializer;
11925039b37SCy Schubert         }
12025039b37SCy Schubert         deinitializer = __LOADSYM(dynamic_library,"deinit");
12125039b37SCy Schubert         if (deinitializer == NULL) {
12225039b37SCy Schubert             log_dlerror();
12325039b37SCy Schubert             log_err("dynlibmod[%d]: unable to load deinit procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
12425039b37SCy Schubert             return 0;
12525039b37SCy Schubert         } else {
12625039b37SCy Schubert             de->func_deinit = (func_deinit_t)(void*)deinitializer;
12725039b37SCy Schubert         }
12825039b37SCy Schubert         operate = __LOADSYM(dynamic_library,"operate");
12925039b37SCy Schubert         if (operate == NULL) {
13025039b37SCy Schubert             log_dlerror();
13125039b37SCy Schubert             log_err("dynlibmod[%d]: unable to load operate procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
13225039b37SCy Schubert             return 0;
13325039b37SCy Schubert         } else {
13425039b37SCy Schubert             de->func_operate = (func_operate_t)(void*)operate;
13525039b37SCy Schubert         }
13625039b37SCy Schubert         inform = __LOADSYM(dynamic_library,"inform_super");
13725039b37SCy Schubert         if (inform == NULL) {
13825039b37SCy Schubert             log_dlerror();
13925039b37SCy Schubert             log_err("dynlibmod[%d]: unable to load inform_super procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
14025039b37SCy Schubert             return 0;
14125039b37SCy Schubert         } else {
14225039b37SCy Schubert             de->func_inform = (func_inform_t)(void*)inform;
14325039b37SCy Schubert         }
14425039b37SCy Schubert         clear = __LOADSYM(dynamic_library,"clear");
14525039b37SCy Schubert         if (clear == NULL) {
14625039b37SCy Schubert             log_dlerror();
14725039b37SCy Schubert             log_err("dynlibmod[%d]: unable to load clear procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
14825039b37SCy Schubert             return 0;
14925039b37SCy Schubert         } else {
15025039b37SCy Schubert             de->func_clear = (func_clear_t)(void*)clear;
15125039b37SCy Schubert         }
15225039b37SCy Schubert         get_mem = __LOADSYM(dynamic_library,"get_mem");
15325039b37SCy Schubert         if (get_mem == NULL) {
15425039b37SCy Schubert             log_dlerror();
15525039b37SCy Schubert             log_err("dynlibmod[%d]: unable to load get_mem procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
15625039b37SCy Schubert             return 0;
15725039b37SCy Schubert         } else {
15825039b37SCy Schubert             de->func_get_mem = (func_get_mem_t)(void*)get_mem;
15925039b37SCy Schubert         }
16025039b37SCy Schubert     }
16125039b37SCy Schubert     de->inplace_cb_delete_wrapped = &inplace_cb_delete_wrapped;
16225039b37SCy Schubert     de->inplace_cb_register_wrapped = &inplace_cb_register_wrapped;
16325039b37SCy Schubert     return de->func_init(env, id);
16425039b37SCy Schubert }
16525039b37SCy Schubert 
16625039b37SCy Schubert /** dynlib module deinit */
dynlibmod_deinit(struct module_env * env,int id)16725039b37SCy Schubert void dynlibmod_deinit(struct module_env* env, int id) {
16825039b37SCy Schubert     struct dynlibmod_env* de = env->modinfo[id];
16925039b37SCy Schubert     if(de == NULL)
17025039b37SCy Schubert         return;
17125039b37SCy Schubert     de->func_deinit(env, id);
17225039b37SCy Schubert     close_library(de->fname, (__DYNMOD)de->dynamic_library);
17325039b37SCy Schubert     dynlib_mod_count--;
17425039b37SCy Schubert     de->fname = NULL;
17525039b37SCy Schubert     free(de);
17625039b37SCy Schubert }
17725039b37SCy Schubert 
17825039b37SCy Schubert /** dynlib module operate on a query */
dynlibmod_operate(struct module_qstate * qstate,enum module_ev event,int id,struct outbound_entry * outbound)17925039b37SCy Schubert void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event,
18025039b37SCy Schubert     int id, struct outbound_entry* outbound) {
18125039b37SCy Schubert     struct dynlibmod_env* de = qstate->env->modinfo[id];
18225039b37SCy Schubert 
18325039b37SCy Schubert     de->func_operate(qstate, event, id, outbound);
18425039b37SCy Schubert }
18525039b37SCy Schubert 
18625039b37SCy Schubert /** dynlib module  */
dynlibmod_inform_super(struct module_qstate * qstate,int id,struct module_qstate * super)18725039b37SCy Schubert void dynlibmod_inform_super(struct module_qstate* qstate, int id,
18825039b37SCy Schubert     struct module_qstate* super) {
18925039b37SCy Schubert     struct dynlibmod_env* de = qstate->env->modinfo[id];
19025039b37SCy Schubert 
19125039b37SCy Schubert     de->func_inform(qstate, id, super);
19225039b37SCy Schubert }
19325039b37SCy Schubert 
19425039b37SCy Schubert /** dynlib module cleanup query state */
dynlibmod_clear(struct module_qstate * qstate,int id)19525039b37SCy Schubert void dynlibmod_clear(struct module_qstate* qstate, int id) {
19625039b37SCy Schubert     struct dynlibmod_env* de = qstate->env->modinfo[id];
19725039b37SCy Schubert 
19825039b37SCy Schubert     de->func_clear(qstate, id);
19925039b37SCy Schubert }
20025039b37SCy Schubert 
20125039b37SCy Schubert /** dynlib module alloc size routine */
dynlibmod_get_mem(struct module_env * env,int id)20225039b37SCy Schubert size_t dynlibmod_get_mem(struct module_env* env, int id) {
20325039b37SCy Schubert     struct dynlibmod_env* de = (struct dynlibmod_env*)env->modinfo[id];
20425039b37SCy Schubert     size_t size;
20525039b37SCy Schubert     verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de);
20625039b37SCy Schubert     if(!de)
20725039b37SCy Schubert         return 0;
20825039b37SCy Schubert 
20925039b37SCy Schubert     size = de->func_get_mem(env, id);
21025039b37SCy Schubert     return size + sizeof(*de);
21125039b37SCy Schubert }
21225039b37SCy Schubert 
dynlib_inplace_cb_reply_generic(struct query_info * qinfo,struct module_qstate * qstate,struct reply_info * rep,int rcode,struct edns_data * edns,struct edns_option ** opt_list_out,struct comm_reply * repinfo,struct regional * region,struct timeval * start_time,int id,void * callback)21325039b37SCy Schubert int dynlib_inplace_cb_reply_generic(struct query_info* qinfo,
21425039b37SCy Schubert     struct module_qstate* qstate, struct reply_info* rep, int rcode,
21525039b37SCy Schubert     struct edns_data* edns, struct edns_option** opt_list_out,
216f44e67d1SCy Schubert     struct comm_reply* repinfo, struct regional* region,
217f44e67d1SCy Schubert     struct timeval* start_time, int id, void* callback) {
21825039b37SCy Schubert     struct cb_pair* cb_pair = (struct cb_pair*) callback;
219f44e67d1SCy Schubert     return ((inplace_cb_reply_func_type*) cb_pair->cb)(qinfo, qstate, rep, rcode, edns, opt_list_out, repinfo, region, start_time, id, cb_pair->cb_arg);
22025039b37SCy Schubert }
22125039b37SCy Schubert 
dynlib_inplace_cb_query_generic(struct query_info * qinfo,uint16_t flags,struct module_qstate * qstate,struct sockaddr_storage * addr,socklen_t addrlen,uint8_t * zone,size_t zonelen,struct regional * region,int id,void * callback)22225039b37SCy Schubert int dynlib_inplace_cb_query_generic(struct query_info* qinfo, uint16_t flags,
22325039b37SCy Schubert     struct module_qstate* qstate, struct sockaddr_storage* addr,
22425039b37SCy Schubert     socklen_t addrlen, uint8_t* zone, size_t zonelen, struct regional* region,
22525039b37SCy Schubert     int id, void* callback) {
22625039b37SCy Schubert     struct cb_pair* cb_pair = (struct cb_pair*) callback;
22725039b37SCy Schubert     return ((inplace_cb_query_func_type*) cb_pair->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region, id, cb_pair->cb_arg);
22825039b37SCy Schubert }
22925039b37SCy Schubert 
dynlib_inplace_cb_edns_back_parsed(struct module_qstate * qstate,int id,void * cb_args)23025039b37SCy Schubert int dynlib_inplace_cb_edns_back_parsed(struct module_qstate* qstate,
23125039b37SCy Schubert     int id, void* cb_args) {
23225039b37SCy Schubert     struct cb_pair* cb_pair = (struct cb_pair*) cb_args;
23325039b37SCy Schubert     return ((inplace_cb_edns_back_parsed_func_type*) cb_pair->cb)(qstate, id, cb_pair->cb_arg);
23425039b37SCy Schubert }
23525039b37SCy Schubert 
dynlib_inplace_cb_query_response(struct module_qstate * qstate,struct dns_msg * response,int id,void * cb_args)23625039b37SCy Schubert int dynlib_inplace_cb_query_response(struct module_qstate* qstate,
23725039b37SCy Schubert     struct dns_msg* response, int id, void* cb_args) {
23825039b37SCy Schubert     struct cb_pair* cb_pair = (struct cb_pair*) cb_args;
23925039b37SCy Schubert     return ((inplace_cb_query_response_func_type*) cb_pair->cb)(qstate, response, id, cb_pair->cb_arg);
24025039b37SCy Schubert }
24125039b37SCy Schubert 
24225039b37SCy Schubert int
inplace_cb_register_wrapped(void * cb,enum inplace_cb_list_type type,void * cbarg,struct module_env * env,int id)24325039b37SCy Schubert inplace_cb_register_wrapped(void* cb, enum inplace_cb_list_type type, void* cbarg,
24425039b37SCy Schubert     struct module_env* env, int id) {
24525039b37SCy Schubert     struct cb_pair* cb_pair = malloc(sizeof(struct cb_pair));
246c0caa2e2SCy Schubert     if(cb_pair == NULL) {
247c0caa2e2SCy Schubert 	log_err("dynlibmod[%d]: malloc failure", id);
248c0caa2e2SCy Schubert         return 0;
249c0caa2e2SCy Schubert     }
25025039b37SCy Schubert     cb_pair->cb = cb;
25125039b37SCy Schubert     cb_pair->cb_arg = cbarg;
25225039b37SCy Schubert     if(type >= inplace_cb_reply && type <= inplace_cb_reply_servfail) {
25325039b37SCy Schubert         return inplace_cb_register(&dynlib_inplace_cb_reply_generic, type, (void*) cb_pair, env, id);
25425039b37SCy Schubert     } else if(type == inplace_cb_query) {
25525039b37SCy Schubert         return inplace_cb_register(&dynlib_inplace_cb_query_generic, type, (void*) cb_pair, env, id);
25625039b37SCy Schubert     } else if(type == inplace_cb_query_response) {
25725039b37SCy Schubert         return inplace_cb_register(&dynlib_inplace_cb_query_response, type, (void*) cb_pair, env, id);
25825039b37SCy Schubert     } else if(type == inplace_cb_edns_back_parsed) {
25925039b37SCy Schubert         return inplace_cb_register(&dynlib_inplace_cb_edns_back_parsed, type, (void*) cb_pair, env, id);
26025039b37SCy Schubert     } else {
261c0caa2e2SCy Schubert         free(cb_pair);
26225039b37SCy Schubert         return 0;
26325039b37SCy Schubert     }
26425039b37SCy Schubert }
26525039b37SCy Schubert 
26625039b37SCy Schubert void
inplace_cb_delete_wrapped(struct module_env * env,enum inplace_cb_list_type type,int id)26725039b37SCy Schubert inplace_cb_delete_wrapped(struct module_env* env, enum inplace_cb_list_type type,
26825039b37SCy Schubert     int id) {
26925039b37SCy Schubert     struct inplace_cb* temp = env->inplace_cb_lists[type];
27025039b37SCy Schubert     struct inplace_cb* prev = NULL;
27125039b37SCy Schubert 
27225039b37SCy Schubert     while(temp) {
27325039b37SCy Schubert         if(temp->id == id) {
27425039b37SCy Schubert             if(!prev) {
27525039b37SCy Schubert                 env->inplace_cb_lists[type] = temp->next;
27625039b37SCy Schubert                 free(temp->cb_arg);
27725039b37SCy Schubert                 free(temp);
27825039b37SCy Schubert                 temp = env->inplace_cb_lists[type];
27925039b37SCy Schubert             }
28025039b37SCy Schubert             else {
28125039b37SCy Schubert                 prev->next = temp->next;
28225039b37SCy Schubert                 free(temp->cb_arg);
28325039b37SCy Schubert                 free(temp);
28425039b37SCy Schubert                 temp = prev->next;
28525039b37SCy Schubert             }
28625039b37SCy Schubert         }
28725039b37SCy Schubert         else {
28825039b37SCy Schubert             prev = temp;
28925039b37SCy Schubert             temp = temp->next;
29025039b37SCy Schubert         }
29125039b37SCy Schubert     }
29225039b37SCy Schubert }
29325039b37SCy Schubert 
29425039b37SCy Schubert 
29525039b37SCy Schubert /**
29625039b37SCy Schubert  * The module function block
29725039b37SCy Schubert  */
29825039b37SCy Schubert static struct module_func_block dynlibmod_block = {
29925039b37SCy Schubert    "dynlib",
30025039b37SCy Schubert    &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate, &dynlibmod_inform_super,
30125039b37SCy Schubert    &dynlibmod_clear, &dynlibmod_get_mem
30225039b37SCy Schubert };
30325039b37SCy Schubert 
dynlibmod_get_funcblock(void)30425039b37SCy Schubert struct module_func_block* dynlibmod_get_funcblock(void)
30525039b37SCy Schubert {
30625039b37SCy Schubert    return &dynlibmod_block;
30725039b37SCy Schubert }
308