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