xref: /freebsd/contrib/unbound/dynlibmod/dynlibmod.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
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
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 
40 static HMODULE open_library(const char* fname) {
41     return LoadLibrary(fname);
42 }
43 
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
53 static void log_dlerror() {
54     log_err("dynlibmod: %s", dlerror());
55 }
56 
57 static void* open_library(const char* fname) {
58     return dlopen(fname, RTLD_LAZY | RTLD_GLOBAL);
59 }
60 
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 */
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     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 */
166 void 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 */
178 void 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  */
186 void 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 */
194 void 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 */
201 size_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 
212 int 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 
221 int 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 
229 int 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 
235 int 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 
241 int
242 inplace_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 
265 void
266 inplace_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  */
297 static 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 
303 struct module_func_block* dynlibmod_get_funcblock(void)
304 {
305    return &dynlibmod_block;
306 }
307