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