xref: /netbsd-src/external/bsd/unbound/dist/dynlibmod/dynlibmod.c (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
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