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