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 int i; 79 if (!de) 80 { 81 log_err("dynlibmod[%d]: malloc failure", dynlib_mod_idx); 82 return 0; 83 } 84 85 env->modinfo[id] = (void*) de; 86 87 de->fname = NULL; 88 for(i = dynlib_mod_idx; 89 i != 0 && cfg_item != NULL; 90 i--, cfg_item = cfg_item->next) {} 91 92 if (cfg_item == NULL || cfg_item->str == NULL || cfg_item->str[0] == 0) { 93 log_err("dynlibmod[%d]: no dynamic library given.", dynlib_mod_idx); 94 return 0; 95 } else { 96 de->fname = cfg_item->str; 97 } 98 verbose(VERB_ALGO, "dynlibmod[%d]: Trying to load library %s", dynlib_mod_idx, de->fname); 99 dynamic_library = open_library(de->fname); 100 de->dynamic_library = (void*)dynamic_library; 101 if (dynamic_library == NULL) { 102 log_dlerror(); 103 log_err("dynlibmod[%d]: unable to load dynamic library \"%s\".", dynlib_mod_idx, de->fname); 104 return 0; 105 } else { 106 __DYNSYM initializer; 107 __DYNSYM deinitializer; 108 __DYNSYM operate; 109 __DYNSYM inform; 110 __DYNSYM clear; 111 __DYNSYM get_mem; 112 initializer = __LOADSYM(dynamic_library,"init"); 113 if (initializer == NULL) { 114 log_dlerror(); 115 log_err("dynlibmod[%d]: unable to load init procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname); 116 return 0; 117 } else { 118 de->func_init = (func_init_t)(void*)initializer; 119 } 120 deinitializer = __LOADSYM(dynamic_library,"deinit"); 121 if (deinitializer == NULL) { 122 log_dlerror(); 123 log_err("dynlibmod[%d]: unable to load deinit procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname); 124 return 0; 125 } else { 126 de->func_deinit = (func_deinit_t)(void*)deinitializer; 127 } 128 operate = __LOADSYM(dynamic_library,"operate"); 129 if (operate == NULL) { 130 log_dlerror(); 131 log_err("dynlibmod[%d]: unable to load operate procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname); 132 return 0; 133 } else { 134 de->func_operate = (func_operate_t)(void*)operate; 135 } 136 inform = __LOADSYM(dynamic_library,"inform_super"); 137 if (inform == NULL) { 138 log_dlerror(); 139 log_err("dynlibmod[%d]: unable to load inform_super procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname); 140 return 0; 141 } else { 142 de->func_inform = (func_inform_t)(void*)inform; 143 } 144 clear = __LOADSYM(dynamic_library,"clear"); 145 if (clear == NULL) { 146 log_dlerror(); 147 log_err("dynlibmod[%d]: unable to load clear procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname); 148 return 0; 149 } else { 150 de->func_clear = (func_clear_t)(void*)clear; 151 } 152 get_mem = __LOADSYM(dynamic_library,"get_mem"); 153 if (get_mem == NULL) { 154 log_dlerror(); 155 log_err("dynlibmod[%d]: unable to load get_mem procedure from dynamic library \"%s\".", dynlib_mod_idx, de->fname); 156 return 0; 157 } else { 158 de->func_get_mem = (func_get_mem_t)(void*)get_mem; 159 } 160 } 161 de->inplace_cb_delete_wrapped = &inplace_cb_delete_wrapped; 162 de->inplace_cb_register_wrapped = &inplace_cb_register_wrapped; 163 return de->func_init(env, id); 164 } 165 166 /** dynlib module deinit */ 167 void dynlibmod_deinit(struct module_env* env, int id) { 168 struct dynlibmod_env* de = env->modinfo[id]; 169 if(de == NULL) 170 return; 171 de->func_deinit(env, id); 172 close_library(de->fname, (__DYNMOD)de->dynamic_library); 173 dynlib_mod_count--; 174 de->fname = NULL; 175 free(de); 176 } 177 178 /** dynlib module operate on a query */ 179 void dynlibmod_operate(struct module_qstate* qstate, enum module_ev event, 180 int id, struct outbound_entry* outbound) { 181 struct dynlibmod_env* de = qstate->env->modinfo[id]; 182 183 de->func_operate(qstate, event, id, outbound); 184 } 185 186 /** dynlib module */ 187 void dynlibmod_inform_super(struct module_qstate* qstate, int id, 188 struct module_qstate* super) { 189 struct dynlibmod_env* de = qstate->env->modinfo[id]; 190 191 de->func_inform(qstate, id, super); 192 } 193 194 /** dynlib module cleanup query state */ 195 void dynlibmod_clear(struct module_qstate* qstate, int id) { 196 struct dynlibmod_env* de = qstate->env->modinfo[id]; 197 198 de->func_clear(qstate, id); 199 } 200 201 /** dynlib module alloc size routine */ 202 size_t dynlibmod_get_mem(struct module_env* env, int id) { 203 struct dynlibmod_env* de = (struct dynlibmod_env*)env->modinfo[id]; 204 size_t size; 205 verbose(VERB_ALGO, "dynlibmod: get_mem, id: %d, de:%p", id, de); 206 if(!de) 207 return 0; 208 209 size = de->func_get_mem(env, id); 210 return size + sizeof(*de); 211 } 212 213 int dynlib_inplace_cb_reply_generic(struct query_info* qinfo, 214 struct module_qstate* qstate, struct reply_info* rep, int rcode, 215 struct edns_data* edns, struct edns_option** opt_list_out, 216 struct comm_reply* repinfo, struct regional* region, 217 struct timeval* start_time, int id, void* callback) { 218 struct cb_pair* cb_pair = (struct cb_pair*) callback; 219 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); 220 } 221 222 int dynlib_inplace_cb_query_generic(struct query_info* qinfo, uint16_t flags, 223 struct module_qstate* qstate, struct sockaddr_storage* addr, 224 socklen_t addrlen, uint8_t* zone, size_t zonelen, struct regional* region, 225 int id, void* callback) { 226 struct cb_pair* cb_pair = (struct cb_pair*) callback; 227 return ((inplace_cb_query_func_type*) cb_pair->cb)(qinfo, flags, qstate, addr, addrlen, zone, zonelen, region, id, cb_pair->cb_arg); 228 } 229 230 int dynlib_inplace_cb_edns_back_parsed(struct module_qstate* qstate, 231 int id, void* cb_args) { 232 struct cb_pair* cb_pair = (struct cb_pair*) cb_args; 233 return ((inplace_cb_edns_back_parsed_func_type*) cb_pair->cb)(qstate, id, cb_pair->cb_arg); 234 } 235 236 int dynlib_inplace_cb_query_response(struct module_qstate* qstate, 237 struct dns_msg* response, int id, void* cb_args) { 238 struct cb_pair* cb_pair = (struct cb_pair*) cb_args; 239 return ((inplace_cb_query_response_func_type*) cb_pair->cb)(qstate, response, id, cb_pair->cb_arg); 240 } 241 242 int 243 inplace_cb_register_wrapped(void* cb, enum inplace_cb_list_type type, void* cbarg, 244 struct module_env* env, int id) { 245 struct cb_pair* cb_pair = malloc(sizeof(struct cb_pair)); 246 if(cb_pair == NULL) { 247 log_err("dynlibmod[%d]: malloc failure", id); 248 return 0; 249 } 250 cb_pair->cb = cb; 251 cb_pair->cb_arg = cbarg; 252 if(type >= inplace_cb_reply && type <= inplace_cb_reply_servfail) { 253 return inplace_cb_register(&dynlib_inplace_cb_reply_generic, type, (void*) cb_pair, env, id); 254 } else if(type == inplace_cb_query) { 255 return inplace_cb_register(&dynlib_inplace_cb_query_generic, type, (void*) cb_pair, env, id); 256 } else if(type == inplace_cb_query_response) { 257 return inplace_cb_register(&dynlib_inplace_cb_query_response, type, (void*) cb_pair, env, id); 258 } else if(type == inplace_cb_edns_back_parsed) { 259 return inplace_cb_register(&dynlib_inplace_cb_edns_back_parsed, type, (void*) cb_pair, env, id); 260 } else { 261 free(cb_pair); 262 return 0; 263 } 264 } 265 266 void 267 inplace_cb_delete_wrapped(struct module_env* env, enum inplace_cb_list_type type, 268 int id) { 269 struct inplace_cb* temp = env->inplace_cb_lists[type]; 270 struct inplace_cb* prev = NULL; 271 272 while(temp) { 273 if(temp->id == id) { 274 if(!prev) { 275 env->inplace_cb_lists[type] = temp->next; 276 free(temp->cb_arg); 277 free(temp); 278 temp = env->inplace_cb_lists[type]; 279 } 280 else { 281 prev->next = temp->next; 282 free(temp->cb_arg); 283 free(temp); 284 temp = prev->next; 285 } 286 } 287 else { 288 prev = temp; 289 temp = temp->next; 290 } 291 } 292 } 293 294 295 /** 296 * The module function block 297 */ 298 static struct module_func_block dynlibmod_block = { 299 "dynlib", 300 &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate, &dynlibmod_inform_super, 301 &dynlibmod_clear, &dynlibmod_get_mem 302 }; 303 304 struct module_func_block* dynlibmod_get_funcblock(void) 305 { 306 return &dynlibmod_block; 307 } 308