Home | History | Annotate | Line # | Download | only in dynlibmod
      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    NULL, NULL, &dynlibmod_init, &dynlibmod_deinit, &dynlibmod_operate,
    301    &dynlibmod_inform_super, &dynlibmod_clear, &dynlibmod_get_mem
    302 };
    303 
    304 struct module_func_block* dynlibmod_get_funcblock(void)
    305 {
    306    return &dynlibmod_block;
    307 }
    308