xref: /openbsd-src/usr.sbin/unbound/daemon/worker.c (revision 98bc733b08604094f4138174a0ee0bb9faaca4bd)
1933707f3Ssthen /*
2933707f3Ssthen  * daemon/worker.c - worker that handles a pending list of requests.
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
240b68ff31Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
250b68ff31Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
260b68ff31Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
270b68ff31Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
280b68ff31Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
290b68ff31Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
300b68ff31Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
310b68ff31Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
320b68ff31Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
330b68ff31Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen /**
37933707f3Ssthen  * \file
38933707f3Ssthen  *
39933707f3Ssthen  * This file implements the worker that handles callbacks on events, for
40933707f3Ssthen  * pending requests.
41933707f3Ssthen  */
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "util/log.h"
44933707f3Ssthen #include "util/net_help.h"
45933707f3Ssthen #include "util/random.h"
46933707f3Ssthen #include "daemon/worker.h"
47933707f3Ssthen #include "daemon/daemon.h"
48933707f3Ssthen #include "daemon/remote.h"
49933707f3Ssthen #include "daemon/acl_list.h"
50933707f3Ssthen #include "util/netevent.h"
51933707f3Ssthen #include "util/config_file.h"
52933707f3Ssthen #include "util/module.h"
53933707f3Ssthen #include "util/regional.h"
54933707f3Ssthen #include "util/storage/slabhash.h"
55933707f3Ssthen #include "services/listen_dnsport.h"
56933707f3Ssthen #include "services/outside_network.h"
57933707f3Ssthen #include "services/outbound_list.h"
58933707f3Ssthen #include "services/cache/rrset.h"
59933707f3Ssthen #include "services/cache/infra.h"
60933707f3Ssthen #include "services/cache/dns.h"
61938a3a5eSflorian #include "services/authzone.h"
62933707f3Ssthen #include "services/mesh.h"
63933707f3Ssthen #include "services/localzone.h"
64eaf2578eSsthen #include "services/rpz.h"
65933707f3Ssthen #include "util/data/msgparse.h"
66933707f3Ssthen #include "util/data/msgencode.h"
67933707f3Ssthen #include "util/data/dname.h"
68933707f3Ssthen #include "util/fptr_wlist.h"
69d896b962Ssthen #include "util/proxy_protocol.h"
70933707f3Ssthen #include "util/tube.h"
712308e98cSsthen #include "util/edns.h"
728b7325afSsthen #include "util/timeval_func.h"
73933707f3Ssthen #include "iterator/iter_fwd.h"
74163a4143Ssthen #include "iterator/iter_hints.h"
75191f22c6Ssthen #include "iterator/iter_utils.h"
76933707f3Ssthen #include "validator/autotrust.h"
77163a4143Ssthen #include "validator/val_anchor.h"
782be9e038Ssthen #include "respip/respip.h"
79e10d3884Sbrad #include "libunbound/context.h"
80e10d3884Sbrad #include "libunbound/libworker.h"
81a58bff56Ssthen #include "sldns/sbuffer.h"
822be9e038Ssthen #include "sldns/wire2str.h"
832be9e038Ssthen #include "util/shm_side/shm_main.h"
842be9e038Ssthen #include "dnscrypt/dnscrypt.h"
85a3167c07Ssthen #include "dnstap/dtstream.h"
86933707f3Ssthen 
87933707f3Ssthen #ifdef HAVE_SYS_TYPES_H
88933707f3Ssthen #  include <sys/types.h>
89933707f3Ssthen #endif
90933707f3Ssthen #ifdef HAVE_NETDB_H
91933707f3Ssthen #include <netdb.h>
92933707f3Ssthen #endif
93933707f3Ssthen #include <signal.h>
94933707f3Ssthen #ifdef UB_ON_WINDOWS
95933707f3Ssthen #include "winrc/win_svc.h"
96933707f3Ssthen #endif
97933707f3Ssthen 
98933707f3Ssthen /** Size of an UDP datagram */
99933707f3Ssthen #define NORMAL_UDP_SIZE	512 /* bytes */
100a58bff56Ssthen /** ratelimit for error responses */
101a58bff56Ssthen #define ERROR_RATELIMIT 100 /* qps */
102933707f3Ssthen 
103933707f3Ssthen /**
104933707f3Ssthen  * seconds to add to prefetch leeway.  This is a TTL that expires old rrsets
105933707f3Ssthen  * earlier than they should in order to put the new update into the cache.
106933707f3Ssthen  * This additional value is to make sure that if not all TTLs are equal in
107933707f3Ssthen  * the message to be updated(and replaced), that rrsets with up to this much
108933707f3Ssthen  * extra TTL are also replaced.  This means that the resulting new message
109933707f3Ssthen  * will have (most likely) this TTL at least, avoiding very small 'split
110933707f3Ssthen  * second' TTLs due to operators choosing relative primes for TTLs (or so).
111933707f3Ssthen  * Also has to be at least one to break ties (and overwrite cached entry).
112933707f3Ssthen  */
113933707f3Ssthen #define PREFETCH_EXPIRY_ADD 60
114933707f3Ssthen 
115933707f3Ssthen /** Report on memory usage by this thread and global */
116933707f3Ssthen static void
117933707f3Ssthen worker_mem_report(struct worker* ATTR_UNUSED(worker),
118933707f3Ssthen 	struct serviced_query* ATTR_UNUSED(cur_serv))
119933707f3Ssthen {
120933707f3Ssthen #ifdef UNBOUND_ALLOC_STATS
12177079be7Ssthen 	/* measure memory leakage */
12277079be7Ssthen 	extern size_t unbound_mem_alloc, unbound_mem_freed;
123933707f3Ssthen 	/* debug func in validator module */
124933707f3Ssthen 	size_t total, front, back, mesh, msg, rrset, infra, ac, superac;
125163a4143Ssthen 	size_t me, iter, val, anch;
126933707f3Ssthen 	int i;
1272be9e038Ssthen #ifdef CLIENT_SUBNET
1282be9e038Ssthen 	size_t subnet = 0;
1292be9e038Ssthen #endif /* CLIENT_SUBNET */
130933707f3Ssthen 	if(verbosity < VERB_ALGO)
131933707f3Ssthen 		return;
132933707f3Ssthen 	front = listen_get_mem(worker->front);
133933707f3Ssthen 	back = outnet_get_mem(worker->back);
134933707f3Ssthen 	msg = slabhash_get_mem(worker->env.msg_cache);
135933707f3Ssthen 	rrset = slabhash_get_mem(&worker->env.rrset_cache->table);
136933707f3Ssthen 	infra = infra_get_mem(worker->env.infra_cache);
137933707f3Ssthen 	mesh = mesh_get_mem(worker->env.mesh);
1388b7325afSsthen 	ac = alloc_get_mem(worker->alloc);
139933707f3Ssthen 	superac = alloc_get_mem(&worker->daemon->superalloc);
140163a4143Ssthen 	anch = anchors_get_mem(worker->env.anchors);
141933707f3Ssthen 	iter = 0;
142933707f3Ssthen 	val = 0;
143933707f3Ssthen 	for(i=0; i<worker->env.mesh->mods.num; i++) {
144933707f3Ssthen 		fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh->
145933707f3Ssthen 			mods.mod[i]->get_mem));
146933707f3Ssthen 		if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0)
147933707f3Ssthen 			val += (*worker->env.mesh->mods.mod[i]->get_mem)
148933707f3Ssthen 				(&worker->env, i);
1492be9e038Ssthen #ifdef CLIENT_SUBNET
1502be9e038Ssthen 		else if(strcmp(worker->env.mesh->mods.mod[i]->name,
151e21c60efSsthen 			"subnetcache")==0)
1522be9e038Ssthen 			subnet += (*worker->env.mesh->mods.mod[i]->get_mem)
1532be9e038Ssthen 				(&worker->env, i);
1542be9e038Ssthen #endif /* CLIENT_SUBNET */
155933707f3Ssthen 		else	iter += (*worker->env.mesh->mods.mod[i]->get_mem)
156933707f3Ssthen 				(&worker->env, i);
157933707f3Ssthen 	}
158933707f3Ssthen 	me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig)
159933707f3Ssthen 		+ comm_point_get_mem(worker->cmd_com)
160933707f3Ssthen 		+ sizeof(worker->rndstate)
161933707f3Ssthen 		+ regional_get_mem(worker->scratchpad)
162933707f3Ssthen 		+ sizeof(*worker->env.scratch_buffer)
163*98bc733bSsthen 		+ sldns_buffer_capacity(worker->env.scratch_buffer);
164*98bc733bSsthen 	if(worker->daemon->env->fwds)
165*98bc733bSsthen 		log_info("forwards=%u", (unsigned)forwards_get_mem(worker->env.fwds));
166*98bc733bSsthen 	if(worker->daemon->env->hints)
167*98bc733bSsthen 		log_info("hints=%u", (unsigned)hints_get_mem(worker->env.hints));
168933707f3Ssthen 	if(worker->thread_num == 0)
169933707f3Ssthen 		me += acl_list_get_mem(worker->daemon->acl);
170933707f3Ssthen 	if(cur_serv) {
171933707f3Ssthen 		me += serviced_get_mem(cur_serv);
172933707f3Ssthen 	}
173933707f3Ssthen 	total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me;
1742be9e038Ssthen #ifdef CLIENT_SUBNET
1752be9e038Ssthen 	total += subnet;
1762be9e038Ssthen 	log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u "
1772be9e038Ssthen 		"rrset=%u infra=%u iter=%u val=%u subnet=%u anchors=%u "
1782be9e038Ssthen 		"alloccache=%u globalalloccache=%u me=%u",
1792be9e038Ssthen 		(unsigned)total, (unsigned)front, (unsigned)back,
1802be9e038Ssthen 		(unsigned)mesh, (unsigned)msg, (unsigned)rrset, (unsigned)infra,
1812be9e038Ssthen 		(unsigned)iter, (unsigned)val,
1822be9e038Ssthen 		(unsigned)subnet, (unsigned)anch, (unsigned)ac,
1832be9e038Ssthen 		(unsigned)superac, (unsigned)me);
1842be9e038Ssthen #else /* no CLIENT_SUBNET */
185933707f3Ssthen 	log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u "
186163a4143Ssthen 		"rrset=%u infra=%u iter=%u val=%u anchors=%u "
187933707f3Ssthen 		"alloccache=%u globalalloccache=%u me=%u",
188933707f3Ssthen 		(unsigned)total, (unsigned)front, (unsigned)back,
189933707f3Ssthen 		(unsigned)mesh, (unsigned)msg, (unsigned)rrset,
190163a4143Ssthen 		(unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch,
191163a4143Ssthen 		(unsigned)ac, (unsigned)superac, (unsigned)me);
1922be9e038Ssthen #endif /* CLIENT_SUBNET */
19377079be7Ssthen 	log_info("Total heap memory estimate: %u  total-alloc: %u  "
19477079be7Ssthen 		"total-free: %u", (unsigned)total,
19577079be7Ssthen 		(unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed);
196933707f3Ssthen #else /* no UNBOUND_ALLOC_STATS */
197933707f3Ssthen 	size_t val = 0;
1982be9e038Ssthen #ifdef CLIENT_SUBNET
1992be9e038Ssthen 	size_t subnet = 0;
2002be9e038Ssthen #endif /* CLIENT_SUBNET */
201933707f3Ssthen 	int i;
202933707f3Ssthen 	if(verbosity < VERB_QUERY)
203933707f3Ssthen 		return;
204933707f3Ssthen 	for(i=0; i<worker->env.mesh->mods.num; i++) {
205933707f3Ssthen 		fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh->
206933707f3Ssthen 			mods.mod[i]->get_mem));
207933707f3Ssthen 		if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0)
208933707f3Ssthen 			val += (*worker->env.mesh->mods.mod[i]->get_mem)
209933707f3Ssthen 				(&worker->env, i);
2102be9e038Ssthen #ifdef CLIENT_SUBNET
2112be9e038Ssthen 		else if(strcmp(worker->env.mesh->mods.mod[i]->name,
212e21c60efSsthen 			"subnetcache")==0)
2132be9e038Ssthen 			subnet += (*worker->env.mesh->mods.mod[i]->get_mem)
2142be9e038Ssthen 				(&worker->env, i);
2152be9e038Ssthen #endif /* CLIENT_SUBNET */
216933707f3Ssthen 	}
2172be9e038Ssthen #ifdef CLIENT_SUBNET
2182be9e038Ssthen 	verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u "
2192be9e038Ssthen 		"subnet=%u",
2202be9e038Ssthen 		(unsigned)slabhash_get_mem(worker->env.msg_cache),
2212be9e038Ssthen 		(unsigned)slabhash_get_mem(&worker->env.rrset_cache->table),
2222be9e038Ssthen 		(unsigned)infra_get_mem(worker->env.infra_cache),
2232be9e038Ssthen 		(unsigned)val, (unsigned)subnet);
2242be9e038Ssthen #else /* no CLIENT_SUBNET */
225933707f3Ssthen 	verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u",
226933707f3Ssthen 		(unsigned)slabhash_get_mem(worker->env.msg_cache),
227933707f3Ssthen 		(unsigned)slabhash_get_mem(&worker->env.rrset_cache->table),
228933707f3Ssthen 		(unsigned)infra_get_mem(worker->env.infra_cache),
229933707f3Ssthen 		(unsigned)val);
2302be9e038Ssthen #endif /* CLIENT_SUBNET */
231933707f3Ssthen #endif /* UNBOUND_ALLOC_STATS */
232933707f3Ssthen }
233933707f3Ssthen 
234933707f3Ssthen void
235933707f3Ssthen worker_send_cmd(struct worker* worker, enum worker_commands cmd)
236933707f3Ssthen {
237933707f3Ssthen 	uint32_t c = (uint32_t)htonl(cmd);
238933707f3Ssthen 	if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) {
239933707f3Ssthen 		log_err("worker send cmd %d failed", (int)cmd);
240933707f3Ssthen 	}
241933707f3Ssthen }
242933707f3Ssthen 
243933707f3Ssthen int
244933707f3Ssthen worker_handle_service_reply(struct comm_point* c, void* arg, int error,
245933707f3Ssthen 	struct comm_reply* reply_info)
246933707f3Ssthen {
247933707f3Ssthen 	struct outbound_entry* e = (struct outbound_entry*)arg;
248933707f3Ssthen 	struct worker* worker = e->qstate->env->worker;
249933707f3Ssthen 	struct serviced_query *sq = e->qsent;
250933707f3Ssthen 
251933707f3Ssthen 	verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
252933707f3Ssthen 	if(error != 0) {
253933707f3Ssthen 		mesh_report_reply(worker->env.mesh, e, reply_info, error);
254933707f3Ssthen 		worker_mem_report(worker, sq);
255933707f3Ssthen 		return 0;
256933707f3Ssthen 	}
257933707f3Ssthen 	/* sanity check. */
2580b68ff31Ssthen 	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
2590b68ff31Ssthen 		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
260933707f3Ssthen 			LDNS_PACKET_QUERY
2610b68ff31Ssthen 		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
262933707f3Ssthen 		/* error becomes timeout for the module as if this reply
263933707f3Ssthen 		 * never arrived. */
264933707f3Ssthen 		verbose(VERB_ALGO, "worker: bad reply handled as timeout");
265933707f3Ssthen 		mesh_report_reply(worker->env.mesh, e, reply_info,
266933707f3Ssthen 			NETEVENT_TIMEOUT);
267933707f3Ssthen 		worker_mem_report(worker, sq);
268933707f3Ssthen 		return 0;
269933707f3Ssthen 	}
270933707f3Ssthen 	mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR);
271933707f3Ssthen 	worker_mem_report(worker, sq);
272933707f3Ssthen 	return 0;
273933707f3Ssthen }
274933707f3Ssthen 
275a58bff56Ssthen /** ratelimit error replies
276a58bff56Ssthen  * @param worker: the worker struct with ratelimit counter
277a58bff56Ssthen  * @param err: error code that would be wanted.
278a58bff56Ssthen  * @return value of err if okay, or -1 if it should be discarded instead.
279a58bff56Ssthen  */
280a58bff56Ssthen static int
281a58bff56Ssthen worker_err_ratelimit(struct worker* worker, int err)
282a58bff56Ssthen {
283a58bff56Ssthen 	if(worker->err_limit_time == *worker->env.now) {
284a58bff56Ssthen 		/* see if limit is exceeded for this second */
285a58bff56Ssthen 		if(worker->err_limit_count++ > ERROR_RATELIMIT)
286a58bff56Ssthen 			return -1;
287a58bff56Ssthen 	} else {
288a58bff56Ssthen 		/* new second, new limits */
289a58bff56Ssthen 		worker->err_limit_time = *worker->env.now;
290a58bff56Ssthen 		worker->err_limit_count = 1;
291a58bff56Ssthen 	}
292a58bff56Ssthen 	return err;
293a58bff56Ssthen }
294a58bff56Ssthen 
2958b7325afSsthen /**
2968b7325afSsthen  * Structure holding the result of the worker_check_request function.
2978b7325afSsthen  * Based on configuration it could be called up to four times; ideally should
2988b7325afSsthen  * be called once.
2998b7325afSsthen  */
3008b7325afSsthen struct check_request_result {
3018b7325afSsthen 	int checked;
3028b7325afSsthen 	int value;
3038b7325afSsthen };
304933707f3Ssthen /** check request sanity.
305933707f3Ssthen  * @param pkt: the wire packet to examine for sanity.
306933707f3Ssthen  * @param worker: parameters for checking.
3078b7325afSsthen  * @param out: struct to update with the result.
308933707f3Ssthen */
3098b7325afSsthen static void
3108b7325afSsthen worker_check_request(sldns_buffer* pkt, struct worker* worker,
3118b7325afSsthen 	struct check_request_result* out)
312933707f3Ssthen {
3138b7325afSsthen 	if(out->checked) return;
3148b7325afSsthen 	out->checked = 1;
3150b68ff31Ssthen 	if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
316933707f3Ssthen 		verbose(VERB_QUERY, "request too short, discarded");
3178b7325afSsthen 		out->value = -1;
3188b7325afSsthen 		return;
319933707f3Ssthen 	}
3200b68ff31Ssthen 	if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
321933707f3Ssthen 		worker->daemon->cfg->harden_large_queries) {
322933707f3Ssthen 		verbose(VERB_QUERY, "request too large, discarded");
3238b7325afSsthen 		out->value = -1;
3248b7325afSsthen 		return;
325933707f3Ssthen 	}
3260b68ff31Ssthen 	if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
327933707f3Ssthen 		verbose(VERB_QUERY, "request has QR bit on, discarded");
3288b7325afSsthen 		out->value = -1;
3298b7325afSsthen 		return;
330933707f3Ssthen 	}
3310b68ff31Ssthen 	if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
3320b68ff31Ssthen 		LDNS_TC_CLR(sldns_buffer_begin(pkt));
333933707f3Ssthen 		verbose(VERB_QUERY, "request bad, has TC bit on");
3348b7325afSsthen 		out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
3358b7325afSsthen 		return;
336933707f3Ssthen 	}
33720237c55Ssthen 	if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY &&
33820237c55Ssthen 		LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY) {
339933707f3Ssthen 		verbose(VERB_QUERY, "request unknown opcode %d",
3400b68ff31Ssthen 			LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
3418b7325afSsthen 		out->value = worker_err_ratelimit(worker, LDNS_RCODE_NOTIMPL);
3428b7325afSsthen 		return;
343933707f3Ssthen 	}
3440b68ff31Ssthen 	if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
345933707f3Ssthen 		verbose(VERB_QUERY, "request wrong nr qd=%d",
3460b68ff31Ssthen 			LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
3478b7325afSsthen 		out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
3488b7325afSsthen 		return;
349933707f3Ssthen 	}
35020237c55Ssthen 	if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0 &&
35120237c55Ssthen 		(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 1 ||
35220237c55Ssthen 		LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_NOTIFY)) {
353933707f3Ssthen 		verbose(VERB_QUERY, "request wrong nr an=%d",
3540b68ff31Ssthen 			LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
3558b7325afSsthen 		out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
3568b7325afSsthen 		return;
357933707f3Ssthen 	}
3580b68ff31Ssthen 	if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
359933707f3Ssthen 		verbose(VERB_QUERY, "request wrong nr ns=%d",
3600b68ff31Ssthen 			LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
3618b7325afSsthen 		out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
3628b7325afSsthen 		return;
363933707f3Ssthen 	}
3640b68ff31Ssthen 	if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
365933707f3Ssthen 		verbose(VERB_QUERY, "request wrong nr ar=%d",
3660b68ff31Ssthen 			LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
3678b7325afSsthen 		out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
3688b7325afSsthen 		return;
369933707f3Ssthen 	}
3708b7325afSsthen 	out->value = 0;
3718b7325afSsthen 	return;
372933707f3Ssthen }
373933707f3Ssthen 
374933707f3Ssthen void
375933707f3Ssthen worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
376933707f3Ssthen 	size_t len, int error, void* arg)
377933707f3Ssthen {
378933707f3Ssthen 	struct worker* worker = (struct worker*)arg;
379933707f3Ssthen 	enum worker_commands cmd;
380933707f3Ssthen 	if(error != NETEVENT_NOERROR) {
381933707f3Ssthen 		free(msg);
382933707f3Ssthen 		if(error == NETEVENT_CLOSED)
383933707f3Ssthen 			comm_base_exit(worker->base);
384933707f3Ssthen 		else	log_info("control event: %d", error);
385933707f3Ssthen 		return;
386933707f3Ssthen 	}
387933707f3Ssthen 	if(len != sizeof(uint32_t)) {
388933707f3Ssthen 		fatal_exit("bad control msg length %d", (int)len);
389933707f3Ssthen 	}
3900b68ff31Ssthen 	cmd = sldns_read_uint32(msg);
391933707f3Ssthen 	free(msg);
392933707f3Ssthen 	switch(cmd) {
393933707f3Ssthen 	case worker_cmd_quit:
394933707f3Ssthen 		verbose(VERB_ALGO, "got control cmd quit");
395933707f3Ssthen 		comm_base_exit(worker->base);
396933707f3Ssthen 		break;
397933707f3Ssthen 	case worker_cmd_stats:
398933707f3Ssthen 		verbose(VERB_ALGO, "got control cmd stats");
399933707f3Ssthen 		server_stats_reply(worker, 1);
400933707f3Ssthen 		break;
401933707f3Ssthen 	case worker_cmd_stats_noreset:
402933707f3Ssthen 		verbose(VERB_ALGO, "got control cmd stats_noreset");
403933707f3Ssthen 		server_stats_reply(worker, 0);
404933707f3Ssthen 		break;
405933707f3Ssthen 	case worker_cmd_remote:
406933707f3Ssthen 		verbose(VERB_ALGO, "got control cmd remote");
407933707f3Ssthen 		daemon_remote_exec(worker);
408933707f3Ssthen 		break;
409933707f3Ssthen 	default:
410933707f3Ssthen 		log_err("bad command %d", (int)cmd);
411933707f3Ssthen 		break;
412933707f3Ssthen 	}
413933707f3Ssthen }
414933707f3Ssthen 
415933707f3Ssthen /** check if a delegation is secure */
416933707f3Ssthen static enum sec_status
417933707f3Ssthen check_delegation_secure(struct reply_info *rep)
418933707f3Ssthen {
419933707f3Ssthen 	/* return smallest security status */
420933707f3Ssthen 	size_t i;
421933707f3Ssthen 	enum sec_status sec = sec_status_secure;
422933707f3Ssthen 	enum sec_status s;
423933707f3Ssthen 	size_t num = rep->an_numrrsets + rep->ns_numrrsets;
424933707f3Ssthen 	/* check if answer and authority are OK */
425933707f3Ssthen 	for(i=0; i<num; i++) {
426933707f3Ssthen 		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
427933707f3Ssthen 			->security;
428933707f3Ssthen 		if(s < sec)
429933707f3Ssthen 			sec = s;
430933707f3Ssthen 	}
431933707f3Ssthen 	/* in additional, only unchecked triggers revalidation */
432933707f3Ssthen 	for(i=num; i<rep->rrset_count; i++) {
433933707f3Ssthen 		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
434933707f3Ssthen 			->security;
435933707f3Ssthen 		if(s == sec_status_unchecked)
436933707f3Ssthen 			return s;
437933707f3Ssthen 	}
438933707f3Ssthen 	return sec;
439933707f3Ssthen }
440933707f3Ssthen 
441933707f3Ssthen /** remove nonsecure from a delegation referral additional section */
442933707f3Ssthen static void
443933707f3Ssthen deleg_remove_nonsecure_additional(struct reply_info* rep)
444933707f3Ssthen {
445933707f3Ssthen 	/* we can simply edit it, since we are working in the scratch region */
446933707f3Ssthen 	size_t i;
447933707f3Ssthen 	enum sec_status s;
448933707f3Ssthen 
449933707f3Ssthen 	for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
450933707f3Ssthen 		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
451933707f3Ssthen 			->security;
452933707f3Ssthen 		if(s != sec_status_secure) {
453933707f3Ssthen 			memmove(rep->rrsets+i, rep->rrsets+i+1,
454933707f3Ssthen 				sizeof(struct ub_packed_rrset_key*)*
455933707f3Ssthen 				(rep->rrset_count - i - 1));
456933707f3Ssthen 			rep->ar_numrrsets--;
457933707f3Ssthen 			rep->rrset_count--;
458933707f3Ssthen 			i--;
459933707f3Ssthen 		}
460933707f3Ssthen 	}
461933707f3Ssthen }
462933707f3Ssthen 
463933707f3Ssthen /** answer nonrecursive query from the cache */
464933707f3Ssthen static int
465933707f3Ssthen answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
466933707f3Ssthen 	uint16_t id, uint16_t flags, struct comm_reply* repinfo,
467933707f3Ssthen 	struct edns_data* edns)
468933707f3Ssthen {
469933707f3Ssthen 	/* for a nonrecursive query return either:
470933707f3Ssthen 	 * 	o an error (servfail; we try to avoid this)
471933707f3Ssthen 	 * 	o a delegation (closest we have; this routine tries that)
472933707f3Ssthen 	 * 	o the answer (checked by answer_from_cache)
473933707f3Ssthen 	 *
474933707f3Ssthen 	 * So, grab a delegation from the rrset cache.
475933707f3Ssthen 	 * Then check if it needs validation, if so, this routine fails,
476933707f3Ssthen 	 * so that iterator can prime and validator can verify rrsets.
477933707f3Ssthen 	 */
478933707f3Ssthen 	uint16_t udpsize = edns->udp_size;
479933707f3Ssthen 	int secure = 0;
480e9c7b4efSsthen 	time_t timenow = *worker->env.now;
4818b7325afSsthen 	int has_cd_bit = (flags&BIT_CD);
4828b7325afSsthen 	int must_validate = (!has_cd_bit || worker->env.cfg->ignore_cd)
483933707f3Ssthen 		&& worker->env.need_to_validate;
484933707f3Ssthen 	struct dns_msg *msg = NULL;
485933707f3Ssthen 	struct delegpt *dp;
486933707f3Ssthen 
487933707f3Ssthen 	dp = dns_cache_find_delegation(&worker->env, qinfo->qname,
488933707f3Ssthen 		qinfo->qname_len, qinfo->qtype, qinfo->qclass,
489d1e2768aSsthen 		worker->scratchpad, &msg, timenow, 0, NULL, 0);
490933707f3Ssthen 	if(!dp) { /* no delegation, need to reprime */
491933707f3Ssthen 		return 0;
492933707f3Ssthen 	}
49377079be7Ssthen 	/* In case we have a local alias, copy it into the delegation message.
49477079be7Ssthen 	 * Shallow copy should be fine, as we'll be done with msg in this
49577079be7Ssthen 	 * function. */
49677079be7Ssthen 	msg->qinfo.local_alias = qinfo->local_alias;
497933707f3Ssthen 	if(must_validate) {
498933707f3Ssthen 		switch(check_delegation_secure(msg->rep)) {
499933707f3Ssthen 		case sec_status_unchecked:
500933707f3Ssthen 			/* some rrsets have not been verified yet, go and
501933707f3Ssthen 			 * let validator do that */
502933707f3Ssthen 			return 0;
503933707f3Ssthen 		case sec_status_bogus:
50420237c55Ssthen 		case sec_status_secure_sentinel_fail:
505933707f3Ssthen 			/* some rrsets are bogus, reply servfail */
506933707f3Ssthen 			edns->edns_version = EDNS_ADVERTISED_VERSION;
507933707f3Ssthen 			edns->udp_size = EDNS_ADVERTISED_SIZE;
508933707f3Ssthen 			edns->ext_rcode = 0;
509933707f3Ssthen 			edns->bits &= EDNS_DO;
51077079be7Ssthen 			if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL,
5119982a05dSsthen 				msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
5129982a05dSsthen 				worker->env.now_tv))
5132ee382b6Ssthen 					return 0;
5148b7325afSsthen 			/* Attach the cached EDE (RFC8914) */
5158b7325afSsthen 			if(worker->env.cfg->ede &&
5168b7325afSsthen 				msg->rep->reason_bogus != LDNS_EDE_NONE) {
5178b7325afSsthen 				edns_opt_list_append_ede(&edns->opt_list_out,
5188b7325afSsthen 					worker->scratchpad, msg->rep->reason_bogus,
5198b7325afSsthen 					msg->rep->reason_bogus_str);
5200bdb4f62Ssthen 			}
521933707f3Ssthen 			error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
522933707f3Ssthen 				&msg->qinfo, id, flags, edns);
523933707f3Ssthen 			if(worker->stats.extended) {
524933707f3Ssthen 				worker->stats.ans_bogus++;
525933707f3Ssthen 				worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++;
526933707f3Ssthen 			}
527933707f3Ssthen 			return 1;
528933707f3Ssthen 		case sec_status_secure:
529933707f3Ssthen 			/* all rrsets are secure */
530933707f3Ssthen 			/* remove non-secure rrsets from the add. section*/
531933707f3Ssthen 			if(worker->env.cfg->val_clean_additional)
532933707f3Ssthen 				deleg_remove_nonsecure_additional(msg->rep);
533933707f3Ssthen 			secure = 1;
534933707f3Ssthen 			break;
535933707f3Ssthen 		case sec_status_indeterminate:
536933707f3Ssthen 		case sec_status_insecure:
537933707f3Ssthen 		default:
538933707f3Ssthen 			/* not secure */
539933707f3Ssthen 			secure = 0;
540933707f3Ssthen 			break;
541933707f3Ssthen 		}
542933707f3Ssthen 	}
543933707f3Ssthen 	/* return this delegation from the cache */
544933707f3Ssthen 	edns->edns_version = EDNS_ADVERTISED_VERSION;
545933707f3Ssthen 	edns->udp_size = EDNS_ADVERTISED_SIZE;
546933707f3Ssthen 	edns->ext_rcode = 0;
547933707f3Ssthen 	edns->bits &= EDNS_DO;
548d896b962Ssthen 	if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO))
549d896b962Ssthen 		edns->edns_present = 0;
55077079be7Ssthen 	if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, msg->rep,
5519982a05dSsthen 		(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad,
5529982a05dSsthen 		worker->env.now_tv))
5532ee382b6Ssthen 			return 0;
554933707f3Ssthen 	msg->rep->flags |= BIT_QR|BIT_RA;
5558b7325afSsthen 	/* Attach the cached EDE (RFC8914) if CD bit is set and the answer is
5568b7325afSsthen 	 * bogus. */
5578b7325afSsthen 	if(worker->env.cfg->ede && has_cd_bit &&
5588b7325afSsthen 		(check_delegation_secure(msg->rep) == sec_status_bogus ||
5598b7325afSsthen 		check_delegation_secure(msg->rep) == sec_status_secure_sentinel_fail) &&
5608b7325afSsthen 		msg->rep->reason_bogus != LDNS_EDE_NONE) {
5618b7325afSsthen 		edns_opt_list_append_ede(&edns->opt_list_out,
5628b7325afSsthen 			worker->scratchpad, msg->rep->reason_bogus,
5638b7325afSsthen 			msg->rep->reason_bogus_str);
5648b7325afSsthen 	}
565e21c60efSsthen 	if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
566933707f3Ssthen 		repinfo->c->buffer, 0, 1, worker->scratchpad,
567933707f3Ssthen 		udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
56877079be7Ssthen 		if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, NULL,
5699982a05dSsthen 			LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
5709982a05dSsthen 			worker->env.now_tv))
571e21c60efSsthen 				edns->opt_list_inplace_cb_out = NULL;
572933707f3Ssthen 		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
573933707f3Ssthen 			&msg->qinfo, id, flags, edns);
574933707f3Ssthen 	}
575933707f3Ssthen 	if(worker->stats.extended) {
576933707f3Ssthen 		if(secure) worker->stats.ans_secure++;
577933707f3Ssthen 		server_stats_insrcode(&worker->stats, repinfo->c->buffer);
578933707f3Ssthen 	}
579933707f3Ssthen 	return 1;
580933707f3Ssthen }
581933707f3Ssthen 
5822be9e038Ssthen /** Apply, if applicable, a response IP action to a cached answer.
5832be9e038Ssthen  * If the answer is rewritten as a result of an action, '*encode_repp' will
5842be9e038Ssthen  * point to the reply info containing the modified answer.  '*encode_repp' will
5852be9e038Ssthen  * be intact otherwise.
5862be9e038Ssthen  * It returns 1 on success, 0 otherwise. */
5872be9e038Ssthen static int
5882be9e038Ssthen apply_respip_action(struct worker* worker, const struct query_info* qinfo,
5892be9e038Ssthen 	struct respip_client_info* cinfo, struct reply_info* rep,
59045872187Ssthen 	struct sockaddr_storage* addr, socklen_t addrlen,
59145872187Ssthen 	struct ub_packed_rrset_key** alias_rrset,
592eaf2578eSsthen 	struct reply_info** encode_repp, struct auth_zones* az)
5932be9e038Ssthen {
594eba819a2Ssthen 	struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
595eaf2578eSsthen 	actinfo.action = respip_none;
5962be9e038Ssthen 
5972be9e038Ssthen 	if(qinfo->qtype != LDNS_RR_TYPE_A &&
5982be9e038Ssthen 		qinfo->qtype != LDNS_RR_TYPE_AAAA &&
5992be9e038Ssthen 		qinfo->qtype != LDNS_RR_TYPE_ANY)
6002be9e038Ssthen 		return 1;
6012be9e038Ssthen 
6022be9e038Ssthen 	if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
6030bdb4f62Ssthen 		alias_rrset, 0, worker->scratchpad, az, NULL))
6042be9e038Ssthen 		return 0;
6052be9e038Ssthen 
6062be9e038Ssthen 	/* xxx_deny actions mean dropping the reply, unless the original reply
6072be9e038Ssthen 	 * was redirected to response-ip data. */
6088b7325afSsthen 	if(actinfo.action == respip_always_deny ||
6098b7325afSsthen 		((actinfo.action == respip_deny ||
6102be9e038Ssthen 		actinfo.action == respip_inform_deny) &&
6118b7325afSsthen 		*encode_repp == rep))
6122be9e038Ssthen 		*encode_repp = NULL;
6132be9e038Ssthen 
6142be9e038Ssthen 	/* If address info is returned, it means the action should be an
6152be9e038Ssthen 	 * 'inform' variant and the information should be logged. */
6162be9e038Ssthen 	if(actinfo.addrinfo) {
617eaf2578eSsthen 		respip_inform_print(&actinfo, qinfo->qname,
6182be9e038Ssthen 			qinfo->qtype, qinfo->qclass, qinfo->local_alias,
61945872187Ssthen 			addr, addrlen);
620eaf2578eSsthen 
621eaf2578eSsthen 		if(worker->stats.extended && actinfo.rpz_used) {
622eaf2578eSsthen 			if(actinfo.rpz_disabled)
623eaf2578eSsthen 				worker->stats.rpz_action[RPZ_DISABLED_ACTION]++;
624eaf2578eSsthen 			if(actinfo.rpz_cname_override)
625eaf2578eSsthen 				worker->stats.rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
626eaf2578eSsthen 			else
627eaf2578eSsthen 				worker->stats.rpz_action[
628eaf2578eSsthen 					respip_action_to_rpz_action(actinfo.action)]++;
629eaf2578eSsthen 		}
6302be9e038Ssthen 	}
6312be9e038Ssthen 
6322be9e038Ssthen 	return 1;
6332be9e038Ssthen }
6342be9e038Ssthen 
6352be9e038Ssthen /** answer query from the cache.
6362be9e038Ssthen  * Normally, the answer message will be built in repinfo->c->buffer; if the
6372be9e038Ssthen  * answer is supposed to be suppressed or the answer is supposed to be an
6382be9e038Ssthen  * incomplete CNAME chain, the buffer is explicitly cleared to signal the
6392be9e038Ssthen  * caller as such.  In the latter case *partial_rep will point to the incomplete
6402be9e038Ssthen  * reply, and this function is (possibly) supposed to be called again with that
6412be9e038Ssthen  * *partial_rep value to complete the chain.  In addition, if the query should
6422be9e038Ssthen  * be completely dropped, '*need_drop' will be set to 1. */
643933707f3Ssthen static int
644933707f3Ssthen answer_from_cache(struct worker* worker, struct query_info* qinfo,
645eaf2578eSsthen 	struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer,
646eaf2578eSsthen 	int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
6472be9e038Ssthen 	struct reply_info** partial_repp,
648933707f3Ssthen 	struct reply_info* rep, uint16_t id, uint16_t flags,
649933707f3Ssthen 	struct comm_reply* repinfo, struct edns_data* edns)
650933707f3Ssthen {
651e9c7b4efSsthen 	time_t timenow = *worker->env.now;
652933707f3Ssthen 	uint16_t udpsize = edns->udp_size;
6532be9e038Ssthen 	struct reply_info* encode_rep = rep;
6542be9e038Ssthen 	struct reply_info* partial_rep = *partial_repp;
6558b7325afSsthen 	int has_cd_bit = (flags&BIT_CD);
6568b7325afSsthen 	int must_validate = (!has_cd_bit || worker->env.cfg->ignore_cd)
657933707f3Ssthen 		&& worker->env.need_to_validate;
6582be9e038Ssthen 	*partial_repp = NULL;  /* avoid accidental further pass */
659eaf2578eSsthen 
660eaf2578eSsthen 	/* Check TTL */
661eaf2578eSsthen 	if(rep->ttl < timenow) {
662eaf2578eSsthen 		/* Check if we need to serve expired now */
663eaf2578eSsthen 		if(worker->env.cfg->serve_expired &&
6642bdc0ed1Ssthen 			!worker->env.cfg->serve_expired_client_timeout
6652bdc0ed1Ssthen #ifdef USE_CACHEDB
6662bdc0ed1Ssthen 			&& !(worker->env.cachedb_enabled &&
6672bdc0ed1Ssthen 			  worker->env.cfg->cachedb_check_when_serve_expired)
6682bdc0ed1Ssthen #endif
6692bdc0ed1Ssthen 			) {
6702308e98cSsthen 				if(worker->env.cfg->serve_expired_ttl &&
6712308e98cSsthen 					rep->serve_expired_ttl < timenow)
6722308e98cSsthen 					return 0;
6738b7325afSsthen 				/* Ignore expired failure answers */
6748b7325afSsthen 				if(FLAGS_GET_RCODE(rep->flags) !=
6758b7325afSsthen 					LDNS_RCODE_NOERROR &&
6768b7325afSsthen 					FLAGS_GET_RCODE(rep->flags) !=
6778b7325afSsthen 					LDNS_RCODE_NXDOMAIN &&
6788b7325afSsthen 					FLAGS_GET_RCODE(rep->flags) !=
6798b7325afSsthen 					LDNS_RCODE_YXDOMAIN)
6808b7325afSsthen 					return 0;
68177079be7Ssthen 				if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
68277079be7Ssthen 					return 0;
683eaf2578eSsthen 				*is_expired_answer = 1;
68477079be7Ssthen 		} else {
685933707f3Ssthen 			/* the rrsets may have been updated in the meantime.
686933707f3Ssthen 			 * we will refetch the message format from the
687933707f3Ssthen 			 * authoritative server
688933707f3Ssthen 			 */
689933707f3Ssthen 			return 0;
690933707f3Ssthen 		}
691eaf2578eSsthen 	} else {
692933707f3Ssthen 		if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
693933707f3Ssthen 			return 0;
69477079be7Ssthen 	}
695eaf2578eSsthen 	/* locked and ids and ttls are OK. */
696eaf2578eSsthen 
697933707f3Ssthen 	/* check CNAME chain (if any) */
698933707f3Ssthen 	if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
699933707f3Ssthen 		htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
700933707f3Ssthen 		htons(LDNS_RR_TYPE_DNAME))) {
701a58bff56Ssthen 		if(!reply_check_cname_chain(qinfo, rep)) {
702933707f3Ssthen 			/* cname chain invalid, redo iterator steps */
703933707f3Ssthen 			verbose(VERB_ALGO, "Cache reply: cname chain broken");
704550cf4a9Ssthen 			goto bail_out;
705933707f3Ssthen 		}
706933707f3Ssthen 	}
707933707f3Ssthen 	/* check security status of the cached answer */
70820237c55Ssthen 	if(must_validate && (rep->security == sec_status_bogus ||
70920237c55Ssthen 		rep->security == sec_status_secure_sentinel_fail)) {
710933707f3Ssthen 		/* BAD cached */
711933707f3Ssthen 		edns->edns_version = EDNS_ADVERTISED_VERSION;
712933707f3Ssthen 		edns->udp_size = EDNS_ADVERTISED_SIZE;
713933707f3Ssthen 		edns->ext_rcode = 0;
714933707f3Ssthen 		edns->bits &= EDNS_DO;
715d896b962Ssthen 		if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO))
716d896b962Ssthen 			edns->edns_present = 0;
71777079be7Ssthen 		if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
7189982a05dSsthen 			LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
7199982a05dSsthen 			worker->env.now_tv))
72077079be7Ssthen 			goto bail_out;
7218b7325afSsthen 		/* Attach the cached EDE (RFC8914) */
7228b7325afSsthen 		if(worker->env.cfg->ede && rep->reason_bogus != LDNS_EDE_NONE) {
7238b7325afSsthen 			edns_opt_list_append_ede(&edns->opt_list_out,
7248b7325afSsthen 					worker->scratchpad, rep->reason_bogus,
7258b7325afSsthen 					rep->reason_bogus_str);
7260bdb4f62Ssthen 		}
727933707f3Ssthen 		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
728933707f3Ssthen 			qinfo, id, flags, edns);
729933707f3Ssthen 		rrset_array_unlock_touch(worker->env.rrset_cache,
730933707f3Ssthen 			worker->scratchpad, rep->ref, rep->rrset_count);
731933707f3Ssthen 		if(worker->stats.extended) {
732933707f3Ssthen 			worker->stats.ans_bogus ++;
733933707f3Ssthen 			worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
734933707f3Ssthen 		}
735933707f3Ssthen 		return 1;
736933707f3Ssthen 	} else if(rep->security == sec_status_unchecked && must_validate) {
737933707f3Ssthen 		verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
738933707f3Ssthen 			"validation");
739933707f3Ssthen 		goto bail_out; /* need to validate cache entry first */
740933707f3Ssthen 	} else if(rep->security == sec_status_secure) {
741eaf2578eSsthen 		if(reply_all_rrsets_secure(rep)) {
742eaf2578eSsthen 			*is_secure_answer = 1;
743eaf2578eSsthen 		} else {
744933707f3Ssthen 			if(must_validate) {
745933707f3Ssthen 				verbose(VERB_ALGO, "Cache reply: secure entry"
746933707f3Ssthen 					" changed status");
747933707f3Ssthen 				goto bail_out; /* rrset changed, re-verify */
748933707f3Ssthen 			}
749eaf2578eSsthen 			*is_secure_answer = 0;
750933707f3Ssthen 		}
751eaf2578eSsthen 	} else *is_secure_answer = 0;
752933707f3Ssthen 
753933707f3Ssthen 	edns->edns_version = EDNS_ADVERTISED_VERSION;
754933707f3Ssthen 	edns->udp_size = EDNS_ADVERTISED_SIZE;
755933707f3Ssthen 	edns->ext_rcode = 0;
756933707f3Ssthen 	edns->bits &= EDNS_DO;
757d896b962Ssthen 	if(worker->env.cfg->disable_edns_do && (edns->bits & EDNS_DO))
758d896b962Ssthen 		edns->edns_present = 0;
7592be9e038Ssthen 	*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
760eaf2578eSsthen 	if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
761eaf2578eSsthen 		!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
76245872187Ssthen 		&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
763eaf2578eSsthen 		&encode_rep, worker->env.auth_zones)) {
7642be9e038Ssthen 		goto bail_out;
7652be9e038Ssthen 	} else if(partial_rep &&
7662be9e038Ssthen 		!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
767eaf2578eSsthen 		must_validate, &encode_rep, worker->scratchpad,
768eaf2578eSsthen 		worker->env.auth_zones)) {
7692be9e038Ssthen 		goto bail_out;
7702be9e038Ssthen 	}
771eaf2578eSsthen 	if(encode_rep != rep) {
772eaf2578eSsthen 		/* if rewritten, it can't be considered "secure" */
773eaf2578eSsthen 		*is_secure_answer = 0;
774eaf2578eSsthen 	}
7752be9e038Ssthen 	if(!encode_rep || *alias_rrset) {
7762be9e038Ssthen 		if(!encode_rep)
7772be9e038Ssthen 			*need_drop = 1;
7782be9e038Ssthen 		else {
7792be9e038Ssthen 			/* If a partial CNAME chain is found, we first need to
7802be9e038Ssthen 			 * make a copy of the reply in the scratchpad so we
7812be9e038Ssthen 			 * can release the locks and lookup the cache again. */
7822be9e038Ssthen 			*partial_repp = reply_info_copy(encode_rep, NULL,
7832be9e038Ssthen 				worker->scratchpad);
7842be9e038Ssthen 			if(!*partial_repp)
7852be9e038Ssthen 				goto bail_out;
7862be9e038Ssthen 		}
7870bdb4f62Ssthen 	} else {
7880bdb4f62Ssthen 		if(*is_expired_answer == 1 &&
7890bdb4f62Ssthen 			worker->env.cfg->ede_serve_expired && worker->env.cfg->ede) {
7900bdb4f62Ssthen 			EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
7910bdb4f62Ssthen 				worker->scratchpad, LDNS_EDE_STALE_ANSWER, "");
7920bdb4f62Ssthen 		}
7938b7325afSsthen 		/* Attach the cached EDE (RFC8914) if CD bit is set and the
7948b7325afSsthen 		 * answer is bogus. */
7958b7325afSsthen 		if(*is_secure_answer == 0 &&
7968b7325afSsthen 			worker->env.cfg->ede && has_cd_bit &&
7978b7325afSsthen 			encode_rep->reason_bogus != LDNS_EDE_NONE) {
7988b7325afSsthen 			edns_opt_list_append_ede(&edns->opt_list_out,
7998b7325afSsthen 				worker->scratchpad, encode_rep->reason_bogus,
8008b7325afSsthen 				encode_rep->reason_bogus_str);
8018b7325afSsthen 		}
8028b7325afSsthen 		if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, encode_rep,
8038b7325afSsthen 			(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad,
8048b7325afSsthen 			worker->env.now_tv))
8058b7325afSsthen 			goto bail_out;
8060bdb4f62Ssthen 		if(!reply_info_answer_encode(qinfo, encode_rep, id, flags,
807933707f3Ssthen 			repinfo->c->buffer, timenow, 1, worker->scratchpad,
8080bdb4f62Ssthen 			udpsize, edns, (int)(edns->bits & EDNS_DO),
8090bdb4f62Ssthen 			*is_secure_answer)) {
8100bdb4f62Ssthen 			if(!inplace_cb_reply_servfail_call(&worker->env, qinfo,
8110bdb4f62Ssthen 				NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo,
8120bdb4f62Ssthen 				worker->scratchpad, worker->env.now_tv))
813e21c60efSsthen 					edns->opt_list_inplace_cb_out = NULL;
814933707f3Ssthen 			error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
815933707f3Ssthen 				qinfo, id, flags, edns);
816933707f3Ssthen 		}
8170bdb4f62Ssthen 	}
818933707f3Ssthen 	/* cannot send the reply right now, because blocking network syscall
819933707f3Ssthen 	 * is bad while holding locks. */
820933707f3Ssthen 	rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
821933707f3Ssthen 		rep->ref, rep->rrset_count);
822933707f3Ssthen 	/* go and return this buffer to the client */
823933707f3Ssthen 	return 1;
824550cf4a9Ssthen 
825550cf4a9Ssthen bail_out:
826550cf4a9Ssthen 	rrset_array_unlock_touch(worker->env.rrset_cache,
827550cf4a9Ssthen 		worker->scratchpad, rep->ref, rep->rrset_count);
828550cf4a9Ssthen 	return 0;
829933707f3Ssthen }
830933707f3Ssthen 
8318240c1b9Ssthen /** Reply to client and perform prefetch to keep cache up to date. */
832933707f3Ssthen static void
833933707f3Ssthen reply_and_prefetch(struct worker* worker, struct query_info* qinfo,
8340bdb4f62Ssthen 	uint16_t flags, struct comm_reply* repinfo, time_t leeway, int noreply,
8350bdb4f62Ssthen 	int rpz_passthru, struct edns_option* opt_list)
836933707f3Ssthen {
8370bdb4f62Ssthen 	(void)opt_list;
838933707f3Ssthen 	/* first send answer to client to keep its latency
839933707f3Ssthen 	 * as small as a cachereply */
8408240c1b9Ssthen 	if(!noreply) {
841550cf4a9Ssthen 		if(repinfo->c->tcp_req_info) {
842550cf4a9Ssthen 			sldns_buffer_copy(
843550cf4a9Ssthen 				repinfo->c->tcp_req_info->spool_buffer,
844550cf4a9Ssthen 				repinfo->c->buffer);
845550cf4a9Ssthen 		}
846933707f3Ssthen 		comm_point_send_reply(repinfo);
847550cf4a9Ssthen 	}
848933707f3Ssthen 	server_stats_prefetch(&worker->stats, worker);
8490bdb4f62Ssthen #ifdef CLIENT_SUBNET
8500bdb4f62Ssthen 	/* Check if the subnet module is enabled. In that case pass over the
8510bdb4f62Ssthen 	 * comm_reply information for ECS generation later. The mesh states are
8520bdb4f62Ssthen 	 * unique when subnet is enabled. */
8530bdb4f62Ssthen 	if(modstack_find(&worker->env.mesh->mods, "subnetcache") != -1
8540bdb4f62Ssthen 		&& worker->env.unique_mesh) {
8550bdb4f62Ssthen 		mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway +
8568b7325afSsthen 			PREFETCH_EXPIRY_ADD, rpz_passthru,
8578b7325afSsthen 			&repinfo->client_addr, opt_list);
8580bdb4f62Ssthen 		return;
8590bdb4f62Ssthen 	}
8600bdb4f62Ssthen #endif
861933707f3Ssthen 	/* create the prefetch in the mesh as a normal lookup without
862933707f3Ssthen 	 * client addrs waiting, which has the cache blacklisted (to bypass
863933707f3Ssthen 	 * the cache and go to the network for the data). */
864933707f3Ssthen 	/* this (potentially) runs the mesh for the new query */
865933707f3Ssthen 	mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway +
8660bdb4f62Ssthen 		PREFETCH_EXPIRY_ADD, rpz_passthru, NULL, NULL);
867933707f3Ssthen }
868933707f3Ssthen 
869933707f3Ssthen /**
870933707f3Ssthen  * Fill CH class answer into buffer. Keeps query.
871933707f3Ssthen  * @param pkt: buffer
872933707f3Ssthen  * @param str: string to put into text record (<255).
8732be9e038Ssthen  * 	array of strings, every string becomes a text record.
8742be9e038Ssthen  * @param num: number of strings in array.
875933707f3Ssthen  * @param edns: edns reply information.
8762ee382b6Ssthen  * @param worker: worker with scratch region.
8772308e98cSsthen  * @param repinfo: reply information for a communication point.
878933707f3Ssthen  */
879933707f3Ssthen static void
8802be9e038Ssthen chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
8812308e98cSsthen 	struct worker* worker, struct comm_reply* repinfo)
882933707f3Ssthen {
8832be9e038Ssthen 	int i;
8840b68ff31Ssthen 	unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
8850b68ff31Ssthen 	unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt));
886e21c60efSsthen 	size_t udpsize = edns->udp_size;
887e21c60efSsthen 	edns->edns_version = EDNS_ADVERTISED_VERSION;
888e21c60efSsthen 	edns->udp_size = EDNS_ADVERTISED_SIZE;
889e21c60efSsthen 	edns->bits &= EDNS_DO;
890e21c60efSsthen 	if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
891e21c60efSsthen 		LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
892e21c60efSsthen 		worker->env.now_tv))
893e21c60efSsthen 			edns->opt_list_inplace_cb_out = NULL;
8940b68ff31Ssthen 	sldns_buffer_clear(pkt);
8950b68ff31Ssthen 	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */
8960b68ff31Ssthen 	sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA));
8970b68ff31Ssthen 	if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt));
8980b68ff31Ssthen 	if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt));
8990b68ff31Ssthen 	sldns_buffer_write_u16(pkt, 1); /* qdcount */
9002be9e038Ssthen 	sldns_buffer_write_u16(pkt, (uint16_t)num); /* ancount */
9010b68ff31Ssthen 	sldns_buffer_write_u16(pkt, 0); /* nscount */
9020b68ff31Ssthen 	sldns_buffer_write_u16(pkt, 0); /* arcount */
903933707f3Ssthen 	(void)query_dname_len(pkt); /* skip qname */
9040b68ff31Ssthen 	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */
9050b68ff31Ssthen 	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */
9062be9e038Ssthen 	for(i=0; i<num; i++) {
9072be9e038Ssthen 		size_t len = strlen(str[i]);
9082be9e038Ssthen 		if(len>255) len=255; /* cap size of TXT record */
909e21c60efSsthen 		if(sldns_buffer_position(pkt)+2+2+2+4+2+1+len+
910e21c60efSsthen 			calc_edns_field_size(edns) > udpsize) {
911e21c60efSsthen 			sldns_buffer_write_u16_at(pkt, 6, i); /* ANCOUNT */
912e21c60efSsthen 			LDNS_TC_SET(sldns_buffer_begin(pkt));
913e21c60efSsthen 			break;
914e21c60efSsthen 		}
9150b68ff31Ssthen 		sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */
9160b68ff31Ssthen 		sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT);
9170b68ff31Ssthen 		sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH);
9180b68ff31Ssthen 		sldns_buffer_write_u32(pkt, 0); /* TTL */
9190b68ff31Ssthen 		sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len);
9200b68ff31Ssthen 		sldns_buffer_write_u8(pkt, len);
9212be9e038Ssthen 		sldns_buffer_write(pkt, str[i], len);
9222be9e038Ssthen 	}
9230b68ff31Ssthen 	sldns_buffer_flip(pkt);
9242be9e038Ssthen 	if(sldns_buffer_capacity(pkt) >=
9252be9e038Ssthen 		sldns_buffer_limit(pkt)+calc_edns_field_size(edns))
926933707f3Ssthen 		attach_edns_record(pkt, edns);
927933707f3Ssthen }
928933707f3Ssthen 
9292be9e038Ssthen /** Reply with one string */
9302be9e038Ssthen static void
9312be9e038Ssthen chaos_replyonestr(sldns_buffer* pkt, const char* str, struct edns_data* edns,
9322308e98cSsthen 	struct worker* worker, struct comm_reply* repinfo)
9332be9e038Ssthen {
9342308e98cSsthen 	chaos_replystr(pkt, (char**)&str, 1, edns, worker, repinfo);
9352be9e038Ssthen }
9362be9e038Ssthen 
9372be9e038Ssthen /**
9382be9e038Ssthen  * Create CH class trustanchor answer.
9392be9e038Ssthen  * @param pkt: buffer
9402be9e038Ssthen  * @param edns: edns reply information.
9412be9e038Ssthen  * @param w: worker with scratch region.
9422308e98cSsthen  * @param repinfo: reply information for a communication point.
9432be9e038Ssthen  */
9442be9e038Ssthen static void
9452308e98cSsthen chaos_trustanchor(sldns_buffer* pkt, struct edns_data* edns, struct worker* w,
9462308e98cSsthen 	struct comm_reply* repinfo)
9472be9e038Ssthen {
9482be9e038Ssthen #define TA_RESPONSE_MAX_TXT 16 /* max number of TXT records */
9492be9e038Ssthen #define TA_RESPONSE_MAX_TAGS 32 /* max number of tags printed per zone */
9502be9e038Ssthen 	char* str_array[TA_RESPONSE_MAX_TXT];
9512be9e038Ssthen 	uint16_t tags[TA_RESPONSE_MAX_TAGS];
9522be9e038Ssthen 	int num = 0;
9532be9e038Ssthen 	struct trust_anchor* ta;
9542be9e038Ssthen 
9552be9e038Ssthen 	if(!w->env.need_to_validate) {
9562be9e038Ssthen 		/* no validator module, reply no trustanchors */
9572308e98cSsthen 		chaos_replystr(pkt, NULL, 0, edns, w, repinfo);
9582be9e038Ssthen 		return;
9592be9e038Ssthen 	}
9602be9e038Ssthen 
9612be9e038Ssthen 	/* fill the string with contents */
9622be9e038Ssthen 	lock_basic_lock(&w->env.anchors->lock);
9632be9e038Ssthen 	RBTREE_FOR(ta, struct trust_anchor*, w->env.anchors->tree) {
9642be9e038Ssthen 		char* str;
9652be9e038Ssthen 		size_t i, numtag, str_len = 255;
9662be9e038Ssthen 		if(num == TA_RESPONSE_MAX_TXT) continue;
9672be9e038Ssthen 		str = (char*)regional_alloc(w->scratchpad, str_len);
9682be9e038Ssthen 		if(!str) continue;
9692be9e038Ssthen 		lock_basic_lock(&ta->lock);
9702be9e038Ssthen 		numtag = anchor_list_keytags(ta, tags, TA_RESPONSE_MAX_TAGS);
9712be9e038Ssthen 		if(numtag == 0) {
9722be9e038Ssthen 			/* empty, insecure point */
9732be9e038Ssthen 			lock_basic_unlock(&ta->lock);
9742be9e038Ssthen 			continue;
9752be9e038Ssthen 		}
9762be9e038Ssthen 		str_array[num] = str;
9772be9e038Ssthen 		num++;
9782be9e038Ssthen 
9792be9e038Ssthen 		/* spool name of anchor */
9802be9e038Ssthen 		(void)sldns_wire2str_dname_buf(ta->name, ta->namelen, str, str_len);
9812be9e038Ssthen 		str_len -= strlen(str); str += strlen(str);
9822be9e038Ssthen 		/* spool tags */
9832be9e038Ssthen 		for(i=0; i<numtag; i++) {
9842be9e038Ssthen 			snprintf(str, str_len, " %u", (unsigned)tags[i]);
9852be9e038Ssthen 			str_len -= strlen(str); str += strlen(str);
9862be9e038Ssthen 		}
9872be9e038Ssthen 		lock_basic_unlock(&ta->lock);
9882be9e038Ssthen 	}
9892be9e038Ssthen 	lock_basic_unlock(&w->env.anchors->lock);
9902be9e038Ssthen 
9912308e98cSsthen 	chaos_replystr(pkt, str_array, num, edns, w, repinfo);
9922be9e038Ssthen 	regional_free_all(w->scratchpad);
9932be9e038Ssthen }
9942be9e038Ssthen 
995933707f3Ssthen /**
996933707f3Ssthen  * Answer CH class queries.
997933707f3Ssthen  * @param w: worker
998933707f3Ssthen  * @param qinfo: query info. Pointer into packet buffer.
999933707f3Ssthen  * @param edns: edns info from query.
10002308e98cSsthen  * @param repinfo: reply information for a communication point.
1001933707f3Ssthen  * @param pkt: packet buffer.
1002933707f3Ssthen  * @return: true if a reply is to be sent.
1003933707f3Ssthen  */
1004933707f3Ssthen static int
1005933707f3Ssthen answer_chaos(struct worker* w, struct query_info* qinfo,
10062308e98cSsthen 	struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* pkt)
1007933707f3Ssthen {
1008933707f3Ssthen 	struct config_file* cfg = w->env.cfg;
1009933707f3Ssthen 	if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT)
1010933707f3Ssthen 		return 0;
1011933707f3Ssthen 	if(query_dname_compare(qinfo->qname,
1012933707f3Ssthen 		(uint8_t*)"\002id\006server") == 0 ||
1013933707f3Ssthen 		query_dname_compare(qinfo->qname,
1014933707f3Ssthen 		(uint8_t*)"\010hostname\004bind") == 0)
1015933707f3Ssthen 	{
1016933707f3Ssthen 		if(cfg->hide_identity)
1017933707f3Ssthen 			return 0;
1018933707f3Ssthen 		if(cfg->identity==NULL || cfg->identity[0]==0) {
1019933707f3Ssthen 			char buf[MAXHOSTNAMELEN+1];
1020933707f3Ssthen 			if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
1021933707f3Ssthen 				buf[MAXHOSTNAMELEN] = 0;
10222308e98cSsthen 				chaos_replyonestr(pkt, buf, edns, w, repinfo);
1023933707f3Ssthen 			} else 	{
1024933707f3Ssthen 				log_err("gethostname: %s", strerror(errno));
10252308e98cSsthen 				chaos_replyonestr(pkt, "no hostname", edns, w, repinfo);
1026933707f3Ssthen 			}
1027933707f3Ssthen 		}
10282308e98cSsthen 		else 	chaos_replyonestr(pkt, cfg->identity, edns, w, repinfo);
1029933707f3Ssthen 		return 1;
1030933707f3Ssthen 	}
1031933707f3Ssthen 	if(query_dname_compare(qinfo->qname,
1032933707f3Ssthen 		(uint8_t*)"\007version\006server") == 0 ||
1033933707f3Ssthen 		query_dname_compare(qinfo->qname,
1034933707f3Ssthen 		(uint8_t*)"\007version\004bind") == 0)
1035933707f3Ssthen 	{
1036933707f3Ssthen 		if(cfg->hide_version)
1037933707f3Ssthen 			return 0;
1038933707f3Ssthen 		if(cfg->version==NULL || cfg->version[0]==0)
10392308e98cSsthen 			chaos_replyonestr(pkt, PACKAGE_STRING, edns, w, repinfo);
10402308e98cSsthen 		else 	chaos_replyonestr(pkt, cfg->version, edns, w, repinfo);
1041933707f3Ssthen 		return 1;
1042933707f3Ssthen 	}
10432be9e038Ssthen 	if(query_dname_compare(qinfo->qname,
10442be9e038Ssthen 		(uint8_t*)"\013trustanchor\007unbound") == 0)
10452be9e038Ssthen 	{
10462be9e038Ssthen 		if(cfg->hide_trustanchor)
10472be9e038Ssthen 			return 0;
10482308e98cSsthen 		chaos_trustanchor(pkt, edns, w, repinfo);
10492be9e038Ssthen 		return 1;
10502be9e038Ssthen 	}
10512be9e038Ssthen 
1052933707f3Ssthen 	return 0;
1053933707f3Ssthen }
1054933707f3Ssthen 
105520237c55Ssthen /**
105620237c55Ssthen  * Answer notify queries.  These are notifies for authoritative zones,
105720237c55Ssthen  * the reply is an ack that the notify has been received.  We need to check
105820237c55Ssthen  * access permission here.
105920237c55Ssthen  * @param w: worker
106020237c55Ssthen  * @param qinfo: query info. Pointer into packet buffer.
106120237c55Ssthen  * @param edns: edns info from query.
106245872187Ssthen  * @param addr: client address.
106345872187Ssthen  * @param addrlen: client address length.
106420237c55Ssthen  * @param pkt: packet buffer.
106520237c55Ssthen  */
106620237c55Ssthen static void
106720237c55Ssthen answer_notify(struct worker* w, struct query_info* qinfo,
106845872187Ssthen 	struct edns_data* edns, sldns_buffer* pkt,
106945872187Ssthen 	struct sockaddr_storage* addr, socklen_t addrlen)
107020237c55Ssthen {
107120237c55Ssthen 	int refused = 0;
107220237c55Ssthen 	int rcode = LDNS_RCODE_NOERROR;
107320237c55Ssthen 	uint32_t serial = 0;
107420237c55Ssthen 	int has_serial;
107520237c55Ssthen 	if(!w->env.auth_zones) return;
107620237c55Ssthen 	has_serial = auth_zone_parse_notify_serial(pkt, &serial);
107720237c55Ssthen 	if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname,
107845872187Ssthen 		qinfo->qname_len, qinfo->qclass, addr,
107945872187Ssthen 		addrlen, has_serial, serial, &refused)) {
108020237c55Ssthen 		rcode = LDNS_RCODE_NOERROR;
108120237c55Ssthen 	} else {
108220237c55Ssthen 		if(refused)
108320237c55Ssthen 			rcode = LDNS_RCODE_REFUSED;
108420237c55Ssthen 		else	rcode = LDNS_RCODE_SERVFAIL;
108520237c55Ssthen 	}
108620237c55Ssthen 
108720237c55Ssthen 	if(verbosity >= VERB_DETAIL) {
108820237c55Ssthen 		char buf[380];
108920237c55Ssthen 		char zname[255+1];
109020237c55Ssthen 		char sr[25];
109120237c55Ssthen 		dname_str(qinfo->qname, zname);
109220237c55Ssthen 		sr[0]=0;
109320237c55Ssthen 		if(has_serial)
109420237c55Ssthen 			snprintf(sr, sizeof(sr), "serial %u ",
109520237c55Ssthen 				(unsigned)serial);
109620237c55Ssthen 		if(rcode == LDNS_RCODE_REFUSED)
109720237c55Ssthen 			snprintf(buf, sizeof(buf),
109820237c55Ssthen 				"refused NOTIFY %sfor %s from", sr, zname);
109920237c55Ssthen 		else if(rcode == LDNS_RCODE_SERVFAIL)
110020237c55Ssthen 			snprintf(buf, sizeof(buf),
110120237c55Ssthen 				"servfail for NOTIFY %sfor %s from", sr, zname);
110220237c55Ssthen 		else	snprintf(buf, sizeof(buf),
110320237c55Ssthen 				"received NOTIFY %sfor %s from", sr, zname);
110445872187Ssthen 		log_addr(VERB_DETAIL, buf, addr, addrlen);
110520237c55Ssthen 	}
110620237c55Ssthen 	edns->edns_version = EDNS_ADVERTISED_VERSION;
110720237c55Ssthen 	edns->udp_size = EDNS_ADVERTISED_SIZE;
110820237c55Ssthen 	edns->ext_rcode = 0;
110920237c55Ssthen 	edns->bits &= EDNS_DO;
111020237c55Ssthen 	error_encode(pkt, rcode, qinfo,
111120237c55Ssthen 		*(uint16_t*)(void *)sldns_buffer_begin(pkt),
111220237c55Ssthen 		sldns_buffer_read_u16_at(pkt, 2), edns);
111320237c55Ssthen 	LDNS_OPCODE_SET(sldns_buffer_begin(pkt), LDNS_PACKET_NOTIFY);
111420237c55Ssthen }
111520237c55Ssthen 
1116e10d3884Sbrad static int
11170b68ff31Ssthen deny_refuse(struct comm_point* c, enum acl_access acl,
11180b68ff31Ssthen 	enum acl_access deny, enum acl_access refuse,
11190bdb4f62Ssthen 	struct worker* worker, struct comm_reply* repinfo,
11208b7325afSsthen 	struct acl_addr* acladdr, int ede,
11218b7325afSsthen 	struct check_request_result* check_result)
11220b68ff31Ssthen {
11230b68ff31Ssthen 	if(acl == deny) {
11240bdb4f62Ssthen 		if(verbosity >= VERB_ALGO) {
112545872187Ssthen 			log_acl_action("dropped", &repinfo->client_addr,
112645872187Ssthen 				repinfo->client_addrlen, acl, acladdr);
11270bdb4f62Ssthen 			log_buf(VERB_ALGO, "dropped", c->buffer);
11280bdb4f62Ssthen 		}
11290b68ff31Ssthen 		comm_point_drop_reply(repinfo);
11300b68ff31Ssthen 		if(worker->stats.extended)
11310b68ff31Ssthen 			worker->stats.unwanted_queries++;
11320b68ff31Ssthen 		return 0;
11330b68ff31Ssthen 	} else if(acl == refuse) {
11340bdb4f62Ssthen 		size_t opt_rr_mark;
11350bdb4f62Ssthen 
11360bdb4f62Ssthen 		if(verbosity >= VERB_ALGO) {
113745872187Ssthen 			log_acl_action("refused", &repinfo->client_addr,
113845872187Ssthen 				repinfo->client_addrlen, acl, acladdr);
11390b68ff31Ssthen 			log_buf(VERB_ALGO, "refuse", c->buffer);
11400bdb4f62Ssthen 		}
11410bdb4f62Ssthen 
11420b68ff31Ssthen 		if(worker->stats.extended)
11430b68ff31Ssthen 			worker->stats.unwanted_queries++;
11448b7325afSsthen 		worker_check_request(c->buffer, worker, check_result);
11458b7325afSsthen 		if(check_result->value != 0) {
11468b7325afSsthen 			if(check_result->value != -1) {
11478b7325afSsthen 				LDNS_QR_SET(sldns_buffer_begin(c->buffer));
11488b7325afSsthen 				LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
11498b7325afSsthen 					check_result->value);
11508b7325afSsthen 				return 1;
11518b7325afSsthen 			}
11520b68ff31Ssthen 			comm_point_drop_reply(repinfo);
11538b7325afSsthen 			return 0;
11540b68ff31Ssthen 		}
11550bdb4f62Ssthen 		/* worker_check_request() above guarantees that the buffer contains at
11560bdb4f62Ssthen 		 * least a header and that qdcount == 1
11570bdb4f62Ssthen 		 */
11580bdb4f62Ssthen 		log_assert(sldns_buffer_limit(c->buffer) >= LDNS_HEADER_SIZE
11590bdb4f62Ssthen 			&& LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) == 1);
11600bdb4f62Ssthen 
1161f46c52bfSsthen 		sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE); /* skip header */
11620bdb4f62Ssthen 
11630bdb4f62Ssthen 		/* check additional section is present and that we respond with EDEs */
11640bdb4f62Ssthen 		if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1
11650bdb4f62Ssthen 			|| !ede) {
11660bdb4f62Ssthen 			LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11670bdb4f62Ssthen 			LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11680bdb4f62Ssthen 			LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11690bdb4f62Ssthen 			LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11700b68ff31Ssthen 			LDNS_QR_SET(sldns_buffer_begin(c->buffer));
11710b68ff31Ssthen 			LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
11720b68ff31Ssthen 				LDNS_RCODE_REFUSED);
1173f46c52bfSsthen 			sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
11740bdb4f62Ssthen 			sldns_buffer_flip(c->buffer);
11750bdb4f62Ssthen 			return 1;
11760bdb4f62Ssthen 		}
11770bdb4f62Ssthen 
11780bdb4f62Ssthen 		if (!query_dname_len(c->buffer)) {
11790bdb4f62Ssthen 			LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11800bdb4f62Ssthen 			LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11810bdb4f62Ssthen 			LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11820bdb4f62Ssthen 			LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11830bdb4f62Ssthen 			LDNS_QR_SET(sldns_buffer_begin(c->buffer));
11840bdb4f62Ssthen 			LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
11850bdb4f62Ssthen 				LDNS_RCODE_FORMERR);
118677079be7Ssthen 			sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
118777079be7Ssthen 			sldns_buffer_flip(c->buffer);
11880b68ff31Ssthen 			return 1;
11890b68ff31Ssthen 		}
11900bdb4f62Ssthen 		/* space available for query type and class? */
11910bdb4f62Ssthen 		if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) {
11920bdb4f62Ssthen                         LDNS_QR_SET(sldns_buffer_begin(c->buffer));
11930bdb4f62Ssthen                         LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
11940bdb4f62Ssthen 				 LDNS_RCODE_FORMERR);
11950bdb4f62Ssthen 			LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11960bdb4f62Ssthen 			LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11970bdb4f62Ssthen 			LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11980bdb4f62Ssthen 			LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
11990bdb4f62Ssthen 			sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
12000bdb4f62Ssthen                         sldns_buffer_flip(c->buffer);
12010bdb4f62Ssthen 			return 1;
12020bdb4f62Ssthen 		}
12030bdb4f62Ssthen 		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
12040bdb4f62Ssthen 		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
12050bdb4f62Ssthen 			LDNS_RCODE_REFUSED);
12060bdb4f62Ssthen 
12070bdb4f62Ssthen 		sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qtype */
12080bdb4f62Ssthen 
12090bdb4f62Ssthen 		sldns_buffer_skip(c->buffer, (ssize_t)sizeof(uint16_t)); /* skip qclass */
12100bdb4f62Ssthen 
12110bdb4f62Ssthen 		/* The OPT RR to be returned should come directly after
12120bdb4f62Ssthen 		 * the query, so mark this spot.
12130bdb4f62Ssthen 		 */
12140bdb4f62Ssthen 		opt_rr_mark = sldns_buffer_position(c->buffer);
12150bdb4f62Ssthen 
12160bdb4f62Ssthen 		/* Skip through the RR records */
12170bdb4f62Ssthen 		if(LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)) != 0 ||
12180bdb4f62Ssthen 			LDNS_NSCOUNT(sldns_buffer_begin(c->buffer)) != 0) {
12190bdb4f62Ssthen 			if(!skip_pkt_rrs(c->buffer,
12200bdb4f62Ssthen 				((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+
12210bdb4f62Ssthen 				((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) {
12220bdb4f62Ssthen 				LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
12230bdb4f62Ssthen 					LDNS_RCODE_FORMERR);
12240bdb4f62Ssthen 				LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12250bdb4f62Ssthen 				LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12260bdb4f62Ssthen 				LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12270bdb4f62Ssthen 				sldns_buffer_set_position(c->buffer, opt_rr_mark);
12280bdb4f62Ssthen 				sldns_buffer_flip(c->buffer);
12290bdb4f62Ssthen 				return 1;
12300bdb4f62Ssthen 			}
12310bdb4f62Ssthen 		}
12320bdb4f62Ssthen 		/* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */
12330bdb4f62Ssthen 		/* domain name must be the root of length 1. */
12340bdb4f62Ssthen 		if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) {
12350bdb4f62Ssthen 			LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12360bdb4f62Ssthen 			LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12370bdb4f62Ssthen 			LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12380bdb4f62Ssthen 			sldns_buffer_set_position(c->buffer, opt_rr_mark);
12390bdb4f62Ssthen 			sldns_buffer_flip(c->buffer);
12400bdb4f62Ssthen 			return 1;
12410bdb4f62Ssthen 		} else {
12420bdb4f62Ssthen 			sldns_buffer_skip(c->buffer, 1); /* skip root label */
12430bdb4f62Ssthen 		}
12440bdb4f62Ssthen 		if(sldns_buffer_remaining(c->buffer) < 2 ||
12450bdb4f62Ssthen 			sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) {
12460bdb4f62Ssthen 			LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12470bdb4f62Ssthen 			LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12480bdb4f62Ssthen 			LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12490bdb4f62Ssthen 			sldns_buffer_set_position(c->buffer, opt_rr_mark);
12500bdb4f62Ssthen 			sldns_buffer_flip(c->buffer);
12510bdb4f62Ssthen 			return 1;
12520bdb4f62Ssthen 		}
12530bdb4f62Ssthen 		/* Write OPT RR directly after the query,
12540bdb4f62Ssthen 		 * so without the (possibly skipped) Answer and NS RRs
12550bdb4f62Ssthen 		 */
12560bdb4f62Ssthen 		LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12570bdb4f62Ssthen 		LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12580bdb4f62Ssthen 		sldns_buffer_clear(c->buffer); /* reset write limit */
12590bdb4f62Ssthen 		sldns_buffer_set_position(c->buffer, opt_rr_mark);
12600bdb4f62Ssthen 
12610bdb4f62Ssthen 		/* Check if OPT record can be written
12620bdb4f62Ssthen 		 * 17 == root label (1) + RR type (2) + UDP Size (2)
12630bdb4f62Ssthen 		 *     + Fields (4) + rdata len (2) + EDE Option code (2)
12640bdb4f62Ssthen 		 *     + EDE Option length (2) + EDE info-code (2)
12650bdb4f62Ssthen 		 */
12660bdb4f62Ssthen 		if (sldns_buffer_available(c->buffer, 17) == 0) {
12670bdb4f62Ssthen 			LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
12680bdb4f62Ssthen 			sldns_buffer_flip(c->buffer);
12690bdb4f62Ssthen 			return 1;
12700bdb4f62Ssthen 		}
12710bdb4f62Ssthen 
12720bdb4f62Ssthen 		LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 1);
12730bdb4f62Ssthen 
12740bdb4f62Ssthen 		/* root label */
12750bdb4f62Ssthen 		sldns_buffer_write_u8(c->buffer, 0);
12760bdb4f62Ssthen 		sldns_buffer_write_u16(c->buffer, LDNS_RR_TYPE_OPT);
12770bdb4f62Ssthen 		sldns_buffer_write_u16(c->buffer, EDNS_ADVERTISED_SIZE);
12780bdb4f62Ssthen 
12790bdb4f62Ssthen 		/* write OPT Record TTL Field */
12800bdb4f62Ssthen 		sldns_buffer_write_u32(c->buffer, 0);
12810bdb4f62Ssthen 
12820bdb4f62Ssthen 		/* write rdata len: EDE option + length + info-code */
12830bdb4f62Ssthen 		sldns_buffer_write_u16(c->buffer, 6);
12840bdb4f62Ssthen 
12850bdb4f62Ssthen 		/* write OPTIONS; add EDE option code */
12860bdb4f62Ssthen 		sldns_buffer_write_u16(c->buffer, LDNS_EDNS_EDE);
12870bdb4f62Ssthen 
12880bdb4f62Ssthen 		/* write single EDE option length (for just 1 info-code) */
12890bdb4f62Ssthen 		sldns_buffer_write_u16(c->buffer, 2);
12900bdb4f62Ssthen 
12910bdb4f62Ssthen 		/* write single EDE info-code */
12920bdb4f62Ssthen 		sldns_buffer_write_u16(c->buffer, LDNS_EDE_PROHIBITED);
12930bdb4f62Ssthen 
12940bdb4f62Ssthen 		sldns_buffer_flip(c->buffer);
12950bdb4f62Ssthen 
12960bdb4f62Ssthen 		verbose(VERB_ALGO, "attached EDE code: %d", LDNS_EDE_PROHIBITED);
12970bdb4f62Ssthen 
12980bdb4f62Ssthen 		return 1;
12990bdb4f62Ssthen 
13000bdb4f62Ssthen 	}
13010b68ff31Ssthen 
13020b68ff31Ssthen 	return -1;
13030b68ff31Ssthen }
13040b68ff31Ssthen 
1305e10d3884Sbrad static int
130645872187Ssthen deny_refuse_all(struct comm_point* c, enum acl_access* acl,
13070bdb4f62Ssthen 	struct worker* worker, struct comm_reply* repinfo,
13088b7325afSsthen 	struct acl_addr** acladdr, int ede, int check_proxy,
13098b7325afSsthen 	struct check_request_result* check_result)
13100b68ff31Ssthen {
131145872187Ssthen 	if(check_proxy) {
131245872187Ssthen 		*acladdr = acl_addr_lookup(worker->daemon->acl,
131345872187Ssthen 			&repinfo->remote_addr, repinfo->remote_addrlen);
131445872187Ssthen 	} else {
131545872187Ssthen 		*acladdr = acl_addr_lookup(worker->daemon->acl,
131645872187Ssthen 			&repinfo->client_addr, repinfo->client_addrlen);
131745872187Ssthen 	}
131845872187Ssthen 	/* If there is no ACL based on client IP use the interface ACL. */
131945872187Ssthen 	if(!(*acladdr) && c->socket) {
132045872187Ssthen 		*acladdr = c->socket->acl;
132145872187Ssthen 	}
132245872187Ssthen 	*acl = acl_get_control(*acladdr);
132345872187Ssthen 	return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo,
13248b7325afSsthen 		*acladdr, ede, check_result);
13250b68ff31Ssthen }
13260b68ff31Ssthen 
1327e10d3884Sbrad static int
13280b68ff31Ssthen deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
13290bdb4f62Ssthen 	struct worker* worker, struct comm_reply* repinfo,
13308b7325afSsthen 	struct acl_addr* acladdr, int ede,
13318b7325afSsthen 	struct check_request_result* check_result)
13320b68ff31Ssthen {
13330bdb4f62Ssthen 	return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local,
13348b7325afSsthen 		worker, repinfo, acladdr, ede, check_result);
13358b7325afSsthen }
13368b7325afSsthen 
13378b7325afSsthen /* Check if the query is blocked by source IP rate limiting.
13388b7325afSsthen  * Returns 1 if it passes the check, 0 otherwise. */
13398b7325afSsthen static int
13408b7325afSsthen check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr,
13418b7325afSsthen 	socklen_t addrlen, int has_cookie, sldns_buffer* pkt)
13428b7325afSsthen {
13438b7325afSsthen 	if(!infra_ip_ratelimit_inc(worker->env.infra_cache, addr, addrlen,
13448b7325afSsthen 			*worker->env.now, has_cookie,
13458b7325afSsthen 			worker->env.cfg->ip_ratelimit_backoff, pkt)) {
13468b7325afSsthen 		/* See if we can pass through with slip factor */
13478b7325afSsthen 		if(!has_cookie && worker->env.cfg->ip_ratelimit_factor != 0 &&
13488b7325afSsthen 			ub_random_max(worker->env.rnd,
13498b7325afSsthen 			worker->env.cfg->ip_ratelimit_factor) == 0) {
13508b7325afSsthen 			char addrbuf[128];
13518b7325afSsthen 			addr_to_str(addr, addrlen, addrbuf, sizeof(addrbuf));
13528b7325afSsthen 			verbose(VERB_QUERY, "ip_ratelimit allowed through for "
13538b7325afSsthen 				"ip address %s because of slip in "
13548b7325afSsthen 				"ip_ratelimit_factor", addrbuf);
13558b7325afSsthen 			return 1;
13568b7325afSsthen 		}
13578b7325afSsthen 		return 0;
13588b7325afSsthen 	}
13598b7325afSsthen 	return 1;
13600b68ff31Ssthen }
13610b68ff31Ssthen 
13620b68ff31Ssthen int
1363933707f3Ssthen worker_handle_request(struct comm_point* c, void* arg, int error,
1364933707f3Ssthen 	struct comm_reply* repinfo)
1365933707f3Ssthen {
1366933707f3Ssthen 	struct worker* worker = (struct worker*)arg;
1367933707f3Ssthen 	int ret;
136877079be7Ssthen 	hashvalue_type h;
1369933707f3Ssthen 	struct lruhash_entry* e;
1370933707f3Ssthen 	struct query_info qinfo;
1371933707f3Ssthen 	struct edns_data edns;
13720bdb4f62Ssthen 	struct edns_option* original_edns_list = NULL;
1373933707f3Ssthen 	enum acl_access acl;
137477079be7Ssthen 	struct acl_addr* acladdr;
13758b7325afSsthen 	int pre_edns_ip_ratelimit = 1;
1376e10d3884Sbrad 	int rc = 0;
13772be9e038Ssthen 	int need_drop = 0;
1378eaf2578eSsthen 	int is_expired_answer = 0;
1379eaf2578eSsthen 	int is_secure_answer = 0;
13800bdb4f62Ssthen 	int rpz_passthru = 0;
13818b7325afSsthen 	long long wait_queue_time = 0;
13822be9e038Ssthen 	/* We might have to chase a CNAME chain internally, in which case
13832be9e038Ssthen 	 * we'll have up to two replies and combine them to build a complete
13842be9e038Ssthen 	 * answer.  These variables control this case. */
13852be9e038Ssthen 	struct ub_packed_rrset_key* alias_rrset = NULL;
13862be9e038Ssthen 	struct reply_info* partial_rep = NULL;
13872be9e038Ssthen 	struct query_info* lookup_qinfo = &qinfo;
1388f6b99bafSsthen 	struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
13892be9e038Ssthen 	struct respip_client_info* cinfo = NULL, cinfo_tmp;
13908b7325afSsthen 	struct timeval wait_time;
13918b7325afSsthen 	struct check_request_result check_result = {0,0};
13927191de28Ssthen 	memset(&qinfo, 0, sizeof(qinfo));
1393933707f3Ssthen 
13942c144df0Ssthen 	if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) {
1395933707f3Ssthen 		/* some bad tcp query DNS formats give these error calls */
1396933707f3Ssthen 		verbose(VERB_ALGO, "handle request called with err=%d", error);
1397933707f3Ssthen 		return 0;
1398933707f3Ssthen 	}
13998b7325afSsthen 
14008b7325afSsthen 	if (worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv)) {
14018b7325afSsthen 		timeval_subtract(&wait_time, worker->env.now_tv, &c->recv_tv);
14028b7325afSsthen 		wait_queue_time = wait_time.tv_sec * 1000000 +  wait_time.tv_usec;
14038b7325afSsthen 		if (worker->stats.max_query_time_us < wait_queue_time)
14048b7325afSsthen 			worker->stats.max_query_time_us = wait_queue_time;
14058b7325afSsthen 		if(wait_queue_time >
14068b7325afSsthen 			(long long)(worker->env.cfg->sock_queue_timeout * 1000000)) {
14078b7325afSsthen 			/* count and drop queries that were sitting in the socket queue too long */
14088b7325afSsthen 			worker->stats.num_queries_timed_out++;
14098b7325afSsthen 			return 0;
14108b7325afSsthen 		}
14118b7325afSsthen 	}
14128b7325afSsthen 
14132be9e038Ssthen #ifdef USE_DNSCRYPT
14142be9e038Ssthen 	repinfo->max_udp_size = worker->daemon->cfg->max_udp_size;
14152be9e038Ssthen 	if(!dnsc_handle_curved_request(worker->daemon->dnscenv, repinfo)) {
14162be9e038Ssthen 		worker->stats.num_query_dnscrypt_crypted_malformed++;
14172be9e038Ssthen 		return 0;
14182be9e038Ssthen 	}
14192be9e038Ssthen 	if(c->dnscrypt && !repinfo->is_dnscrypted) {
14202be9e038Ssthen 		char buf[LDNS_MAX_DOMAINLEN+1];
14212be9e038Ssthen 		/* Check if this is unencrypted and asking for certs */
14228b7325afSsthen 		worker_check_request(c->buffer, worker, &check_result);
14238b7325afSsthen 		if(check_result.value != 0) {
14242be9e038Ssthen 			verbose(VERB_ALGO,
14252be9e038Ssthen 				"dnscrypt: worker check request: bad query.");
142645872187Ssthen 			log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
142745872187Ssthen 				repinfo->client_addrlen);
14282be9e038Ssthen 			comm_point_drop_reply(repinfo);
14292be9e038Ssthen 			return 0;
14302be9e038Ssthen 		}
14312be9e038Ssthen 		if(!query_info_parse(&qinfo, c->buffer)) {
14322be9e038Ssthen 			verbose(VERB_ALGO,
14332be9e038Ssthen 				"dnscrypt: worker parse request: formerror.");
143445872187Ssthen 			log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
143545872187Ssthen 				repinfo->client_addrlen);
14362be9e038Ssthen 			comm_point_drop_reply(repinfo);
14372be9e038Ssthen 			return 0;
14382be9e038Ssthen 		}
14392be9e038Ssthen 		dname_str(qinfo.qname, buf);
14402be9e038Ssthen 		if(!(qinfo.qtype == LDNS_RR_TYPE_TXT &&
14412be9e038Ssthen 			strcasecmp(buf,
14422be9e038Ssthen 			worker->daemon->dnscenv->provider_name) == 0)) {
14432be9e038Ssthen 			verbose(VERB_ALGO,
1444bdfc4d55Sflorian 				"dnscrypt: not TXT \"%s\". Received: %s \"%s\"",
14452be9e038Ssthen 				worker->daemon->dnscenv->provider_name,
14462be9e038Ssthen 				sldns_rr_descript(qinfo.qtype)->_name,
14472be9e038Ssthen 				buf);
14482be9e038Ssthen 			comm_point_drop_reply(repinfo);
14492be9e038Ssthen 			worker->stats.num_query_dnscrypt_cleartext++;
14502be9e038Ssthen 			return 0;
14512be9e038Ssthen 		}
14522be9e038Ssthen 		worker->stats.num_query_dnscrypt_cert++;
14532be9e038Ssthen 		sldns_buffer_rewind(c->buffer);
14542be9e038Ssthen 	} else if(c->dnscrypt && repinfo->is_dnscrypted) {
14552be9e038Ssthen 		worker->stats.num_query_dnscrypt_crypted++;
14562be9e038Ssthen 	}
14572be9e038Ssthen #endif
1458e10d3884Sbrad #ifdef USE_DNSTAP
1459191f22c6Ssthen 	/*
1460191f22c6Ssthen 	 * sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler
1461191f22c6Ssthen 	 */
1462191f22c6Ssthen 	if(worker->dtenv.log_client_query_messages) {
146345872187Ssthen 		log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen);
14642bdc0ed1Ssthen 		log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
14652bdc0ed1Ssthen 		dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer,
14668b7325afSsthen 		((worker->env.cfg->sock_queue_timeout && timeval_isset(&c->recv_tv))?&c->recv_tv:NULL));
1467191f22c6Ssthen 	}
1468e10d3884Sbrad #endif
146945872187Ssthen 	/* Check deny/refuse ACLs */
147045872187Ssthen 	if(repinfo->is_proxied) {
147145872187Ssthen 		if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
14728b7325afSsthen 			worker->env.cfg->ede, 1, &check_result)) != -1) {
1473e10d3884Sbrad 			if(ret == 1)
1474e10d3884Sbrad 				goto send_reply;
14750b68ff31Ssthen 			return ret;
1476933707f3Ssthen 		}
147745872187Ssthen 	}
147845872187Ssthen 	if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
14798b7325afSsthen 		worker->env.cfg->ede, 0, &check_result)) != -1) {
148045872187Ssthen 		if(ret == 1)
148145872187Ssthen 			goto send_reply;
148245872187Ssthen 		return ret;
148345872187Ssthen 	}
148445872187Ssthen 
14858b7325afSsthen 	worker_check_request(c->buffer, worker, &check_result);
14868b7325afSsthen 	if(check_result.value != 0) {
1487933707f3Ssthen 		verbose(VERB_ALGO, "worker check request: bad query.");
148845872187Ssthen 		log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
14898b7325afSsthen 		if(check_result.value != -1) {
14900b68ff31Ssthen 			LDNS_QR_SET(sldns_buffer_begin(c->buffer));
14918b7325afSsthen 			LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
14928b7325afSsthen 				check_result.value);
1493933707f3Ssthen 			return 1;
1494933707f3Ssthen 		}
1495933707f3Ssthen 		comm_point_drop_reply(repinfo);
1496933707f3Ssthen 		return 0;
1497933707f3Ssthen 	}
149877079be7Ssthen 
1499933707f3Ssthen 	worker->stats.num_queries++;
1500f46c52bfSsthen 	pre_edns_ip_ratelimit = !worker->env.cfg->do_answer_cookie
1501f46c52bfSsthen 		|| sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE
1502f46c52bfSsthen 		|| LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) == 0;
150377079be7Ssthen 
15048b7325afSsthen 	/* If the IP rate limiting check needs extra EDNS information (e.g.,
15058b7325afSsthen 	 * DNS Cookies) postpone the check until after EDNS is parsed. */
15068b7325afSsthen 	if(pre_edns_ip_ratelimit) {
15078b7325afSsthen 		/* NOTE: we always check the repinfo->client_address.
15088b7325afSsthen 		 *       IP ratelimiting is implicitly disabled for proxies. */
15098b7325afSsthen 		if(!check_ip_ratelimit(worker, &repinfo->client_addr,
15108b7325afSsthen 			repinfo->client_addrlen, 0, c->buffer)) {
151177079be7Ssthen 			worker->stats.num_queries_ip_ratelimited++;
151277079be7Ssthen 			comm_point_drop_reply(repinfo);
151377079be7Ssthen 			return 0;
151477079be7Ssthen 		}
151577079be7Ssthen 	}
151677079be7Ssthen 
1517933707f3Ssthen 	if(!query_info_parse(&qinfo, c->buffer)) {
1518933707f3Ssthen 		verbose(VERB_ALGO, "worker parse request: formerror.");
151945872187Ssthen 		log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
152045872187Ssthen 			repinfo->client_addrlen);
15217191de28Ssthen 		memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */
1522a58bff56Ssthen 		if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
1523a58bff56Ssthen 			comm_point_drop_reply(repinfo);
1524a58bff56Ssthen 			return 0;
1525a58bff56Ssthen 		}
15260b68ff31Ssthen 		sldns_buffer_rewind(c->buffer);
15270b68ff31Ssthen 		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
15280b68ff31Ssthen 		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
1529933707f3Ssthen 			LDNS_RCODE_FORMERR);
1530e10d3884Sbrad 		goto send_reply;
1531933707f3Ssthen 	}
1532933707f3Ssthen 	if(worker->env.cfg->log_queries) {
1533933707f3Ssthen 		char ip[128];
153445872187Ssthen 		addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip));
1535f6b99bafSsthen 		log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
1536933707f3Ssthen 	}
1537933707f3Ssthen 	if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
1538933707f3Ssthen 		qinfo.qtype == LDNS_RR_TYPE_IXFR) {
1539933707f3Ssthen 		verbose(VERB_ALGO, "worker request: refused zone transfer.");
154045872187Ssthen 		log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
154145872187Ssthen 			repinfo->client_addrlen);
15420b68ff31Ssthen 		sldns_buffer_rewind(c->buffer);
15430b68ff31Ssthen 		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
15440b68ff31Ssthen 		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
1545933707f3Ssthen 			LDNS_RCODE_REFUSED);
1546933707f3Ssthen 		if(worker->stats.extended) {
1547933707f3Ssthen 			worker->stats.qtype[qinfo.qtype]++;
1548933707f3Ssthen 		}
1549e10d3884Sbrad 		goto send_reply;
1550933707f3Ssthen 	}
155177079be7Ssthen 	if(qinfo.qtype == LDNS_RR_TYPE_OPT ||
155277079be7Ssthen 		qinfo.qtype == LDNS_RR_TYPE_TSIG ||
155377079be7Ssthen 		qinfo.qtype == LDNS_RR_TYPE_TKEY ||
155477079be7Ssthen 		qinfo.qtype == LDNS_RR_TYPE_MAILA ||
155577079be7Ssthen 		qinfo.qtype == LDNS_RR_TYPE_MAILB ||
155677079be7Ssthen 		(qinfo.qtype >= 128 && qinfo.qtype <= 248)) {
155777079be7Ssthen 		verbose(VERB_ALGO, "worker request: formerror for meta-type.");
155845872187Ssthen 		log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
155945872187Ssthen 			repinfo->client_addrlen);
156077079be7Ssthen 		if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
156177079be7Ssthen 			comm_point_drop_reply(repinfo);
156277079be7Ssthen 			return 0;
156377079be7Ssthen 		}
156477079be7Ssthen 		sldns_buffer_rewind(c->buffer);
156577079be7Ssthen 		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
156677079be7Ssthen 		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
156777079be7Ssthen 			LDNS_RCODE_FORMERR);
156877079be7Ssthen 		if(worker->stats.extended) {
156977079be7Ssthen 			worker->stats.qtype[qinfo.qtype]++;
157077079be7Ssthen 		}
157177079be7Ssthen 		goto send_reply;
157277079be7Ssthen 	}
15738b7325afSsthen 	if((ret=parse_edns_from_query_pkt(
15748b7325afSsthen 			c->buffer, &edns, worker->env.cfg, c, repinfo,
15758b7325afSsthen 			(worker->env.now ? *worker->env.now : time(NULL)),
1576*98bc733bSsthen 			worker->scratchpad,
1577*98bc733bSsthen 			worker->daemon->cookie_secrets)) != 0) {
157824893edcSsthen 		struct edns_data reply_edns;
1579933707f3Ssthen 		verbose(VERB_ALGO, "worker parse edns: formerror.");
158045872187Ssthen 		log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
158145872187Ssthen 			repinfo->client_addrlen);
158224893edcSsthen 		memset(&reply_edns, 0, sizeof(reply_edns));
158324893edcSsthen 		reply_edns.edns_present = 1;
158424893edcSsthen 		error_encode(c->buffer, ret, &qinfo,
158524893edcSsthen 			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
158624893edcSsthen 			sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
15872ee382b6Ssthen 		regional_free_all(worker->scratchpad);
1588e10d3884Sbrad 		goto send_reply;
1589933707f3Ssthen 	}
15902308e98cSsthen 	if(edns.edns_present) {
15912308e98cSsthen 		if(edns.edns_version != 0) {
1592e21c60efSsthen 			edns.opt_list_in = NULL;
1593e21c60efSsthen 			edns.opt_list_out = NULL;
1594e21c60efSsthen 			edns.opt_list_inplace_cb_out = NULL;
1595933707f3Ssthen 			verbose(VERB_ALGO, "query with bad edns version.");
159645872187Ssthen 			log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
159745872187Ssthen 				repinfo->client_addrlen);
15988b7325afSsthen 			extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
1599e10d3884Sbrad 				*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
16008b7325afSsthen 				sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
16012ee382b6Ssthen 			regional_free_all(worker->scratchpad);
1602e10d3884Sbrad 			goto send_reply;
1603933707f3Ssthen 		}
16042308e98cSsthen 		if(edns.udp_size < NORMAL_UDP_SIZE &&
1605933707f3Ssthen 		   worker->daemon->cfg->harden_short_bufsize) {
1606933707f3Ssthen 			verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
1607933707f3Ssthen 				(int)edns.udp_size);
160845872187Ssthen 			log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
160945872187Ssthen 				repinfo->client_addrlen);
1610933707f3Ssthen 			edns.udp_size = NORMAL_UDP_SIZE;
1611933707f3Ssthen 		}
16122308e98cSsthen 	}
16138b7325afSsthen 
16148b7325afSsthen 	/* Get stats for cookies */
16158b7325afSsthen 	server_stats_downstream_cookie(&worker->stats, &edns);
16168b7325afSsthen 
16178b7325afSsthen 	/* If the IP rate limiting check was postponed, check now. */
16188b7325afSsthen 	if(!pre_edns_ip_ratelimit) {
16198b7325afSsthen 		/* NOTE: we always check the repinfo->client_address.
16208b7325afSsthen 		 *       IP ratelimiting is implicitly disabled for proxies. */
16218b7325afSsthen 		if(!check_ip_ratelimit(worker, &repinfo->client_addr,
16228b7325afSsthen 			repinfo->client_addrlen, edns.cookie_valid,
16238b7325afSsthen 			c->buffer)) {
16248b7325afSsthen 			worker->stats.num_queries_ip_ratelimited++;
16258b7325afSsthen 			comm_point_drop_reply(repinfo);
16268b7325afSsthen 			return 0;
16278b7325afSsthen 		}
16288b7325afSsthen 	}
16298b7325afSsthen 
16308b7325afSsthen 	/* "if, else if" sequence below deals with downstream DNS Cookies */
16318b7325afSsthen 	if(acl != acl_allow_cookie)
16328b7325afSsthen 		; /* pass; No cookie downstream processing whatsoever */
16338b7325afSsthen 
16348b7325afSsthen 	else if(edns.cookie_valid)
16358b7325afSsthen 		; /* pass; Valid cookie is good! */
16368b7325afSsthen 
16378b7325afSsthen 	else if(c->type != comm_udp)
16388b7325afSsthen 		; /* pass; Stateful transport */
16398b7325afSsthen 
16408b7325afSsthen 	else if(edns.cookie_present) {
16418b7325afSsthen 		/* Cookie present, but not valid: Cookie was bad! */
16428b7325afSsthen 		extended_error_encode(c->buffer,
16438b7325afSsthen 			LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
16448b7325afSsthen 			*(uint16_t*)(void *)
16458b7325afSsthen 			sldns_buffer_begin(c->buffer),
16468b7325afSsthen 			sldns_buffer_read_u16_at(c->buffer, 2),
16478b7325afSsthen 			0, &edns);
16488b7325afSsthen 		regional_free_all(worker->scratchpad);
16498b7325afSsthen 		goto send_reply;
16508b7325afSsthen 	} else {
16518b7325afSsthen 		/* Cookie required, but no cookie present on UDP */
16528b7325afSsthen 		verbose(VERB_ALGO, "worker request: "
16538b7325afSsthen 			"need cookie or stateful transport");
16548b7325afSsthen 		log_addr(VERB_ALGO, "from",&repinfo->remote_addr
16558b7325afSsthen 		                          , repinfo->remote_addrlen);
16568b7325afSsthen 		EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
16578b7325afSsthen 			worker->scratchpad, LDNS_EDE_OTHER,
16588b7325afSsthen 			"DNS Cookie needed for UDP replies");
16598b7325afSsthen 		error_encode(c->buffer,
16608b7325afSsthen 			(LDNS_RCODE_REFUSED|BIT_TC), &qinfo,
16618b7325afSsthen 			*(uint16_t*)(void *)
16628b7325afSsthen 			sldns_buffer_begin(c->buffer),
16638b7325afSsthen 			sldns_buffer_read_u16_at(c->buffer, 2),
16648b7325afSsthen 			&edns);
16658b7325afSsthen 		regional_free_all(worker->scratchpad);
16668b7325afSsthen 		goto send_reply;
16678b7325afSsthen 	}
16688b7325afSsthen 
1669e9c7b4efSsthen 	if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
1670e9c7b4efSsthen 		c->type == comm_udp) {
1671e9c7b4efSsthen 		verbose(VERB_QUERY,
1672e9c7b4efSsthen 			"worker request: max UDP reply size modified"
1673e9c7b4efSsthen 			" (%d to max-udp-size)", (int)edns.udp_size);
167445872187Ssthen 		log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
167545872187Ssthen 			repinfo->client_addrlen);
1676e9c7b4efSsthen 		edns.udp_size = worker->daemon->cfg->max_udp_size;
1677e9c7b4efSsthen 	}
1678e9c7b4efSsthen 	if(edns.udp_size < LDNS_HEADER_SIZE) {
1679933707f3Ssthen 		verbose(VERB_ALGO, "worker request: edns is too small.");
168045872187Ssthen 		log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
168145872187Ssthen 			repinfo->client_addrlen);
16820b68ff31Ssthen 		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
16830b68ff31Ssthen 		LDNS_TC_SET(sldns_buffer_begin(c->buffer));
16840b68ff31Ssthen 		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
1685933707f3Ssthen 			LDNS_RCODE_SERVFAIL);
16860b68ff31Ssthen 		sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
16870b68ff31Ssthen 		sldns_buffer_write_at(c->buffer, 4,
1688933707f3Ssthen 			(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
16890b68ff31Ssthen 		sldns_buffer_flip(c->buffer);
16902ee382b6Ssthen 		regional_free_all(worker->scratchpad);
1691e10d3884Sbrad 		goto send_reply;
1692933707f3Ssthen 	}
1693933707f3Ssthen 	if(worker->stats.extended)
1694933707f3Ssthen 		server_stats_insquery(&worker->stats, c, qinfo.qtype,
1695933707f3Ssthen 			qinfo.qclass, &edns, repinfo);
1696933707f3Ssthen 	if(c->type != comm_udp)
1697933707f3Ssthen 		edns.udp_size = 65535; /* max size for TCP replies */
1698933707f3Ssthen 	if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
16992308e98cSsthen 		&edns, repinfo, c->buffer)) {
17002ee382b6Ssthen 		regional_free_all(worker->scratchpad);
1701e10d3884Sbrad 		goto send_reply;
1702933707f3Ssthen 	}
170320237c55Ssthen 	if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
170420237c55Ssthen 		LDNS_PACKET_NOTIFY) {
170545872187Ssthen 		answer_notify(worker, &qinfo, &edns, c->buffer,
170645872187Ssthen 			&repinfo->client_addr, repinfo->client_addrlen);
170720237c55Ssthen 		regional_free_all(worker->scratchpad);
170820237c55Ssthen 		goto send_reply;
170920237c55Ssthen 	}
171077079be7Ssthen 	if(local_zones_answer(worker->daemon->local_zones, &worker->env, &qinfo,
171177079be7Ssthen 		&edns, c->buffer, worker->scratchpad, repinfo, acladdr->taglist,
171277079be7Ssthen 		acladdr->taglen, acladdr->tag_actions,
171377079be7Ssthen 		acladdr->tag_actions_size, acladdr->tag_datas,
171477079be7Ssthen 		acladdr->tag_datas_size, worker->daemon->cfg->tagname,
171577079be7Ssthen 		worker->daemon->cfg->num_tags, acladdr->view)) {
1716933707f3Ssthen 		regional_free_all(worker->scratchpad);
17170b68ff31Ssthen 		if(sldns_buffer_limit(c->buffer) == 0) {
1718933707f3Ssthen 			comm_point_drop_reply(repinfo);
1719933707f3Ssthen 			return 0;
1720933707f3Ssthen 		}
1721e10d3884Sbrad 		goto send_reply;
1722933707f3Ssthen 	}
1723938a3a5eSflorian 	if(worker->env.auth_zones &&
1724e21c60efSsthen 		rpz_callback_from_worker_request(worker->env.auth_zones,
1725eaf2578eSsthen 		&worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
17260bdb4f62Ssthen 		repinfo, acladdr->taglist, acladdr->taglen, &worker->stats,
17270bdb4f62Ssthen 		&rpz_passthru)) {
1728eaf2578eSsthen 		regional_free_all(worker->scratchpad);
1729eaf2578eSsthen 		if(sldns_buffer_limit(c->buffer) == 0) {
1730eaf2578eSsthen 			comm_point_drop_reply(repinfo);
1731eaf2578eSsthen 			return 0;
1732eaf2578eSsthen 		}
1733eaf2578eSsthen 		goto send_reply;
1734eaf2578eSsthen 	}
1735eaf2578eSsthen 	if(worker->env.auth_zones &&
1736938a3a5eSflorian 		auth_zones_answer(worker->env.auth_zones, &worker->env,
17372308e98cSsthen 		&qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
1738938a3a5eSflorian 		regional_free_all(worker->scratchpad);
1739938a3a5eSflorian 		if(sldns_buffer_limit(c->buffer) == 0) {
1740938a3a5eSflorian 			comm_point_drop_reply(repinfo);
1741938a3a5eSflorian 			return 0;
1742938a3a5eSflorian 		}
1743938a3a5eSflorian 		/* set RA for everyone that can have recursion (based on
1744938a3a5eSflorian 		 * access control list) */
1745938a3a5eSflorian 		if(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer)) &&
1746938a3a5eSflorian 		   acl != acl_deny_non_local && acl != acl_refuse_non_local)
1747938a3a5eSflorian 			LDNS_RA_SET(sldns_buffer_begin(c->buffer));
1748938a3a5eSflorian 		goto send_reply;
1749938a3a5eSflorian 	}
17500b68ff31Ssthen 
17510b68ff31Ssthen 	/* We've looked in our local zones. If the answer isn't there, we
17520b68ff31Ssthen 	 * might need to bail out based on ACLs now. */
17530bdb4f62Ssthen 	if((ret=deny_refuse_non_local(c, acl, worker, repinfo, acladdr,
17548b7325afSsthen 		worker->env.cfg->ede, &check_result)) != -1)
17550b68ff31Ssthen 	{
17562ee382b6Ssthen 		regional_free_all(worker->scratchpad);
1757e10d3884Sbrad 		if(ret == 1)
1758e10d3884Sbrad 			goto send_reply;
17590b68ff31Ssthen 		return ret;
17600b68ff31Ssthen 	}
17610b68ff31Ssthen 
17620b68ff31Ssthen 	/* If this request does not have the recursion bit set, verify
176320237c55Ssthen 	 * ACLs allow the recursion bit to be treated as set. */
176420237c55Ssthen 	if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
176520237c55Ssthen 		acl == acl_allow_setrd ) {
176620237c55Ssthen 		LDNS_RD_SET(sldns_buffer_begin(c->buffer));
176720237c55Ssthen 	}
176820237c55Ssthen 
176920237c55Ssthen 	/* If this request does not have the recursion bit set, verify
17700b68ff31Ssthen 	 * ACLs allow the snooping. */
17710b68ff31Ssthen 	if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
1772933707f3Ssthen 		acl != acl_allow_snoop ) {
17730bdb4f62Ssthen 		if(worker->env.cfg->ede) {
17740bdb4f62Ssthen 			EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
17750bdb4f62Ssthen 				worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
17760bdb4f62Ssthen 		}
1777bdfc4d55Sflorian 		error_encode(c->buffer, LDNS_RCODE_REFUSED, &qinfo,
1778bdfc4d55Sflorian 			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
17790bdb4f62Ssthen 			sldns_buffer_read_u16_at(c->buffer, 2), &edns);
17802ee382b6Ssthen 		regional_free_all(worker->scratchpad);
1781933707f3Ssthen 		log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
178245872187Ssthen 			&repinfo->client_addr, repinfo->client_addrlen);
17830bdb4f62Ssthen 
1784e10d3884Sbrad 		goto send_reply;
1785933707f3Ssthen 	}
178677079be7Ssthen 
178777079be7Ssthen 	/* If we've found a local alias, replace the qname with the alias
178877079be7Ssthen 	 * target before resolving it. */
178977079be7Ssthen 	if(qinfo.local_alias) {
179077079be7Ssthen 		struct ub_packed_rrset_key* rrset = qinfo.local_alias->rrset;
179177079be7Ssthen 		struct packed_rrset_data* d = rrset->entry.data;
179277079be7Ssthen 
179377079be7Ssthen 		/* Sanity check: our current implementation only supports
179477079be7Ssthen 		 * a single CNAME RRset as a local alias. */
179577079be7Ssthen 		if(qinfo.local_alias->next ||
179677079be7Ssthen 			rrset->rk.type != htons(LDNS_RR_TYPE_CNAME) ||
179777079be7Ssthen 			d->count != 1) {
179877079be7Ssthen 			log_err("assumption failure: unexpected local alias");
179977079be7Ssthen 			regional_free_all(worker->scratchpad);
180077079be7Ssthen 			return 0; /* drop it */
180177079be7Ssthen 		}
180277079be7Ssthen 		qinfo.qname = d->rr_data[0] + 2;
180377079be7Ssthen 		qinfo.qname_len = d->rr_len[0] - 2;
180477079be7Ssthen 	}
180577079be7Ssthen 
18062be9e038Ssthen 	/* If we may apply IP-based actions to the answer, build the client
18072be9e038Ssthen 	 * information.  As this can be expensive, skip it if there is
18082be9e038Ssthen 	 * absolutely no possibility of it. */
1809eaf2578eSsthen 	if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
18102be9e038Ssthen 		(qinfo.qtype == LDNS_RR_TYPE_A ||
18112be9e038Ssthen 		qinfo.qtype == LDNS_RR_TYPE_AAAA ||
18122be9e038Ssthen 		qinfo.qtype == LDNS_RR_TYPE_ANY)) {
18132be9e038Ssthen 		cinfo_tmp.taglist = acladdr->taglist;
18142be9e038Ssthen 		cinfo_tmp.taglen = acladdr->taglen;
18152be9e038Ssthen 		cinfo_tmp.tag_actions = acladdr->tag_actions;
18162be9e038Ssthen 		cinfo_tmp.tag_actions_size = acladdr->tag_actions_size;
18172be9e038Ssthen 		cinfo_tmp.tag_datas = acladdr->tag_datas;
18182be9e038Ssthen 		cinfo_tmp.tag_datas_size = acladdr->tag_datas_size;
18192be9e038Ssthen 		cinfo_tmp.view = acladdr->view;
18202be9e038Ssthen 		cinfo_tmp.respip_set = worker->daemon->respip_set;
18212be9e038Ssthen 		cinfo = &cinfo_tmp;
18222be9e038Ssthen 	}
18232be9e038Ssthen 
18240bdb4f62Ssthen 	/* Keep the original edns list around. The pointer could change if there is
18250bdb4f62Ssthen 	 * a cached answer (through the inplace callback function there).
18260bdb4f62Ssthen 	 * No need to actually copy the contents as they shouldn't change.
18270bdb4f62Ssthen 	 * Used while prefetching and subnet is enabled. */
18280bdb4f62Ssthen 	original_edns_list = edns.opt_list_in;
18292be9e038Ssthen lookup_cache:
18302be9e038Ssthen 	/* Lookup the cache.  In case we chase an intermediate CNAME chain
18312be9e038Ssthen 	 * this is a two-pass operation, and lookup_qinfo is different for
18322be9e038Ssthen 	 * each pass.  We should still pass the original qinfo to
18332be9e038Ssthen 	 * answer_from_cache(), however, since it's used to build the reply. */
1834e21c60efSsthen 	if(!edns_bypass_cache_stage(edns.opt_list_in, &worker->env)) {
1835eaf2578eSsthen 		is_expired_answer = 0;
1836eaf2578eSsthen 		is_secure_answer = 0;
18372be9e038Ssthen 		h = query_info_hash(lookup_qinfo, sldns_buffer_read_u16_at(c->buffer, 2));
18382be9e038Ssthen 		if((e=slabhash_lookup(worker->env.msg_cache, h, lookup_qinfo, 0))) {
1839d1e2768aSsthen 			struct reply_info* rep = (struct reply_info*)e->data;
1840933707f3Ssthen 			/* answer from cache - we have acquired a readlock on it */
1841d1e2768aSsthen 			if(answer_from_cache(worker, &qinfo, cinfo, &need_drop,
1842d1e2768aSsthen 				&is_expired_answer, &is_secure_answer,
1843d1e2768aSsthen 				&alias_rrset, &partial_rep, rep,
1844e10d3884Sbrad 				*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
18450b68ff31Ssthen 				sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
1846933707f3Ssthen 				&edns)) {
18472be9e038Ssthen 				/* prefetch it if the prefetch TTL expired.
18482be9e038Ssthen 				 * Note that if there is more than one pass
18492be9e038Ssthen 				 * its qname must be that used for cache
18502be9e038Ssthen 				 * lookup. */
1851d1e2768aSsthen 				if((worker->env.cfg->prefetch &&
1852d1e2768aSsthen 					*worker->env.now >= rep->prefetch_ttl) ||
1853eaf2578eSsthen 					(worker->env.cfg->serve_expired &&
1854d1e2768aSsthen 					*worker->env.now > rep->ttl)) {
1855eaf2578eSsthen 
1856d1e2768aSsthen 					time_t leeway = rep->ttl - *worker->env.now;
1857d1e2768aSsthen 					if(rep->ttl < *worker->env.now)
185877079be7Ssthen 						leeway = 0;
1859933707f3Ssthen 					lock_rw_unlock(&e->lock);
18600bdb4f62Ssthen 
18612be9e038Ssthen 					reply_and_prefetch(worker, lookup_qinfo,
18620b68ff31Ssthen 						sldns_buffer_read_u16_at(c->buffer, 2),
18638240c1b9Ssthen 						repinfo, leeway,
18640bdb4f62Ssthen 						(partial_rep || need_drop),
18650bdb4f62Ssthen 						rpz_passthru,
18660bdb4f62Ssthen 						original_edns_list);
18672be9e038Ssthen 					if(!partial_rep) {
1868e10d3884Sbrad 						rc = 0;
18692ee382b6Ssthen 						regional_free_all(worker->scratchpad);
1870e10d3884Sbrad 						goto send_reply_rc;
1871933707f3Ssthen 					}
18722be9e038Ssthen 				} else if(!partial_rep) {
1873933707f3Ssthen 					lock_rw_unlock(&e->lock);
18742ee382b6Ssthen 					regional_free_all(worker->scratchpad);
1875e10d3884Sbrad 					goto send_reply;
18767191de28Ssthen 				} else {
18777191de28Ssthen 					/* Note that we've already released the
18787191de28Ssthen 					 * lock if we're here after prefetch. */
18797191de28Ssthen 					lock_rw_unlock(&e->lock);
1880933707f3Ssthen 				}
18812be9e038Ssthen 				/* We've found a partial reply ending with an
18822be9e038Ssthen 				 * alias.  Replace the lookup qinfo for the
18832be9e038Ssthen 				 * alias target and lookup the cache again to
18842be9e038Ssthen 				 * (possibly) complete the reply.  As we're
18852be9e038Ssthen 				 * passing the "base" reply, there will be no
18862be9e038Ssthen 				 * more alias chasing. */
18872be9e038Ssthen 				memset(&qinfo_tmp, 0, sizeof(qinfo_tmp));
18882be9e038Ssthen 				get_cname_target(alias_rrset, &qinfo_tmp.qname,
18892be9e038Ssthen 					&qinfo_tmp.qname_len);
18902be9e038Ssthen 				if(!qinfo_tmp.qname) {
18912be9e038Ssthen 					log_err("unexpected: invalid answer alias");
18922be9e038Ssthen 					regional_free_all(worker->scratchpad);
18932be9e038Ssthen 					return 0; /* drop query */
18942be9e038Ssthen 				}
18952be9e038Ssthen 				qinfo_tmp.qtype = qinfo.qtype;
18962be9e038Ssthen 				qinfo_tmp.qclass = qinfo.qclass;
18972be9e038Ssthen 				lookup_qinfo = &qinfo_tmp;
18982be9e038Ssthen 				goto lookup_cache;
18992be9e038Ssthen 			}
1900933707f3Ssthen 			verbose(VERB_ALGO, "answer from the cache failed");
1901933707f3Ssthen 			lock_rw_unlock(&e->lock);
1902933707f3Ssthen 		}
19030bdb4f62Ssthen 
19040b68ff31Ssthen 		if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) {
1905933707f3Ssthen 			if(answer_norec_from_cache(worker, &qinfo,
1906e10d3884Sbrad 				*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
19070b68ff31Ssthen 				sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
1908933707f3Ssthen 				&edns)) {
19092ee382b6Ssthen 				regional_free_all(worker->scratchpad);
1910e10d3884Sbrad 				goto send_reply;
1911933707f3Ssthen 			}
1912933707f3Ssthen 			verbose(VERB_ALGO, "answer norec from cache -- "
1913933707f3Ssthen 				"need to validate or not primed");
1914933707f3Ssthen 		}
191577079be7Ssthen 	}
19160b68ff31Ssthen 	sldns_buffer_rewind(c->buffer);
1917933707f3Ssthen 	server_stats_querymiss(&worker->stats, worker);
1918933707f3Ssthen 
1919933707f3Ssthen 	if(verbosity >= VERB_CLIENT) {
1920933707f3Ssthen 		if(c->type == comm_udp)
1921933707f3Ssthen 			log_addr(VERB_CLIENT, "udp request from",
192245872187Ssthen 				&repinfo->client_addr, repinfo->client_addrlen);
1923933707f3Ssthen 		else	log_addr(VERB_CLIENT, "tcp request from",
192445872187Ssthen 				&repinfo->client_addr, repinfo->client_addrlen);
1925933707f3Ssthen 	}
1926933707f3Ssthen 
1927933707f3Ssthen 	/* grab a work request structure for this new request */
19282be9e038Ssthen 	mesh_new_client(worker->env.mesh, &qinfo, cinfo,
19290b68ff31Ssthen 		sldns_buffer_read_u16_at(c->buffer, 2),
19300bdb4f62Ssthen 		&edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
19310bdb4f62Ssthen 		rpz_passthru);
19322ee382b6Ssthen 	regional_free_all(worker->scratchpad);
1933933707f3Ssthen 	worker_mem_report(worker, NULL);
1934933707f3Ssthen 	return 0;
1935e10d3884Sbrad 
1936e10d3884Sbrad send_reply:
1937e10d3884Sbrad 	rc = 1;
1938e10d3884Sbrad send_reply_rc:
19392be9e038Ssthen 	if(need_drop) {
19402be9e038Ssthen 		comm_point_drop_reply(repinfo);
19412be9e038Ssthen 		return 0;
19422be9e038Ssthen 	}
1943eaf2578eSsthen 	if(is_expired_answer) {
1944eaf2578eSsthen 		worker->stats.ans_expired++;
1945eaf2578eSsthen 	}
19462c144df0Ssthen 	server_stats_insrcode(&worker->stats, c->buffer);
1947eaf2578eSsthen 	if(worker->stats.extended) {
1948eaf2578eSsthen 		if(is_secure_answer) worker->stats.ans_secure++;
1949eaf2578eSsthen 	}
1950e10d3884Sbrad #ifdef USE_DNSTAP
1951191f22c6Ssthen 	/*
1952191f22c6Ssthen 	 * sending src (client)/dst (local service) addresses over DNSTAP from send_reply code label (when we serviced local zone for ex.)
1953191f22c6Ssthen 	 */
19542bdc0ed1Ssthen 	if(worker->dtenv.log_client_response_messages && rc !=0) {
19552bdc0ed1Ssthen 		log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr, repinfo->c->socket->addrlen);
195645872187Ssthen 		log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
19572bdc0ed1Ssthen 		dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr, c->type, c->ssl, c->buffer);
1958191f22c6Ssthen 	}
1959e10d3884Sbrad #endif
196077079be7Ssthen 	if(worker->env.cfg->log_replies)
196177079be7Ssthen 	{
1962ebf5bb73Ssthen 		struct timeval tv;
1963ebf5bb73Ssthen 		memset(&tv, 0, sizeof(tv));
1964c3b38330Ssthen 		if(qinfo.local_alias && qinfo.local_alias->rrset &&
1965c3b38330Ssthen 			qinfo.local_alias->rrset->rk.dname) {
1966c3b38330Ssthen 			/* log original qname, before the local alias was
1967c3b38330Ssthen 			 * used to resolve that CNAME to something else */
1968c3b38330Ssthen 			qinfo.qname = qinfo.local_alias->rrset->rk.dname;
196945872187Ssthen 			log_reply_info(NO_VERBOSE, &qinfo,
197045872187Ssthen 				&repinfo->client_addr, repinfo->client_addrlen,
1971f46c52bfSsthen 				tv, 1, c->buffer,
19722bdc0ed1Ssthen 				(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL),
1973f46c52bfSsthen 				c->type);
1974c3b38330Ssthen 		} else {
197545872187Ssthen 			log_reply_info(NO_VERBOSE, &qinfo,
197645872187Ssthen 				&repinfo->client_addr, repinfo->client_addrlen,
1977f46c52bfSsthen 				tv, 1, c->buffer,
19782bdc0ed1Ssthen 				(worker->env.cfg->log_destaddr?(void*)repinfo->c->socket->addr:NULL),
1979f46c52bfSsthen 				c->type);
1980c3b38330Ssthen 		}
198177079be7Ssthen 	}
19822be9e038Ssthen #ifdef USE_DNSCRYPT
19832be9e038Ssthen 	if(!dnsc_handle_uncurved_request(repinfo)) {
19842be9e038Ssthen 		return 0;
19852be9e038Ssthen 	}
19862be9e038Ssthen #endif
1987e10d3884Sbrad 	return rc;
1988933707f3Ssthen }
1989933707f3Ssthen 
1990933707f3Ssthen void
1991933707f3Ssthen worker_sighandler(int sig, void* arg)
1992933707f3Ssthen {
1993e10d3884Sbrad 	/* note that log, print, syscalls here give race conditions.
1994e10d3884Sbrad 	 * And cause hangups if the log-lock is held by the application. */
1995933707f3Ssthen 	struct worker* worker = (struct worker*)arg;
1996933707f3Ssthen 	switch(sig) {
1997933707f3Ssthen #ifdef SIGHUP
1998933707f3Ssthen 		case SIGHUP:
1999933707f3Ssthen 			comm_base_exit(worker->base);
2000933707f3Ssthen 			break;
2001933707f3Ssthen #endif
20020bdb4f62Ssthen #ifdef SIGBREAK
20030bdb4f62Ssthen 		case SIGBREAK:
20040bdb4f62Ssthen #endif
2005933707f3Ssthen 		case SIGINT:
2006933707f3Ssthen 			worker->need_to_exit = 1;
2007933707f3Ssthen 			comm_base_exit(worker->base);
2008933707f3Ssthen 			break;
2009933707f3Ssthen #ifdef SIGQUIT
2010933707f3Ssthen 		case SIGQUIT:
2011933707f3Ssthen 			worker->need_to_exit = 1;
2012933707f3Ssthen 			comm_base_exit(worker->base);
2013933707f3Ssthen 			break;
2014933707f3Ssthen #endif
2015933707f3Ssthen 		case SIGTERM:
2016933707f3Ssthen 			worker->need_to_exit = 1;
2017933707f3Ssthen 			comm_base_exit(worker->base);
2018933707f3Ssthen 			break;
2019933707f3Ssthen 		default:
2020e10d3884Sbrad 			/* unknown signal, ignored */
2021933707f3Ssthen 			break;
2022933707f3Ssthen 	}
2023933707f3Ssthen }
2024933707f3Ssthen 
2025933707f3Ssthen /** restart statistics timer for worker, if enabled */
2026933707f3Ssthen static void
2027933707f3Ssthen worker_restart_timer(struct worker* worker)
2028933707f3Ssthen {
2029933707f3Ssthen 	if(worker->env.cfg->stat_interval > 0) {
2030933707f3Ssthen 		struct timeval tv;
2031933707f3Ssthen #ifndef S_SPLINT_S
2032933707f3Ssthen 		tv.tv_sec = worker->env.cfg->stat_interval;
2033933707f3Ssthen 		tv.tv_usec = 0;
2034933707f3Ssthen #endif
2035933707f3Ssthen 		comm_timer_set(worker->stat_timer, &tv);
2036933707f3Ssthen 	}
2037933707f3Ssthen }
2038933707f3Ssthen 
2039933707f3Ssthen void worker_stat_timer_cb(void* arg)
2040933707f3Ssthen {
2041933707f3Ssthen 	struct worker* worker = (struct worker*)arg;
2042933707f3Ssthen 	server_stats_log(&worker->stats, worker, worker->thread_num);
2043933707f3Ssthen 	mesh_stats(worker->env.mesh, "mesh has");
2044933707f3Ssthen 	worker_mem_report(worker, NULL);
20452be9e038Ssthen 	/* SHM is enabled, process data to SHM */
20462be9e038Ssthen 	if (worker->daemon->cfg->shm_enable) {
20472be9e038Ssthen 		shm_main_run(worker);
20482be9e038Ssthen 	}
2049933707f3Ssthen 	if(!worker->daemon->cfg->stat_cumulative) {
2050933707f3Ssthen 		worker_stats_clear(worker);
2051933707f3Ssthen 	}
2052933707f3Ssthen 	/* start next timer */
2053933707f3Ssthen 	worker_restart_timer(worker);
2054933707f3Ssthen }
2055933707f3Ssthen 
2056933707f3Ssthen void worker_probe_timer_cb(void* arg)
2057933707f3Ssthen {
2058933707f3Ssthen 	struct worker* worker = (struct worker*)arg;
2059933707f3Ssthen 	struct timeval tv;
2060933707f3Ssthen #ifndef S_SPLINT_S
2061933707f3Ssthen 	tv.tv_sec = (time_t)autr_probe_timer(&worker->env);
2062933707f3Ssthen 	tv.tv_usec = 0;
2063933707f3Ssthen #endif
2064933707f3Ssthen 	if(tv.tv_sec != 0)
2065933707f3Ssthen 		comm_timer_set(worker->env.probe_timer, &tv);
2066933707f3Ssthen }
2067933707f3Ssthen 
2068933707f3Ssthen struct worker*
2069933707f3Ssthen worker_create(struct daemon* daemon, int id, int* ports, int n)
2070933707f3Ssthen {
2071933707f3Ssthen 	unsigned int seed;
2072933707f3Ssthen 	struct worker* worker = (struct worker*)calloc(1,
2073933707f3Ssthen 		sizeof(struct worker));
2074933707f3Ssthen 	if(!worker)
2075933707f3Ssthen 		return NULL;
2076933707f3Ssthen 	worker->numports = n;
2077933707f3Ssthen 	worker->ports = (int*)memdup(ports, sizeof(int)*n);
2078933707f3Ssthen 	if(!worker->ports) {
2079933707f3Ssthen 		free(worker);
2080933707f3Ssthen 		return NULL;
2081933707f3Ssthen 	}
2082933707f3Ssthen 	worker->daemon = daemon;
2083933707f3Ssthen 	worker->thread_num = id;
2084933707f3Ssthen 	if(!(worker->cmd = tube_create())) {
2085933707f3Ssthen 		free(worker->ports);
2086933707f3Ssthen 		free(worker);
2087933707f3Ssthen 		return NULL;
2088933707f3Ssthen 	}
2089933707f3Ssthen 	/* create random state here to avoid locking trouble in RAND_bytes */
2090ebf5bb73Ssthen 	if(!(worker->rndstate = ub_initstate(daemon->rand))) {
2091933707f3Ssthen 		log_err("could not init random numbers.");
2092933707f3Ssthen 		tube_delete(worker->cmd);
2093933707f3Ssthen 		free(worker->ports);
2094933707f3Ssthen 		free(worker);
2095933707f3Ssthen 		return NULL;
2096933707f3Ssthen 	}
2097452a1548Ssthen 	explicit_bzero(&seed, sizeof(seed));
2098933707f3Ssthen 	return worker;
2099933707f3Ssthen }
2100933707f3Ssthen 
2101933707f3Ssthen int
2102933707f3Ssthen worker_init(struct worker* worker, struct config_file *cfg,
2103933707f3Ssthen 	struct listen_port* ports, int do_sigs)
2104933707f3Ssthen {
2105e10d3884Sbrad #ifdef USE_DNSTAP
2106e10d3884Sbrad 	struct dt_env* dtenv = &worker->dtenv;
2107e10d3884Sbrad #else
2108e10d3884Sbrad 	void* dtenv = NULL;
2109e10d3884Sbrad #endif
211045872187Ssthen #ifdef HAVE_GETTID
211145872187Ssthen 	worker->thread_tid = gettid();
211245872187Ssthen #endif
2113933707f3Ssthen 	worker->need_to_exit = 0;
2114933707f3Ssthen 	worker->base = comm_base_create(do_sigs);
2115933707f3Ssthen 	if(!worker->base) {
2116933707f3Ssthen 		log_err("could not create event handling base");
2117933707f3Ssthen 		worker_delete(worker);
2118933707f3Ssthen 		return 0;
2119933707f3Ssthen 	}
2120af4988b1Ssthen 	comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept,
2121af4988b1Ssthen 		&worker_start_accept, worker);
2122933707f3Ssthen 	if(do_sigs) {
2123933707f3Ssthen #ifdef SIGHUP
2124933707f3Ssthen 		ub_thread_sig_unblock(SIGHUP);
2125933707f3Ssthen #endif
21260bdb4f62Ssthen #ifdef SIGBREAK
21270bdb4f62Ssthen 		ub_thread_sig_unblock(SIGBREAK);
21280bdb4f62Ssthen #endif
2129933707f3Ssthen 		ub_thread_sig_unblock(SIGINT);
2130933707f3Ssthen #ifdef SIGQUIT
2131933707f3Ssthen 		ub_thread_sig_unblock(SIGQUIT);
2132933707f3Ssthen #endif
2133933707f3Ssthen 		ub_thread_sig_unblock(SIGTERM);
2134933707f3Ssthen #ifndef LIBEVENT_SIGNAL_PROBLEM
2135933707f3Ssthen 		worker->comsig = comm_signal_create(worker->base,
2136933707f3Ssthen 			worker_sighandler, worker);
2137933707f3Ssthen 		if(!worker->comsig
2138933707f3Ssthen #ifdef SIGHUP
2139933707f3Ssthen 			|| !comm_signal_bind(worker->comsig, SIGHUP)
2140933707f3Ssthen #endif
2141933707f3Ssthen #ifdef SIGQUIT
2142933707f3Ssthen 			|| !comm_signal_bind(worker->comsig, SIGQUIT)
2143933707f3Ssthen #endif
2144933707f3Ssthen 			|| !comm_signal_bind(worker->comsig, SIGTERM)
21450bdb4f62Ssthen #ifdef SIGBREAK
21460bdb4f62Ssthen 			|| !comm_signal_bind(worker->comsig, SIGBREAK)
21470bdb4f62Ssthen #endif
2148933707f3Ssthen 			|| !comm_signal_bind(worker->comsig, SIGINT)) {
2149933707f3Ssthen 			log_err("could not create signal handlers");
2150933707f3Ssthen 			worker_delete(worker);
2151933707f3Ssthen 			return 0;
2152933707f3Ssthen 		}
2153933707f3Ssthen #endif /* LIBEVENT_SIGNAL_PROBLEM */
2154933707f3Ssthen 		if(!daemon_remote_open_accept(worker->daemon->rc,
2155933707f3Ssthen 			worker->daemon->rc_ports, worker)) {
2156933707f3Ssthen 			worker_delete(worker);
2157933707f3Ssthen 			return 0;
2158933707f3Ssthen 		}
2159933707f3Ssthen #ifdef UB_ON_WINDOWS
2160933707f3Ssthen 		wsvc_setup_worker(worker);
2161933707f3Ssthen #endif /* UB_ON_WINDOWS */
2162933707f3Ssthen 	} else { /* !do_sigs */
2163933707f3Ssthen 		worker->comsig = NULL;
2164933707f3Ssthen 	}
21652c144df0Ssthen #ifdef USE_DNSTAP
21662c144df0Ssthen 	if(cfg->dnstap) {
21672c144df0Ssthen 		log_assert(worker->daemon->dtenv != NULL);
21682c144df0Ssthen 		memcpy(&worker->dtenv, worker->daemon->dtenv, sizeof(struct dt_env));
21692c144df0Ssthen 		if(!dt_init(&worker->dtenv, worker->base))
21702c144df0Ssthen 			fatal_exit("dt_init failed");
21712c144df0Ssthen 	}
21722c144df0Ssthen #endif
2173933707f3Ssthen 	worker->front = listen_create(worker->base, ports,
2174933707f3Ssthen 		cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
21752308e98cSsthen 		cfg->do_tcp_keepalive
21762308e98cSsthen 			? cfg->tcp_keepalive_timeout
21772308e98cSsthen 			: cfg->tcp_idle_timeout,
21782c144df0Ssthen 		cfg->harden_large_queries, cfg->http_max_streams,
2179eba819a2Ssthen 		cfg->http_endpoint, cfg->http_notls_downstream,
2180eba819a2Ssthen 		worker->daemon->tcl, worker->daemon->listen_sslctx,
21812308e98cSsthen 		dtenv, worker_handle_request, worker);
2182933707f3Ssthen 	if(!worker->front) {
2183933707f3Ssthen 		log_err("could not create listening sockets");
2184933707f3Ssthen 		worker_delete(worker);
2185933707f3Ssthen 		return 0;
2186933707f3Ssthen 	}
2187933707f3Ssthen 	worker->back = outside_network_create(worker->base,
2188933707f3Ssthen 		cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports,
2189933707f3Ssthen 		cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
2190a3167c07Ssthen 		cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
2191933707f3Ssthen 		worker->daemon->env->infra_cache, worker->rndstate,
2192933707f3Ssthen 		cfg->use_caps_bits_for_id, worker->ports, worker->numports,
219332e31f52Ssthen 		cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
219432e31f52Ssthen 		&worker_alloc_cleanup, worker,
2195bdfc4d55Sflorian 		cfg->do_udp || cfg->udp_upstream_without_downstream,
2196bdfc4d55Sflorian 		worker->daemon->connect_sslctx, cfg->delay_close,
2197191f22c6Ssthen 		cfg->tls_use_sni, dtenv, cfg->udp_connect,
2198191f22c6Ssthen 		cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
2199191f22c6Ssthen 		cfg->tcp_auth_query_timeout);
2200933707f3Ssthen 	if(!worker->back) {
2201933707f3Ssthen 		log_err("could not create outgoing sockets");
2202933707f3Ssthen 		worker_delete(worker);
2203933707f3Ssthen 		return 0;
2204933707f3Ssthen 	}
2205191f22c6Ssthen 	iterator_set_ip46_support(&worker->daemon->mods, worker->daemon->env,
2206191f22c6Ssthen 		worker->back);
2207933707f3Ssthen 	/* start listening to commands */
2208933707f3Ssthen 	if(!tube_setup_bg_listen(worker->cmd, worker->base,
2209933707f3Ssthen 		&worker_handle_control_cmd, worker)) {
2210933707f3Ssthen 		log_err("could not create control compt.");
2211933707f3Ssthen 		worker_delete(worker);
2212933707f3Ssthen 		return 0;
2213933707f3Ssthen 	}
2214933707f3Ssthen 	worker->stat_timer = comm_timer_create(worker->base,
2215933707f3Ssthen 		worker_stat_timer_cb, worker);
2216933707f3Ssthen 	if(!worker->stat_timer) {
2217933707f3Ssthen 		log_err("could not create statistics timer");
2218933707f3Ssthen 	}
2219933707f3Ssthen 
2220933707f3Ssthen 	/* we use the msg_buffer_size as a good estimate for what the
2221933707f3Ssthen 	 * user wants for memory usage sizes */
2222933707f3Ssthen 	worker->scratchpad = regional_create_custom(cfg->msg_buffer_size);
2223933707f3Ssthen 	if(!worker->scratchpad) {
2224933707f3Ssthen 		log_err("malloc failure");
2225933707f3Ssthen 		worker_delete(worker);
2226933707f3Ssthen 		return 0;
2227933707f3Ssthen 	}
2228933707f3Ssthen 
2229933707f3Ssthen 	server_stats_init(&worker->stats, cfg);
22308b7325afSsthen 	worker->alloc = worker->daemon->worker_allocs[worker->thread_num];
22318b7325afSsthen 	alloc_set_id_cleanup(worker->alloc, &worker_alloc_cleanup, worker);
2232933707f3Ssthen 	worker->env = *worker->daemon->env;
2233933707f3Ssthen 	comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv);
2234933707f3Ssthen 	worker->env.worker = worker;
2235bdfc4d55Sflorian 	worker->env.worker_base = worker->base;
2236933707f3Ssthen 	worker->env.send_query = &worker_send_query;
22378b7325afSsthen 	worker->env.alloc = worker->alloc;
2238bdfc4d55Sflorian 	worker->env.outnet = worker->back;
2239933707f3Ssthen 	worker->env.rnd = worker->rndstate;
22407191de28Ssthen 	/* If case prefetch is triggered, the corresponding mesh will clear
22417191de28Ssthen 	 * the scratchpad for the module env in the middle of request handling.
22427191de28Ssthen 	 * It would be prone to a use-after-free kind of bug, so we avoid
22437191de28Ssthen 	 * sharing it with worker's own scratchpad at the cost of having
22447191de28Ssthen 	 * one more pad per worker. */
22457191de28Ssthen 	worker->env.scratch = regional_create_custom(cfg->msg_buffer_size);
22467191de28Ssthen 	if(!worker->env.scratch) {
22477191de28Ssthen 		log_err("malloc failure");
22487191de28Ssthen 		worker_delete(worker);
22497191de28Ssthen 		return 0;
22507191de28Ssthen 	}
2251933707f3Ssthen 	worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
2252191f22c6Ssthen 	if(!worker->env.mesh) {
2253191f22c6Ssthen 		log_err("malloc failure");
2254191f22c6Ssthen 		worker_delete(worker);
2255191f22c6Ssthen 		return 0;
2256191f22c6Ssthen 	}
2257eaf2578eSsthen 	/* Pass on daemon variables that we would need in the mesh area */
2258eaf2578eSsthen 	worker->env.mesh->use_response_ip = worker->daemon->use_response_ip;
2259eaf2578eSsthen 	worker->env.mesh->use_rpz = worker->daemon->use_rpz;
2260eaf2578eSsthen 
2261933707f3Ssthen 	worker->env.detach_subs = &mesh_detach_subs;
2262933707f3Ssthen 	worker->env.attach_sub = &mesh_attach_sub;
22632be9e038Ssthen 	worker->env.add_sub = &mesh_add_sub;
2264933707f3Ssthen 	worker->env.kill_sub = &mesh_state_delete;
2265933707f3Ssthen 	worker->env.detect_cycle = &mesh_detect_cycle;
22660b68ff31Ssthen 	worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
2267191f22c6Ssthen 	if(!worker->env.scratch_buffer) {
2268191f22c6Ssthen 		log_err("malloc failure");
2269191f22c6Ssthen 		worker_delete(worker);
2270191f22c6Ssthen 		return 0;
2271191f22c6Ssthen 	}
2272933707f3Ssthen 	/* one probe timer per process -- if we have 5011 anchors */
2273933707f3Ssthen 	if(autr_get_num_anchors(worker->env.anchors) > 0
2274933707f3Ssthen #ifndef THREADS_DISABLED
2275933707f3Ssthen 		&& worker->thread_num == 0
2276933707f3Ssthen #endif
2277933707f3Ssthen 		) {
2278933707f3Ssthen 		struct timeval tv;
2279933707f3Ssthen 		tv.tv_sec = 0;
2280933707f3Ssthen 		tv.tv_usec = 0;
2281933707f3Ssthen 		worker->env.probe_timer = comm_timer_create(worker->base,
2282933707f3Ssthen 			worker_probe_timer_cb, worker);
2283933707f3Ssthen 		if(!worker->env.probe_timer) {
2284933707f3Ssthen 			log_err("could not create 5011-probe timer");
2285933707f3Ssthen 		} else {
2286933707f3Ssthen 			/* let timer fire, then it can reset itself */
2287933707f3Ssthen 			comm_timer_set(worker->env.probe_timer, &tv);
2288933707f3Ssthen 		}
2289933707f3Ssthen 	}
2290938a3a5eSflorian 	/* zone transfer tasks, setup once per process, if any */
2291938a3a5eSflorian 	if(worker->env.auth_zones
2292938a3a5eSflorian #ifndef THREADS_DISABLED
2293938a3a5eSflorian 		&& worker->thread_num == 0
2294938a3a5eSflorian #endif
2295938a3a5eSflorian 		) {
2296938a3a5eSflorian 		auth_xfer_pickup_initial(worker->env.auth_zones, &worker->env);
2297191f22c6Ssthen 		auth_zones_pickup_zonemd_verify(worker->env.auth_zones,
2298191f22c6Ssthen 			&worker->env);
2299938a3a5eSflorian 	}
2300a3167c07Ssthen #ifdef USE_DNSTAP
2301a3167c07Ssthen 	if(worker->daemon->cfg->dnstap
2302a3167c07Ssthen #ifndef THREADS_DISABLED
2303a3167c07Ssthen 		&& worker->thread_num == 0
2304a3167c07Ssthen #endif
2305a3167c07Ssthen 		) {
2306a3167c07Ssthen 		if(!dt_io_thread_start(dtenv->dtio, comm_base_internal(
2307a3167c07Ssthen 			worker->base), worker->daemon->num)) {
2308a3167c07Ssthen 			log_err("could not start dnstap io thread");
2309a3167c07Ssthen 			worker_delete(worker);
2310a3167c07Ssthen 			return 0;
2311a3167c07Ssthen 		}
2312a3167c07Ssthen 	}
2313a3167c07Ssthen #endif /* USE_DNSTAP */
2314933707f3Ssthen 	worker_mem_report(worker, NULL);
2315933707f3Ssthen 	/* if statistics enabled start timer */
2316933707f3Ssthen 	if(worker->env.cfg->stat_interval > 0) {
2317933707f3Ssthen 		verbose(VERB_ALGO, "set statistics interval %d secs",
2318933707f3Ssthen 			worker->env.cfg->stat_interval);
2319933707f3Ssthen 		worker_restart_timer(worker);
2320933707f3Ssthen 	}
2321d896b962Ssthen 	pp_init(&sldns_write_uint16, &sldns_write_uint32);
2322933707f3Ssthen 	return 1;
2323933707f3Ssthen }
2324933707f3Ssthen 
2325933707f3Ssthen void
2326933707f3Ssthen worker_work(struct worker* worker)
2327933707f3Ssthen {
2328933707f3Ssthen 	comm_base_dispatch(worker->base);
2329933707f3Ssthen }
2330933707f3Ssthen 
2331933707f3Ssthen void
2332933707f3Ssthen worker_delete(struct worker* worker)
2333933707f3Ssthen {
2334933707f3Ssthen 	if(!worker)
2335933707f3Ssthen 		return;
2336933707f3Ssthen 	if(worker->env.mesh && verbosity >= VERB_OPS) {
2337933707f3Ssthen 		server_stats_log(&worker->stats, worker, worker->thread_num);
2338933707f3Ssthen 		mesh_stats(worker->env.mesh, "mesh has");
2339933707f3Ssthen 		worker_mem_report(worker, NULL);
2340933707f3Ssthen 	}
2341933707f3Ssthen 	outside_network_quit_prepare(worker->back);
2342933707f3Ssthen 	mesh_delete(worker->env.mesh);
23430b68ff31Ssthen 	sldns_buffer_free(worker->env.scratch_buffer);
2344933707f3Ssthen 	listen_delete(worker->front);
2345933707f3Ssthen 	outside_network_delete(worker->back);
2346933707f3Ssthen 	comm_signal_delete(worker->comsig);
2347933707f3Ssthen 	tube_delete(worker->cmd);
2348933707f3Ssthen 	comm_timer_delete(worker->stat_timer);
2349933707f3Ssthen 	comm_timer_delete(worker->env.probe_timer);
2350933707f3Ssthen 	free(worker->ports);
2351933707f3Ssthen 	if(worker->thread_num == 0) {
2352933707f3Ssthen #ifdef UB_ON_WINDOWS
2353933707f3Ssthen 		wsvc_desetup_worker(worker);
2354933707f3Ssthen #endif /* UB_ON_WINDOWS */
2355933707f3Ssthen 	}
2356a3167c07Ssthen #ifdef USE_DNSTAP
2357a3167c07Ssthen 	if(worker->daemon->cfg->dnstap
2358a3167c07Ssthen #ifndef THREADS_DISABLED
2359a3167c07Ssthen 		&& worker->thread_num == 0
2360a3167c07Ssthen #endif
2361a3167c07Ssthen 		) {
2362a3167c07Ssthen 		dt_io_thread_stop(worker->dtenv.dtio);
2363a3167c07Ssthen 	}
2364a3167c07Ssthen 	dt_deinit(&worker->dtenv);
2365a3167c07Ssthen #endif /* USE_DNSTAP */
2366933707f3Ssthen 	comm_base_delete(worker->base);
2367933707f3Ssthen 	ub_randfree(worker->rndstate);
23688b7325afSsthen 	/* don't touch worker->alloc, as it's maintained in daemon */
23697191de28Ssthen 	regional_destroy(worker->env.scratch);
2370933707f3Ssthen 	regional_destroy(worker->scratchpad);
2371933707f3Ssthen 	free(worker);
2372933707f3Ssthen }
2373933707f3Ssthen 
2374933707f3Ssthen struct outbound_entry*
237577079be7Ssthen worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
2376e21c60efSsthen 	int want_dnssec, int nocaps, int check_ratelimit,
2377e21c60efSsthen 	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
2378e21c60efSsthen 	size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
2379e21c60efSsthen 	struct module_qstate* q, int* was_ratelimited)
2380933707f3Ssthen {
2381933707f3Ssthen 	struct worker* worker = q->env->worker;
2382933707f3Ssthen 	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
2383933707f3Ssthen 		q->region, sizeof(*e));
2384933707f3Ssthen 	if(!e)
2385933707f3Ssthen 		return NULL;
2386933707f3Ssthen 	e->qstate = q;
238777079be7Ssthen 	e->qsent = outnet_serviced_query(worker->back, qinfo, flags, dnssec,
2388e21c60efSsthen 		want_dnssec, nocaps, check_ratelimit, tcp_upstream,
238920237c55Ssthen 		ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
2390e21c60efSsthen 		worker_handle_service_reply, e, worker->back->udp_buff, q->env,
2391e21c60efSsthen 		was_ratelimited);
2392933707f3Ssthen 	if(!e->qsent) {
2393933707f3Ssthen 		return NULL;
2394933707f3Ssthen 	}
2395933707f3Ssthen 	return e;
2396933707f3Ssthen }
2397933707f3Ssthen 
2398933707f3Ssthen void
2399933707f3Ssthen worker_alloc_cleanup(void* arg)
2400933707f3Ssthen {
2401933707f3Ssthen 	struct worker* worker = (struct worker*)arg;
2402933707f3Ssthen 	slabhash_clear(&worker->env.rrset_cache->table);
2403933707f3Ssthen 	slabhash_clear(worker->env.msg_cache);
2404933707f3Ssthen }
2405933707f3Ssthen 
2406933707f3Ssthen void worker_stats_clear(struct worker* worker)
2407933707f3Ssthen {
2408933707f3Ssthen 	server_stats_init(&worker->stats, worker->env.cfg);
2409933707f3Ssthen 	mesh_stats_clear(worker->env.mesh);
2410933707f3Ssthen 	worker->back->unwanted_replies = 0;
2411e10d3884Sbrad 	worker->back->num_tcp_outgoing = 0;
2412d1e2768aSsthen 	worker->back->num_udp_outgoing = 0;
2413933707f3Ssthen }
2414933707f3Ssthen 
2415af4988b1Ssthen void worker_start_accept(void* arg)
2416af4988b1Ssthen {
2417af4988b1Ssthen 	struct worker* worker = (struct worker*)arg;
2418af4988b1Ssthen 	listen_start_accept(worker->front);
2419af4988b1Ssthen 	if(worker->thread_num == 0)
2420af4988b1Ssthen 		daemon_remote_start_accept(worker->daemon->rc);
2421af4988b1Ssthen }
2422af4988b1Ssthen 
2423af4988b1Ssthen void worker_stop_accept(void* arg)
2424af4988b1Ssthen {
2425af4988b1Ssthen 	struct worker* worker = (struct worker*)arg;
2426af4988b1Ssthen 	listen_stop_accept(worker->front);
2427af4988b1Ssthen 	if(worker->thread_num == 0)
2428af4988b1Ssthen 		daemon_remote_stop_accept(worker->daemon->rc);
2429af4988b1Ssthen }
2430af4988b1Ssthen 
2431933707f3Ssthen /* --- fake callbacks for fptr_wlist to work --- */
243277079be7Ssthen struct outbound_entry* libworker_send_query(
243377079be7Ssthen 	struct query_info* ATTR_UNUSED(qinfo),
243477079be7Ssthen 	uint16_t ATTR_UNUSED(flags), int ATTR_UNUSED(dnssec),
243577079be7Ssthen 	int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps),
2436e21c60efSsthen 	int ATTR_UNUSED(check_ratelimit),
243777079be7Ssthen 	struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
2438e21c60efSsthen 	uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
243920237c55Ssthen 	int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
2440e21c60efSsthen 	struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
2441933707f3Ssthen {
2442933707f3Ssthen 	log_assert(0);
2443933707f3Ssthen 	return 0;
2444933707f3Ssthen }
2445933707f3Ssthen 
2446933707f3Ssthen int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
2447933707f3Ssthen 	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
2448933707f3Ssthen         struct comm_reply* ATTR_UNUSED(reply_info))
2449933707f3Ssthen {
2450933707f3Ssthen 	log_assert(0);
2451933707f3Ssthen 	return 0;
2452933707f3Ssthen }
2453933707f3Ssthen 
2454933707f3Ssthen void libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
2455933707f3Ssthen         uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
2456933707f3Ssthen         int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
2457933707f3Ssthen {
2458933707f3Ssthen 	log_assert(0);
2459933707f3Ssthen }
2460933707f3Ssthen 
2461933707f3Ssthen void libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
24620b68ff31Ssthen 	sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
24632308e98cSsthen 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
2464933707f3Ssthen {
2465933707f3Ssthen 	log_assert(0);
2466933707f3Ssthen }
2467933707f3Ssthen 
2468933707f3Ssthen void libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
24690b68ff31Ssthen 	sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
24702308e98cSsthen 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
24710b68ff31Ssthen {
24720b68ff31Ssthen 	log_assert(0);
24730b68ff31Ssthen }
24740b68ff31Ssthen 
24750b68ff31Ssthen void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
24760b68ff31Ssthen 	sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
24772308e98cSsthen 	char* ATTR_UNUSED(why_bogus), int ATTR_UNUSED(was_ratelimited))
2478933707f3Ssthen {
2479933707f3Ssthen 	log_assert(0);
2480933707f3Ssthen }
2481933707f3Ssthen 
2482933707f3Ssthen int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
2483933707f3Ssthen {
2484933707f3Ssthen 	log_assert(0);
2485933707f3Ssthen 	return 0;
2486933707f3Ssthen }
2487933707f3Ssthen 
2488933707f3Ssthen int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
2489933707f3Ssthen {
2490933707f3Ssthen 	log_assert(0);
2491933707f3Ssthen 	return 0;
2492933707f3Ssthen }
2493933707f3Ssthen 
2494933707f3Ssthen int codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
2495933707f3Ssthen {
2496933707f3Ssthen 	log_assert(0);
2497933707f3Ssthen 	return 0;
2498933707f3Ssthen }
2499933707f3Ssthen 
2500a3167c07Ssthen #ifdef USE_DNSTAP
2501a3167c07Ssthen void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
2502a3167c07Ssthen 	void* ATTR_UNUSED(arg))
2503a3167c07Ssthen {
2504a3167c07Ssthen 	log_assert(0);
2505a3167c07Ssthen }
2506a3167c07Ssthen #endif
2507a3167c07Ssthen 
2508a3167c07Ssthen #ifdef USE_DNSTAP
2509a3167c07Ssthen void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
2510a3167c07Ssthen 	void* ATTR_UNUSED(arg))
2511a3167c07Ssthen {
2512a3167c07Ssthen 	log_assert(0);
2513a3167c07Ssthen }
2514a3167c07Ssthen #endif
2515