1933707f3Ssthen /* 2933707f3Ssthen * services/modstack.c - stack of modules 3933707f3Ssthen * 4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved. 5933707f3Ssthen * 6933707f3Ssthen * This software is open source. 7933707f3Ssthen * 8933707f3Ssthen * Redistribution and use in source and binary forms, with or without 9933707f3Ssthen * modification, are permitted provided that the following conditions 10933707f3Ssthen * are met: 11933707f3Ssthen * 12933707f3Ssthen * Redistributions of source code must retain the above copyright notice, 13933707f3Ssthen * this list of conditions and the following disclaimer. 14933707f3Ssthen * 15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice, 16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation 17933707f3Ssthen * and/or other materials provided with the distribution. 18933707f3Ssthen * 19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may 20933707f3Ssthen * be used to endorse or promote products derived from this software without 21933707f3Ssthen * specific prior written permission. 22933707f3Ssthen * 23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34933707f3Ssthen */ 35933707f3Ssthen 36933707f3Ssthen /** 37933707f3Ssthen * \file 38933707f3Ssthen * 39933707f3Ssthen * This file contains functions to help maintain a stack of modules. 40933707f3Ssthen */ 41933707f3Ssthen #include "config.h" 42933707f3Ssthen #include <ctype.h> 43933707f3Ssthen #include "services/modstack.h" 44933707f3Ssthen #include "util/module.h" 45933707f3Ssthen #include "util/fptr_wlist.h" 4698f3ca02Sbrad #include "dns64/dns64.h" 47933707f3Ssthen #include "iterator/iterator.h" 48933707f3Ssthen #include "validator/validator.h" 492be9e038Ssthen #include "respip/respip.h" 50933707f3Ssthen 51933707f3Ssthen #ifdef WITH_PYTHONMODULE 52933707f3Ssthen #include "pythonmod/pythonmod.h" 53933707f3Ssthen #endif 54a3167c07Ssthen #ifdef WITH_DYNLIBMODULE 55a3167c07Ssthen #include "dynlibmod/dynlibmod.h" 56a3167c07Ssthen #endif 572ee382b6Ssthen #ifdef USE_CACHEDB 582ee382b6Ssthen #include "cachedb/cachedb.h" 592ee382b6Ssthen #endif 602be9e038Ssthen #ifdef USE_IPSECMOD 612be9e038Ssthen #include "ipsecmod/ipsecmod.h" 622be9e038Ssthen #endif 632be9e038Ssthen #ifdef CLIENT_SUBNET 642be9e038Ssthen #include "edns-subnet/subnetmod.h" 652be9e038Ssthen #endif 668240c1b9Ssthen #ifdef USE_IPSET 678240c1b9Ssthen #include "ipset/ipset.h" 688240c1b9Ssthen #endif 69933707f3Ssthen 70933707f3Ssthen /** count number of modules (words) in the string */ 71933707f3Ssthen static int 72933707f3Ssthen count_modules(const char* s) 73933707f3Ssthen { 74933707f3Ssthen int num = 0; 75933707f3Ssthen if(!s) 76933707f3Ssthen return 0; 77933707f3Ssthen while(*s) { 78933707f3Ssthen /* skip whitespace */ 7998f3ca02Sbrad while(*s && isspace((unsigned char)*s)) 80933707f3Ssthen s++; 8198f3ca02Sbrad if(*s && !isspace((unsigned char)*s)) { 82933707f3Ssthen /* skip identifier */ 83933707f3Ssthen num++; 8498f3ca02Sbrad while(*s && !isspace((unsigned char)*s)) 85933707f3Ssthen s++; 86933707f3Ssthen } 87933707f3Ssthen } 88933707f3Ssthen return num; 89933707f3Ssthen } 90933707f3Ssthen 91933707f3Ssthen void 92933707f3Ssthen modstack_init(struct module_stack* stack) 93933707f3Ssthen { 94933707f3Ssthen stack->num = 0; 95933707f3Ssthen stack->mod = NULL; 96933707f3Ssthen } 97933707f3Ssthen 98*98bc733bSsthen void 99*98bc733bSsthen modstack_free(struct module_stack* stack) 100*98bc733bSsthen { 101*98bc733bSsthen if(!stack) 102*98bc733bSsthen return; 103*98bc733bSsthen stack->num = 0; 104*98bc733bSsthen free(stack->mod); 105*98bc733bSsthen stack->mod = NULL; 106*98bc733bSsthen } 107*98bc733bSsthen 108933707f3Ssthen int 109933707f3Ssthen modstack_config(struct module_stack* stack, const char* module_conf) 110933707f3Ssthen { 111933707f3Ssthen int i; 112933707f3Ssthen verbose(VERB_QUERY, "module config: \"%s\"", module_conf); 113933707f3Ssthen stack->num = count_modules(module_conf); 114933707f3Ssthen if(stack->num == 0) { 115933707f3Ssthen log_err("error: no modules specified"); 116933707f3Ssthen return 0; 117933707f3Ssthen } 118933707f3Ssthen if(stack->num > MAX_MODULE) { 119933707f3Ssthen log_err("error: too many modules (%d max %d)", 120933707f3Ssthen stack->num, MAX_MODULE); 121933707f3Ssthen return 0; 122933707f3Ssthen } 123933707f3Ssthen stack->mod = (struct module_func_block**)calloc((size_t) 124933707f3Ssthen stack->num, sizeof(struct module_func_block*)); 125933707f3Ssthen if(!stack->mod) { 126933707f3Ssthen log_err("out of memory"); 127933707f3Ssthen return 0; 128933707f3Ssthen } 129933707f3Ssthen for(i=0; i<stack->num; i++) { 130933707f3Ssthen stack->mod[i] = module_factory(&module_conf); 131933707f3Ssthen if(!stack->mod[i]) { 132c3b38330Ssthen char md[256]; 1338b7325afSsthen char * s = md; 134c3b38330Ssthen snprintf(md, sizeof(md), "%s", module_conf); 1358b7325afSsthen /* Leading spaces are present on errors. */ 1368b7325afSsthen while (*s && isspace((unsigned char)*s)) 1378b7325afSsthen s++; 1388b7325afSsthen if(strchr(s, ' ')) *(strchr(s, ' ')) = 0; 1398b7325afSsthen if(strchr(s, '\t')) *(strchr(s, '\t')) = 0; 140c3b38330Ssthen log_err("Unknown value in module-config, module: '%s'." 141c3b38330Ssthen " This module is not present (not compiled in)," 1428b7325afSsthen " See the list of linked modules with unbound -V", s); 143933707f3Ssthen return 0; 144933707f3Ssthen } 145933707f3Ssthen } 146933707f3Ssthen return 1; 147933707f3Ssthen } 148933707f3Ssthen 149933707f3Ssthen /** The list of module names */ 150933707f3Ssthen const char** 151933707f3Ssthen module_list_avail(void) 152933707f3Ssthen { 153933707f3Ssthen /* these are the modules available */ 154933707f3Ssthen static const char* names[] = { 15598f3ca02Sbrad "dns64", 156933707f3Ssthen #ifdef WITH_PYTHONMODULE 157933707f3Ssthen "python", 158933707f3Ssthen #endif 159a3167c07Ssthen #ifdef WITH_DYNLIBMODULE 160a3167c07Ssthen "dynlib", 161a3167c07Ssthen #endif 1622ee382b6Ssthen #ifdef USE_CACHEDB 1632ee382b6Ssthen "cachedb", 1642ee382b6Ssthen #endif 1652be9e038Ssthen #ifdef USE_IPSECMOD 1662be9e038Ssthen "ipsecmod", 1672be9e038Ssthen #endif 1682be9e038Ssthen #ifdef CLIENT_SUBNET 1692be9e038Ssthen "subnetcache", 1702be9e038Ssthen #endif 1718240c1b9Ssthen #ifdef USE_IPSET 1728240c1b9Ssthen "ipset", 1738240c1b9Ssthen #endif 1742be9e038Ssthen "respip", 175933707f3Ssthen "validator", 176933707f3Ssthen "iterator", 177933707f3Ssthen NULL}; 178933707f3Ssthen return names; 179933707f3Ssthen } 180933707f3Ssthen 181933707f3Ssthen /** func block get function type */ 182933707f3Ssthen typedef struct module_func_block* (*fbgetfunctype)(void); 183933707f3Ssthen 184933707f3Ssthen /** The list of module func blocks */ 185933707f3Ssthen static fbgetfunctype* 186933707f3Ssthen module_funcs_avail(void) 187933707f3Ssthen { 188933707f3Ssthen static struct module_func_block* (*fb[])(void) = { 18998f3ca02Sbrad &dns64_get_funcblock, 190933707f3Ssthen #ifdef WITH_PYTHONMODULE 191933707f3Ssthen &pythonmod_get_funcblock, 192933707f3Ssthen #endif 193a3167c07Ssthen #ifdef WITH_DYNLIBMODULE 194a3167c07Ssthen &dynlibmod_get_funcblock, 195a3167c07Ssthen #endif 1962ee382b6Ssthen #ifdef USE_CACHEDB 1972ee382b6Ssthen &cachedb_get_funcblock, 1982ee382b6Ssthen #endif 1992be9e038Ssthen #ifdef USE_IPSECMOD 2002be9e038Ssthen &ipsecmod_get_funcblock, 2012be9e038Ssthen #endif 2022be9e038Ssthen #ifdef CLIENT_SUBNET 2032be9e038Ssthen &subnetmod_get_funcblock, 2042be9e038Ssthen #endif 2058240c1b9Ssthen #ifdef USE_IPSET 2068240c1b9Ssthen &ipset_get_funcblock, 2078240c1b9Ssthen #endif 2082be9e038Ssthen &respip_get_funcblock, 209933707f3Ssthen &val_get_funcblock, 210933707f3Ssthen &iter_get_funcblock, 211933707f3Ssthen NULL}; 212933707f3Ssthen return fb; 213933707f3Ssthen } 214933707f3Ssthen 215933707f3Ssthen struct 216933707f3Ssthen module_func_block* module_factory(const char** str) 217933707f3Ssthen { 218933707f3Ssthen int i = 0; 219933707f3Ssthen const char* s = *str; 220933707f3Ssthen const char** names = module_list_avail(); 221933707f3Ssthen fbgetfunctype* fb = module_funcs_avail(); 22298f3ca02Sbrad while(*s && isspace((unsigned char)*s)) 223933707f3Ssthen s++; 224933707f3Ssthen while(names[i]) { 225933707f3Ssthen if(strncmp(names[i], s, strlen(names[i])) == 0) { 226933707f3Ssthen s += strlen(names[i]); 227933707f3Ssthen *str = s; 228933707f3Ssthen return (*fb[i])(); 229933707f3Ssthen } 230933707f3Ssthen i++; 231933707f3Ssthen } 232933707f3Ssthen return NULL; 233933707f3Ssthen } 234933707f3Ssthen 235933707f3Ssthen int 236*98bc733bSsthen modstack_call_startup(struct module_stack* stack, const char* module_conf, 237933707f3Ssthen struct module_env* env) 238933707f3Ssthen { 239933707f3Ssthen int i; 240933707f3Ssthen if(stack->num != 0) 241*98bc733bSsthen fatal_exit("unexpected already initialised modules"); 242933707f3Ssthen /* fixed setup of the modules */ 243933707f3Ssthen if(!modstack_config(stack, module_conf)) { 244933707f3Ssthen return 0; 245933707f3Ssthen } 246*98bc733bSsthen for(i=0; i<stack->num; i++) { 247*98bc733bSsthen if(stack->mod[i]->startup == NULL) 248*98bc733bSsthen continue; 249*98bc733bSsthen verbose(VERB_OPS, "startup module %d: %s", 250*98bc733bSsthen i, stack->mod[i]->name); 251*98bc733bSsthen fptr_ok(fptr_whitelist_mod_startup(stack->mod[i]->startup)); 252*98bc733bSsthen if(!(*stack->mod[i]->startup)(env, i)) { 253*98bc733bSsthen log_err("module startup for module %s failed", 254*98bc733bSsthen stack->mod[i]->name); 255*98bc733bSsthen return 0; 256*98bc733bSsthen } 257*98bc733bSsthen } 258*98bc733bSsthen return 1; 259*98bc733bSsthen } 260*98bc733bSsthen 261*98bc733bSsthen int 262*98bc733bSsthen modstack_call_init(struct module_stack* stack, const char* module_conf, 263*98bc733bSsthen struct module_env* env) 264*98bc733bSsthen { 265*98bc733bSsthen int i, changed = 0; 266933707f3Ssthen env->need_to_validate = 0; /* set by module init below */ 267933707f3Ssthen for(i=0; i<stack->num; i++) { 268*98bc733bSsthen while(*module_conf && isspace(*module_conf)) 269*98bc733bSsthen module_conf++; 270*98bc733bSsthen if(strncmp(stack->mod[i]->name, module_conf, 271*98bc733bSsthen strlen(stack->mod[i]->name))) { 272*98bc733bSsthen if(stack->mod[i]->startup || stack->mod[i]->destartup) { 273*98bc733bSsthen log_err("changed module ordering during reload not supported, for module that needs startup"); 274*98bc733bSsthen return 0; 275*98bc733bSsthen } else { 276*98bc733bSsthen changed = 1; 277*98bc733bSsthen } 278*98bc733bSsthen } 279*98bc733bSsthen module_conf += strlen(stack->mod[i]->name); 280*98bc733bSsthen } 281*98bc733bSsthen if(changed) { 282*98bc733bSsthen modstack_free(stack); 283*98bc733bSsthen if(!modstack_config(stack, module_conf)) { 284*98bc733bSsthen return 0; 285*98bc733bSsthen } 286*98bc733bSsthen } 287*98bc733bSsthen 288*98bc733bSsthen for(i=0; i<stack->num; i++) { 289933707f3Ssthen verbose(VERB_OPS, "init module %d: %s", 290933707f3Ssthen i, stack->mod[i]->name); 291933707f3Ssthen fptr_ok(fptr_whitelist_mod_init(stack->mod[i]->init)); 292933707f3Ssthen if(!(*stack->mod[i]->init)(env, i)) { 293933707f3Ssthen log_err("module init for module %s failed", 294933707f3Ssthen stack->mod[i]->name); 295933707f3Ssthen return 0; 296933707f3Ssthen } 297933707f3Ssthen } 298933707f3Ssthen return 1; 299933707f3Ssthen } 300933707f3Ssthen 301933707f3Ssthen void 302*98bc733bSsthen modstack_call_deinit(struct module_stack* stack, struct module_env* env) 303933707f3Ssthen { 304933707f3Ssthen int i; 305933707f3Ssthen for(i=0; i<stack->num; i++) { 306933707f3Ssthen fptr_ok(fptr_whitelist_mod_deinit(stack->mod[i]->deinit)); 307933707f3Ssthen (*stack->mod[i]->deinit)(env, i); 308933707f3Ssthen } 309*98bc733bSsthen } 310*98bc733bSsthen 311*98bc733bSsthen void 312*98bc733bSsthen modstack_call_destartup(struct module_stack* stack, struct module_env* env) 313*98bc733bSsthen { 314*98bc733bSsthen int i; 315*98bc733bSsthen for(i=0; i<stack->num; i++) { 316*98bc733bSsthen if(stack->mod[i]->destartup == NULL) 317*98bc733bSsthen continue; 318*98bc733bSsthen fptr_ok(fptr_whitelist_mod_destartup(stack->mod[i]->destartup)); 319*98bc733bSsthen (*stack->mod[i]->destartup)(env, i); 320*98bc733bSsthen } 321933707f3Ssthen } 322933707f3Ssthen 323933707f3Ssthen int 324933707f3Ssthen modstack_find(struct module_stack* stack, const char* name) 325933707f3Ssthen { 326933707f3Ssthen int i; 327933707f3Ssthen for(i=0; i<stack->num; i++) { 328933707f3Ssthen if(strcmp(stack->mod[i]->name, name) == 0) 329933707f3Ssthen return i; 330933707f3Ssthen } 331933707f3Ssthen return -1; 332933707f3Ssthen } 3332be9e038Ssthen 3342be9e038Ssthen size_t 3352be9e038Ssthen mod_get_mem(struct module_env* env, const char* name) 3362be9e038Ssthen { 3372be9e038Ssthen int m = modstack_find(&env->mesh->mods, name); 3382be9e038Ssthen if(m != -1) { 3392be9e038Ssthen fptr_ok(fptr_whitelist_mod_get_mem(env->mesh-> 3402be9e038Ssthen mods.mod[m]->get_mem)); 3412be9e038Ssthen return (*env->mesh->mods.mod[m]->get_mem)(env, m); 3422be9e038Ssthen } 3432be9e038Ssthen return 0; 3442be9e038Ssthen } 345