xref: /openbsd-src/usr.sbin/unbound/util/module.c (revision 2bdc0ed15d5bcb82703283d48e5e85ed47cc34d3)
1933707f3Ssthen /*
2933707f3Ssthen  * util/module.c - module interface
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen /**
36933707f3Ssthen  * \file
37933707f3Ssthen  * Implementation of module.h.
38933707f3Ssthen  */
39933707f3Ssthen 
40933707f3Ssthen #include "config.h"
41933707f3Ssthen #include "util/module.h"
4277079be7Ssthen #include "sldns/wire2str.h"
430bdb4f62Ssthen #include "util/config_file.h"
440bdb4f62Ssthen #include "util/regional.h"
450bdb4f62Ssthen #include "util/data/dname.h"
460bdb4f62Ssthen #include "util/net_help.h"
47933707f3Ssthen 
48933707f3Ssthen const char*
strextstate(enum module_ext_state s)49933707f3Ssthen strextstate(enum module_ext_state s)
50933707f3Ssthen {
51933707f3Ssthen 	switch(s) {
52933707f3Ssthen 	case module_state_initial: return "module_state_initial";
53933707f3Ssthen 	case module_wait_reply: return "module_wait_reply";
54933707f3Ssthen 	case module_wait_module: return "module_wait_module";
55933707f3Ssthen 	case module_restart_next: return "module_restart_next";
56933707f3Ssthen 	case module_wait_subquery: return "module_wait_subquery";
57933707f3Ssthen 	case module_error: return "module_error";
58933707f3Ssthen 	case module_finished: return "module_finished";
59933707f3Ssthen 	}
60933707f3Ssthen 	return "bad_extstate_value";
61933707f3Ssthen }
62933707f3Ssthen 
63933707f3Ssthen const char*
strmodulevent(enum module_ev e)64933707f3Ssthen strmodulevent(enum module_ev e)
65933707f3Ssthen {
66933707f3Ssthen 	switch(e) {
67933707f3Ssthen 	case module_event_new: return "module_event_new";
68933707f3Ssthen 	case module_event_pass: return "module_event_pass";
69933707f3Ssthen 	case module_event_reply: return "module_event_reply";
70933707f3Ssthen 	case module_event_noreply: return "module_event_noreply";
71933707f3Ssthen 	case module_event_capsfail: return "module_event_capsfail";
72933707f3Ssthen 	case module_event_moddone: return "module_event_moddone";
73933707f3Ssthen 	case module_event_error: return "module_event_error";
74933707f3Ssthen 	}
75933707f3Ssthen 	return "bad_event_value";
76933707f3Ssthen }
7777079be7Ssthen 
errinf(struct module_qstate * qstate,const char * str)780bdb4f62Ssthen void errinf(struct module_qstate* qstate, const char* str)
790bdb4f62Ssthen {
800bdb4f62Ssthen 	errinf_ede(qstate, str, LDNS_EDE_NONE);
810bdb4f62Ssthen }
820bdb4f62Ssthen 
errinf_ede(struct module_qstate * qstate,const char * str,sldns_ede_code reason_bogus)830bdb4f62Ssthen void errinf_ede(struct module_qstate* qstate,
840bdb4f62Ssthen 	const char* str, sldns_ede_code reason_bogus)
850bdb4f62Ssthen {
860bdb4f62Ssthen 	struct errinf_strlist* p;
878b7325afSsthen 	if(!str || (qstate->env->cfg->val_log_level < 2 &&
888b7325afSsthen 		!qstate->env->cfg->log_servfail)) {
890bdb4f62Ssthen 		return;
908b7325afSsthen 	}
910bdb4f62Ssthen 	p = (struct errinf_strlist*)regional_alloc(qstate->region, sizeof(*p));
920bdb4f62Ssthen 	if(!p) {
930bdb4f62Ssthen 		log_err("malloc failure in validator-error-info string");
940bdb4f62Ssthen 		return;
950bdb4f62Ssthen 	}
960bdb4f62Ssthen 	p->next = NULL;
970bdb4f62Ssthen 	p->str = regional_strdup(qstate->region, str);
980bdb4f62Ssthen 	p->reason_bogus = reason_bogus;
990bdb4f62Ssthen 	if(!p->str) {
1000bdb4f62Ssthen 		log_err("malloc failure in validator-error-info string");
1010bdb4f62Ssthen 		return;
1020bdb4f62Ssthen 	}
1030bdb4f62Ssthen 	/* add at end */
1040bdb4f62Ssthen 	if(qstate->errinf) {
1050bdb4f62Ssthen 		struct errinf_strlist* q = qstate->errinf;
1060bdb4f62Ssthen 		while(q->next)
1070bdb4f62Ssthen 			q = q->next;
1080bdb4f62Ssthen 		q->next = p;
1090bdb4f62Ssthen 	} else	qstate->errinf = p;
1100bdb4f62Ssthen }
1110bdb4f62Ssthen 
errinf_origin(struct module_qstate * qstate,struct sock_list * origin)1120bdb4f62Ssthen void errinf_origin(struct module_qstate* qstate, struct sock_list *origin)
1130bdb4f62Ssthen {
1140bdb4f62Ssthen 	struct sock_list* p;
1150bdb4f62Ssthen 	if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
1160bdb4f62Ssthen 		return;
1170bdb4f62Ssthen 	for(p=origin; p; p=p->next) {
1180bdb4f62Ssthen 		char buf[256];
1190bdb4f62Ssthen 		if(p == origin)
1200bdb4f62Ssthen 			snprintf(buf, sizeof(buf), "from ");
1210bdb4f62Ssthen 		else	snprintf(buf, sizeof(buf), "and ");
1220bdb4f62Ssthen 		if(p->len == 0)
1230bdb4f62Ssthen 			snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf),
1240bdb4f62Ssthen 				"cache");
1250bdb4f62Ssthen 		else
1260bdb4f62Ssthen 			addr_to_str(&p->addr, p->len, buf+strlen(buf),
1270bdb4f62Ssthen 				sizeof(buf)-strlen(buf));
1280bdb4f62Ssthen 		errinf(qstate, buf);
1290bdb4f62Ssthen 	}
1300bdb4f62Ssthen }
1310bdb4f62Ssthen 
errinf_to_str_bogus(struct module_qstate * qstate,struct regional * region)132*2bdc0ed1Ssthen char* errinf_to_str_bogus(struct module_qstate* qstate, struct regional* region)
1330bdb4f62Ssthen {
1340bdb4f62Ssthen 	char buf[20480];
1350bdb4f62Ssthen 	char* p = buf;
1360bdb4f62Ssthen 	size_t left = sizeof(buf);
1370bdb4f62Ssthen 	struct errinf_strlist* s;
1380bdb4f62Ssthen 	char dname[LDNS_MAX_DOMAINLEN+1];
1390bdb4f62Ssthen 	char t[16], c[16];
1400bdb4f62Ssthen 	sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
1410bdb4f62Ssthen 	sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
1420bdb4f62Ssthen 	dname_str(qstate->qinfo.qname, dname);
1430bdb4f62Ssthen 	snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c);
1440bdb4f62Ssthen 	left -= strlen(p); p += strlen(p);
1450bdb4f62Ssthen 	if(!qstate->errinf)
1460bdb4f62Ssthen 		snprintf(p, left, " misc failure");
1470bdb4f62Ssthen 	else for(s=qstate->errinf; s; s=s->next) {
1480bdb4f62Ssthen 		snprintf(p, left, " %s", s->str);
1490bdb4f62Ssthen 		left -= strlen(p); p += strlen(p);
1500bdb4f62Ssthen 	}
151*2bdc0ed1Ssthen 	if(region)
152*2bdc0ed1Ssthen 		p = regional_strdup(region, buf);
153*2bdc0ed1Ssthen 	else
1540bdb4f62Ssthen 		p = strdup(buf);
1550bdb4f62Ssthen 	if(!p)
1560bdb4f62Ssthen 		log_err("malloc failure in errinf_to_str");
1570bdb4f62Ssthen 	return p;
1580bdb4f62Ssthen }
1590bdb4f62Ssthen 
1608b7325afSsthen /* Try to find the latest (most specific) dnssec failure */
errinf_to_reason_bogus(struct module_qstate * qstate)1610bdb4f62Ssthen sldns_ede_code errinf_to_reason_bogus(struct module_qstate* qstate)
1620bdb4f62Ssthen {
1630bdb4f62Ssthen 	struct errinf_strlist* s;
1648b7325afSsthen 	sldns_ede_code ede = LDNS_EDE_NONE;
1650bdb4f62Ssthen 	for(s=qstate->errinf; s; s=s->next) {
1668b7325afSsthen 		if(s->reason_bogus == LDNS_EDE_NONE) continue;
1678b7325afSsthen 		if(ede != LDNS_EDE_NONE
1688b7325afSsthen 			&& ede != LDNS_EDE_DNSSEC_BOGUS
1698b7325afSsthen 			&& s->reason_bogus == LDNS_EDE_DNSSEC_BOGUS) continue;
1708b7325afSsthen 		ede = s->reason_bogus;
1710bdb4f62Ssthen 	}
1728b7325afSsthen 	return ede;
1730bdb4f62Ssthen }
1740bdb4f62Ssthen 
errinf_to_str_servfail(struct module_qstate * qstate)1750bdb4f62Ssthen char* errinf_to_str_servfail(struct module_qstate* qstate)
1760bdb4f62Ssthen {
1770bdb4f62Ssthen 	char buf[20480];
1780bdb4f62Ssthen 	char* p = buf;
1790bdb4f62Ssthen 	size_t left = sizeof(buf);
1800bdb4f62Ssthen 	struct errinf_strlist* s;
1810bdb4f62Ssthen 	char dname[LDNS_MAX_DOMAINLEN+1];
1820bdb4f62Ssthen 	char t[16], c[16];
1830bdb4f62Ssthen 	sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
1840bdb4f62Ssthen 	sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
1850bdb4f62Ssthen 	dname_str(qstate->qinfo.qname, dname);
1860bdb4f62Ssthen 	snprintf(p, left, "SERVFAIL <%s %s %s>:", dname, t, c);
1870bdb4f62Ssthen 	left -= strlen(p); p += strlen(p);
1880bdb4f62Ssthen 	if(!qstate->errinf)
1890bdb4f62Ssthen 		snprintf(p, left, " misc failure");
1900bdb4f62Ssthen 	else for(s=qstate->errinf; s; s=s->next) {
1910bdb4f62Ssthen 		snprintf(p, left, " %s", s->str);
1920bdb4f62Ssthen 		left -= strlen(p); p += strlen(p);
1930bdb4f62Ssthen 	}
194*2bdc0ed1Ssthen 	p = regional_strdup(qstate->region, buf);
1950bdb4f62Ssthen 	if(!p)
1960bdb4f62Ssthen 		log_err("malloc failure in errinf_to_str");
1970bdb4f62Ssthen 	return p;
1980bdb4f62Ssthen }
1990bdb4f62Ssthen 
errinf_to_str_misc(struct module_qstate * qstate)200d896b962Ssthen char* errinf_to_str_misc(struct module_qstate* qstate)
201d896b962Ssthen {
202d896b962Ssthen 	char buf[20480];
203d896b962Ssthen 	char* p = buf;
204d896b962Ssthen 	size_t left = sizeof(buf);
205d896b962Ssthen 	struct errinf_strlist* s;
206d896b962Ssthen 	if(!qstate->errinf)
207d896b962Ssthen 		snprintf(p, left, "misc failure");
208d896b962Ssthen 	else for(s=qstate->errinf; s; s=s->next) {
209d896b962Ssthen 		snprintf(p, left, "%s%s", (s==qstate->errinf?"":" "), s->str);
210d896b962Ssthen 		left -= strlen(p); p += strlen(p);
211d896b962Ssthen 	}
212*2bdc0ed1Ssthen 	p = regional_strdup(qstate->region, buf);
213d896b962Ssthen 	if(!p)
214d896b962Ssthen 		log_err("malloc failure in errinf_to_str");
215d896b962Ssthen 	return p;
216d896b962Ssthen }
217d896b962Ssthen 
errinf_rrset(struct module_qstate * qstate,struct ub_packed_rrset_key * rr)2180bdb4f62Ssthen void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr)
2190bdb4f62Ssthen {
2200bdb4f62Ssthen 	char buf[1024];
2210bdb4f62Ssthen 	char dname[LDNS_MAX_DOMAINLEN+1];
2220bdb4f62Ssthen 	char t[16], c[16];
2230bdb4f62Ssthen 	if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !rr)
2240bdb4f62Ssthen 		return;
2250bdb4f62Ssthen 	sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t));
2260bdb4f62Ssthen 	sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c));
2270bdb4f62Ssthen 	dname_str(rr->rk.dname, dname);
2280bdb4f62Ssthen 	snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c);
2290bdb4f62Ssthen 	errinf(qstate, buf);
2300bdb4f62Ssthen }
2310bdb4f62Ssthen 
errinf_dname(struct module_qstate * qstate,const char * str,uint8_t * dname)2320bdb4f62Ssthen void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname)
2330bdb4f62Ssthen {
2340bdb4f62Ssthen 	char b[1024];
2350bdb4f62Ssthen 	char buf[LDNS_MAX_DOMAINLEN+1];
2360bdb4f62Ssthen 	if((qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail) || !str || !dname)
2370bdb4f62Ssthen 		return;
2380bdb4f62Ssthen 	dname_str(dname, buf);
2390bdb4f62Ssthen 	snprintf(b, sizeof(b), "%s %s", str, buf);
2400bdb4f62Ssthen 	errinf(qstate, b);
2410bdb4f62Ssthen }
2420bdb4f62Ssthen 
24377079be7Ssthen int
edns_known_options_init(struct module_env * env)24477079be7Ssthen edns_known_options_init(struct module_env* env)
24577079be7Ssthen {
24677079be7Ssthen 	env->edns_known_options_num = 0;
24777079be7Ssthen 	env->edns_known_options = (struct edns_known_option*)calloc(
24877079be7Ssthen 		MAX_KNOWN_EDNS_OPTS, sizeof(struct edns_known_option));
24977079be7Ssthen 	if(!env->edns_known_options) return 0;
25077079be7Ssthen 	return 1;
25177079be7Ssthen }
25277079be7Ssthen 
25377079be7Ssthen void
edns_known_options_delete(struct module_env * env)25477079be7Ssthen edns_known_options_delete(struct module_env* env)
25577079be7Ssthen {
25677079be7Ssthen 	free(env->edns_known_options);
25777079be7Ssthen 	env->edns_known_options = NULL;
25877079be7Ssthen 	env->edns_known_options_num = 0;
25977079be7Ssthen }
26077079be7Ssthen 
26177079be7Ssthen int
edns_register_option(uint16_t opt_code,int bypass_cache_stage,int no_aggregation,struct module_env * env)26277079be7Ssthen edns_register_option(uint16_t opt_code, int bypass_cache_stage,
26377079be7Ssthen 	int no_aggregation, struct module_env* env)
26477079be7Ssthen {
26577079be7Ssthen 	size_t i;
26677079be7Ssthen 	if(env->worker) {
26777079be7Ssthen 		log_err("invalid edns registration: "
26877079be7Ssthen 			"trying to register option after module init phase");
26977079be7Ssthen 		return 0;
27077079be7Ssthen 	}
27177079be7Ssthen 
27277079be7Ssthen 	/**
27377079be7Ssthen 	 * Checking if we are full first is faster but it does not provide
27477079be7Ssthen 	 * the option to change the flags when the array is full.
27577079be7Ssthen 	 * It only impacts unbound initialization, leave it for now.
27677079be7Ssthen 	 */
27777079be7Ssthen 	/* Check if the option is already registered. */
27877079be7Ssthen 	for(i=0; i<env->edns_known_options_num; i++)
27977079be7Ssthen 		if(env->edns_known_options[i].opt_code == opt_code)
28077079be7Ssthen 			break;
28177079be7Ssthen 	/* If it is not yet registered check if we have space to add a new one. */
28277079be7Ssthen 	if(i == env->edns_known_options_num) {
28377079be7Ssthen 		if(env->edns_known_options_num >= MAX_KNOWN_EDNS_OPTS) {
28477079be7Ssthen 			log_err("invalid edns registration: maximum options reached");
28577079be7Ssthen 			return 0;
28677079be7Ssthen 		}
28777079be7Ssthen 		env->edns_known_options_num++;
28877079be7Ssthen 	}
28977079be7Ssthen 	env->edns_known_options[i].opt_code = opt_code;
29077079be7Ssthen 	env->edns_known_options[i].bypass_cache_stage = bypass_cache_stage;
29177079be7Ssthen 	env->edns_known_options[i].no_aggregation = no_aggregation;
29277079be7Ssthen 	return 1;
29377079be7Ssthen }
29477079be7Ssthen 
2952be9e038Ssthen int
inplace_cb_register(void * cb,enum inplace_cb_list_type type,void * cbarg,struct module_env * env,int id)2962be9e038Ssthen inplace_cb_register(void* cb, enum inplace_cb_list_type type, void* cbarg,
2972be9e038Ssthen 	struct module_env* env, int id)
29877079be7Ssthen {
2992be9e038Ssthen 	struct inplace_cb* callback;
3002be9e038Ssthen 	struct inplace_cb** prevp;
30177079be7Ssthen 	if(env->worker) {
30277079be7Ssthen 		log_err("invalid edns callback registration: "
30377079be7Ssthen 			"trying to register callback after module init phase");
30477079be7Ssthen 		return 0;
30577079be7Ssthen 	}
30677079be7Ssthen 
3072be9e038Ssthen 	callback = (struct inplace_cb*)calloc(1, sizeof(*callback));
30877079be7Ssthen 	if(callback == NULL) {
30977079be7Ssthen 		log_err("out of memory during edns callback registration.");
31077079be7Ssthen 		return 0;
31177079be7Ssthen 	}
3122be9e038Ssthen 	callback->id = id;
31377079be7Ssthen 	callback->next = NULL;
31477079be7Ssthen 	callback->cb = cb;
3152be9e038Ssthen 	callback->cb_arg = cbarg;
31677079be7Ssthen 
3172be9e038Ssthen 	prevp = (struct inplace_cb**) &env->inplace_cb_lists[type];
31877079be7Ssthen 	/* append at end of list */
31977079be7Ssthen 	while(*prevp != NULL)
32077079be7Ssthen 		prevp = &((*prevp)->next);
32177079be7Ssthen 	*prevp = callback;
32277079be7Ssthen 	return 1;
32377079be7Ssthen }
32477079be7Ssthen 
32577079be7Ssthen void
inplace_cb_delete(struct module_env * env,enum inplace_cb_list_type type,int id)3262be9e038Ssthen inplace_cb_delete(struct module_env* env, enum inplace_cb_list_type type,
3272be9e038Ssthen 	int id)
32877079be7Ssthen {
3292be9e038Ssthen 	struct inplace_cb* temp = env->inplace_cb_lists[type];
3302be9e038Ssthen 	struct inplace_cb* prev = NULL;
33177079be7Ssthen 
3322be9e038Ssthen 	while(temp) {
3332be9e038Ssthen 		if(temp->id == id) {
3342be9e038Ssthen 			if(!prev) {
3352be9e038Ssthen 				env->inplace_cb_lists[type] = temp->next;
3362be9e038Ssthen 				free(temp);
3372be9e038Ssthen 				temp = env->inplace_cb_lists[type];
3382be9e038Ssthen 			}
3392be9e038Ssthen 			else {
3402be9e038Ssthen 				prev->next = temp->next;
3412be9e038Ssthen 				free(temp);
3422be9e038Ssthen 				temp = prev->next;
3432be9e038Ssthen 			}
3442be9e038Ssthen 		}
3452be9e038Ssthen 		else {
3462be9e038Ssthen 			prev = temp;
3472be9e038Ssthen 			temp = temp->next;
3482be9e038Ssthen 		}
3492be9e038Ssthen 	}
35077079be7Ssthen }
35177079be7Ssthen 
35277079be7Ssthen struct edns_known_option*
edns_option_is_known(uint16_t opt_code,struct module_env * env)35377079be7Ssthen edns_option_is_known(uint16_t opt_code, struct module_env* env)
35477079be7Ssthen {
35577079be7Ssthen 	size_t i;
35677079be7Ssthen 	for(i=0; i<env->edns_known_options_num; i++)
35777079be7Ssthen 		if(env->edns_known_options[i].opt_code == opt_code)
35877079be7Ssthen 			return env->edns_known_options + i;
35977079be7Ssthen 	return NULL;
36077079be7Ssthen }
36177079be7Ssthen 
36277079be7Ssthen int
edns_bypass_cache_stage(struct edns_option * list,struct module_env * env)36377079be7Ssthen edns_bypass_cache_stage(struct edns_option* list, struct module_env* env)
36477079be7Ssthen {
36577079be7Ssthen 	size_t i;
36677079be7Ssthen 	for(; list; list=list->next)
36777079be7Ssthen 		for(i=0; i<env->edns_known_options_num; i++)
36877079be7Ssthen 			if(env->edns_known_options[i].opt_code == list->opt_code &&
36977079be7Ssthen 				env->edns_known_options[i].bypass_cache_stage == 1)
37077079be7Ssthen 					return 1;
37177079be7Ssthen 	return 0;
37277079be7Ssthen }
37377079be7Ssthen 
37477079be7Ssthen int
unique_mesh_state(struct edns_option * list,struct module_env * env)3752be9e038Ssthen unique_mesh_state(struct edns_option* list, struct module_env* env)
37677079be7Ssthen {
37777079be7Ssthen 	size_t i;
3782be9e038Ssthen 	if(env->unique_mesh)
3792be9e038Ssthen 		return 1;
38077079be7Ssthen 	for(; list; list=list->next)
38177079be7Ssthen 		for(i=0; i<env->edns_known_options_num; i++)
38277079be7Ssthen 			if(env->edns_known_options[i].opt_code == list->opt_code &&
38377079be7Ssthen 				env->edns_known_options[i].no_aggregation == 1)
38477079be7Ssthen 					return 1;
38577079be7Ssthen 	return 0;
38677079be7Ssthen }
38777079be7Ssthen 
38877079be7Ssthen void
log_edns_known_options(enum verbosity_value level,struct module_env * env)38977079be7Ssthen log_edns_known_options(enum verbosity_value level, struct module_env* env)
39077079be7Ssthen {
39177079be7Ssthen 	size_t i;
39277079be7Ssthen 	char str[32], *s;
39377079be7Ssthen 	size_t slen;
39477079be7Ssthen 	if(env->edns_known_options_num > 0 && verbosity >= level) {
39577079be7Ssthen 		verbose(level, "EDNS known options:");
39677079be7Ssthen 		verbose(level, "  Code:    Bypass_cache_stage: Aggregate_mesh:");
39777079be7Ssthen 		for(i=0; i<env->edns_known_options_num; i++) {
39877079be7Ssthen 			s = str;
39977079be7Ssthen 			slen = sizeof(str);
40077079be7Ssthen 			(void)sldns_wire2str_edns_option_code_print(&s, &slen,
40177079be7Ssthen 				env->edns_known_options[i].opt_code);
40277079be7Ssthen 			verbose(level, "  %-8.8s %-19s %-15s", str,
40377079be7Ssthen 				env->edns_known_options[i].bypass_cache_stage?"YES":"NO",
40477079be7Ssthen 				env->edns_known_options[i].no_aggregation?"NO":"YES");
40577079be7Ssthen 		}
40677079be7Ssthen 	}
40777079be7Ssthen }
4082308e98cSsthen 
4092308e98cSsthen void
copy_state_to_super(struct module_qstate * qstate,int ATTR_UNUSED (id),struct module_qstate * super)4102308e98cSsthen copy_state_to_super(struct module_qstate* qstate, int ATTR_UNUSED(id),
4112308e98cSsthen 	struct module_qstate* super)
4122308e98cSsthen {
4132308e98cSsthen 	/* Overwrite super's was_ratelimited only when it was not set */
4142308e98cSsthen 	if(!super->was_ratelimited) {
4152308e98cSsthen 		super->was_ratelimited = qstate->was_ratelimited;
4162308e98cSsthen 	}
4172308e98cSsthen }
418