xref: /freebsd/contrib/unbound/util/module.c (revision 9e6bbe47a503137f1698232070cb4c1a4f14be10)
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 #include "util/config_file.h"
44 #include "util/regional.h"
45 #include "util/data/dname.h"
46 #include "util/net_help.h"
47 
48 const char*
49 strextstate(enum module_ext_state s)
50 {
51 	switch(s) {
52 	case module_state_initial: return "module_state_initial";
53 	case module_wait_reply: return "module_wait_reply";
54 	case module_wait_module: return "module_wait_module";
55 	case module_restart_next: return "module_restart_next";
56 	case module_wait_subquery: return "module_wait_subquery";
57 	case module_error: return "module_error";
58 	case module_finished: return "module_finished";
59 	}
60 	return "bad_extstate_value";
61 }
62 
63 const char*
64 strmodulevent(enum module_ev e)
65 {
66 	switch(e) {
67 	case module_event_new: return "module_event_new";
68 	case module_event_pass: return "module_event_pass";
69 	case module_event_reply: return "module_event_reply";
70 	case module_event_noreply: return "module_event_noreply";
71 	case module_event_capsfail: return "module_event_capsfail";
72 	case module_event_moddone: return "module_event_moddone";
73 	case module_event_error: return "module_event_error";
74 	}
75 	return "bad_event_value";
76 }
77 
78 void errinf(struct module_qstate* qstate, const char* str)
79 {
80 	errinf_ede(qstate, str, LDNS_EDE_NONE);
81 }
82 
83 void errinf_ede(struct module_qstate* qstate,
84 	const char* str, sldns_ede_code reason_bogus)
85 {
86 	struct errinf_strlist* p;
87 	if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str)
88 		return;
89 	p = (struct errinf_strlist*)regional_alloc(qstate->region, sizeof(*p));
90 	if(!p) {
91 		log_err("malloc failure in validator-error-info string");
92 		return;
93 	}
94 	p->next = NULL;
95 	p->str = regional_strdup(qstate->region, str);
96 	p->reason_bogus = reason_bogus;
97 	if(!p->str) {
98 		log_err("malloc failure in validator-error-info string");
99 		return;
100 	}
101 	/* add at end */
102 	if(qstate->errinf) {
103 		struct errinf_strlist* q = qstate->errinf;
104 		while(q->next)
105 			q = q->next;
106 		q->next = p;
107 	} else	qstate->errinf = p;
108 }
109 
110 void errinf_origin(struct module_qstate* qstate, struct sock_list *origin)
111 {
112 	struct sock_list* p;
113 	if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
114 		return;
115 	for(p=origin; p; p=p->next) {
116 		char buf[256];
117 		if(p == origin)
118 			snprintf(buf, sizeof(buf), "from ");
119 		else	snprintf(buf, sizeof(buf), "and ");
120 		if(p->len == 0)
121 			snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf),
122 				"cache");
123 		else
124 			addr_to_str(&p->addr, p->len, buf+strlen(buf),
125 				sizeof(buf)-strlen(buf));
126 		errinf(qstate, buf);
127 	}
128 }
129 
130 char* errinf_to_str_bogus(struct module_qstate* qstate)
131 {
132 	char buf[20480];
133 	char* p = buf;
134 	size_t left = sizeof(buf);
135 	struct errinf_strlist* s;
136 	char dname[LDNS_MAX_DOMAINLEN+1];
137 	char t[16], c[16];
138 	sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
139 	sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
140 	dname_str(qstate->qinfo.qname, dname);
141 	snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c);
142 	left -= strlen(p); p += strlen(p);
143 	if(!qstate->errinf)
144 		snprintf(p, left, " misc failure");
145 	else for(s=qstate->errinf; s; s=s->next) {
146 		snprintf(p, left, " %s", s->str);
147 		left -= strlen(p); p += strlen(p);
148 	}
149 	p = strdup(buf);
150 	if(!p)
151 		log_err("malloc failure in errinf_to_str");
152 	return p;
153 }
154 
155 sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate)
156 {
157 	struct errinf_strlist* s;
158 	for(s=qstate->errinf; s; s=s->next) {
159 		if (s->reason_bogus != LDNS_EDE_NONE) {
160 			return s->reason_bogus;
161 		}
162 	}
163 	return LDNS_EDE_NONE;
164 }
165 
166 char* errinf_to_str_servfail(struct module_qstate* qstate)
167 {
168 	char buf[20480];
169 	char* p = buf;
170 	size_t left = sizeof(buf);
171 	struct errinf_strlist* s;
172 	char dname[LDNS_MAX_DOMAINLEN+1];
173 	char t[16], c[16];
174 	sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
175 	sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
176 	dname_str(qstate->qinfo.qname, dname);
177 	snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c);
178 	left -= strlen(p); p += strlen(p);
179 	if(!qstate->errinf)
180 		snprintf(p, left, " misc failure");
181 	else for(s=qstate->errinf; s; s=s->next) {
182 		snprintf(p, left, " %s", s->str);
183 		left -= strlen(p); p += strlen(p);
184 	}
185 	p = strdup(buf);
186 	if(!p)
187 		log_err("malloc failure in errinf_to_str");
188 	return p;
189 }
190 
191 void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr)
192 {
193 	char buf[1024];
194 	char dname[LDNS_MAX_DOMAINLEN+1];
195 	char t[16], c[16];
196 	if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !rr)
197 		return;
198 	sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t));
199 	sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c));
200 	dname_str(rr->rk.dname, dname);
201 	snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c);
202 	errinf(qstate, buf);
203 }
204 
205 void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname)
206 {
207 	char b[1024];
208 	char buf[LDNS_MAX_DOMAINLEN+1];
209 	if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str || !dname)
210 		return;
211 	dname_str(dname, buf);
212 	snprintf(b, sizeof(b), "%s %s", str, buf);
213 	errinf(qstate, b);
214 }
215 
216 int
217 edns_known_options_init(struct module_env* env)
218 {
219 	env->edns_known_options_num = 0;
220 	env->edns_known_options = (struct edns_known_option*)calloc(
221 		MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option));
222 	if(!env->edns_known_options) return 0;
223 	return 1;
224 }
225 
226 void
227 edns_known_options_delete(struct module_env* env)
228 {
229 	free(env->edns_known_options);
230 	env->edns_known_options = NULL;
231 	env->edns_known_options_num = 0;
232 }
233 
234 int
235 edns_register_option(uint16_t opt_code, int bypass_cache_stage,
236 	int no_aggregation, struct module_env* env)
237 {
238 	size_t i;
239 	if(env->worker) {
240 		log_err("invalid edns registration: "
241 			"trying to register option after module init phase");
242 		return 0;
243 	}
244 
245 	/**
246 	 * Checking if we are full first is faster but it does not provide
247 	 * the option to change the flags when the array is full.
248 	 * It only impacts unbound initialization, leave it for now.
249 	 */
250 	/* Check if the option is already registered. */
251 	for(i=0; i<env->edns_known_options_num; i++)
252 		if(env->edns_known_options[i].opt_code == opt_code)
253 			break;
254 	/* If it is not yet registered check if we have space to add a new one. */
255 	if(i == env->edns_known_options_num) {
256 		if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) {
257 			log_err("invalid edns registration: maximum options reached");
258 			return 0;
259 		}
260 		env->edns_known_options_num++;
261 	}
262 	env->edns_known_options[i].opt_code = opt_code;
263 	env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage;
264 	env->edns_known_options[i].no_aggregation = no_aggregation;
265 	return 1;
266 }
267 
268 int
269 inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
270 	struct module_env* env, int id)
271 {
272 	struct inplace_cb* callback;
273 	struct inplace_cb** prevp;
274 	if(env->worker) {
275 		log_err("invalid edns callback registration: "
276 			"trying to register callback after module init phase");
277 		return 0;
278 	}
279 
280 	callback = (struct inplace_cb*)calloc(1, sizeof(*callback));
281 	if(callback == NULL) {
282 		log_err("out of memory during edns callback registration.");
283 		return 0;
284 	}
285 	callback->id = id;
286 	callback->next = NULL;
287 	callback->cb = cb;
288 	callback->cb_arg = cbarg;
289 
290 	prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
291 	/* append at end of list */
292 	while(*prevp != NULL)
293 		prevp = &((*prevp)->next);
294 	*prevp = callback;
295 	return 1;
296 }
297 
298 void
299 inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
300 	int id)
301 {
302 	struct inplace_cb* temp = env->inplace_cb_lists[type];
303 	struct inplace_cb* prev = NULL;
304 
305 	while(temp) {
306 		if(temp->id == id) {
307 			if(!prev) {
308 				env->inplace_cb_lists[type] = temp->next;
309 				free(temp);
310 				temp = env->inplace_cb_lists[type];
311 			}
312 			else {
313 				prev->next = temp->next;
314 				free(temp);
315 				temp = prev->next;
316 			}
317 		}
318 		else {
319 			prev = temp;
320 			temp = temp->next;
321 		}
322 	}
323 }
324 
325 struct edns_known_option*
326 edns_option_is_known(uint16_t opt_code, struct module_env* env)
327 {
328 	size_t i;
329 	for(i=0; i<env->edns_known_options_num; i++)
330 		if(env->edns_known_options[i].opt_code == opt_code)
331 			return env->edns_known_options + i;
332 	return NULL;
333 }
334 
335 int
336 edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
337 {
338 	size_t i;
339 	for(; list; list=list->next)
340 		for(i=0; i<env->edns_known_options_num; i++)
341 			if(env->edns_known_options[i].opt_code == list->opt_code &&
342 				env->edns_known_options[i].bypass_cache_stage == 1)
343 					return 1;
344 	return 0;
345 }
346 
347 int
348 unique_mesh_state(struct edns_option* list, struct module_env* env)
349 {
350 	size_t i;
351 	if(env->unique_mesh)
352 		return 1;
353 	for(; list; list=list->next)
354 		for(i=0; i<env->edns_known_options_num; i++)
355 			if(env->edns_known_options[i].opt_code == list->opt_code &&
356 				env->edns_known_options[i].no_aggregation == 1)
357 					return 1;
358 	return 0;
359 }
360 
361 void
362 log_edns_known_options(enum verbosity_value level, struct module_env* env)
363 {
364 	size_t i;
365 	char str[32], *s;
366 	size_t slen;
367 	if(env->edns_known_options_num > 0 && verbosity >= level) {
368 		verbose(level, "EDNS known options:");
369 		verbose(level, "  Code:    Bypass_cache_stage: Aggregate_mesh:");
370 		for(i=0; i<env->edns_known_options_num; i++) {
371 			s = str;
372 			slen = sizeof(str);
373 			(void)sldns_wire2str_edns_option_code_print(&s, &slen,
374 				env->edns_known_options[i].opt_code);
375 			verbose(level, "  %-8.8s %-19s %-15s", str,
376 				env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
377 				env->edns_known_options[i].no_aggregation?"NO":"YES");
378 		}
379 	}
380 }
381 
382 void
383 copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
384 	struct module_qstate* super)
385 {
386 	/* Overwrite super's was_ratelimited only when it was not set */
387 	if(!super->was_ratelimited) {
388 		super->was_ratelimited = qstate->was_ratelimited;
389 	}
390 }
391