Coverage Report

Created: 2025-07-11 06:08

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