1238106Sdes/*
2238106Sdes * libunbound/worker.c - worker thread or process that resolves
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
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes */
35238106Sdes
36238106Sdes/**
37238106Sdes * \file
38238106Sdes *
39238106Sdes * This file contains the worker process or thread that performs
40238106Sdes * the DNS resolving and validation. The worker is called by a procedure
41238106Sdes * and if in the background continues until exit, if in the foreground
42238106Sdes * returns from the procedure when done.
43238106Sdes */
44238106Sdes#include "config.h"
45249141Sdes#ifdef HAVE_SSL
46238106Sdes#include <openssl/ssl.h>
47249141Sdes#endif
48238106Sdes#include "libunbound/libworker.h"
49238106Sdes#include "libunbound/context.h"
50238106Sdes#include "libunbound/unbound.h"
51255579Sdes#include "libunbound/worker.h"
52269257Sdes#include "libunbound/unbound-event.h"
53238106Sdes#include "services/outside_network.h"
54238106Sdes#include "services/mesh.h"
55238106Sdes#include "services/localzone.h"
56238106Sdes#include "services/cache/rrset.h"
57238106Sdes#include "services/outbound_list.h"
58255579Sdes#include "util/fptr_wlist.h"
59238106Sdes#include "util/module.h"
60238106Sdes#include "util/regional.h"
61238106Sdes#include "util/random.h"
62238106Sdes#include "util/config_file.h"
63238106Sdes#include "util/netevent.h"
64238106Sdes#include "util/storage/lookup3.h"
65238106Sdes#include "util/storage/slabhash.h"
66238106Sdes#include "util/net_help.h"
67238106Sdes#include "util/data/dname.h"
68238106Sdes#include "util/data/msgreply.h"
69238106Sdes#include "util/data/msgencode.h"
70238106Sdes#include "util/tube.h"
71238106Sdes#include "iterator/iter_fwd.h"
72238106Sdes#include "iterator/iter_hints.h"
73291767Sdes#include "sldns/sbuffer.h"
74291767Sdes#include "sldns/str2wire.h"
75238106Sdes
76238106Sdes/** handle new query command for bg worker */
77238106Sdesstatic void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
78238106Sdes
79269257Sdes/** delete libworker env */
80238106Sdesstatic void
81269257Sdeslibworker_delete_env(struct libworker* w)
82238106Sdes{
83238106Sdes	if(w->env) {
84238106Sdes		outside_network_quit_prepare(w->back);
85238106Sdes		mesh_delete(w->env->mesh);
86238106Sdes		context_release_alloc(w->ctx, w->env->alloc,
87238106Sdes			!w->is_bg || w->is_bg_thread);
88269257Sdes		sldns_buffer_free(w->env->scratch_buffer);
89238106Sdes		regional_destroy(w->env->scratch);
90238106Sdes		forwards_delete(w->env->fwds);
91238106Sdes		hints_delete(w->env->hints);
92238106Sdes		ub_randfree(w->env->rnd);
93238106Sdes		free(w->env);
94238106Sdes	}
95249141Sdes#ifdef HAVE_SSL
96238106Sdes	SSL_CTX_free(w->sslctx);
97249141Sdes#endif
98238106Sdes	outside_network_delete(w->back);
99269257Sdes}
100269257Sdes
101269257Sdes/** delete libworker struct */
102269257Sdesstatic void
103269257Sdeslibworker_delete(struct libworker* w)
104269257Sdes{
105269257Sdes	if(!w) return;
106269257Sdes	libworker_delete_env(w);
107238106Sdes	comm_base_delete(w->base);
108238106Sdes	free(w);
109238106Sdes}
110238106Sdes
111269257Sdesvoid
112269257Sdeslibworker_delete_event(struct libworker* w)
113269257Sdes{
114269257Sdes	if(!w) return;
115269257Sdes	libworker_delete_env(w);
116269257Sdes	comm_base_delete_no_base(w->base);
117269257Sdes	free(w);
118269257Sdes}
119269257Sdes
120238106Sdes/** setup fresh libworker struct */
121238106Sdesstatic struct libworker*
122269257Sdeslibworker_setup(struct ub_ctx* ctx, int is_bg, struct event_base* eb)
123238106Sdes{
124238106Sdes	unsigned int seed;
125238106Sdes	struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
126238106Sdes	struct config_file* cfg = ctx->env->cfg;
127238106Sdes	int* ports;
128238106Sdes	int numports;
129238106Sdes	if(!w) return NULL;
130238106Sdes	w->is_bg = is_bg;
131238106Sdes	w->ctx = ctx;
132238106Sdes	w->env = (struct module_env*)malloc(sizeof(*w->env));
133238106Sdes	if(!w->env) {
134238106Sdes		free(w);
135238106Sdes		return NULL;
136238106Sdes	}
137238106Sdes	*w->env = *ctx->env;
138238106Sdes	w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
139238106Sdes	if(!w->env->alloc) {
140238106Sdes		libworker_delete(w);
141238106Sdes		return NULL;
142238106Sdes	}
143238106Sdes	w->thread_num = w->env->alloc->thread_num;
144238106Sdes	alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
145238106Sdes	if(!w->is_bg || w->is_bg_thread) {
146238106Sdes		lock_basic_lock(&ctx->cfglock);
147238106Sdes	}
148238106Sdes	w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
149269257Sdes	w->env->scratch_buffer = sldns_buffer_new(cfg->msg_buffer_size);
150238106Sdes	w->env->fwds = forwards_create();
151238106Sdes	if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
152238106Sdes		forwards_delete(w->env->fwds);
153238106Sdes		w->env->fwds = NULL;
154238106Sdes	}
155238106Sdes	w->env->hints = hints_create();
156238106Sdes	if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
157238106Sdes		hints_delete(w->env->hints);
158238106Sdes		w->env->hints = NULL;
159238106Sdes	}
160238106Sdes	if(cfg->ssl_upstream) {
161238106Sdes		w->sslctx = connect_sslctx_create(NULL, NULL, NULL);
162238106Sdes		if(!w->sslctx) {
163238106Sdes			/* to make the setup fail after unlock */
164238106Sdes			hints_delete(w->env->hints);
165238106Sdes			w->env->hints = NULL;
166238106Sdes		}
167238106Sdes	}
168238106Sdes	if(!w->is_bg || w->is_bg_thread) {
169238106Sdes		lock_basic_unlock(&ctx->cfglock);
170238106Sdes	}
171238106Sdes	if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
172238106Sdes		!w->env->hints) {
173238106Sdes		libworker_delete(w);
174238106Sdes		return NULL;
175238106Sdes	}
176238106Sdes	w->env->worker = (struct worker*)w;
177238106Sdes	w->env->probe_timer = NULL;
178238106Sdes	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
179238106Sdes		(((unsigned int)w->thread_num)<<17);
180238106Sdes	seed ^= (unsigned int)w->env->alloc->next_id;
181238106Sdes	if(!w->is_bg || w->is_bg_thread) {
182238106Sdes		lock_basic_lock(&ctx->cfglock);
183238106Sdes	}
184238106Sdes	if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) {
185238106Sdes		if(!w->is_bg || w->is_bg_thread) {
186238106Sdes			lock_basic_unlock(&ctx->cfglock);
187238106Sdes		}
188238106Sdes		seed = 0;
189238106Sdes		libworker_delete(w);
190238106Sdes		return NULL;
191238106Sdes	}
192238106Sdes	if(!w->is_bg || w->is_bg_thread) {
193238106Sdes		lock_basic_unlock(&ctx->cfglock);
194238106Sdes	}
195238106Sdes	if(1) {
196238106Sdes		/* primitive lockout for threading: if it overwrites another
197238106Sdes		 * thread it is like wiping the cache (which is likely empty
198238106Sdes		 * at the start) */
199238106Sdes		/* note we are holding the ctx lock in normal threaded
200238106Sdes		 * cases so that is solved properly, it is only for many ctx
201238106Sdes		 * in different threads that this may clash */
202238106Sdes		static int done_raninit = 0;
203238106Sdes		if(!done_raninit) {
204238106Sdes			done_raninit = 1;
205238106Sdes			hash_set_raninit((uint32_t)ub_random(w->env->rnd));
206238106Sdes		}
207238106Sdes	}
208238106Sdes	seed = 0;
209238106Sdes
210269257Sdes	if(eb)
211269257Sdes		w->base = comm_base_create_event(eb);
212269257Sdes	else	w->base = comm_base_create(0);
213238106Sdes	if(!w->base) {
214238106Sdes		libworker_delete(w);
215238106Sdes		return NULL;
216238106Sdes	}
217238106Sdes	if(!w->is_bg || w->is_bg_thread) {
218238106Sdes		lock_basic_lock(&ctx->cfglock);
219238106Sdes	}
220238106Sdes	numports = cfg_condense_ports(cfg, &ports);
221238106Sdes	if(numports == 0) {
222269257Sdes		int locked = !w->is_bg || w->is_bg_thread;
223238106Sdes		libworker_delete(w);
224269257Sdes		if(locked) {
225269257Sdes			lock_basic_unlock(&ctx->cfglock);
226269257Sdes		}
227238106Sdes		return NULL;
228238106Sdes	}
229238106Sdes	w->back = outside_network_create(w->base, cfg->msg_buffer_size,
230238106Sdes		(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
231238106Sdes		cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
232238106Sdes		cfg->do_tcp?cfg->outgoing_num_tcp:0,
233238106Sdes		w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
234238106Sdes		ports, numports, cfg->unwanted_threshold,
235269257Sdes		&libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx,
236285206Sdes		cfg->delay_close, NULL);
237238106Sdes	if(!w->is_bg || w->is_bg_thread) {
238238106Sdes		lock_basic_unlock(&ctx->cfglock);
239238106Sdes	}
240238106Sdes	free(ports);
241238106Sdes	if(!w->back) {
242238106Sdes		libworker_delete(w);
243238106Sdes		return NULL;
244238106Sdes	}
245238106Sdes	w->env->mesh = mesh_create(&ctx->mods, w->env);
246238106Sdes	if(!w->env->mesh) {
247238106Sdes		libworker_delete(w);
248238106Sdes		return NULL;
249238106Sdes	}
250238106Sdes	w->env->send_query = &libworker_send_query;
251238106Sdes	w->env->detach_subs = &mesh_detach_subs;
252238106Sdes	w->env->attach_sub = &mesh_attach_sub;
253238106Sdes	w->env->kill_sub = &mesh_state_delete;
254238106Sdes	w->env->detect_cycle = &mesh_detect_cycle;
255238106Sdes	comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
256238106Sdes	return w;
257238106Sdes}
258238106Sdes
259269257Sdesstruct libworker* libworker_create_event(struct ub_ctx* ctx,
260269257Sdes	struct event_base* eb)
261269257Sdes{
262269257Sdes	return libworker_setup(ctx, 0, eb);
263269257Sdes}
264269257Sdes
265238106Sdes/** handle cancel command for bg worker */
266238106Sdesstatic void
267238106Sdeshandle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
268238106Sdes{
269238106Sdes	struct ctx_query* q;
270238106Sdes	if(w->is_bg_thread) {
271238106Sdes		lock_basic_lock(&w->ctx->cfglock);
272238106Sdes		q = context_deserialize_cancel(w->ctx, buf, len);
273238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
274238106Sdes	} else {
275238106Sdes		q = context_deserialize_cancel(w->ctx, buf, len);
276238106Sdes	}
277238106Sdes	if(!q) {
278238106Sdes		/* probably simply lookup failed, i.e. the message had been
279238106Sdes		 * processed and answered before the cancel arrived */
280238106Sdes		return;
281238106Sdes	}
282238106Sdes	q->cancelled = 1;
283238106Sdes	free(buf);
284238106Sdes}
285238106Sdes
286238106Sdes/** do control command coming into bg server */
287238106Sdesstatic void
288238106Sdeslibworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
289238106Sdes{
290238106Sdes	switch(context_serial_getcmd(msg, len)) {
291238106Sdes		default:
292238106Sdes		case UB_LIBCMD_ANSWER:
293238106Sdes			log_err("unknown command for bg worker %d",
294238106Sdes				(int)context_serial_getcmd(msg, len));
295238106Sdes			/* and fall through to quit */
296238106Sdes		case UB_LIBCMD_QUIT:
297238106Sdes			free(msg);
298238106Sdes			comm_base_exit(w->base);
299238106Sdes			break;
300238106Sdes		case UB_LIBCMD_NEWQUERY:
301238106Sdes			handle_newq(w, msg, len);
302238106Sdes			break;
303238106Sdes		case UB_LIBCMD_CANCEL:
304238106Sdes			handle_cancel(w, msg, len);
305238106Sdes			break;
306238106Sdes	}
307238106Sdes}
308238106Sdes
309238106Sdes/** handle control command coming into server */
310238106Sdesvoid
311238106Sdeslibworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
312238106Sdes	uint8_t* msg, size_t len, int err, void* arg)
313238106Sdes{
314238106Sdes	struct libworker* w = (struct libworker*)arg;
315238106Sdes
316238106Sdes	if(err != 0) {
317238106Sdes		free(msg);
318238106Sdes		/* it is of no use to go on, exit */
319238106Sdes		comm_base_exit(w->base);
320238106Sdes		return;
321238106Sdes	}
322238106Sdes	libworker_do_cmd(w, msg, len); /* also frees the buf */
323238106Sdes}
324238106Sdes
325238106Sdes/** the background thread func */
326238106Sdesstatic void*
327238106Sdeslibworker_dobg(void* arg)
328238106Sdes{
329238106Sdes	/* setup */
330238106Sdes	uint32_t m;
331238106Sdes	struct libworker* w = (struct libworker*)arg;
332238106Sdes	struct ub_ctx* ctx;
333238106Sdes	if(!w) {
334238106Sdes		log_err("libunbound bg worker init failed, nomem");
335238106Sdes		return NULL;
336238106Sdes	}
337238106Sdes	ctx = w->ctx;
338238106Sdes	log_thread_set(&w->thread_num);
339238106Sdes#ifdef THREADS_DISABLED
340238106Sdes	/* we are forked */
341238106Sdes	w->is_bg_thread = 0;
342238106Sdes	/* close non-used parts of the pipes */
343238106Sdes	tube_close_write(ctx->qq_pipe);
344238106Sdes	tube_close_read(ctx->rr_pipe);
345238106Sdes#endif
346238106Sdes	if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
347238106Sdes		libworker_handle_control_cmd, w)) {
348238106Sdes		log_err("libunbound bg worker init failed, no bglisten");
349238106Sdes		return NULL;
350238106Sdes	}
351238106Sdes	if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
352238106Sdes		log_err("libunbound bg worker init failed, no bgwrite");
353238106Sdes		return NULL;
354238106Sdes	}
355238106Sdes
356238106Sdes	/* do the work */
357238106Sdes	comm_base_dispatch(w->base);
358238106Sdes
359238106Sdes	/* cleanup */
360238106Sdes	m = UB_LIBCMD_QUIT;
361238106Sdes	tube_remove_bg_listen(w->ctx->qq_pipe);
362238106Sdes	tube_remove_bg_write(w->ctx->rr_pipe);
363238106Sdes	libworker_delete(w);
364238106Sdes	(void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
365238106Sdes		(uint32_t)sizeof(m), 0);
366238106Sdes#ifdef THREADS_DISABLED
367238106Sdes	/* close pipes from forked process before exit */
368238106Sdes	tube_close_read(ctx->qq_pipe);
369238106Sdes	tube_close_write(ctx->rr_pipe);
370238106Sdes#endif
371238106Sdes	return NULL;
372238106Sdes}
373238106Sdes
374238106Sdesint libworker_bg(struct ub_ctx* ctx)
375238106Sdes{
376238106Sdes	struct libworker* w;
377238106Sdes	/* fork or threadcreate */
378238106Sdes	lock_basic_lock(&ctx->cfglock);
379238106Sdes	if(ctx->dothread) {
380238106Sdes		lock_basic_unlock(&ctx->cfglock);
381269257Sdes		w = libworker_setup(ctx, 1, NULL);
382238106Sdes		if(!w) return UB_NOMEM;
383238106Sdes		w->is_bg_thread = 1;
384238106Sdes#ifdef ENABLE_LOCK_CHECKS
385238106Sdes		w->thread_num = 1; /* for nicer DEBUG checklocks */
386238106Sdes#endif
387238106Sdes		ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
388238106Sdes	} else {
389238106Sdes		lock_basic_unlock(&ctx->cfglock);
390238106Sdes#ifndef HAVE_FORK
391238106Sdes		/* no fork on windows */
392238106Sdes		return UB_FORKFAIL;
393238106Sdes#else /* HAVE_FORK */
394238106Sdes		switch((ctx->bg_pid=fork())) {
395238106Sdes			case 0:
396269257Sdes				w = libworker_setup(ctx, 1, NULL);
397238106Sdes				if(!w) fatal_exit("out of memory");
398238106Sdes				/* close non-used parts of the pipes */
399238106Sdes				tube_close_write(ctx->qq_pipe);
400238106Sdes				tube_close_read(ctx->rr_pipe);
401238106Sdes				(void)libworker_dobg(w);
402238106Sdes				exit(0);
403238106Sdes				break;
404238106Sdes			case -1:
405238106Sdes				return UB_FORKFAIL;
406238106Sdes			default:
407269257Sdes				/* close non-used parts, so that the worker
408269257Sdes				 * bgprocess gets 'pipe closed' when the
409269257Sdes				 * main process exits */
410269257Sdes				tube_close_read(ctx->qq_pipe);
411269257Sdes				tube_close_write(ctx->rr_pipe);
412238106Sdes				break;
413238106Sdes		}
414238106Sdes#endif /* HAVE_FORK */
415238106Sdes	}
416238106Sdes	return UB_NOERROR;
417238106Sdes}
418238106Sdes
419238106Sdes/** get msg reply struct (in temp region) */
420238106Sdesstatic struct reply_info*
421269257Sdesparse_reply(sldns_buffer* pkt, struct regional* region, struct query_info* qi)
422238106Sdes{
423238106Sdes	struct reply_info* rep;
424238106Sdes	struct msg_parse* msg;
425238106Sdes	if(!(msg = regional_alloc(region, sizeof(*msg)))) {
426238106Sdes		return NULL;
427238106Sdes	}
428238106Sdes	memset(msg, 0, sizeof(*msg));
429269257Sdes	sldns_buffer_set_position(pkt, 0);
430238106Sdes	if(parse_packet(pkt, msg, region) != 0)
431238106Sdes		return 0;
432238106Sdes	if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
433238106Sdes		return 0;
434238106Sdes	}
435238106Sdes	return rep;
436238106Sdes}
437238106Sdes
438238106Sdes/** insert canonname */
439238106Sdesstatic int
440238106Sdesfill_canon(struct ub_result* res, uint8_t* s)
441238106Sdes{
442238106Sdes	char buf[255+2];
443238106Sdes	dname_str(s, buf);
444238106Sdes	res->canonname = strdup(buf);
445238106Sdes	return res->canonname != 0;
446238106Sdes}
447238106Sdes
448238106Sdes/** fill data into result */
449238106Sdesstatic int
450238106Sdesfill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
451249141Sdes	uint8_t* finalcname, struct query_info* rq, struct reply_info* rep)
452238106Sdes{
453238106Sdes	size_t i;
454238106Sdes	struct packed_rrset_data* data;
455249141Sdes	res->ttl = 0;
456238106Sdes	if(!answer) {
457238106Sdes		if(finalcname) {
458238106Sdes			if(!fill_canon(res, finalcname))
459238106Sdes				return 0; /* out of memory */
460238106Sdes		}
461249141Sdes		if(rep->rrset_count != 0)
462249141Sdes			res->ttl = (int)rep->ttl;
463238106Sdes		res->data = (char**)calloc(1, sizeof(char*));
464238106Sdes		res->len = (int*)calloc(1, sizeof(int));
465238106Sdes		return (res->data && res->len);
466238106Sdes	}
467238106Sdes	data = (struct packed_rrset_data*)answer->entry.data;
468238106Sdes	if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
469238106Sdes		if(!fill_canon(res, answer->rk.dname))
470238106Sdes			return 0; /* out of memory */
471238106Sdes	} else	res->canonname = NULL;
472238106Sdes	res->data = (char**)calloc(data->count+1, sizeof(char*));
473238106Sdes	res->len = (int*)calloc(data->count+1, sizeof(int));
474238106Sdes	if(!res->data || !res->len)
475238106Sdes		return 0; /* out of memory */
476238106Sdes	for(i=0; i<data->count; i++) {
477238106Sdes		/* remove rdlength from rdata */
478238106Sdes		res->len[i] = (int)(data->rr_len[i] - 2);
479238106Sdes		res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
480238106Sdes		if(!res->data[i])
481238106Sdes			return 0; /* out of memory */
482238106Sdes	}
483249141Sdes	/* ttl for positive answers, from CNAME and answer RRs */
484249141Sdes	if(data->count != 0) {
485249141Sdes		size_t j;
486249141Sdes		res->ttl = (int)data->ttl;
487249141Sdes		for(j=0; j<rep->an_numrrsets; j++) {
488249141Sdes			struct packed_rrset_data* d =
489249141Sdes				(struct packed_rrset_data*)rep->rrsets[j]->
490249141Sdes				entry.data;
491249141Sdes			if((int)d->ttl < res->ttl)
492249141Sdes				res->ttl = (int)d->ttl;
493249141Sdes		}
494249141Sdes	}
495249141Sdes	/* ttl for negative answers */
496249141Sdes	if(data->count == 0 && rep->rrset_count != 0)
497249141Sdes		res->ttl = (int)rep->ttl;
498238106Sdes	res->data[data->count] = NULL;
499238106Sdes	res->len[data->count] = 0;
500238106Sdes	return 1;
501238106Sdes}
502238106Sdes
503238106Sdes/** fill result from parsed message, on error fills servfail */
504238106Sdesvoid
505269257Sdeslibworker_enter_result(struct ub_result* res, sldns_buffer* buf,
506238106Sdes	struct regional* temp, enum sec_status msg_security)
507238106Sdes{
508238106Sdes	struct query_info rq;
509238106Sdes	struct reply_info* rep;
510238106Sdes	res->rcode = LDNS_RCODE_SERVFAIL;
511238106Sdes	rep = parse_reply(buf, temp, &rq);
512238106Sdes	if(!rep) {
513238106Sdes		log_err("cannot parse buf");
514238106Sdes		return; /* error parsing buf, or out of memory */
515238106Sdes	}
516238106Sdes	if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
517249141Sdes		reply_find_final_cname_target(&rq, rep), &rq, rep))
518238106Sdes		return; /* out of memory */
519238106Sdes	/* rcode, havedata, nxdomain, secure, bogus */
520238106Sdes	res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
521238106Sdes	if(res->data && res->data[0])
522238106Sdes		res->havedata = 1;
523238106Sdes	if(res->rcode == LDNS_RCODE_NXDOMAIN)
524238106Sdes		res->nxdomain = 1;
525238106Sdes	if(msg_security == sec_status_secure)
526238106Sdes		res->secure = 1;
527238106Sdes	if(msg_security == sec_status_bogus)
528238106Sdes		res->bogus = 1;
529238106Sdes}
530238106Sdes
531238106Sdes/** fillup fg results */
532238106Sdesstatic void
533269257Sdeslibworker_fillup_fg(struct ctx_query* q, int rcode, sldns_buffer* buf,
534238106Sdes	enum sec_status s, char* why_bogus)
535238106Sdes{
536238106Sdes	if(why_bogus)
537238106Sdes		q->res->why_bogus = strdup(why_bogus);
538238106Sdes	if(rcode != 0) {
539238106Sdes		q->res->rcode = rcode;
540238106Sdes		q->msg_security = s;
541238106Sdes		return;
542238106Sdes	}
543238106Sdes
544238106Sdes	q->res->rcode = LDNS_RCODE_SERVFAIL;
545238106Sdes	q->msg_security = 0;
546269257Sdes	q->msg = memdup(sldns_buffer_begin(buf), sldns_buffer_limit(buf));
547269257Sdes	q->msg_len = sldns_buffer_limit(buf);
548238106Sdes	if(!q->msg) {
549238106Sdes		return; /* the error is in the rcode */
550238106Sdes	}
551238106Sdes
552238106Sdes	/* canonname and results */
553238106Sdes	q->msg_security = s;
554238106Sdes	libworker_enter_result(q->res, buf, q->w->env->scratch, s);
555238106Sdes}
556238106Sdes
557238106Sdesvoid
558269257Sdeslibworker_fg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
559238106Sdes	char* why_bogus)
560238106Sdes{
561238106Sdes	struct ctx_query* q = (struct ctx_query*)arg;
562238106Sdes	/* fg query is done; exit comm base */
563238106Sdes	comm_base_exit(q->w->base);
564238106Sdes
565238106Sdes	libworker_fillup_fg(q, rcode, buf, s, why_bogus);
566238106Sdes}
567238106Sdes
568238106Sdes/** setup qinfo and edns */
569238106Sdesstatic int
570238106Sdessetup_qinfo_edns(struct libworker* w, struct ctx_query* q,
571238106Sdes	struct query_info* qinfo, struct edns_data* edns)
572238106Sdes{
573238106Sdes	qinfo->qtype = (uint16_t)q->res->qtype;
574238106Sdes	qinfo->qclass = (uint16_t)q->res->qclass;
575269257Sdes	qinfo->qname = sldns_str2wire_dname(q->res->qname, &qinfo->qname_len);
576269257Sdes	if(!qinfo->qname) {
577238106Sdes		return 0;
578238106Sdes	}
579238106Sdes	edns->edns_present = 1;
580238106Sdes	edns->ext_rcode = 0;
581238106Sdes	edns->edns_version = 0;
582238106Sdes	edns->bits = EDNS_DO;
583269257Sdes	if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
584269257Sdes		edns->udp_size = (uint16_t)sldns_buffer_capacity(
585238106Sdes			w->back->udp_buff);
586238106Sdes	else	edns->udp_size = 65535;
587238106Sdes	return 1;
588238106Sdes}
589238106Sdes
590238106Sdesint libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
591238106Sdes{
592269257Sdes	struct libworker* w = libworker_setup(ctx, 0, NULL);
593238106Sdes	uint16_t qflags, qid;
594238106Sdes	struct query_info qinfo;
595238106Sdes	struct edns_data edns;
596238106Sdes	if(!w)
597238106Sdes		return UB_INITFAIL;
598238106Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
599238106Sdes		libworker_delete(w);
600238106Sdes		return UB_SYNTAX;
601238106Sdes	}
602238106Sdes	qid = 0;
603238106Sdes	qflags = BIT_RD;
604238106Sdes	q->w = w;
605238106Sdes	/* see if there is a fixed answer */
606269257Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
607269257Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
608238106Sdes	if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
609285206Sdes		w->back->udp_buff, w->env->scratch, NULL)) {
610238106Sdes		regional_free_all(w->env->scratch);
611238106Sdes		libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
612238106Sdes			w->back->udp_buff, sec_status_insecure, NULL);
613238106Sdes		libworker_delete(w);
614238106Sdes		free(qinfo.qname);
615238106Sdes		return UB_NOERROR;
616238106Sdes	}
617238106Sdes	/* process new query */
618238106Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
619238106Sdes		w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
620238106Sdes		free(qinfo.qname);
621238106Sdes		return UB_NOMEM;
622238106Sdes	}
623238106Sdes	free(qinfo.qname);
624238106Sdes
625238106Sdes	/* wait for reply */
626238106Sdes	comm_base_dispatch(w->base);
627238106Sdes
628238106Sdes	libworker_delete(w);
629238106Sdes	return UB_NOERROR;
630238106Sdes}
631238106Sdes
632269257Sdesvoid
633269257Sdeslibworker_event_done_cb(void* arg, int rcode, sldns_buffer* buf,
634269257Sdes	enum sec_status s, char* why_bogus)
635269257Sdes{
636269257Sdes	struct ctx_query* q = (struct ctx_query*)arg;
637269257Sdes	ub_event_callback_t cb = (ub_event_callback_t)q->cb;
638269257Sdes	void* cb_arg = q->cb_arg;
639269257Sdes	int cancelled = q->cancelled;
640269257Sdes
641269257Sdes	/* delete it now */
642269257Sdes	struct ub_ctx* ctx = q->w->ctx;
643269257Sdes	lock_basic_lock(&ctx->cfglock);
644269257Sdes	(void)rbtree_delete(&ctx->queries, q->node.key);
645269257Sdes	ctx->num_async--;
646269257Sdes	context_query_delete(q);
647269257Sdes	lock_basic_unlock(&ctx->cfglock);
648269257Sdes
649269257Sdes	if(!cancelled) {
650269257Sdes		/* call callback */
651269257Sdes		int sec = 0;
652269257Sdes		if(s == sec_status_bogus)
653269257Sdes			sec = 1;
654269257Sdes		else if(s == sec_status_secure)
655269257Sdes			sec = 2;
656269257Sdes		(*cb)(cb_arg, rcode, (void*)sldns_buffer_begin(buf),
657269257Sdes			(int)sldns_buffer_limit(buf), sec, why_bogus);
658269257Sdes	}
659269257Sdes}
660269257Sdes
661269257Sdesint libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
662269257Sdes	int* async_id)
663269257Sdes{
664269257Sdes	struct libworker* w = ctx->event_worker;
665269257Sdes	uint16_t qflags, qid;
666269257Sdes	struct query_info qinfo;
667269257Sdes	struct edns_data edns;
668269257Sdes	if(!w)
669269257Sdes		return UB_INITFAIL;
670269257Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns))
671269257Sdes		return UB_SYNTAX;
672269257Sdes	qid = 0;
673269257Sdes	qflags = BIT_RD;
674269257Sdes	q->w = w;
675269257Sdes	/* see if there is a fixed answer */
676269257Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
677269257Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
678269257Sdes	if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
679285206Sdes		w->back->udp_buff, w->env->scratch, NULL)) {
680269257Sdes		regional_free_all(w->env->scratch);
681269257Sdes		free(qinfo.qname);
682269257Sdes		libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
683269257Sdes			w->back->udp_buff, sec_status_insecure, NULL);
684269257Sdes		return UB_NOERROR;
685269257Sdes	}
686269257Sdes	/* process new query */
687269257Sdes	if(async_id)
688269257Sdes		*async_id = q->querynum;
689269257Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
690269257Sdes		w->back->udp_buff, qid, libworker_event_done_cb, q)) {
691269257Sdes		free(qinfo.qname);
692269257Sdes		return UB_NOMEM;
693269257Sdes	}
694269257Sdes	free(qinfo.qname);
695269257Sdes	return UB_NOERROR;
696269257Sdes}
697269257Sdes
698238106Sdes/** add result to the bg worker result queue */
699238106Sdesstatic void
700269257Sdesadd_bg_result(struct libworker* w, struct ctx_query* q, sldns_buffer* pkt,
701238106Sdes	int err, char* reason)
702238106Sdes{
703238106Sdes	uint8_t* msg = NULL;
704238106Sdes	uint32_t len = 0;
705238106Sdes
706238106Sdes	/* serialize and delete unneeded q */
707238106Sdes	if(w->is_bg_thread) {
708238106Sdes		lock_basic_lock(&w->ctx->cfglock);
709238106Sdes		if(reason)
710238106Sdes			q->res->why_bogus = strdup(reason);
711238106Sdes		if(pkt) {
712269257Sdes			q->msg_len = sldns_buffer_remaining(pkt);
713269257Sdes			q->msg = memdup(sldns_buffer_begin(pkt), q->msg_len);
714238106Sdes			if(!q->msg)
715238106Sdes				msg = context_serialize_answer(q, UB_NOMEM,
716238106Sdes				NULL, &len);
717238106Sdes			else	msg = context_serialize_answer(q, err,
718238106Sdes				NULL, &len);
719238106Sdes		} else msg = context_serialize_answer(q, err, NULL, &len);
720238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
721238106Sdes	} else {
722238106Sdes		if(reason)
723238106Sdes			q->res->why_bogus = strdup(reason);
724238106Sdes		msg = context_serialize_answer(q, err, pkt, &len);
725238106Sdes		(void)rbtree_delete(&w->ctx->queries, q->node.key);
726238106Sdes		w->ctx->num_async--;
727238106Sdes		context_query_delete(q);
728238106Sdes	}
729238106Sdes
730238106Sdes	if(!msg) {
731238106Sdes		log_err("out of memory for async answer");
732238106Sdes		return;
733238106Sdes	}
734238106Sdes	if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
735238106Sdes		log_err("out of memory for async answer");
736238106Sdes		return;
737238106Sdes	}
738238106Sdes}
739238106Sdes
740238106Sdesvoid
741269257Sdeslibworker_bg_done_cb(void* arg, int rcode, sldns_buffer* buf, enum sec_status s,
742238106Sdes	char* why_bogus)
743238106Sdes{
744238106Sdes	struct ctx_query* q = (struct ctx_query*)arg;
745238106Sdes
746238106Sdes	if(q->cancelled) {
747238106Sdes		if(q->w->is_bg_thread) {
748238106Sdes			/* delete it now */
749238106Sdes			struct ub_ctx* ctx = q->w->ctx;
750238106Sdes			lock_basic_lock(&ctx->cfglock);
751238106Sdes			(void)rbtree_delete(&ctx->queries, q->node.key);
752238106Sdes			ctx->num_async--;
753238106Sdes			context_query_delete(q);
754238106Sdes			lock_basic_unlock(&ctx->cfglock);
755238106Sdes		}
756238106Sdes		/* cancelled, do not give answer */
757238106Sdes		return;
758238106Sdes	}
759238106Sdes	q->msg_security = s;
760249141Sdes	if(!buf)
761249141Sdes		buf = q->w->env->scratch_buffer;
762238106Sdes	if(rcode != 0) {
763238106Sdes		error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
764238106Sdes	}
765238106Sdes	add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus);
766238106Sdes}
767238106Sdes
768238106Sdes
769238106Sdes/** handle new query command for bg worker */
770238106Sdesstatic void
771238106Sdeshandle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
772238106Sdes{
773238106Sdes	uint16_t qflags, qid;
774238106Sdes	struct query_info qinfo;
775238106Sdes	struct edns_data edns;
776238106Sdes	struct ctx_query* q;
777238106Sdes	if(w->is_bg_thread) {
778238106Sdes		lock_basic_lock(&w->ctx->cfglock);
779238106Sdes		q = context_lookup_new_query(w->ctx, buf, len);
780238106Sdes		lock_basic_unlock(&w->ctx->cfglock);
781238106Sdes	} else {
782238106Sdes		q = context_deserialize_new_query(w->ctx, buf, len);
783238106Sdes	}
784238106Sdes	free(buf);
785238106Sdes	if(!q) {
786238106Sdes		log_err("failed to deserialize newq");
787238106Sdes		return;
788238106Sdes	}
789238106Sdes	if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
790238106Sdes		add_bg_result(w, q, NULL, UB_SYNTAX, NULL);
791238106Sdes		return;
792238106Sdes	}
793238106Sdes	qid = 0;
794238106Sdes	qflags = BIT_RD;
795238106Sdes	/* see if there is a fixed answer */
796269257Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
797269257Sdes	sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
798238106Sdes	if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns,
799285206Sdes		w->back->udp_buff, w->env->scratch, NULL)) {
800238106Sdes		regional_free_all(w->env->scratch);
801238106Sdes		q->msg_security = sec_status_insecure;
802238106Sdes		add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
803238106Sdes		free(qinfo.qname);
804238106Sdes		return;
805238106Sdes	}
806238106Sdes	q->w = w;
807238106Sdes	/* process new query */
808238106Sdes	if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
809238106Sdes		w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
810238106Sdes		add_bg_result(w, q, NULL, UB_NOMEM, NULL);
811238106Sdes	}
812238106Sdes	free(qinfo.qname);
813238106Sdes}
814238106Sdes
815238106Sdesvoid libworker_alloc_cleanup(void* arg)
816238106Sdes{
817238106Sdes	struct libworker* w = (struct libworker*)arg;
818238106Sdes	slabhash_clear(&w->env->rrset_cache->table);
819238106Sdes        slabhash_clear(w->env->msg_cache);
820238106Sdes}
821238106Sdes
822238106Sdesstruct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
823238106Sdes        uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
824285206Sdes	int want_dnssec, int nocaps, struct sockaddr_storage* addr,
825285206Sdes	socklen_t addrlen, uint8_t* zone, size_t zonelen,
826285206Sdes	struct module_qstate* q)
827238106Sdes{
828238106Sdes	struct libworker* w = (struct libworker*)q->env->worker;
829238106Sdes	struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
830238106Sdes		q->region, sizeof(*e));
831238106Sdes	if(!e)
832238106Sdes		return NULL;
833238106Sdes	e->qstate = q;
834238106Sdes	e->qsent = outnet_serviced_query(w->back, qname,
835285206Sdes		qnamelen, qtype, qclass, flags, dnssec, want_dnssec, nocaps,
836238106Sdes		q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
837238106Sdes		addrlen, zone, zonelen, libworker_handle_service_reply, e,
838249141Sdes		w->back->udp_buff);
839238106Sdes	if(!e->qsent) {
840238106Sdes		return NULL;
841238106Sdes	}
842238106Sdes	return e;
843238106Sdes}
844238106Sdes
845238106Sdesint
846238106Sdeslibworker_handle_reply(struct comm_point* c, void* arg, int error,
847238106Sdes        struct comm_reply* reply_info)
848238106Sdes{
849238106Sdes	struct module_qstate* q = (struct module_qstate*)arg;
850238106Sdes	struct libworker* lw = (struct libworker*)q->env->worker;
851238106Sdes	struct outbound_entry e;
852238106Sdes	e.qstate = q;
853238106Sdes	e.qsent = NULL;
854238106Sdes
855238106Sdes	if(error != 0) {
856238106Sdes		mesh_report_reply(lw->env->mesh, &e, reply_info, error);
857238106Sdes		return 0;
858238106Sdes	}
859238106Sdes	/* sanity check. */
860269257Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
861269257Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
862238106Sdes			LDNS_PACKET_QUERY
863269257Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
864238106Sdes		/* error becomes timeout for the module as if this reply
865238106Sdes		 * never arrived. */
866238106Sdes		mesh_report_reply(lw->env->mesh, &e, reply_info,
867238106Sdes			NETEVENT_TIMEOUT);
868238106Sdes		return 0;
869238106Sdes	}
870238106Sdes	mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
871238106Sdes	return 0;
872238106Sdes}
873238106Sdes
874238106Sdesint
875238106Sdeslibworker_handle_service_reply(struct comm_point* c, void* arg, int error,
876238106Sdes        struct comm_reply* reply_info)
877238106Sdes{
878238106Sdes	struct outbound_entry* e = (struct outbound_entry*)arg;
879238106Sdes	struct libworker* lw = (struct libworker*)e->qstate->env->worker;
880238106Sdes
881238106Sdes	if(error != 0) {
882238106Sdes		mesh_report_reply(lw->env->mesh, e, reply_info, error);
883238106Sdes		return 0;
884238106Sdes	}
885238106Sdes	/* sanity check. */
886269257Sdes	if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
887269257Sdes		|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
888238106Sdes			LDNS_PACKET_QUERY
889269257Sdes		|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
890238106Sdes		/* error becomes timeout for the module as if this reply
891238106Sdes		 * never arrived. */
892238106Sdes		mesh_report_reply(lw->env->mesh, e, reply_info,
893238106Sdes			NETEVENT_TIMEOUT);
894238106Sdes		return 0;
895238106Sdes	}
896238106Sdes	mesh_report_reply(lw->env->mesh,  e, reply_info, NETEVENT_NOERROR);
897238106Sdes	return 0;
898238106Sdes}
899238106Sdes
900238106Sdes/* --- fake callbacks for fptr_wlist to work --- */
901238106Sdesvoid worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
902238106Sdes	uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
903238106Sdes	int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
904238106Sdes{
905238106Sdes	log_assert(0);
906238106Sdes}
907238106Sdes
908238106Sdesint worker_handle_request(struct comm_point* ATTR_UNUSED(c),
909238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
910238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
911238106Sdes{
912238106Sdes	log_assert(0);
913238106Sdes	return 0;
914238106Sdes}
915238106Sdes
916238106Sdesint worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
917238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
918238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
919238106Sdes{
920238106Sdes	log_assert(0);
921238106Sdes	return 0;
922238106Sdes}
923238106Sdes
924238106Sdesint worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
925238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
926238106Sdes        struct comm_reply* ATTR_UNUSED(reply_info))
927238106Sdes{
928238106Sdes	log_assert(0);
929238106Sdes	return 0;
930238106Sdes}
931238106Sdes
932238106Sdesint remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
933238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
934238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
935238106Sdes{
936238106Sdes	log_assert(0);
937238106Sdes	return 0;
938238106Sdes}
939238106Sdes
940238106Sdesint remote_control_callback(struct comm_point* ATTR_UNUSED(c),
941238106Sdes	void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
942238106Sdes        struct comm_reply* ATTR_UNUSED(repinfo))
943238106Sdes{
944238106Sdes	log_assert(0);
945238106Sdes	return 0;
946238106Sdes}
947238106Sdes
948238106Sdesvoid worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
949238106Sdes{
950238106Sdes	log_assert(0);
951238106Sdes}
952238106Sdes
953238106Sdesstruct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
954238106Sdes	size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
955238106Sdes	uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
956238106Sdes	int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
957285206Sdes	int ATTR_UNUSED(nocaps), struct sockaddr_storage* ATTR_UNUSED(addr),
958255579Sdes	socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
959255579Sdes	size_t ATTR_UNUSED(zonelen), struct module_qstate* ATTR_UNUSED(q))
960238106Sdes{
961238106Sdes	log_assert(0);
962238106Sdes	return 0;
963238106Sdes}
964238106Sdes
965238106Sdesvoid
966238106Sdesworker_alloc_cleanup(void* ATTR_UNUSED(arg))
967238106Sdes{
968238106Sdes	log_assert(0);
969238106Sdes}
970238106Sdes
971238106Sdesvoid worker_stat_timer_cb(void* ATTR_UNUSED(arg))
972238106Sdes{
973238106Sdes	log_assert(0);
974238106Sdes}
975238106Sdes
976238106Sdesvoid worker_probe_timer_cb(void* ATTR_UNUSED(arg))
977238106Sdes{
978238106Sdes	log_assert(0);
979238106Sdes}
980238106Sdes
981238106Sdesvoid worker_start_accept(void* ATTR_UNUSED(arg))
982238106Sdes{
983238106Sdes	log_assert(0);
984238106Sdes}
985238106Sdes
986238106Sdesvoid worker_stop_accept(void* ATTR_UNUSED(arg))
987238106Sdes{
988238106Sdes	log_assert(0);
989238106Sdes}
990238106Sdes
991238106Sdesint order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
992238106Sdes{
993238106Sdes	log_assert(0);
994238106Sdes	return 0;
995238106Sdes}
996238106Sdes
997238106Sdesint
998238106Sdescodeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
999238106Sdes{
1000238106Sdes	log_assert(0);
1001238106Sdes	return 0;
1002238106Sdes}
1003238106Sdes
1004238106Sdesint replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
1005238106Sdes{
1006238106Sdes        log_assert(0);
1007238106Sdes        return 0;
1008238106Sdes}
1009238106Sdes
1010238106Sdesvoid remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
1011238106Sdes{
1012238106Sdes        log_assert(0);
1013238106Sdes}
1014238106Sdes
1015238106Sdes#ifdef UB_ON_WINDOWS
1016238106Sdesvoid
1017238106Sdesworker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
1018238106Sdes        ATTR_UNUSED(arg)) {
1019238106Sdes        log_assert(0);
1020238106Sdes}
1021238106Sdes
1022238106Sdesvoid
1023238106Sdeswsvc_cron_cb(void* ATTR_UNUSED(arg))
1024238106Sdes{
1025238106Sdes        log_assert(0);
1026238106Sdes}
1027238106Sdes#endif /* UB_ON_WINDOWS */
1028