worker.c revision 266114
1238106Sdes/*
2238106Sdes * daemon/worker.c - worker that handles a pending list of requests.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24266114Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25266114Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26266114Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27266114Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28266114Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29266114Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30266114Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31266114Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32266114Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33266114Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file implements the worker that handles callbacks on events, for
40238106Sdes * pending requests.
41238106Sdes */
42238106Sdes#include "config.h"
43238106Sdes#include "util/log.h"
44238106Sdes#include "util/net_help.h"
45238106Sdes#include "util/random.h"
46238106Sdes#include "daemon/worker.h"
47238106Sdes#include "daemon/daemon.h"
48238106Sdes#include "daemon/remote.h"
49238106Sdes#include "daemon/acl_list.h"
50238106Sdes#include "util/netevent.h"
51238106Sdes#include "util/config_file.h"
52238106Sdes#include "util/module.h"
53238106Sdes#include "util/regional.h"
54238106Sdes#include "util/storage/slabhash.h"
55238106Sdes#include "services/listen_dnsport.h"
56238106Sdes#include "services/outside_network.h"
57238106Sdes#include "services/outbound_list.h"
58238106Sdes#include "services/cache/rrset.h"
59238106Sdes#include "services/cache/infra.h"
60238106Sdes#include "services/cache/dns.h"
61238106Sdes#include "services/mesh.h"
62238106Sdes#include "services/localzone.h"
63238106Sdes#include "util/data/msgparse.h"
64238106Sdes#include "util/data/msgencode.h"
65238106Sdes#include "util/data/dname.h"
66238106Sdes#include "util/fptr_wlist.h"
67238106Sdes#include "util/tube.h"
68238106Sdes#include "iterator/iter_fwd.h"
69238106Sdes#include "iterator/iter_hints.h"
70238106Sdes#include "validator/autotrust.h"
71238106Sdes#include "validator/val_anchor.h"
72255579Sdes#include "libunbound/context.h"
73255579Sdes#include "libunbound/libworker.h"
74266114Sdes#include "ldns/sbuffer.h"
75238106Sdes
76238106Sdes#ifdef HAVE_SYS_TYPES_H
77238106Sdes#  include <sys/types.h>
78238106Sdes#endif
79238106Sdes#ifdef HAVE_NETDB_H
80238106Sdes#include <netdb.h>
81238106Sdes#endif
82238106Sdes#include <signal.h>
83238106Sdes#ifdef UB_ON_WINDOWS
84238106Sdes#include "winrc/win_svc.h"
85238106Sdes#endif
86238106Sdes
87238106Sdes/** Size of an UDP datagram */
88238106Sdes#define NORMAL_UDP_SIZE	512 /* bytes */
89238106Sdes
90238106Sdes/**
91238106Sdes * seconds to add to prefetch leeway.  This is a TTL that expires old rrsets
92238106Sdes * earlier than they should in order to put the new update into the cache.
93238106Sdes * This additional value is to make sure that if not all TTLs are equal in
94238106Sdes * the message to be updated(and replaced), that rrsets with up to this much
95238106Sdes * extra TTL are also replaced.  This means that the resulting new message
96238106Sdes * will have (most likely) this TTL at least, avoiding very small 'split
97238106Sdes * second' TTLs due to operators choosing relative primes for TTLs (or so).
98238106Sdes * Also has to be at least one to break ties (and overwrite cached entry).
99238106Sdes */
100238106Sdes#define PREFETCH_EXPIRY_ADD 60
101238106Sdes
102238106Sdes#ifdef UNBOUND_ALLOC_STATS
103238106Sdes/** measure memory leakage */
104238106Sdesstatic void
105238106Sdesdebug_memleak(size_t accounted, size_t heap,
106238106Sdes	size_t total_alloc, size_t total_free)
107238106Sdes{
108238106Sdes	static int init = 0;
109238106Sdes	static size_t base_heap, base_accounted, base_alloc, base_free;
110238106Sdes	size_t base_af, cur_af, grow_af, grow_acc;
111238106Sdes	if(!init) {
112238106Sdes		init = 1;
113238106Sdes		base_heap = heap;
114238106Sdes		base_accounted = accounted;
115238106Sdes		base_alloc = total_alloc;
116238106Sdes		base_free = total_free;
117238106Sdes	}
118238106Sdes	base_af = base_alloc - base_free;
119238106Sdes	cur_af = total_alloc - total_free;
120238106Sdes	grow_af = cur_af - base_af;
121238106Sdes	grow_acc = accounted - base_accounted;
122238106Sdes	log_info("Leakage: %d leaked. growth: %u use, %u acc, %u heap",
123238106Sdes		(int)(grow_af - grow_acc), (unsigned)grow_af,
124238106Sdes		(unsigned)grow_acc, (unsigned)(heap - base_heap));
125238106Sdes}
126238106Sdes
127238106Sdes/** give debug heap size indication */
128238106Sdesstatic void
129238106Sdesdebug_total_mem(size_t calctotal)
130238106Sdes{
131238106Sdes#ifdef HAVE_SBRK
132238106Sdes	extern void* unbound_start_brk;
133238106Sdes	extern size_t unbound_mem_alloc, unbound_mem_freed;
134238106Sdes	void* cur = sbrk(0);
135238106Sdes	int total = cur-unbound_start_brk;
136238106Sdes	log_info("Total heap memory estimate: %u  total-alloc: %u  "
137238106Sdes		"total-free: %u", (unsigned)total,
138238106Sdes		(unsigned)unbound_mem_alloc, (unsigned)unbound_mem_freed);
139238106Sdes	debug_memleak(calctotal, (size_t)total,
140238106Sdes		unbound_mem_alloc, unbound_mem_freed);
141238106Sdes#else
142238106Sdes	(void)calctotal;
143238106Sdes#endif /* HAVE_SBRK */
144238106Sdes}
145238106Sdes#endif /* UNBOUND_ALLOC_STATS */
146238106Sdes
147238106Sdes/** Report on memory usage by this thread and global */
148238106Sdesstatic void
149238106Sdesworker_mem_report(struct worker* ATTR_UNUSED(worker),
150238106Sdes	struct serviced_query* ATTR_UNUSED(cur_serv))
151238106Sdes{
152238106Sdes#ifdef UNBOUND_ALLOC_STATS
153238106Sdes	/* debug func in validator module */
154238106Sdes	size_t total, front, back, mesh, msg, rrset, infra, ac, superac;
155238106Sdes	size_t me, iter, val, anch;
156238106Sdes	int i;
157238106Sdes	if(verbosity < VERB_ALGO)
158238106Sdes		return;
159238106Sdes	front = listen_get_mem(worker->front);
160238106Sdes	back = outnet_get_mem(worker->back);
161238106Sdes	msg = slabhash_get_mem(worker->env.msg_cache);
162238106Sdes	rrset = slabhash_get_mem(&worker->env.rrset_cache->table);
163238106Sdes	infra = infra_get_mem(worker->env.infra_cache);
164238106Sdes	mesh = mesh_get_mem(worker->env.mesh);
165238106Sdes	ac = alloc_get_mem(&worker->alloc);
166238106Sdes	superac = alloc_get_mem(&worker->daemon->superalloc);
167238106Sdes	anch = anchors_get_mem(worker->env.anchors);
168238106Sdes	iter = 0;
169238106Sdes	val = 0;
170238106Sdes	for(i=0; i<worker->env.mesh->mods.num; i++) {
171238106Sdes		fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh->
172238106Sdes			mods.mod[i]->get_mem));
173238106Sdes		if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0)
174238106Sdes			val += (*worker->env.mesh->mods.mod[i]->get_mem)
175238106Sdes				(&worker->env, i);
176238106Sdes		else	iter += (*worker->env.mesh->mods.mod[i]->get_mem)
177238106Sdes				(&worker->env, i);
178238106Sdes	}
179238106Sdes	me = sizeof(*worker) + sizeof(*worker->base) + sizeof(*worker->comsig)
180238106Sdes		+ comm_point_get_mem(worker->cmd_com)
181238106Sdes		+ sizeof(worker->rndstate)
182238106Sdes		+ regional_get_mem(worker->scratchpad)
183238106Sdes		+ sizeof(*worker->env.scratch_buffer)
184266114Sdes		+ sldns_buffer_capacity(worker->env.scratch_buffer)
185238106Sdes		+ forwards_get_mem(worker->env.fwds)
186238106Sdes		+ hints_get_mem(worker->env.hints);
187238106Sdes	if(worker->thread_num == 0)
188238106Sdes		me += acl_list_get_mem(worker->daemon->acl);
189238106Sdes	if(cur_serv) {
190238106Sdes		me += serviced_get_mem(cur_serv);
191238106Sdes	}
192238106Sdes	total = front+back+mesh+msg+rrset+infra+iter+val+ac+superac+me;
193238106Sdes	log_info("Memory conditions: %u front=%u back=%u mesh=%u msg=%u "
194238106Sdes		"rrset=%u infra=%u iter=%u val=%u anchors=%u "
195238106Sdes		"alloccache=%u globalalloccache=%u me=%u",
196238106Sdes		(unsigned)total, (unsigned)front, (unsigned)back,
197238106Sdes		(unsigned)mesh, (unsigned)msg, (unsigned)rrset,
198238106Sdes		(unsigned)infra, (unsigned)iter, (unsigned)val, (unsigned)anch,
199238106Sdes		(unsigned)ac, (unsigned)superac, (unsigned)me);
200238106Sdes	debug_total_mem(total);
201238106Sdes#else /* no UNBOUND_ALLOC_STATS */
202238106Sdes	size_t val = 0;
203238106Sdes	int i;
204238106Sdes	if(verbosity < VERB_QUERY)
205238106Sdes		return;
206238106Sdes	for(i=0; i<worker->env.mesh->mods.num; i++) {
207238106Sdes		fptr_ok(fptr_whitelist_mod_get_mem(worker->env.mesh->
208238106Sdes			mods.mod[i]->get_mem));
209238106Sdes		if(strcmp(worker->env.mesh->mods.mod[i]->name, "validator")==0)
210238106Sdes			val += (*worker->env.mesh->mods.mod[i]->get_mem)
211238106Sdes				(&worker->env, i);
212238106Sdes	}
213238106Sdes	verbose(VERB_QUERY, "cache memory msg=%u rrset=%u infra=%u val=%u",
214238106Sdes		(unsigned)slabhash_get_mem(worker->env.msg_cache),
215238106Sdes		(unsigned)slabhash_get_mem(&worker->env.rrset_cache->table),
216238106Sdes		(unsigned)infra_get_mem(worker->env.infra_cache),
217238106Sdes		(unsigned)val);
218238106Sdes#endif /* UNBOUND_ALLOC_STATS */
219238106Sdes}
220238106Sdes
221238106Sdesvoid
222238106Sdesworker_send_cmd(struct worker* worker, enum worker_commands cmd)
223238106Sdes{
224238106Sdes	uint32_t c = (uint32_t)htonl(cmd);
225238106Sdes	if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) {
226238106Sdes		log_err("worker send cmd %d failed", (int)cmd);
227238106Sdes	}
228238106Sdes}
229238106Sdes
230238106Sdesint
231238106Sdesworker_handle_reply(struct comm_point* c, void* arg, int error,
232238106Sdes	struct comm_reply* reply_info)
233238106Sdes{
234238106Sdes	struct module_qstate* q = (struct module_qstate*)arg;
235238106Sdes	struct worker* worker = q->env->worker;
236238106Sdes	struct outbound_entry e;
237238106Sdes	e.qstate = q;
238238106Sdes	e.qsent = NULL;
239238106Sdes
240238106Sdes	if(error != 0) {
241238106Sdes		mesh_report_reply(worker->env.mesh, &e, reply_info, error);
242238106Sdes		worker_mem_report(worker, NULL);
243238106Sdes		return 0;
244238106Sdes	}
245238106Sdes	/* sanity check. */
246266114Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
247266114Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
248238106Sdes			LDNS_PACKET_QUERY
249266114Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
250238106Sdes		/* error becomes timeout for the module as if this reply
251238106Sdes		 * never arrived. */
252238106Sdes		mesh_report_reply(worker->env.mesh, &e, reply_info,
253238106Sdes			NETEVENT_TIMEOUT);
254238106Sdes		worker_mem_report(worker, NULL);
255238106Sdes		return 0;
256238106Sdes	}
257238106Sdes	mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR);
258238106Sdes	worker_mem_report(worker, NULL);
259238106Sdes	return 0;
260238106Sdes}
261238106Sdes
262238106Sdesint
263238106Sdesworker_handle_service_reply(struct comm_point* c, void* arg, int error,
264238106Sdes	struct comm_reply* reply_info)
265238106Sdes{
266238106Sdes	struct outbound_entry* e = (struct outbound_entry*)arg;
267238106Sdes	struct worker* worker = e->qstate->env->worker;
268238106Sdes	struct serviced_query *sq = e->qsent;
269238106Sdes
270238106Sdes	verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
271238106Sdes	if(error != 0) {
272238106Sdes		mesh_report_reply(worker->env.mesh, e, reply_info, error);
273238106Sdes		worker_mem_report(worker, sq);
274238106Sdes		return 0;
275238106Sdes	}
276238106Sdes	/* sanity check. */
277266114Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
278266114Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
279238106Sdes			LDNS_PACKET_QUERY
280266114Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
281238106Sdes		/* error becomes timeout for the module as if this reply
282238106Sdes		 * never arrived. */
283238106Sdes		verbose(VERB_ALGO, "worker: bad reply handled as timeout");
284238106Sdes		mesh_report_reply(worker->env.mesh, e, reply_info,
285238106Sdes			NETEVENT_TIMEOUT);
286238106Sdes		worker_mem_report(worker, sq);
287238106Sdes		return 0;
288238106Sdes	}
289238106Sdes	mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR);
290238106Sdes	worker_mem_report(worker, sq);
291238106Sdes	return 0;
292238106Sdes}
293238106Sdes
294238106Sdes/** check request sanity.
295238106Sdes * @param pkt: the wire packet to examine for sanity.
296238106Sdes * @param worker: parameters for checking.
297238106Sdes * @return error code, 0 OK, or -1 discard.
298238106Sdes*/
299238106Sdesstatic int
300266114Sdesworker_check_request(sldns_buffer* pkt, struct worker* worker)
301238106Sdes{
302266114Sdes	if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
303238106Sdes		verbose(VERB_QUERY, "request too short, discarded");
304238106Sdes		return -1;
305238106Sdes	}
306266114Sdes	if(sldns_buffer_limit(pkt) > NORMAL_UDP_SIZE &&
307238106Sdes		worker->daemon->cfg->harden_large_queries) {
308238106Sdes		verbose(VERB_QUERY, "request too large, discarded");
309238106Sdes		return -1;
310238106Sdes	}
311266114Sdes	if(LDNS_QR_WIRE(sldns_buffer_begin(pkt))) {
312238106Sdes		verbose(VERB_QUERY, "request has QR bit on, discarded");
313238106Sdes		return -1;
314238106Sdes	}
315266114Sdes	if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
316266114Sdes		LDNS_TC_CLR(sldns_buffer_begin(pkt));
317238106Sdes		verbose(VERB_QUERY, "request bad, has TC bit on");
318238106Sdes		return LDNS_RCODE_FORMERR;
319238106Sdes	}
320266114Sdes	if(LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)) != LDNS_PACKET_QUERY) {
321238106Sdes		verbose(VERB_QUERY, "request unknown opcode %d",
322266114Sdes			LDNS_OPCODE_WIRE(sldns_buffer_begin(pkt)));
323238106Sdes		return LDNS_RCODE_NOTIMPL;
324238106Sdes	}
325266114Sdes	if(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) != 1) {
326238106Sdes		verbose(VERB_QUERY, "request wrong nr qd=%d",
327266114Sdes			LDNS_QDCOUNT(sldns_buffer_begin(pkt)));
328238106Sdes		return LDNS_RCODE_FORMERR;
329238106Sdes	}
330266114Sdes	if(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) != 0) {
331238106Sdes		verbose(VERB_QUERY, "request wrong nr an=%d",
332266114Sdes			LDNS_ANCOUNT(sldns_buffer_begin(pkt)));
333238106Sdes		return LDNS_RCODE_FORMERR;
334238106Sdes	}
335266114Sdes	if(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) != 0) {
336238106Sdes		verbose(VERB_QUERY, "request wrong nr ns=%d",
337266114Sdes			LDNS_NSCOUNT(sldns_buffer_begin(pkt)));
338238106Sdes		return LDNS_RCODE_FORMERR;
339238106Sdes	}
340266114Sdes	if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
341238106Sdes		verbose(VERB_QUERY, "request wrong nr ar=%d",
342266114Sdes			LDNS_ARCOUNT(sldns_buffer_begin(pkt)));
343238106Sdes		return LDNS_RCODE_FORMERR;
344238106Sdes	}
345238106Sdes	return 0;
346238106Sdes}
347238106Sdes
348238106Sdesvoid
349238106Sdesworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
350238106Sdes	size_t len, int error, void* arg)
351238106Sdes{
352238106Sdes	struct worker* worker = (struct worker*)arg;
353238106Sdes	enum worker_commands cmd;
354238106Sdes	if(error != NETEVENT_NOERROR) {
355238106Sdes		free(msg);
356238106Sdes		if(error == NETEVENT_CLOSED)
357238106Sdes			comm_base_exit(worker->base);
358238106Sdes		else	log_info("control event: %d", error);
359238106Sdes		return;
360238106Sdes	}
361238106Sdes	if(len != sizeof(uint32_t)) {
362238106Sdes		fatal_exit("bad control msg length %d", (int)len);
363238106Sdes	}
364266114Sdes	cmd = sldns_read_uint32(msg);
365238106Sdes	free(msg);
366238106Sdes	switch(cmd) {
367238106Sdes	case worker_cmd_quit:
368238106Sdes		verbose(VERB_ALGO, "got control cmd quit");
369238106Sdes		comm_base_exit(worker->base);
370238106Sdes		break;
371238106Sdes	case worker_cmd_stats:
372238106Sdes		verbose(VERB_ALGO, "got control cmd stats");
373238106Sdes		server_stats_reply(worker, 1);
374238106Sdes		break;
375238106Sdes	case worker_cmd_stats_noreset:
376238106Sdes		verbose(VERB_ALGO, "got control cmd stats_noreset");
377238106Sdes		server_stats_reply(worker, 0);
378238106Sdes		break;
379238106Sdes	case worker_cmd_remote:
380238106Sdes		verbose(VERB_ALGO, "got control cmd remote");
381238106Sdes		daemon_remote_exec(worker);
382238106Sdes		break;
383238106Sdes	default:
384238106Sdes		log_err("bad command %d", (int)cmd);
385238106Sdes		break;
386238106Sdes	}
387238106Sdes}
388238106Sdes
389238106Sdes/** check if a delegation is secure */
390238106Sdesstatic enum sec_status
391238106Sdescheck_delegation_secure(struct reply_info *rep)
392238106Sdes{
393238106Sdes	/* return smallest security status */
394238106Sdes	size_t i;
395238106Sdes	enum sec_status sec = sec_status_secure;
396238106Sdes	enum sec_status s;
397238106Sdes	size_t num = rep->an_numrrsets + rep->ns_numrrsets;
398238106Sdes	/* check if answer and authority are OK */
399238106Sdes	for(i=0; i<num; i++) {
400238106Sdes		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
401238106Sdes			->security;
402238106Sdes		if(s < sec)
403238106Sdes			sec = s;
404238106Sdes	}
405238106Sdes	/* in additional, only unchecked triggers revalidation */
406238106Sdes	for(i=num; i<rep->rrset_count; i++) {
407238106Sdes		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
408238106Sdes			->security;
409238106Sdes		if(s == sec_status_unchecked)
410238106Sdes			return s;
411238106Sdes	}
412238106Sdes	return sec;
413238106Sdes}
414238106Sdes
415238106Sdes/** remove nonsecure from a delegation referral additional section */
416238106Sdesstatic void
417238106Sdesdeleg_remove_nonsecure_additional(struct reply_info* rep)
418238106Sdes{
419238106Sdes	/* we can simply edit it, since we are working in the scratch region */
420238106Sdes	size_t i;
421238106Sdes	enum sec_status s;
422238106Sdes
423238106Sdes	for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
424238106Sdes		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
425238106Sdes			->security;
426238106Sdes		if(s != sec_status_secure) {
427238106Sdes			memmove(rep->rrsets+i, rep->rrsets+i+1,
428238106Sdes				sizeof(struct ub_packed_rrset_key*)*
429238106Sdes				(rep->rrset_count - i - 1));
430238106Sdes			rep->ar_numrrsets--;
431238106Sdes			rep->rrset_count--;
432238106Sdes			i--;
433238106Sdes		}
434238106Sdes	}
435238106Sdes}
436238106Sdes
437238106Sdes/** answer nonrecursive query from the cache */
438238106Sdesstatic int
439238106Sdesanswer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
440238106Sdes	uint16_t id, uint16_t flags, struct comm_reply* repinfo,
441238106Sdes	struct edns_data* edns)
442238106Sdes{
443238106Sdes	/* for a nonrecursive query return either:
444238106Sdes	 * 	o an error (servfail; we try to avoid this)
445238106Sdes	 * 	o a delegation (closest we have; this routine tries that)
446238106Sdes	 * 	o the answer (checked by answer_from_cache)
447238106Sdes	 *
448238106Sdes	 * So, grab a delegation from the rrset cache.
449238106Sdes	 * Then check if it needs validation, if so, this routine fails,
450238106Sdes	 * so that iterator can prime and validator can verify rrsets.
451238106Sdes	 */
452238106Sdes	uint16_t udpsize = edns->udp_size;
453238106Sdes	int secure = 0;
454266114Sdes	time_t timenow = *worker->env.now;
455238106Sdes	int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd)
456238106Sdes		&& worker->env.need_to_validate;
457238106Sdes	struct dns_msg *msg = NULL;
458238106Sdes	struct delegpt *dp;
459238106Sdes
460238106Sdes	dp = dns_cache_find_delegation(&worker->env, qinfo->qname,
461238106Sdes		qinfo->qname_len, qinfo->qtype, qinfo->qclass,
462238106Sdes		worker->scratchpad, &msg, timenow);
463238106Sdes	if(!dp) { /* no delegation, need to reprime */
464238106Sdes		regional_free_all(worker->scratchpad);
465238106Sdes		return 0;
466238106Sdes	}
467238106Sdes	if(must_validate) {
468238106Sdes		switch(check_delegation_secure(msg->rep)) {
469238106Sdes		case sec_status_unchecked:
470238106Sdes			/* some rrsets have not been verified yet, go and
471238106Sdes			 * let validator do that */
472238106Sdes			regional_free_all(worker->scratchpad);
473238106Sdes			return 0;
474238106Sdes		case sec_status_bogus:
475238106Sdes			/* some rrsets are bogus, reply servfail */
476238106Sdes			edns->edns_version = EDNS_ADVERTISED_VERSION;
477238106Sdes			edns->udp_size = EDNS_ADVERTISED_SIZE;
478238106Sdes			edns->ext_rcode = 0;
479238106Sdes			edns->bits &= EDNS_DO;
480238106Sdes			error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
481238106Sdes				&msg->qinfo, id, flags, edns);
482238106Sdes			regional_free_all(worker->scratchpad);
483238106Sdes			if(worker->stats.extended) {
484238106Sdes				worker->stats.ans_bogus++;
485238106Sdes				worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL]++;
486238106Sdes			}
487238106Sdes			return 1;
488238106Sdes		case sec_status_secure:
489238106Sdes			/* all rrsets are secure */
490238106Sdes			/* remove non-secure rrsets from the add. section*/
491238106Sdes			if(worker->env.cfg->val_clean_additional)
492238106Sdes				deleg_remove_nonsecure_additional(msg->rep);
493238106Sdes			secure = 1;
494238106Sdes			break;
495238106Sdes		case sec_status_indeterminate:
496238106Sdes		case sec_status_insecure:
497238106Sdes		default:
498238106Sdes			/* not secure */
499238106Sdes			secure = 0;
500238106Sdes			break;
501238106Sdes		}
502238106Sdes	}
503238106Sdes	/* return this delegation from the cache */
504238106Sdes	edns->edns_version = EDNS_ADVERTISED_VERSION;
505238106Sdes	edns->udp_size = EDNS_ADVERTISED_SIZE;
506238106Sdes	edns->ext_rcode = 0;
507238106Sdes	edns->bits &= EDNS_DO;
508238106Sdes	msg->rep->flags |= BIT_QR|BIT_RA;
509238106Sdes	if(!reply_info_answer_encode(&msg->qinfo, msg->rep, id, flags,
510238106Sdes		repinfo->c->buffer, 0, 1, worker->scratchpad,
511238106Sdes		udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
512238106Sdes		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
513238106Sdes			&msg->qinfo, id, flags, edns);
514238106Sdes	}
515238106Sdes	regional_free_all(worker->scratchpad);
516238106Sdes	if(worker->stats.extended) {
517238106Sdes		if(secure) worker->stats.ans_secure++;
518238106Sdes		server_stats_insrcode(&worker->stats, repinfo->c->buffer);
519238106Sdes	}
520238106Sdes	return 1;
521238106Sdes}
522238106Sdes
523238106Sdes/** answer query from the cache */
524238106Sdesstatic int
525238106Sdesanswer_from_cache(struct worker* worker, struct query_info* qinfo,
526238106Sdes	struct reply_info* rep, uint16_t id, uint16_t flags,
527238106Sdes	struct comm_reply* repinfo, struct edns_data* edns)
528238106Sdes{
529266114Sdes	time_t timenow = *worker->env.now;
530238106Sdes	uint16_t udpsize = edns->udp_size;
531238106Sdes	int secure;
532238106Sdes	int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd)
533238106Sdes		&& worker->env.need_to_validate;
534238106Sdes	/* see if it is possible */
535238106Sdes	if(rep->ttl < timenow) {
536238106Sdes		/* the rrsets may have been updated in the meantime.
537238106Sdes		 * we will refetch the message format from the
538238106Sdes		 * authoritative server
539238106Sdes		 */
540238106Sdes		return 0;
541238106Sdes	}
542238106Sdes	if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
543238106Sdes		return 0;
544238106Sdes	/* locked and ids and ttls are OK. */
545238106Sdes	/* check CNAME chain (if any) */
546238106Sdes	if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
547238106Sdes		htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
548238106Sdes		htons(LDNS_RR_TYPE_DNAME))) {
549238106Sdes		if(!reply_check_cname_chain(rep)) {
550238106Sdes			/* cname chain invalid, redo iterator steps */
551238106Sdes			verbose(VERB_ALGO, "Cache reply: cname chain broken");
552238106Sdes		bail_out:
553238106Sdes			rrset_array_unlock_touch(worker->env.rrset_cache,
554238106Sdes				worker->scratchpad, rep->ref, rep->rrset_count);
555238106Sdes			regional_free_all(worker->scratchpad);
556238106Sdes			return 0;
557238106Sdes		}
558238106Sdes	}
559238106Sdes	/* check security status of the cached answer */
560238106Sdes	if( rep->security == sec_status_bogus && must_validate) {
561238106Sdes		/* BAD cached */
562238106Sdes		edns->edns_version = EDNS_ADVERTISED_VERSION;
563238106Sdes		edns->udp_size = EDNS_ADVERTISED_SIZE;
564238106Sdes		edns->ext_rcode = 0;
565238106Sdes		edns->bits &= EDNS_DO;
566238106Sdes		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
567238106Sdes			qinfo, id, flags, edns);
568238106Sdes		rrset_array_unlock_touch(worker->env.rrset_cache,
569238106Sdes			worker->scratchpad, rep->ref, rep->rrset_count);
570238106Sdes		regional_free_all(worker->scratchpad);
571238106Sdes		if(worker->stats.extended) {
572238106Sdes			worker->stats.ans_bogus ++;
573238106Sdes			worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
574238106Sdes		}
575238106Sdes		return 1;
576238106Sdes	} else if( rep->security == sec_status_unchecked && must_validate) {
577238106Sdes		verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
578238106Sdes			"validation");
579238106Sdes		goto bail_out; /* need to validate cache entry first */
580238106Sdes	} else if(rep->security == sec_status_secure) {
581238106Sdes		if(reply_all_rrsets_secure(rep))
582238106Sdes			secure = 1;
583238106Sdes		else	{
584238106Sdes			if(must_validate) {
585238106Sdes				verbose(VERB_ALGO, "Cache reply: secure entry"
586238106Sdes					" changed status");
587238106Sdes				goto bail_out; /* rrset changed, re-verify */
588238106Sdes			}
589238106Sdes			secure = 0;
590238106Sdes		}
591238106Sdes	} else	secure = 0;
592238106Sdes
593238106Sdes	edns->edns_version = EDNS_ADVERTISED_VERSION;
594238106Sdes	edns->udp_size = EDNS_ADVERTISED_SIZE;
595238106Sdes	edns->ext_rcode = 0;
596238106Sdes	edns->bits &= EDNS_DO;
597238106Sdes	if(!reply_info_answer_encode(qinfo, rep, id, flags,
598238106Sdes		repinfo->c->buffer, timenow, 1, worker->scratchpad,
599238106Sdes		udpsize, edns, (int)(edns->bits & EDNS_DO), secure)) {
600238106Sdes		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
601238106Sdes			qinfo, id, flags, edns);
602238106Sdes	}
603238106Sdes	/* cannot send the reply right now, because blocking network syscall
604238106Sdes	 * is bad while holding locks. */
605238106Sdes	rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
606238106Sdes		rep->ref, rep->rrset_count);
607238106Sdes	regional_free_all(worker->scratchpad);
608238106Sdes	if(worker->stats.extended) {
609238106Sdes		if(secure) worker->stats.ans_secure++;
610238106Sdes		server_stats_insrcode(&worker->stats, repinfo->c->buffer);
611238106Sdes	}
612238106Sdes	/* go and return this buffer to the client */
613238106Sdes	return 1;
614238106Sdes}
615238106Sdes
616238106Sdes/** Reply to client and perform prefetch to keep cache up to date */
617238106Sdesstatic void
618238106Sdesreply_and_prefetch(struct worker* worker, struct query_info* qinfo,
619266114Sdes	uint16_t flags, struct comm_reply* repinfo, time_t leeway)
620238106Sdes{
621238106Sdes	/* first send answer to client to keep its latency
622238106Sdes	 * as small as a cachereply */
623238106Sdes	comm_point_send_reply(repinfo);
624238106Sdes	server_stats_prefetch(&worker->stats, worker);
625238106Sdes
626238106Sdes	/* create the prefetch in the mesh as a normal lookup without
627238106Sdes	 * client addrs waiting, which has the cache blacklisted (to bypass
628238106Sdes	 * the cache and go to the network for the data). */
629238106Sdes	/* this (potentially) runs the mesh for the new query */
630238106Sdes	mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway +
631238106Sdes		PREFETCH_EXPIRY_ADD);
632238106Sdes}
633238106Sdes
634238106Sdes/**
635238106Sdes * Fill CH class answer into buffer. Keeps query.
636238106Sdes * @param pkt: buffer
637238106Sdes * @param str: string to put into text record (<255).
638238106Sdes * @param edns: edns reply information.
639238106Sdes */
640238106Sdesstatic void
641266114Sdeschaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns)
642238106Sdes{
643238106Sdes	size_t len = strlen(str);
644266114Sdes	unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt));
645266114Sdes	unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt));
646238106Sdes	if(len>255) len=255; /* cap size of TXT record */
647266114Sdes	sldns_buffer_clear(pkt);
648266114Sdes	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */
649266114Sdes	sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA));
650266114Sdes	if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt));
651266114Sdes	if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt));
652266114Sdes	sldns_buffer_write_u16(pkt, 1); /* qdcount */
653266114Sdes	sldns_buffer_write_u16(pkt, 1); /* ancount */
654266114Sdes	sldns_buffer_write_u16(pkt, 0); /* nscount */
655266114Sdes	sldns_buffer_write_u16(pkt, 0); /* arcount */
656238106Sdes	(void)query_dname_len(pkt); /* skip qname */
657266114Sdes	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */
658266114Sdes	sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */
659266114Sdes	sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */
660266114Sdes	sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT);
661266114Sdes	sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH);
662266114Sdes	sldns_buffer_write_u32(pkt, 0); /* TTL */
663266114Sdes	sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len);
664266114Sdes	sldns_buffer_write_u8(pkt, len);
665266114Sdes	sldns_buffer_write(pkt, str, len);
666266114Sdes	sldns_buffer_flip(pkt);
667238106Sdes	edns->edns_version = EDNS_ADVERTISED_VERSION;
668238106Sdes	edns->udp_size = EDNS_ADVERTISED_SIZE;
669238106Sdes	edns->bits &= EDNS_DO;
670238106Sdes	attach_edns_record(pkt, edns);
671238106Sdes}
672238106Sdes
673238106Sdes/**
674238106Sdes * Answer CH class queries.
675238106Sdes * @param w: worker
676238106Sdes * @param qinfo: query info. Pointer into packet buffer.
677238106Sdes * @param edns: edns info from query.
678238106Sdes * @param pkt: packet buffer.
679238106Sdes * @return: true if a reply is to be sent.
680238106Sdes */
681238106Sdesstatic int
682238106Sdesanswer_chaos(struct worker* w, struct query_info* qinfo,
683266114Sdes	struct edns_data* edns, sldns_buffer* pkt)
684238106Sdes{
685238106Sdes	struct config_file* cfg = w->env.cfg;
686238106Sdes	if(qinfo->qtype != LDNS_RR_TYPE_ANY && qinfo->qtype != LDNS_RR_TYPE_TXT)
687238106Sdes		return 0;
688238106Sdes	if(query_dname_compare(qinfo->qname,
689238106Sdes		(uint8_t*)"\002id\006server") == 0 ||
690238106Sdes		query_dname_compare(qinfo->qname,
691238106Sdes		(uint8_t*)"\010hostname\004bind") == 0)
692238106Sdes	{
693238106Sdes		if(cfg->hide_identity)
694238106Sdes			return 0;
695238106Sdes		if(cfg->identity==NULL || cfg->identity[0]==0) {
696238106Sdes			char buf[MAXHOSTNAMELEN+1];
697238106Sdes			if (gethostname(buf, MAXHOSTNAMELEN) == 0) {
698238106Sdes				buf[MAXHOSTNAMELEN] = 0;
699238106Sdes				chaos_replystr(pkt, buf, edns);
700238106Sdes			} else 	{
701238106Sdes				log_err("gethostname: %s", strerror(errno));
702238106Sdes				chaos_replystr(pkt, "no hostname", edns);
703238106Sdes			}
704238106Sdes		}
705238106Sdes		else 	chaos_replystr(pkt, cfg->identity, edns);
706238106Sdes		return 1;
707238106Sdes	}
708238106Sdes	if(query_dname_compare(qinfo->qname,
709238106Sdes		(uint8_t*)"\007version\006server") == 0 ||
710238106Sdes		query_dname_compare(qinfo->qname,
711238106Sdes		(uint8_t*)"\007version\004bind") == 0)
712238106Sdes	{
713238106Sdes		if(cfg->hide_version)
714238106Sdes			return 0;
715238106Sdes		if(cfg->version==NULL || cfg->version[0]==0)
716238106Sdes			chaos_replystr(pkt, PACKAGE_STRING, edns);
717238106Sdes		else 	chaos_replystr(pkt, cfg->version, edns);
718238106Sdes		return 1;
719238106Sdes	}
720238106Sdes	return 0;
721238106Sdes}
722238106Sdes
723266114Sdesstatic int
724266114Sdesdeny_refuse(struct comm_point* c, enum acl_access acl,
725266114Sdes	enum acl_access deny, enum acl_access refuse,
726266114Sdes	struct worker* worker, struct comm_reply* repinfo)
727266114Sdes{
728266114Sdes	if(acl == deny) {
729266114Sdes		comm_point_drop_reply(repinfo);
730266114Sdes		if(worker->stats.extended)
731266114Sdes			worker->stats.unwanted_queries++;
732266114Sdes		return 0;
733266114Sdes	} else if(acl == refuse) {
734266114Sdes		log_addr(VERB_ALGO, "refused query from",
735266114Sdes			&repinfo->addr, repinfo->addrlen);
736266114Sdes		log_buf(VERB_ALGO, "refuse", c->buffer);
737266114Sdes		if(worker->stats.extended)
738266114Sdes			worker->stats.unwanted_queries++;
739266114Sdes		if(worker_check_request(c->buffer, worker) == -1) {
740266114Sdes			comm_point_drop_reply(repinfo);
741266114Sdes			return 0; /* discard this */
742266114Sdes		}
743266114Sdes		sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
744266114Sdes		sldns_buffer_write_at(c->buffer, 4,
745266114Sdes			(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
746266114Sdes		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
747266114Sdes		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
748266114Sdes			LDNS_RCODE_REFUSED);
749266114Sdes		return 1;
750266114Sdes	}
751266114Sdes
752266114Sdes	return -1;
753266114Sdes}
754266114Sdes
755266114Sdesstatic int
756266114Sdesdeny_refuse_all(struct comm_point* c, enum acl_access acl,
757266114Sdes	struct worker* worker, struct comm_reply* repinfo)
758266114Sdes{
759266114Sdes	return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo);
760266114Sdes}
761266114Sdes
762266114Sdesstatic int
763266114Sdesdeny_refuse_non_local(struct comm_point* c, enum acl_access acl,
764266114Sdes	struct worker* worker, struct comm_reply* repinfo)
765266114Sdes{
766266114Sdes	return deny_refuse(c, acl, acl_deny_non_local, acl_refuse_non_local, worker, repinfo);
767266114Sdes}
768266114Sdes
769238106Sdesint
770238106Sdesworker_handle_request(struct comm_point* c, void* arg, int error,
771238106Sdes	struct comm_reply* repinfo)
772238106Sdes{
773238106Sdes	struct worker* worker = (struct worker*)arg;
774238106Sdes	int ret;
775238106Sdes	hashvalue_t h;
776238106Sdes	struct lruhash_entry* e;
777238106Sdes	struct query_info qinfo;
778238106Sdes	struct edns_data edns;
779238106Sdes	enum acl_access acl;
780238106Sdes
781238106Sdes	if(error != NETEVENT_NOERROR) {
782238106Sdes		/* some bad tcp query DNS formats give these error calls */
783238106Sdes		verbose(VERB_ALGO, "handle request called with err=%d", error);
784238106Sdes		return 0;
785238106Sdes	}
786238106Sdes	acl = acl_list_lookup(worker->daemon->acl, &repinfo->addr,
787238106Sdes		repinfo->addrlen);
788266114Sdes	if((ret=deny_refuse_all(c, acl, worker, repinfo)) != -1)
789266114Sdes	{
790266114Sdes		return ret;
791238106Sdes	}
792238106Sdes	if((ret=worker_check_request(c->buffer, worker)) != 0) {
793238106Sdes		verbose(VERB_ALGO, "worker check request: bad query.");
794238106Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
795238106Sdes		if(ret != -1) {
796266114Sdes			LDNS_QR_SET(sldns_buffer_begin(c->buffer));
797266114Sdes			LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
798238106Sdes			return 1;
799238106Sdes		}
800238106Sdes		comm_point_drop_reply(repinfo);
801238106Sdes		return 0;
802238106Sdes	}
803238106Sdes	worker->stats.num_queries++;
804238106Sdes	/* see if query is in the cache */
805238106Sdes	if(!query_info_parse(&qinfo, c->buffer)) {
806238106Sdes		verbose(VERB_ALGO, "worker parse request: formerror.");
807238106Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
808266114Sdes		sldns_buffer_rewind(c->buffer);
809266114Sdes		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
810266114Sdes		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
811238106Sdes			LDNS_RCODE_FORMERR);
812238106Sdes		server_stats_insrcode(&worker->stats, c->buffer);
813238106Sdes		return 1;
814238106Sdes	}
815238106Sdes	if(worker->env.cfg->log_queries) {
816238106Sdes		char ip[128];
817238106Sdes		addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
818238106Sdes		log_nametypeclass(0, ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
819238106Sdes	}
820238106Sdes	if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
821238106Sdes		qinfo.qtype == LDNS_RR_TYPE_IXFR) {
822238106Sdes		verbose(VERB_ALGO, "worker request: refused zone transfer.");
823238106Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
824266114Sdes		sldns_buffer_rewind(c->buffer);
825266114Sdes		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
826266114Sdes		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
827238106Sdes			LDNS_RCODE_REFUSED);
828238106Sdes		if(worker->stats.extended) {
829238106Sdes			worker->stats.qtype[qinfo.qtype]++;
830238106Sdes			server_stats_insrcode(&worker->stats, c->buffer);
831238106Sdes		}
832238106Sdes		return 1;
833238106Sdes	}
834238106Sdes	if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
835238106Sdes		verbose(VERB_ALGO, "worker parse edns: formerror.");
836238106Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
837266114Sdes		sldns_buffer_rewind(c->buffer);
838266114Sdes		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
839266114Sdes		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
840238106Sdes		server_stats_insrcode(&worker->stats, c->buffer);
841238106Sdes		return 1;
842238106Sdes	}
843238106Sdes	if(edns.edns_present && edns.edns_version != 0) {
844238106Sdes		edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
845238106Sdes		edns.edns_version = EDNS_ADVERTISED_VERSION;
846238106Sdes		edns.udp_size = EDNS_ADVERTISED_SIZE;
847238106Sdes		edns.bits &= EDNS_DO;
848238106Sdes		verbose(VERB_ALGO, "query with bad edns version.");
849238106Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
850238106Sdes		error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
851266114Sdes		    *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
852266114Sdes			sldns_buffer_read_u16_at(c->buffer, 2), NULL);
853238106Sdes		attach_edns_record(c->buffer, &edns);
854238106Sdes		return 1;
855238106Sdes	}
856238106Sdes	if(edns.edns_present && edns.udp_size < NORMAL_UDP_SIZE &&
857238106Sdes		worker->daemon->cfg->harden_short_bufsize) {
858238106Sdes		verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
859238106Sdes			(int)edns.udp_size);
860238106Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
861238106Sdes		edns.udp_size = NORMAL_UDP_SIZE;
862238106Sdes	}
863266114Sdes	if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
864266114Sdes		c->type == comm_udp) {
865266114Sdes		verbose(VERB_QUERY,
866266114Sdes			"worker request: max UDP reply size modified"
867266114Sdes			" (%d to max-udp-size)", (int)edns.udp_size);
868266114Sdes		log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
869266114Sdes		edns.udp_size = worker->daemon->cfg->max_udp_size;
870266114Sdes	}
871266114Sdes	if(edns.udp_size < LDNS_HEADER_SIZE) {
872238106Sdes		verbose(VERB_ALGO, "worker request: edns is too small.");
873238106Sdes		log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen);
874266114Sdes		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
875266114Sdes		LDNS_TC_SET(sldns_buffer_begin(c->buffer));
876266114Sdes		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
877238106Sdes			LDNS_RCODE_SERVFAIL);
878266114Sdes		sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
879266114Sdes		sldns_buffer_write_at(c->buffer, 4,
880238106Sdes			(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
881266114Sdes		sldns_buffer_flip(c->buffer);
882238106Sdes		return 1;
883238106Sdes	}
884238106Sdes	if(worker->stats.extended)
885238106Sdes		server_stats_insquery(&worker->stats, c, qinfo.qtype,
886238106Sdes			qinfo.qclass, &edns, repinfo);
887238106Sdes	if(c->type != comm_udp)
888238106Sdes		edns.udp_size = 65535; /* max size for TCP replies */
889238106Sdes	if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
890238106Sdes		&edns, c->buffer)) {
891238106Sdes		server_stats_insrcode(&worker->stats, c->buffer);
892238106Sdes		return 1;
893238106Sdes	}
894238106Sdes	if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
895238106Sdes		c->buffer, worker->scratchpad)) {
896238106Sdes		regional_free_all(worker->scratchpad);
897266114Sdes		if(sldns_buffer_limit(c->buffer) == 0) {
898238106Sdes			comm_point_drop_reply(repinfo);
899238106Sdes			return 0;
900238106Sdes		}
901238106Sdes		server_stats_insrcode(&worker->stats, c->buffer);
902238106Sdes		return 1;
903238106Sdes	}
904266114Sdes
905266114Sdes	/* We've looked in our local zones. If the answer isn't there, we
906266114Sdes	 * might need to bail out based on ACLs now. */
907266114Sdes	if((ret=deny_refuse_non_local(c, acl, worker, repinfo)) != -1)
908266114Sdes	{
909266114Sdes		return ret;
910266114Sdes	}
911266114Sdes
912266114Sdes	/* If this request does not have the recursion bit set, verify
913266114Sdes	 * ACLs allow the snooping. */
914266114Sdes	if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
915238106Sdes		acl != acl_allow_snoop ) {
916266114Sdes		sldns_buffer_set_limit(c->buffer, LDNS_HEADER_SIZE);
917266114Sdes		sldns_buffer_write_at(c->buffer, 4,
918238106Sdes			(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
919266114Sdes		LDNS_QR_SET(sldns_buffer_begin(c->buffer));
920266114Sdes		LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
921238106Sdes			LDNS_RCODE_REFUSED);
922266114Sdes		sldns_buffer_flip(c->buffer);
923238106Sdes		server_stats_insrcode(&worker->stats, c->buffer);
924238106Sdes		log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
925238106Sdes			&repinfo->addr, repinfo->addrlen);
926238106Sdes		return 1;
927238106Sdes	}
928238106Sdes	h = query_info_hash(&qinfo);
929238106Sdes	if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
930238106Sdes		/* answer from cache - we have acquired a readlock on it */
931238106Sdes		if(answer_from_cache(worker, &qinfo,
932238106Sdes			(struct reply_info*)e->data,
933266114Sdes			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
934266114Sdes			sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
935238106Sdes			&edns)) {
936238106Sdes			/* prefetch it if the prefetch TTL expired */
937238106Sdes			if(worker->env.cfg->prefetch && *worker->env.now >=
938238106Sdes				((struct reply_info*)e->data)->prefetch_ttl) {
939266114Sdes				time_t leeway = ((struct reply_info*)e->
940238106Sdes					data)->ttl - *worker->env.now;
941238106Sdes				lock_rw_unlock(&e->lock);
942238106Sdes				reply_and_prefetch(worker, &qinfo,
943266114Sdes					sldns_buffer_read_u16_at(c->buffer, 2),
944238106Sdes					repinfo, leeway);
945238106Sdes				return 0;
946238106Sdes			}
947238106Sdes			lock_rw_unlock(&e->lock);
948238106Sdes			return 1;
949238106Sdes		}
950238106Sdes		verbose(VERB_ALGO, "answer from the cache failed");
951238106Sdes		lock_rw_unlock(&e->lock);
952238106Sdes	}
953266114Sdes	if(!LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) {
954238106Sdes		if(answer_norec_from_cache(worker, &qinfo,
955266114Sdes			*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
956266114Sdes			sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
957238106Sdes			&edns)) {
958238106Sdes			return 1;
959238106Sdes		}
960238106Sdes		verbose(VERB_ALGO, "answer norec from cache -- "
961238106Sdes			"need to validate or not primed");
962238106Sdes	}
963266114Sdes	sldns_buffer_rewind(c->buffer);
964238106Sdes	server_stats_querymiss(&worker->stats, worker);
965238106Sdes
966238106Sdes	if(verbosity >= VERB_CLIENT) {
967238106Sdes		if(c->type == comm_udp)
968238106Sdes			log_addr(VERB_CLIENT, "udp request from",
969238106Sdes				&repinfo->addr, repinfo->addrlen);
970238106Sdes		else	log_addr(VERB_CLIENT, "tcp request from",
971238106Sdes				&repinfo->addr, repinfo->addrlen);
972238106Sdes	}
973238106Sdes
974238106Sdes	/* grab a work request structure for this new request */
975238106Sdes	mesh_new_client(worker->env.mesh, &qinfo,
976266114Sdes		sldns_buffer_read_u16_at(c->buffer, 2),
977266114Sdes	    &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer));
978238106Sdes	worker_mem_report(worker, NULL);
979238106Sdes	return 0;
980238106Sdes}
981238106Sdes
982238106Sdesvoid
983238106Sdesworker_sighandler(int sig, void* arg)
984238106Sdes{
985238106Sdes	/* note that log, print, syscalls here give race conditions. */
986238106Sdes	/* we still print DETAIL logs, because this is extensive per message
987238106Sdes	 * logging anyway, and the operator may then have an interest
988238106Sdes	 * in the cause for unbound to exit */
989238106Sdes	struct worker* worker = (struct worker*)arg;
990238106Sdes	switch(sig) {
991238106Sdes#ifdef SIGHUP
992238106Sdes		case SIGHUP:
993238106Sdes			verbose(VERB_QUERY, "caught signal SIGHUP");
994238106Sdes			comm_base_exit(worker->base);
995238106Sdes			break;
996238106Sdes#endif
997238106Sdes		case SIGINT:
998238106Sdes			verbose(VERB_QUERY, "caught signal SIGINT");
999238106Sdes			worker->need_to_exit = 1;
1000238106Sdes			comm_base_exit(worker->base);
1001238106Sdes			break;
1002238106Sdes#ifdef SIGQUIT
1003238106Sdes		case SIGQUIT:
1004238106Sdes			verbose(VERB_QUERY, "caught signal SIGQUIT");
1005238106Sdes			worker->need_to_exit = 1;
1006238106Sdes			comm_base_exit(worker->base);
1007238106Sdes			break;
1008238106Sdes#endif
1009238106Sdes		case SIGTERM:
1010238106Sdes			verbose(VERB_QUERY, "caught signal SIGTERM");
1011238106Sdes			worker->need_to_exit = 1;
1012238106Sdes			comm_base_exit(worker->base);
1013238106Sdes			break;
1014238106Sdes		default:
1015238106Sdes			log_err("unknown signal: %d, ignored", sig);
1016238106Sdes			break;
1017238106Sdes	}
1018238106Sdes}
1019238106Sdes
1020238106Sdes/** restart statistics timer for worker, if enabled */
1021238106Sdesstatic void
1022238106Sdesworker_restart_timer(struct worker* worker)
1023238106Sdes{
1024238106Sdes	if(worker->env.cfg->stat_interval > 0) {
1025238106Sdes		struct timeval tv;
1026238106Sdes#ifndef S_SPLINT_S
1027238106Sdes		tv.tv_sec = worker->env.cfg->stat_interval;
1028238106Sdes		tv.tv_usec = 0;
1029238106Sdes#endif
1030238106Sdes		comm_timer_set(worker->stat_timer, &tv);
1031238106Sdes	}
1032238106Sdes}
1033238106Sdes
1034238106Sdesvoid worker_stat_timer_cb(void* arg)
1035238106Sdes{
1036238106Sdes	struct worker* worker = (struct worker*)arg;
1037238106Sdes	server_stats_log(&worker->stats, worker, worker->thread_num);
1038238106Sdes	mesh_stats(worker->env.mesh, "mesh has");
1039238106Sdes	worker_mem_report(worker, NULL);
1040238106Sdes	if(!worker->daemon->cfg->stat_cumulative) {
1041238106Sdes		worker_stats_clear(worker);
1042238106Sdes	}
1043238106Sdes	/* start next timer */
1044238106Sdes	worker_restart_timer(worker);
1045238106Sdes}
1046238106Sdes
1047238106Sdesvoid worker_probe_timer_cb(void* arg)
1048238106Sdes{
1049238106Sdes	struct worker* worker = (struct worker*)arg;
1050238106Sdes	struct timeval tv;
1051238106Sdes#ifndef S_SPLINT_S
1052238106Sdes	tv.tv_sec = (time_t)autr_probe_timer(&worker->env);
1053238106Sdes	tv.tv_usec = 0;
1054238106Sdes#endif
1055238106Sdes	if(tv.tv_sec != 0)
1056238106Sdes		comm_timer_set(worker->env.probe_timer, &tv);
1057238106Sdes}
1058238106Sdes
1059238106Sdesstruct worker*
1060238106Sdesworker_create(struct daemon* daemon, int id, int* ports, int n)
1061238106Sdes{
1062238106Sdes	unsigned int seed;
1063238106Sdes	struct worker* worker = (struct worker*)calloc(1,
1064238106Sdes		sizeof(struct worker));
1065238106Sdes	if(!worker)
1066238106Sdes		return NULL;
1067238106Sdes	worker->numports = n;
1068238106Sdes	worker->ports = (int*)memdup(ports, sizeof(int)*n);
1069238106Sdes	if(!worker->ports) {
1070238106Sdes		free(worker);
1071238106Sdes		return NULL;
1072238106Sdes	}
1073238106Sdes	worker->daemon = daemon;
1074238106Sdes	worker->thread_num = id;
1075238106Sdes	if(!(worker->cmd = tube_create())) {
1076238106Sdes		free(worker->ports);
1077238106Sdes		free(worker);
1078238106Sdes		return NULL;
1079238106Sdes	}
1080238106Sdes	/* create random state here to avoid locking trouble in RAND_bytes */
1081238106Sdes	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
1082238106Sdes		(((unsigned int)worker->thread_num)<<17);
1083238106Sdes		/* shift thread_num so it does not match out pid bits */
1084238106Sdes	if(!(worker->rndstate = ub_initstate(seed, daemon->rand))) {
1085238106Sdes		seed = 0;
1086238106Sdes		log_err("could not init random numbers.");
1087238106Sdes		tube_delete(worker->cmd);
1088238106Sdes		free(worker->ports);
1089238106Sdes		free(worker);
1090238106Sdes		return NULL;
1091238106Sdes	}
1092238106Sdes	seed = 0;
1093238106Sdes	return worker;
1094238106Sdes}
1095238106Sdes
1096238106Sdesint
1097238106Sdesworker_init(struct worker* worker, struct config_file *cfg,
1098238106Sdes	struct listen_port* ports, int do_sigs)
1099238106Sdes{
1100238106Sdes	worker->need_to_exit = 0;
1101238106Sdes	worker->base = comm_base_create(do_sigs);
1102238106Sdes	if(!worker->base) {
1103238106Sdes		log_err("could not create event handling base");
1104238106Sdes		worker_delete(worker);
1105238106Sdes		return 0;
1106238106Sdes	}
1107238106Sdes	comm_base_set_slow_accept_handlers(worker->base, &worker_stop_accept,
1108238106Sdes		&worker_start_accept, worker);
1109238106Sdes	if(do_sigs) {
1110238106Sdes#ifdef SIGHUP
1111238106Sdes		ub_thread_sig_unblock(SIGHUP);
1112238106Sdes#endif
1113238106Sdes		ub_thread_sig_unblock(SIGINT);
1114238106Sdes#ifdef SIGQUIT
1115238106Sdes		ub_thread_sig_unblock(SIGQUIT);
1116238106Sdes#endif
1117238106Sdes		ub_thread_sig_unblock(SIGTERM);
1118238106Sdes#ifndef LIBEVENT_SIGNAL_PROBLEM
1119238106Sdes		worker->comsig = comm_signal_create(worker->base,
1120238106Sdes			worker_sighandler, worker);
1121238106Sdes		if(!worker->comsig
1122238106Sdes#ifdef SIGHUP
1123238106Sdes			|| !comm_signal_bind(worker->comsig, SIGHUP)
1124238106Sdes#endif
1125238106Sdes#ifdef SIGQUIT
1126238106Sdes			|| !comm_signal_bind(worker->comsig, SIGQUIT)
1127238106Sdes#endif
1128238106Sdes			|| !comm_signal_bind(worker->comsig, SIGTERM)
1129238106Sdes			|| !comm_signal_bind(worker->comsig, SIGINT)) {
1130238106Sdes			log_err("could not create signal handlers");
1131238106Sdes			worker_delete(worker);
1132238106Sdes			return 0;
1133238106Sdes		}
1134238106Sdes#endif /* LIBEVENT_SIGNAL_PROBLEM */
1135238106Sdes		if(!daemon_remote_open_accept(worker->daemon->rc,
1136238106Sdes			worker->daemon->rc_ports, worker)) {
1137238106Sdes			worker_delete(worker);
1138238106Sdes			return 0;
1139238106Sdes		}
1140238106Sdes#ifdef UB_ON_WINDOWS
1141238106Sdes		wsvc_setup_worker(worker);
1142238106Sdes#endif /* UB_ON_WINDOWS */
1143238106Sdes	} else { /* !do_sigs */
1144238106Sdes		worker->comsig = NULL;
1145238106Sdes	}
1146238106Sdes	worker->front = listen_create(worker->base, ports,
1147238106Sdes		cfg->msg_buffer_size, (int)cfg->incoming_num_tcp,
1148238106Sdes		worker->daemon->listen_sslctx, worker_handle_request, worker);
1149238106Sdes	if(!worker->front) {
1150238106Sdes		log_err("could not create listening sockets");
1151238106Sdes		worker_delete(worker);
1152238106Sdes		return 0;
1153238106Sdes	}
1154238106Sdes	worker->back = outside_network_create(worker->base,
1155238106Sdes		cfg->msg_buffer_size, (size_t)cfg->outgoing_num_ports,
1156238106Sdes		cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
1157238106Sdes		cfg->do_tcp?cfg->outgoing_num_tcp:0,
1158238106Sdes		worker->daemon->env->infra_cache, worker->rndstate,
1159238106Sdes		cfg->use_caps_bits_for_id, worker->ports, worker->numports,
1160238106Sdes		cfg->unwanted_threshold, &worker_alloc_cleanup, worker,
1161266114Sdes		cfg->do_udp, worker->daemon->connect_sslctx, cfg->delay_close);
1162238106Sdes	if(!worker->back) {
1163238106Sdes		log_err("could not create outgoing sockets");
1164238106Sdes		worker_delete(worker);
1165238106Sdes		return 0;
1166238106Sdes	}
1167238106Sdes	/* start listening to commands */
1168238106Sdes	if(!tube_setup_bg_listen(worker->cmd, worker->base,
1169238106Sdes		&worker_handle_control_cmd, worker)) {
1170238106Sdes		log_err("could not create control compt.");
1171238106Sdes		worker_delete(worker);
1172238106Sdes		return 0;
1173238106Sdes	}
1174238106Sdes	worker->stat_timer = comm_timer_create(worker->base,
1175238106Sdes		worker_stat_timer_cb, worker);
1176238106Sdes	if(!worker->stat_timer) {
1177238106Sdes		log_err("could not create statistics timer");
1178238106Sdes	}
1179238106Sdes
1180238106Sdes	/* we use the msg_buffer_size as a good estimate for what the
1181238106Sdes	 * user wants for memory usage sizes */
1182238106Sdes	worker->scratchpad = regional_create_custom(cfg->msg_buffer_size);
1183238106Sdes	if(!worker->scratchpad) {
1184238106Sdes		log_err("malloc failure");
1185238106Sdes		worker_delete(worker);
1186238106Sdes		return 0;
1187238106Sdes	}
1188238106Sdes
1189238106Sdes	server_stats_init(&worker->stats, cfg);
1190238106Sdes	alloc_init(&worker->alloc, &worker->daemon->superalloc,
1191238106Sdes		worker->thread_num);
1192238106Sdes	alloc_set_id_cleanup(&worker->alloc, &worker_alloc_cleanup, worker);
1193238106Sdes	worker->env = *worker->daemon->env;
1194238106Sdes	comm_base_timept(worker->base, &worker->env.now, &worker->env.now_tv);
1195238106Sdes	if(worker->thread_num == 0)
1196238106Sdes		log_set_time(worker->env.now);
1197238106Sdes	worker->env.worker = worker;
1198238106Sdes	worker->env.send_query = &worker_send_query;
1199238106Sdes	worker->env.alloc = &worker->alloc;
1200238106Sdes	worker->env.rnd = worker->rndstate;
1201238106Sdes	worker->env.scratch = worker->scratchpad;
1202238106Sdes	worker->env.mesh = mesh_create(&worker->daemon->mods, &worker->env);
1203238106Sdes	worker->env.detach_subs = &mesh_detach_subs;
1204238106Sdes	worker->env.attach_sub = &mesh_attach_sub;
1205238106Sdes	worker->env.kill_sub = &mesh_state_delete;
1206238106Sdes	worker->env.detect_cycle = &mesh_detect_cycle;
1207266114Sdes	worker->env.scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
1208238106Sdes	if(!(worker->env.fwds = forwards_create()) ||
1209238106Sdes		!forwards_apply_cfg(worker->env.fwds, cfg)) {
1210238106Sdes		log_err("Could not set forward zones");
1211238106Sdes		worker_delete(worker);
1212238106Sdes		return 0;
1213238106Sdes	}
1214238106Sdes	if(!(worker->env.hints = hints_create()) ||
1215238106Sdes		!hints_apply_cfg(worker->env.hints, cfg)) {
1216238106Sdes		log_err("Could not set root or stub hints");
1217238106Sdes		worker_delete(worker);
1218238106Sdes		return 0;
1219238106Sdes	}
1220238106Sdes	/* one probe timer per process -- if we have 5011 anchors */
1221238106Sdes	if(autr_get_num_anchors(worker->env.anchors) > 0
1222238106Sdes#ifndef THREADS_DISABLED
1223238106Sdes		&& worker->thread_num == 0
1224238106Sdes#endif
1225238106Sdes		) {
1226238106Sdes		struct timeval tv;
1227238106Sdes		tv.tv_sec = 0;
1228238106Sdes		tv.tv_usec = 0;
1229238106Sdes		worker->env.probe_timer = comm_timer_create(worker->base,
1230238106Sdes			worker_probe_timer_cb, worker);
1231238106Sdes		if(!worker->env.probe_timer) {
1232238106Sdes			log_err("could not create 5011-probe timer");
1233238106Sdes		} else {
1234238106Sdes			/* let timer fire, then it can reset itself */
1235238106Sdes			comm_timer_set(worker->env.probe_timer, &tv);
1236238106Sdes		}
1237238106Sdes	}
1238238106Sdes	if(!worker->env.mesh || !worker->env.scratch_buffer) {
1239238106Sdes		worker_delete(worker);
1240238106Sdes		return 0;
1241238106Sdes	}
1242238106Sdes	worker_mem_report(worker, NULL);
1243238106Sdes	/* if statistics enabled start timer */
1244238106Sdes	if(worker->env.cfg->stat_interval > 0) {
1245238106Sdes		verbose(VERB_ALGO, "set statistics interval %d secs",
1246238106Sdes			worker->env.cfg->stat_interval);
1247238106Sdes		worker_restart_timer(worker);
1248238106Sdes	}
1249238106Sdes	return 1;
1250238106Sdes}
1251238106Sdes
1252238106Sdesvoid
1253238106Sdesworker_work(struct worker* worker)
1254238106Sdes{
1255238106Sdes	comm_base_dispatch(worker->base);
1256238106Sdes}
1257238106Sdes
1258238106Sdesvoid
1259238106Sdesworker_delete(struct worker* worker)
1260238106Sdes{
1261238106Sdes	if(!worker)
1262238106Sdes		return;
1263238106Sdes	if(worker->env.mesh && verbosity >= VERB_OPS) {
1264238106Sdes		server_stats_log(&worker->stats, worker, worker->thread_num);
1265238106Sdes		mesh_stats(worker->env.mesh, "mesh has");
1266238106Sdes		worker_mem_report(worker, NULL);
1267238106Sdes	}
1268238106Sdes	outside_network_quit_prepare(worker->back);
1269238106Sdes	mesh_delete(worker->env.mesh);
1270266114Sdes	sldns_buffer_free(worker->env.scratch_buffer);
1271238106Sdes	forwards_delete(worker->env.fwds);
1272238106Sdes	hints_delete(worker->env.hints);
1273238106Sdes	listen_delete(worker->front);
1274238106Sdes	outside_network_delete(worker->back);
1275238106Sdes	comm_signal_delete(worker->comsig);
1276238106Sdes	tube_delete(worker->cmd);
1277238106Sdes	comm_timer_delete(worker->stat_timer);
1278238106Sdes	comm_timer_delete(worker->env.probe_timer);
1279238106Sdes	free(worker->ports);
1280238106Sdes	if(worker->thread_num == 0) {
1281238106Sdes		log_set_time(NULL);
1282238106Sdes#ifdef UB_ON_WINDOWS
1283238106Sdes		wsvc_desetup_worker(worker);
1284238106Sdes#endif /* UB_ON_WINDOWS */
1285238106Sdes	}
1286238106Sdes	comm_base_delete(worker->base);
1287238106Sdes	ub_randfree(worker->rndstate);
1288238106Sdes	alloc_clear(&worker->alloc);
1289238106Sdes	regional_destroy(worker->scratchpad);
1290238106Sdes	free(worker);
1291238106Sdes}
1292238106Sdes
1293238106Sdesstruct outbound_entry*
1294238106Sdesworker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
1295238106Sdes	uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec,
1296238106Sdes	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
1297238106Sdes	size_t zonelen, struct module_qstate* q)
1298238106Sdes{
1299238106Sdes	struct worker* worker = q->env->worker;
1300238106Sdes	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
1301238106Sdes		q->region, sizeof(*e));
1302238106Sdes	if(!e)
1303238106Sdes		return NULL;
1304238106Sdes	e->qstate = q;
1305238106Sdes	e->qsent = outnet_serviced_query(worker->back, qname,
1306238106Sdes		qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
1307238106Sdes		q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
1308238106Sdes		addrlen, zone, zonelen, worker_handle_service_reply, e,
1309249141Sdes		worker->back->udp_buff);
1310238106Sdes	if(!e->qsent) {
1311238106Sdes		return NULL;
1312238106Sdes	}
1313238106Sdes	return e;
1314238106Sdes}
1315238106Sdes
1316238106Sdesvoid
1317238106Sdesworker_alloc_cleanup(void* arg)
1318238106Sdes{
1319238106Sdes	struct worker* worker = (struct worker*)arg;
1320238106Sdes	slabhash_clear(&worker->env.rrset_cache->table);
1321238106Sdes	slabhash_clear(worker->env.msg_cache);
1322238106Sdes}
1323238106Sdes
1324238106Sdesvoid worker_stats_clear(struct worker* worker)
1325238106Sdes{
1326238106Sdes	server_stats_init(&worker->stats, worker->env.cfg);
1327238106Sdes	mesh_stats_clear(worker->env.mesh);
1328238106Sdes	worker->back->unwanted_replies = 0;
1329238106Sdes}
1330238106Sdes
1331238106Sdesvoid worker_start_accept(void* arg)
1332238106Sdes{
1333238106Sdes	struct worker* worker = (struct worker*)arg;
1334238106Sdes	listen_start_accept(worker->front);
1335238106Sdes	if(worker->thread_num == 0)
1336238106Sdes		daemon_remote_start_accept(worker->daemon->rc);
1337238106Sdes}
1338238106Sdes
1339238106Sdesvoid worker_stop_accept(void* arg)
1340238106Sdes{
1341238106Sdes	struct worker* worker = (struct worker*)arg;
1342238106Sdes	listen_stop_accept(worker->front);
1343238106Sdes	if(worker->thread_num == 0)
1344238106Sdes		daemon_remote_stop_accept(worker->daemon->rc);
1345238106Sdes}
1346238106Sdes
1347238106Sdes/* --- fake callbacks for fptr_wlist to work --- */
1348238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname),
1349238106Sdes	size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
1350238106Sdes	uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
1351238106Sdes	int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
1352238106Sdes	struct sockaddr_storage* ATTR_UNUSED(addr),
1353255579Sdes	socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
1354255579Sdes	size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
1355238106Sdes{
1356238106Sdes	log_assert(0);
1357238106Sdes	return 0;
1358238106Sdes}
1359238106Sdes
1360238106Sdesint libworker_handle_reply(struct comm_point* ATTR_UNUSED(c),
1361238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
1362238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
1363238106Sdes{
1364238106Sdes	log_assert(0);
1365238106Sdes	return 0;
1366238106Sdes}
1367238106Sdes
1368238106Sdesint libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
1369238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
1370238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
1371238106Sdes{
1372238106Sdes	log_assert(0);
1373238106Sdes	return 0;
1374238106Sdes}
1375238106Sdes
1376238106Sdesvoid libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
1377238106Sdes        uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
1378238106Sdes        int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
1379238106Sdes{
1380238106Sdes	log_assert(0);
1381238106Sdes}
1382238106Sdes
1383238106Sdesvoid libworker_fg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
1384266114Sdes        sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
1385238106Sdes	char* ATTR_UNUSED(why_bogus))
1386238106Sdes{
1387238106Sdes	log_assert(0);
1388238106Sdes}
1389238106Sdes
1390238106Sdesvoid libworker_bg_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
1391266114Sdes        sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
1392238106Sdes	char* ATTR_UNUSED(why_bogus))
1393238106Sdes{
1394238106Sdes	log_assert(0);
1395238106Sdes}
1396238106Sdes
1397266114Sdesvoid libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
1398266114Sdes        sldns_buffer* ATTR_UNUSED(buf), enum sec_status ATTR_UNUSED(s),
1399266114Sdes	char* ATTR_UNUSED(why_bogus))
1400266114Sdes{
1401266114Sdes	log_assert(0);
1402266114Sdes}
1403266114Sdes
1404238106Sdesint context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1405238106Sdes{
1406238106Sdes	log_assert(0);
1407238106Sdes	return 0;
1408238106Sdes}
1409238106Sdes
1410238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
1411238106Sdes{
1412238106Sdes        log_assert(0);
1413238106Sdes        return 0;
1414238106Sdes}
1415238106Sdes
1416238106Sdesint codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1417238106Sdes{
1418238106Sdes        log_assert(0);
1419238106Sdes        return 0;
1420238106Sdes}
1421238106Sdes
1422