1/**
2 * \file
3 * This file contains the dynamic library module for Unbound.
4 * This loads a dynamic library (.dll, .so) and calls that for the
5 * module actions.
6 */
7#include "config.h"
8#include "dynlibmod/dynlibmod.h"
9#include "util/module.h"
10#include "util/config_file.h"
11
12#if HAVE_WINDOWS_H
13#include <windows.h>
14#define __DYNMOD HMODULE
15#define __DYNSYM FARPROC
16#define __LOADSYM GetProcAddress
17static void log_dlerror() {
18    DWORD dwLastError = GetLastError();
19    LPSTR MessageBuffer;
20    DWORD dwBufferLength;
21    DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
22        FORMAT_MESSAGE_IGNORE_INSERTS |
23        FORMAT_MESSAGE_FROM_SYSTEM ;
24    if((dwBufferLength = FormatMessageA(
25        dwFormatFlags,
26        NULL, // module to get message from (NULL == system)
27        dwLastError,
28        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // default language
29        (LPSTR) &MessageBuffer,
30        0,
31        NULL
32        )))
33    {
34        log_err("dynlibmod: %s (%ld)", MessageBuffer, dwLastError);
35        LocalFree(MessageBuffer);
36    }
37
38}
39
40static HMODULE open_library(const char* fname) {
41    return LoadLibrary(fname);
42}
43
44static void close_library(const char* fname, __DYNMOD handle) {
45	(void)fname;
46	(void)handle;
47}
48#else
49#include <dlfcn.h>
50#define __DYNMOD void*
51#define __DYNSYM void*
52#define __LOADSYM dlsym
53static void log_dlerror() {
54    log_err("dynlibmod: %s", dlerror());
55}
56
57static void* open_library(const char* fname) {
58    return dlopen(fname, RTLD_LAZY | RTLD_GLOBAL);
59}
60
61static void close_library(const char* fname, __DYNMOD handle) {
62	if(!handle) return;
63	if(dlclose(handle) != 0) {
64		log_err("dlclose %s: %s", fname, strerror(errno));
65	}
66}
67#endif
68
69/** module counter for multiple dynlib modules */
70static int dynlib_mod_count = 0;
71
72/** dynlib module init */
73int dynlibmod_init(struct module_env* env, int id) {
74    int dynlib_mod_idx = dynlib_mod_count++;
75    struct config_strlist* cfg_item = env->cfg->dynlib_file;
76    struct dynlibmod_env* de = (struct dynlibmod_env*)calloc(1, sizeof(struct dynlibmod_env));
77    __DYNMOD dynamic_library;
78    if (!de)
79    {
80        log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx);
81        return 0;
82    }
83
84    env->modinfo[id] = (void*) de;
85
86    de->fname = NULL;
87    for(int i = dynlib_mod_idx;
88        i != 0 && cfg_item != NULL;
89        i--, cfg_item = cfg_item->next) {}
90
91    if (cfg_item == NULL || cfg_item->str == NULL || cfg_item->str[0] == 0) {
92        log_err("dynlibmod[%d]: no dynamic library given.", dynlib_mod_idx);
93        return 0;
94    } else {
95        de->fname = cfg_item->str;
96    }
97    verbose(VERB_ALGO, "dynlibmod[%d]: Trying to load library %s", dynlib_mod_idx, de->fname);
98    dynamic_library = open_library(de->fname);
99    de->dynamic_library = (void*)dynamic_library;
100    if (dynamic_library == NULL) {
101        log_dlerror();
102        log_err("dynlibmod[%d]: unable to load dynamic library \"%s\".", dynlib_mod_idx, de->fname);
103        return 0;
104    } else {
105	__DYNSYM initializer;
106	__DYNSYM deinitializer;
107	__DYNSYM operate;
108	__DYNSYM inform;
109	__DYNSYM clear;
110	__DYNSYM get_mem;
111        initializer = __LOADSYM(dynamic_library,"init");
112        if (initializer == NULL) {
113            log_dlerror();
114            log_err("dynlibmod[%d]: unable to load init procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
115            return 0;
116        } else {
117            de->func_init = (func_init_t)(void*)initializer;
118        }
119        deinitializer = __LOADSYM(dynamic_library,"deinit");
120        if (deinitializer == NULL) {
121            log_dlerror();
122            log_err("dynlibmod[%d]: unable to load deinit procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
123            return 0;
124        } else {
125            de->func_deinit = (func_deinit_t)(void*)deinitializer;
126        }
127        operate = __LOADSYM(dynamic_library,"operate");
128        if (operate == NULL) {
129            log_dlerror();
130            log_err("dynlibmod[%d]: unable to load operate procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
131            return 0;
132        } else {
133            de->func_operate = (func_operate_t)(void*)operate;
134        }
135        inform = __LOADSYM(dynamic_library,"inform_super");
136        if (inform == NULL) {
137            log_dlerror();
138            log_err("dynlibmod[%d]: unable to load inform_super procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
139            return 0;
140        } else {
141            de->func_inform = (func_inform_t)(void*)inform;
142        }
143        clear = __LOADSYM(dynamic_library,"clear");
144        if (clear == NULL) {
145            log_dlerror();
146            log_err("dynlibmod[%d]: unable to load clear procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
147            return 0;
148        } else {
149            de->func_clear = (func_clear_t)(void*)clear;
150        }
151        get_mem = __LOADSYM(dynamic_library,"get_mem");
152        if (get_mem == NULL) {
153            log_dlerror();
154            log_err("dynlibmod[%d]: unable to load get_mem procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
155            return 0;
156        } else {
157            de->func_get_mem = (func_get_mem_t)(void*)get_mem;
158        }
159    }
160    de->inplace_cb_delete_wrapped = &inplace_cb_delete_wrapped;
161    de->inplace_cb_register_wrapped = &inplace_cb_register_wrapped;
162    return de->func_init(env, id);
163}
164
165/** dynlib module deinit */
166void dynlibmod_deinit(struct module_env* env, int id) {
167    struct dynlibmod_env* de = env->modinfo[id];
168    if(de == NULL)
169        return;
170    de->func_deinit(env, id);
171    close_library(de->fname, (__DYNMOD)de->dynamic_library);
172    dynlib_mod_count--;
173    de->fname = NULL;
174    free(de);
175}
176
177/** dynlib module operate on a query */
178void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event,
179    int id, struct outbound_entry* outbound) {
180    struct dynlibmod_env* de = qstate->env->modinfo[id];
181
182    de->func_operate(qstate, event, id, outbound);
183}
184
185/** dynlib module  */
186void dynlibmod_inform_super(struct module_qstate* qstate, int id,
187    struct module_qstate* super) {
188    struct dynlibmod_env* de = qstate->env->modinfo[id];
189
190    de->func_inform(qstate, id, super);
191}
192
193/** dynlib module cleanup query state */
194void dynlibmod_clear(struct module_qstate* qstate, int id) {
195    struct dynlibmod_env* de = qstate->env->modinfo[id];
196
197    de->func_clear(qstate, id);
198}
199
200/** dynlib module alloc size routine */
201size_t dynlibmod_get_mem(struct module_env* env, int id) {
202    struct dynlibmod_env* de = (struct dynlibmod_env*)env->modinfo[id];
203    size_t size;
204    verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de);
205    if(!de)
206        return 0;
207
208    size = de->func_get_mem(env, id);
209    return size + sizeof(*de);
210}
211
212int dynlib_inplace_cb_reply_generic(struct query_info* qinfo,
213    struct module_qstate* qstate, struct reply_info* rep, int rcode,
214    struct edns_data* edns, struct edns_option** opt_list_out,
215    struct comm_reply* repinfo, struct regional* region,
216    struct timeval* start_time, int id, void* callback) {
217    struct cb_pair* cb_pair = (struct cb_pair*) callback;
218    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);
219}
220
221int dynlib_inplace_cb_query_generic(struct query_info* qinfo, uint16_t flags,
222    struct module_qstate* qstate, struct sockaddr_storage* addr,
223    socklen_t addrlen, uint8_t* zone, size_t zonelen, struct regional* region,
224    int id, void* callback) {
225    struct cb_pair* cb_pair = (struct cb_pair*) callback;
226    return ((inplace_cb_query_func_type*) cb_pair->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region, id, cb_pair->cb_arg);
227}
228
229int dynlib_inplace_cb_edns_back_parsed(struct module_qstate* qstate,
230    int id, void* cb_args) {
231    struct cb_pair* cb_pair = (struct cb_pair*) cb_args;
232    return ((inplace_cb_edns_back_parsed_func_type*) cb_pair->cb)(qstate, id, cb_pair->cb_arg);
233}
234
235int dynlib_inplace_cb_query_response(struct module_qstate* qstate,
236    struct dns_msg* response, int id, void* cb_args) {
237    struct cb_pair* cb_pair = (struct cb_pair*) cb_args;
238    return ((inplace_cb_query_response_func_type*) cb_pair->cb)(qstate, response, id, cb_pair->cb_arg);
239}
240
241int
242inplace_cb_register_wrapped(void* cb, enum inplace_cb_list_type type, void* cbarg,
243    struct module_env* env, int id) {
244    struct cb_pair* cb_pair = malloc(sizeof(struct cb_pair));
245    if(cb_pair == NULL) {
246	log_err("dynlibmod[%d]: malloc failure", id);
247        return 0;
248    }
249    cb_pair->cb = cb;
250    cb_pair->cb_arg = cbarg;
251    if(type >= inplace_cb_reply && type <= inplace_cb_reply_servfail) {
252        return inplace_cb_register(&dynlib_inplace_cb_reply_generic, type, (void*) cb_pair, env, id);
253    } else if(type == inplace_cb_query) {
254        return inplace_cb_register(&dynlib_inplace_cb_query_generic, type, (void*) cb_pair, env, id);
255    } else if(type == inplace_cb_query_response) {
256        return inplace_cb_register(&dynlib_inplace_cb_query_response, type, (void*) cb_pair, env, id);
257    } else if(type == inplace_cb_edns_back_parsed) {
258        return inplace_cb_register(&dynlib_inplace_cb_edns_back_parsed, type, (void*) cb_pair, env, id);
259    } else {
260        free(cb_pair);
261        return 0;
262    }
263}
264
265void
266inplace_cb_delete_wrapped(struct module_env* env, enum inplace_cb_list_type type,
267    int id) {
268    struct inplace_cb* temp = env->inplace_cb_lists[type];
269    struct inplace_cb* prev = NULL;
270
271    while(temp) {
272        if(temp->id == id) {
273            if(!prev) {
274                env->inplace_cb_lists[type] = temp->next;
275                free(temp->cb_arg);
276                free(temp);
277                temp = env->inplace_cb_lists[type];
278            }
279            else {
280                prev->next = temp->next;
281                free(temp->cb_arg);
282                free(temp);
283                temp = prev->next;
284            }
285        }
286        else {
287            prev = temp;
288            temp = temp->next;
289        }
290    }
291}
292
293
294/**
295 * The module function block
296 */
297static struct module_func_block dynlibmod_block = {
298   "dynlib",
299   &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate, &dynlibmod_inform_super,
300   &dynlibmod_clear, &dynlibmod_get_mem
301};
302
303struct module_func_block* dynlibmod_get_funcblock(void)
304{
305   return &dynlibmod_block;
306}
307