1ae8c6e27Sflorian /* 2ae8c6e27Sflorian * services/modstack.c - stack of modules 3ae8c6e27Sflorian * 4ae8c6e27Sflorian * Copyright (c) 2007, NLnet Labs. All rights reserved. 5ae8c6e27Sflorian * 6ae8c6e27Sflorian * This software is open source. 7ae8c6e27Sflorian * 8ae8c6e27Sflorian * Redistribution and use in source and binary forms, with or without 9ae8c6e27Sflorian * modification, are permitted provided that the following conditions 10ae8c6e27Sflorian * are met: 11ae8c6e27Sflorian * 12ae8c6e27Sflorian * Redistributions of source code must retain the above copyright notice, 13ae8c6e27Sflorian * this list of conditions and the following disclaimer. 14ae8c6e27Sflorian * 15ae8c6e27Sflorian * Redistributions in binary form must reproduce the above copyright notice, 16ae8c6e27Sflorian * this list of conditions and the following disclaimer in the documentation 17ae8c6e27Sflorian * and/or other materials provided with the distribution. 18ae8c6e27Sflorian * 19ae8c6e27Sflorian * Neither the name of the NLNET LABS nor the names of its contributors may 20ae8c6e27Sflorian * be used to endorse or promote products derived from this software without 21ae8c6e27Sflorian * specific prior written permission. 22ae8c6e27Sflorian * 23ae8c6e27Sflorian * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24ae8c6e27Sflorian * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25ae8c6e27Sflorian * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26ae8c6e27Sflorian * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27ae8c6e27Sflorian * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28ae8c6e27Sflorian * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29ae8c6e27Sflorian * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30ae8c6e27Sflorian * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31ae8c6e27Sflorian * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32ae8c6e27Sflorian * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33ae8c6e27Sflorian * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34ae8c6e27Sflorian */ 35ae8c6e27Sflorian 36ae8c6e27Sflorian /** 37ae8c6e27Sflorian * \file 38ae8c6e27Sflorian * 39ae8c6e27Sflorian * This file contains functions to help maintain a stack of modules. 40ae8c6e27Sflorian */ 41ae8c6e27Sflorian #include "config.h" 42ae8c6e27Sflorian #include <ctype.h> 43ae8c6e27Sflorian #include "services/modstack.h" 44ae8c6e27Sflorian #include "util/module.h" 45ae8c6e27Sflorian #include "util/fptr_wlist.h" 46ae8c6e27Sflorian #include "dns64/dns64.h" 47ae8c6e27Sflorian #include "iterator/iterator.h" 48ae8c6e27Sflorian #include "validator/validator.h" 49ae8c6e27Sflorian #include "respip/respip.h" 50ae8c6e27Sflorian 51ae8c6e27Sflorian #ifdef WITH_PYTHONMODULE 52ae8c6e27Sflorian #include "pythonmod/pythonmod.h" 53ae8c6e27Sflorian #endif 54e47fef9eSflorian #ifdef WITH_DYNLIBMODULE 55e47fef9eSflorian #include "dynlibmod/dynlibmod.h" 56e47fef9eSflorian #endif 57ae8c6e27Sflorian #ifdef USE_CACHEDB 58ae8c6e27Sflorian #include "cachedb/cachedb.h" 59ae8c6e27Sflorian #endif 60ae8c6e27Sflorian #ifdef USE_IPSECMOD 61ae8c6e27Sflorian #include "ipsecmod/ipsecmod.h" 62ae8c6e27Sflorian #endif 63ae8c6e27Sflorian #ifdef CLIENT_SUBNET 64ae8c6e27Sflorian #include "edns-subnet/subnetmod.h" 65ae8c6e27Sflorian #endif 66da8c8390Sflorian #ifdef USE_IPSET 67da8c8390Sflorian #include "ipset/ipset.h" 68da8c8390Sflorian #endif 69ae8c6e27Sflorian 70ae8c6e27Sflorian /** count number of modules (words) in the string */ 71ae8c6e27Sflorian static int 72ae8c6e27Sflorian count_modules(const char* s) 73ae8c6e27Sflorian { 74ae8c6e27Sflorian int num = 0; 75ae8c6e27Sflorian if(!s) 76ae8c6e27Sflorian return 0; 77ae8c6e27Sflorian while(*s) { 78ae8c6e27Sflorian /* skip whitespace */ 79ae8c6e27Sflorian while(*s && isspace((unsigned char)*s)) 80ae8c6e27Sflorian s++; 81ae8c6e27Sflorian if(*s && !isspace((unsigned char)*s)) { 82ae8c6e27Sflorian /* skip identifier */ 83ae8c6e27Sflorian num++; 84ae8c6e27Sflorian while(*s && !isspace((unsigned char)*s)) 85ae8c6e27Sflorian s++; 86ae8c6e27Sflorian } 87ae8c6e27Sflorian } 88ae8c6e27Sflorian return num; 89ae8c6e27Sflorian } 90ae8c6e27Sflorian 91ae8c6e27Sflorian void 92ae8c6e27Sflorian modstack_init(struct module_stack* stack) 93ae8c6e27Sflorian { 94ae8c6e27Sflorian stack->num = 0; 95ae8c6e27Sflorian stack->mod = NULL; 96ae8c6e27Sflorian } 97ae8c6e27Sflorian 98*7037e34cSflorian void 99*7037e34cSflorian modstack_free(struct module_stack* stack) 100*7037e34cSflorian { 101*7037e34cSflorian if(!stack) 102*7037e34cSflorian return; 103*7037e34cSflorian stack->num = 0; 104*7037e34cSflorian free(stack->mod); 105*7037e34cSflorian stack->mod = NULL; 106*7037e34cSflorian } 107*7037e34cSflorian 108ae8c6e27Sflorian int 109ae8c6e27Sflorian modstack_config(struct module_stack* stack, const char* module_conf) 110ae8c6e27Sflorian { 111ae8c6e27Sflorian int i; 112ae8c6e27Sflorian verbose(VERB_QUERY, "module config: \"%s\"", module_conf); 113ae8c6e27Sflorian stack->num = count_modules(module_conf); 114ae8c6e27Sflorian if(stack->num == 0) { 115ae8c6e27Sflorian log_err("error: no modules specified"); 116ae8c6e27Sflorian return 0; 117ae8c6e27Sflorian } 118ae8c6e27Sflorian if(stack->num > MAX_MODULE) { 119ae8c6e27Sflorian log_err("error: too many modules (%d max %d)", 120ae8c6e27Sflorian stack->num, MAX_MODULE); 121ae8c6e27Sflorian return 0; 122ae8c6e27Sflorian } 123ae8c6e27Sflorian stack->mod = (struct module_func_block**)calloc((size_t) 124ae8c6e27Sflorian stack->num, sizeof(struct module_func_block*)); 125ae8c6e27Sflorian if(!stack->mod) { 126ae8c6e27Sflorian log_err("out of memory"); 127ae8c6e27Sflorian return 0; 128ae8c6e27Sflorian } 129ae8c6e27Sflorian for(i=0; i<stack->num; i++) { 130ae8c6e27Sflorian stack->mod[i] = module_factory(&module_conf); 131ae8c6e27Sflorian if(!stack->mod[i]) { 132988ebc2dSflorian char md[256]; 133d500c338Sflorian char * s = md; 134988ebc2dSflorian snprintf(md, sizeof(md), "%s", module_conf); 135d500c338Sflorian /* Leading spaces are present on errors. */ 136d500c338Sflorian while (*s && isspace((unsigned char)*s)) 137d500c338Sflorian s++; 138d500c338Sflorian if(strchr(s, ' ')) *(strchr(s, ' ')) = 0; 139d500c338Sflorian if(strchr(s, '\t')) *(strchr(s, '\t')) = 0; 140988ebc2dSflorian log_err("Unknown value in module-config, module: '%s'." 141988ebc2dSflorian " This module is not present (not compiled in)," 142d500c338Sflorian " See the list of linked modules with unbound -V", s); 143ae8c6e27Sflorian return 0; 144ae8c6e27Sflorian } 145ae8c6e27Sflorian } 146ae8c6e27Sflorian return 1; 147ae8c6e27Sflorian } 148ae8c6e27Sflorian 149ae8c6e27Sflorian /** The list of module names */ 150ae8c6e27Sflorian const char** 151ae8c6e27Sflorian module_list_avail(void) 152ae8c6e27Sflorian { 153ae8c6e27Sflorian /* these are the modules available */ 154ae8c6e27Sflorian static const char* names[] = { 155ae8c6e27Sflorian "dns64", 156ae8c6e27Sflorian #ifdef WITH_PYTHONMODULE 157ae8c6e27Sflorian "python", 158ae8c6e27Sflorian #endif 159e47fef9eSflorian #ifdef WITH_DYNLIBMODULE 160e47fef9eSflorian "dynlib", 161e47fef9eSflorian #endif 162ae8c6e27Sflorian #ifdef USE_CACHEDB 163ae8c6e27Sflorian "cachedb", 164ae8c6e27Sflorian #endif 165ae8c6e27Sflorian #ifdef USE_IPSECMOD 166ae8c6e27Sflorian "ipsecmod", 167ae8c6e27Sflorian #endif 168ae8c6e27Sflorian #ifdef CLIENT_SUBNET 169ae8c6e27Sflorian "subnetcache", 170ae8c6e27Sflorian #endif 171da8c8390Sflorian #ifdef USE_IPSET 172da8c8390Sflorian "ipset", 173da8c8390Sflorian #endif 174ae8c6e27Sflorian "respip", 175ae8c6e27Sflorian "validator", 176ae8c6e27Sflorian "iterator", 177ae8c6e27Sflorian NULL}; 178ae8c6e27Sflorian return names; 179ae8c6e27Sflorian } 180ae8c6e27Sflorian 181ae8c6e27Sflorian /** func block get function type */ 182ae8c6e27Sflorian typedef struct module_func_block* (*fbgetfunctype)(void); 183ae8c6e27Sflorian 184ae8c6e27Sflorian /** The list of module func blocks */ 185ae8c6e27Sflorian static fbgetfunctype* 186ae8c6e27Sflorian module_funcs_avail(void) 187ae8c6e27Sflorian { 188ae8c6e27Sflorian static struct module_func_block* (*fb[])(void) = { 189ae8c6e27Sflorian &dns64_get_funcblock, 190ae8c6e27Sflorian #ifdef WITH_PYTHONMODULE 191ae8c6e27Sflorian &pythonmod_get_funcblock, 192ae8c6e27Sflorian #endif 193e47fef9eSflorian #ifdef WITH_DYNLIBMODULE 194e47fef9eSflorian &dynlibmod_get_funcblock, 195e47fef9eSflorian #endif 196ae8c6e27Sflorian #ifdef USE_CACHEDB 197ae8c6e27Sflorian &cachedb_get_funcblock, 198ae8c6e27Sflorian #endif 199ae8c6e27Sflorian #ifdef USE_IPSECMOD 200ae8c6e27Sflorian &ipsecmod_get_funcblock, 201ae8c6e27Sflorian #endif 202ae8c6e27Sflorian #ifdef CLIENT_SUBNET 203ae8c6e27Sflorian &subnetmod_get_funcblock, 204ae8c6e27Sflorian #endif 205da8c8390Sflorian #ifdef USE_IPSET 206da8c8390Sflorian &ipset_get_funcblock, 207da8c8390Sflorian #endif 208ae8c6e27Sflorian &respip_get_funcblock, 209ae8c6e27Sflorian &val_get_funcblock, 210ae8c6e27Sflorian &iter_get_funcblock, 211ae8c6e27Sflorian NULL}; 212ae8c6e27Sflorian return fb; 213ae8c6e27Sflorian } 214ae8c6e27Sflorian 215ae8c6e27Sflorian struct 216ae8c6e27Sflorian module_func_block* module_factory(const char** str) 217ae8c6e27Sflorian { 218ae8c6e27Sflorian int i = 0; 219ae8c6e27Sflorian const char* s = *str; 220ae8c6e27Sflorian const char** names = module_list_avail(); 221ae8c6e27Sflorian fbgetfunctype* fb = module_funcs_avail(); 222ae8c6e27Sflorian while(*s && isspace((unsigned char)*s)) 223ae8c6e27Sflorian s++; 224ae8c6e27Sflorian while(names[i]) { 225ae8c6e27Sflorian if(strncmp(names[i], s, strlen(names[i])) == 0) { 226ae8c6e27Sflorian s += strlen(names[i]); 227ae8c6e27Sflorian *str = s; 228ae8c6e27Sflorian return (*fb[i])(); 229ae8c6e27Sflorian } 230ae8c6e27Sflorian i++; 231ae8c6e27Sflorian } 232ae8c6e27Sflorian return NULL; 233ae8c6e27Sflorian } 234ae8c6e27Sflorian 235ae8c6e27Sflorian int 236*7037e34cSflorian modstack_call_startup(struct module_stack* stack, const char* module_conf, 237ae8c6e27Sflorian struct module_env* env) 238ae8c6e27Sflorian { 239ae8c6e27Sflorian int i; 240ae8c6e27Sflorian if(stack->num != 0) 241*7037e34cSflorian fatal_exit("unexpected already initialised modules"); 242ae8c6e27Sflorian /* fixed setup of the modules */ 243ae8c6e27Sflorian if(!modstack_config(stack, module_conf)) { 244ae8c6e27Sflorian return 0; 245ae8c6e27Sflorian } 246*7037e34cSflorian for(i=0; i<stack->num; i++) { 247*7037e34cSflorian if(stack->mod[i]->startup == NULL) 248*7037e34cSflorian continue; 249*7037e34cSflorian verbose(VERB_OPS, "startup module %d: %s", 250*7037e34cSflorian i, stack->mod[i]->name); 251*7037e34cSflorian fptr_ok(fptr_whitelist_mod_startup(stack->mod[i]->startup)); 252*7037e34cSflorian if(!(*stack->mod[i]->startup)(env, i)) { 253*7037e34cSflorian log_err("module startup for module %s failed", 254*7037e34cSflorian stack->mod[i]->name); 255*7037e34cSflorian return 0; 256*7037e34cSflorian } 257*7037e34cSflorian } 258*7037e34cSflorian return 1; 259*7037e34cSflorian } 260*7037e34cSflorian 261*7037e34cSflorian int 262*7037e34cSflorian modstack_call_init(struct module_stack* stack, const char* module_conf, 263*7037e34cSflorian struct module_env* env) 264*7037e34cSflorian { 265*7037e34cSflorian int i, changed = 0; 266ae8c6e27Sflorian env->need_to_validate = 0; /* set by module init below */ 267ae8c6e27Sflorian for(i=0; i<stack->num; i++) { 268*7037e34cSflorian while(*module_conf && isspace(*module_conf)) 269*7037e34cSflorian module_conf++; 270*7037e34cSflorian if(strncmp(stack->mod[i]->name, module_conf, 271*7037e34cSflorian strlen(stack->mod[i]->name))) { 272*7037e34cSflorian if(stack->mod[i]->startup || stack->mod[i]->destartup) { 273*7037e34cSflorian log_err("changed module ordering during reload not supported, for module that needs startup"); 274*7037e34cSflorian return 0; 275*7037e34cSflorian } else { 276*7037e34cSflorian changed = 1; 277*7037e34cSflorian } 278*7037e34cSflorian } 279*7037e34cSflorian module_conf += strlen(stack->mod[i]->name); 280*7037e34cSflorian } 281*7037e34cSflorian if(changed) { 282*7037e34cSflorian modstack_free(stack); 283*7037e34cSflorian if(!modstack_config(stack, module_conf)) { 284*7037e34cSflorian return 0; 285*7037e34cSflorian } 286*7037e34cSflorian } 287*7037e34cSflorian 288*7037e34cSflorian for(i=0; i<stack->num; i++) { 289ae8c6e27Sflorian verbose(VERB_OPS, "init module %d: %s", 290ae8c6e27Sflorian i, stack->mod[i]->name); 291ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_init(stack->mod[i]->init)); 292ae8c6e27Sflorian if(!(*stack->mod[i]->init)(env, i)) { 293ae8c6e27Sflorian log_err("module init for module %s failed", 294ae8c6e27Sflorian stack->mod[i]->name); 295ae8c6e27Sflorian return 0; 296ae8c6e27Sflorian } 297ae8c6e27Sflorian } 298ae8c6e27Sflorian return 1; 299ae8c6e27Sflorian } 300ae8c6e27Sflorian 301ae8c6e27Sflorian void 302*7037e34cSflorian modstack_call_deinit(struct module_stack* stack, struct module_env* env) 303ae8c6e27Sflorian { 304ae8c6e27Sflorian int i; 305ae8c6e27Sflorian for(i=0; i<stack->num; i++) { 306ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_deinit(stack->mod[i]->deinit)); 307ae8c6e27Sflorian (*stack->mod[i]->deinit)(env, i); 308ae8c6e27Sflorian } 309*7037e34cSflorian } 310*7037e34cSflorian 311*7037e34cSflorian void 312*7037e34cSflorian modstack_call_destartup(struct module_stack* stack, struct module_env* env) 313*7037e34cSflorian { 314*7037e34cSflorian int i; 315*7037e34cSflorian for(i=0; i<stack->num; i++) { 316*7037e34cSflorian if(stack->mod[i]->destartup == NULL) 317*7037e34cSflorian continue; 318*7037e34cSflorian fptr_ok(fptr_whitelist_mod_destartup(stack->mod[i]->destartup)); 319*7037e34cSflorian (*stack->mod[i]->destartup)(env, i); 320*7037e34cSflorian } 321ae8c6e27Sflorian } 322ae8c6e27Sflorian 323ae8c6e27Sflorian int 324ae8c6e27Sflorian modstack_find(struct module_stack* stack, const char* name) 325ae8c6e27Sflorian { 326ae8c6e27Sflorian int i; 327ae8c6e27Sflorian for(i=0; i<stack->num; i++) { 328ae8c6e27Sflorian if(strcmp(stack->mod[i]->name, name) == 0) 329ae8c6e27Sflorian return i; 330ae8c6e27Sflorian } 331ae8c6e27Sflorian return -1; 332ae8c6e27Sflorian } 333ae8c6e27Sflorian 334ae8c6e27Sflorian size_t 335ae8c6e27Sflorian mod_get_mem(struct module_env* env, const char* name) 336ae8c6e27Sflorian { 337ae8c6e27Sflorian int m = modstack_find(&env->mesh->mods, name); 338ae8c6e27Sflorian if(m != -1) { 339ae8c6e27Sflorian fptr_ok(fptr_whitelist_mod_get_mem(env->mesh-> 340ae8c6e27Sflorian mods.mod[m]->get_mem)); 341ae8c6e27Sflorian return (*env->mesh->mods.mod[m]->get_mem)(env, m); 342ae8c6e27Sflorian } 343ae8c6e27Sflorian return 0; 344ae8c6e27Sflorian } 345