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
log_dlerror()17 static 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
open_library(const char * fname)40 static HMODULE open_library(const char* fname) {
41 return LoadLibrary(fname);
42 }
43
close_library(const char * fname,__DYNMOD handle)44 static 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
log_dlerror()53 static void log_dlerror() {
54 log_err("dynlibmod: %s", dlerror());
55 }
56
open_library(const char * fname)57 static void* open_library(const char* fname) {
58 return dlopen(fname, RTLD_LAZY | RTLD_GLOBAL);
59 }
60
close_library(const char * fname,__DYNMOD handle)61 static 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 */
70 static int dynlib_mod_count = 0;
71
72 /** dynlib module init */
dynlibmod_init(struct module_env * env,int id)73 int 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 int i;
79 if (!de)
80 {
81 log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx);
82 return 0;
83 }
84
85 env->modinfo[id] = (void*) de;
86
87 de->fname = NULL;
88 for(i = dynlib_mod_idx;
89 i != 0 && cfg_item != NULL;
90 i--, cfg_item = cfg_item->next) {}
91
92 if (cfg_item == NULL || cfg_item->str == NULL || cfg_item->str[0] == 0) {
93 log_err("dynlibmod[%d]: no dynamic library given.", dynlib_mod_idx);
94 return 0;
95 } else {
96 de->fname = cfg_item->str;
97 }
98 verbose(VERB_ALGO, "dynlibmod[%d]: Trying to load library %s", dynlib_mod_idx, de->fname);
99 dynamic_library = open_library(de->fname);
100 de->dynamic_library = (void*)dynamic_library;
101 if (dynamic_library == NULL) {
102 log_dlerror();
103 log_err("dynlibmod[%d]: unable to load dynamic library \"%s\".", dynlib_mod_idx, de->fname);
104 return 0;
105 } else {
106 __DYNSYM initializer;
107 __DYNSYM deinitializer;
108 __DYNSYM operate;
109 __DYNSYM inform;
110 __DYNSYM clear;
111 __DYNSYM get_mem;
112 initializer = __LOADSYM(dynamic_library,"init");
113 if (initializer == NULL) {
114 log_dlerror();
115 log_err("dynlibmod[%d]: unable to load init procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
116 return 0;
117 } else {
118 de->func_init = (func_init_t)(void*)initializer;
119 }
120 deinitializer = __LOADSYM(dynamic_library,"deinit");
121 if (deinitializer == NULL) {
122 log_dlerror();
123 log_err("dynlibmod[%d]: unable to load deinit procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
124 return 0;
125 } else {
126 de->func_deinit = (func_deinit_t)(void*)deinitializer;
127 }
128 operate = __LOADSYM(dynamic_library,"operate");
129 if (operate == NULL) {
130 log_dlerror();
131 log_err("dynlibmod[%d]: unable to load operate procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
132 return 0;
133 } else {
134 de->func_operate = (func_operate_t)(void*)operate;
135 }
136 inform = __LOADSYM(dynamic_library,"inform_super");
137 if (inform == NULL) {
138 log_dlerror();
139 log_err("dynlibmod[%d]: unable to load inform_super procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
140 return 0;
141 } else {
142 de->func_inform = (func_inform_t)(void*)inform;
143 }
144 clear = __LOADSYM(dynamic_library,"clear");
145 if (clear == NULL) {
146 log_dlerror();
147 log_err("dynlibmod[%d]: unable to load clear procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
148 return 0;
149 } else {
150 de->func_clear = (func_clear_t)(void*)clear;
151 }
152 get_mem = __LOADSYM(dynamic_library,"get_mem");
153 if (get_mem == NULL) {
154 log_dlerror();
155 log_err("dynlibmod[%d]: unable to load get_mem procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname);
156 return 0;
157 } else {
158 de->func_get_mem = (func_get_mem_t)(void*)get_mem;
159 }
160 }
161 de->inplace_cb_delete_wrapped = &inplace_cb_delete_wrapped;
162 de->inplace_cb_register_wrapped = &inplace_cb_register_wrapped;
163 return de->func_init(env, id);
164 }
165
166 /** dynlib module deinit */
dynlibmod_deinit(struct module_env * env,int id)167 void dynlibmod_deinit(struct module_env* env, int id) {
168 struct dynlibmod_env* de = env->modinfo[id];
169 if(de == NULL)
170 return;
171 de->func_deinit(env, id);
172 close_library(de->fname, (__DYNMOD)de->dynamic_library);
173 dynlib_mod_count--;
174 de->fname = NULL;
175 free(de);
176 }
177
178 /** dynlib module operate on a query */
dynlibmod_operate(struct module_qstate * qstate,enum module_ev event,int id,struct outbound_entry * outbound)179 void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event,
180 int id, struct outbound_entry* outbound) {
181 struct dynlibmod_env* de = qstate->env->modinfo[id];
182
183 de->func_operate(qstate, event, id, outbound);
184 }
185
186 /** dynlib module */
dynlibmod_inform_super(struct module_qstate * qstate,int id,struct module_qstate * super)187 void dynlibmod_inform_super(struct module_qstate* qstate, int id,
188 struct module_qstate* super) {
189 struct dynlibmod_env* de = qstate->env->modinfo[id];
190
191 de->func_inform(qstate, id, super);
192 }
193
194 /** dynlib module cleanup query state */
dynlibmod_clear(struct module_qstate * qstate,int id)195 void dynlibmod_clear(struct module_qstate* qstate, int id) {
196 struct dynlibmod_env* de = qstate->env->modinfo[id];
197
198 de->func_clear(qstate, id);
199 }
200
201 /** dynlib module alloc size routine */
dynlibmod_get_mem(struct module_env * env,int id)202 size_t dynlibmod_get_mem(struct module_env* env, int id) {
203 struct dynlibmod_env* de = (struct dynlibmod_env*)env->modinfo[id];
204 size_t size;
205 verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de);
206 if(!de)
207 return 0;
208
209 size = de->func_get_mem(env, id);
210 return size + sizeof(*de);
211 }
212
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)213 int dynlib_inplace_cb_reply_generic(struct query_info* qinfo,
214 struct module_qstate* qstate, struct reply_info* rep, int rcode,
215 struct edns_data* edns, struct edns_option** opt_list_out,
216 struct comm_reply* repinfo, struct regional* region,
217 struct timeval* start_time, int id, void* callback) {
218 struct cb_pair* cb_pair = (struct cb_pair*) callback;
219 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);
220 }
221
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)222 int dynlib_inplace_cb_query_generic(struct query_info* qinfo, uint16_t flags,
223 struct module_qstate* qstate, struct sockaddr_storage* addr,
224 socklen_t addrlen, uint8_t* zone, size_t zonelen, struct regional* region,
225 int id, void* callback) {
226 struct cb_pair* cb_pair = (struct cb_pair*) callback;
227 return ((inplace_cb_query_func_type*) cb_pair->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region, id, cb_pair->cb_arg);
228 }
229
dynlib_inplace_cb_edns_back_parsed(struct module_qstate * qstate,int id,void * cb_args)230 int dynlib_inplace_cb_edns_back_parsed(struct module_qstate* qstate,
231 int id, void* cb_args) {
232 struct cb_pair* cb_pair = (struct cb_pair*) cb_args;
233 return ((inplace_cb_edns_back_parsed_func_type*) cb_pair->cb)(qstate, id, cb_pair->cb_arg);
234 }
235
dynlib_inplace_cb_query_response(struct module_qstate * qstate,struct dns_msg * response,int id,void * cb_args)236 int dynlib_inplace_cb_query_response(struct module_qstate* qstate,
237 struct dns_msg* response, int id, void* cb_args) {
238 struct cb_pair* cb_pair = (struct cb_pair*) cb_args;
239 return ((inplace_cb_query_response_func_type*) cb_pair->cb)(qstate, response, id, cb_pair->cb_arg);
240 }
241
242 int
inplace_cb_register_wrapped(void * cb,enum inplace_cb_list_type type,void * cbarg,struct module_env * env,int id)243 inplace_cb_register_wrapped(void* cb, enum inplace_cb_list_type type, void* cbarg,
244 struct module_env* env, int id) {
245 struct cb_pair* cb_pair = malloc(sizeof(struct cb_pair));
246 if(cb_pair == NULL) {
247 log_err("dynlibmod[%d]: malloc failure", id);
248 return 0;
249 }
250 cb_pair->cb = cb;
251 cb_pair->cb_arg = cbarg;
252 if(type >= inplace_cb_reply && type <= inplace_cb_reply_servfail) {
253 return inplace_cb_register(&dynlib_inplace_cb_reply_generic, type, (void*) cb_pair, env, id);
254 } else if(type == inplace_cb_query) {
255 return inplace_cb_register(&dynlib_inplace_cb_query_generic, type, (void*) cb_pair, env, id);
256 } else if(type == inplace_cb_query_response) {
257 return inplace_cb_register(&dynlib_inplace_cb_query_response, type, (void*) cb_pair, env, id);
258 } else if(type == inplace_cb_edns_back_parsed) {
259 return inplace_cb_register(&dynlib_inplace_cb_edns_back_parsed, type, (void*) cb_pair, env, id);
260 } else {
261 free(cb_pair);
262 return 0;
263 }
264 }
265
266 void
inplace_cb_delete_wrapped(struct module_env * env,enum inplace_cb_list_type type,int id)267 inplace_cb_delete_wrapped(struct module_env* env, enum inplace_cb_list_type type,
268 int id) {
269 struct inplace_cb* temp = env->inplace_cb_lists[type];
270 struct inplace_cb* prev = NULL;
271
272 while(temp) {
273 if(temp->id == id) {
274 if(!prev) {
275 env->inplace_cb_lists[type] = temp->next;
276 free(temp->cb_arg);
277 free(temp);
278 temp = env->inplace_cb_lists[type];
279 }
280 else {
281 prev->next = temp->next;
282 free(temp->cb_arg);
283 free(temp);
284 temp = prev->next;
285 }
286 }
287 else {
288 prev = temp;
289 temp = temp->next;
290 }
291 }
292 }
293
294
295 /**
296 * The module function block
297 */
298 static struct module_func_block dynlibmod_block = {
299 "dynlib",
300 NULL, NULL, &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate,
301 &dynlibmod_inform_super, &dynlibmod_clear, &dynlibmod_get_mem
302 };
303
dynlibmod_get_funcblock(void)304 struct module_func_block* dynlibmod_get_funcblock(void)
305 {
306 return &dynlibmod_block;
307 }
308