xref: /openbsd-src/sbin/unwind/libunbound/services/modstack.c (revision 7037e34cdfd270b3989fb1829c7cd3439048bd3a)
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