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