module.c revision 356345
1/*
2 * util/module.c - module interface
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 * \file
37 * Implementation of module.h.
38 */
39
40#include "config.h"
41#include "util/module.h"
42#include "sldns/wire2str.h"
43
44const char*
45strextstate(enum module_ext_state s)
46{
47	switch(s) {
48	case module_state_initial: return "module_state_initial";
49	case module_wait_reply: return "module_wait_reply";
50	case module_wait_module: return "module_wait_module";
51	case module_restart_next: return "module_restart_next";
52	case module_wait_subquery: return "module_wait_subquery";
53	case module_error: return "module_error";
54	case module_finished: return "module_finished";
55	}
56	return "bad_extstate_value";
57}
58
59const char*
60strmodulevent(enum module_ev e)
61{
62	switch(e) {
63	case module_event_new: return "module_event_new";
64	case module_event_pass: return "module_event_pass";
65	case module_event_reply: return "module_event_reply";
66	case module_event_noreply: return "module_event_noreply";
67	case module_event_capsfail: return "module_event_capsfail";
68	case module_event_moddone: return "module_event_moddone";
69	case module_event_error: return "module_event_error";
70	}
71	return "bad_event_value";
72}
73
74int
75edns_known_options_init(struct module_env* env)
76{
77	env->edns_known_options_num = 0;
78	env->edns_known_options = (struct edns_known_option*)calloc(
79		MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option));
80	if(!env->edns_known_options) return 0;
81	return 1;
82}
83
84void
85edns_known_options_delete(struct module_env* env)
86{
87	free(env->edns_known_options);
88	env->edns_known_options = NULL;
89	env->edns_known_options_num = 0;
90}
91
92int
93edns_register_option(uint16_t opt_code, int bypass_cache_stage,
94	int no_aggregation, struct module_env* env)
95{
96	size_t i;
97	if(env->worker) {
98		log_err("invalid edns registration: "
99			"trying to register option after module init phase");
100		return 0;
101	}
102
103	/**
104	 * Checking if we are full first is faster but it does not provide
105	 * the option to change the flags when the array is full.
106	 * It only impacts unbound initialization, leave it for now.
107	 */
108	/* Check if the option is already registered. */
109	for(i=0; i<env->edns_known_options_num; i++)
110		if(env->edns_known_options[i].opt_code == opt_code)
111			break;
112	/* If it is not yet registered check if we have space to add a new one. */
113	if(i == env->edns_known_options_num) {
114		if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) {
115			log_err("invalid edns registration: maximum options reached");
116			return 0;
117		}
118		env->edns_known_options_num++;
119	}
120	env->edns_known_options[i].opt_code = opt_code;
121	env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage;
122	env->edns_known_options[i].no_aggregation = no_aggregation;
123	return 1;
124}
125
126int
127inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
128	struct module_env* env, int id)
129{
130	struct inplace_cb* callback;
131	struct inplace_cb** prevp;
132	if(env->worker) {
133		log_err("invalid edns callback registration: "
134			"trying to register callback after module init phase");
135		return 0;
136	}
137
138	callback = (struct inplace_cb*)calloc(1, sizeof(*callback));
139	if(callback == NULL) {
140		log_err("out of memory during edns callback registration.");
141		return 0;
142	}
143	callback->id = id;
144	callback->next = NULL;
145	callback->cb = cb;
146	callback->cb_arg = cbarg;
147
148	prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
149	/* append at end of list */
150	while(*prevp != NULL)
151		prevp = &((*prevp)->next);
152	*prevp = callback;
153	return 1;
154}
155
156void
157inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
158	int id)
159{
160	struct inplace_cb* temp = env->inplace_cb_lists[type];
161	struct inplace_cb* prev = NULL;
162
163	while(temp) {
164		if(temp->id == id) {
165			if(!prev) {
166				env->inplace_cb_lists[type] = temp->next;
167				free(temp);
168				temp = env->inplace_cb_lists[type];
169			}
170			else {
171				prev->next = temp->next;
172				free(temp);
173				temp = prev->next;
174			}
175		}
176		else {
177			prev = temp;
178			temp = temp->next;
179		}
180	}
181}
182
183struct edns_known_option*
184edns_option_is_known(uint16_t opt_code, struct module_env* env)
185{
186	size_t i;
187	for(i=0; i<env->edns_known_options_num; i++)
188		if(env->edns_known_options[i].opt_code == opt_code)
189			return env->edns_known_options + i;
190	return NULL;
191}
192
193int
194edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
195{
196	size_t i;
197	for(; list; list=list->next)
198		for(i=0; i<env->edns_known_options_num; i++)
199			if(env->edns_known_options[i].opt_code == list->opt_code &&
200				env->edns_known_options[i].bypass_cache_stage == 1)
201					return 1;
202	return 0;
203}
204
205int
206unique_mesh_state(struct edns_option* list, struct module_env* env)
207{
208	size_t i;
209	if(env->unique_mesh)
210		return 1;
211	for(; list; list=list->next)
212		for(i=0; i<env->edns_known_options_num; i++)
213			if(env->edns_known_options[i].opt_code == list->opt_code &&
214				env->edns_known_options[i].no_aggregation == 1)
215					return 1;
216	return 0;
217}
218
219void
220log_edns_known_options(enum verbosity_value level, struct module_env* env)
221{
222	size_t i;
223	char str[32], *s;
224	size_t slen;
225	if(env->edns_known_options_num > 0 && verbosity >= level) {
226		verbose(level, "EDNS known options:");
227		verbose(level, "  Code:    Bypass_cache_stage: Aggregate_mesh:");
228		for(i=0; i<env->edns_known_options_num; i++) {
229			s = str;
230			slen = sizeof(str);
231			(void)sldns_wire2str_edns_option_code_print(&s, &slen,
232				env->edns_known_options[i].opt_code);
233			verbose(level, "  %-8.8s %-19s %-15s", str,
234				env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
235				env->edns_known_options[i].no_aggregation?"NO":"YES");
236		}
237	}
238}
239
240void
241copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
242	struct module_qstate* super)
243{
244	/* Overwrite super's was_ratelimited only when it was not set */
245	if(!super->was_ratelimited) {
246		super->was_ratelimited = qstate->was_ratelimited;
247	}
248}
249