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