libunbound.c revision 291767
1/*
2 * unbound.c - unbound validating resolver public API implementation
3 *
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
5 *
6 * This software is open source.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * Neither the name of the NLNET LABS nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36/**
37 * \file
38 *
39 * This file contains functions to resolve DNS queries and
40 * validate the answers. Synchonously and asynchronously.
41 *
42 */
43
44/* include the public api first, it should be able to stand alone */
45#include "libunbound/unbound.h"
46#include "libunbound/unbound-event.h"
47#include "config.h"
48#include <ctype.h>
49#include "libunbound/context.h"
50#include "libunbound/libworker.h"
51#include "util/locks.h"
52#include "util/config_file.h"
53#include "util/alloc.h"
54#include "util/module.h"
55#include "util/regional.h"
56#include "util/log.h"
57#include "util/random.h"
58#include "util/net_help.h"
59#include "util/tube.h"
60#include "services/modstack.h"
61#include "services/localzone.h"
62#include "services/cache/infra.h"
63#include "services/cache/rrset.h"
64#include "sldns/sbuffer.h"
65#ifdef HAVE_PTHREAD
66#include <signal.h>
67#endif
68#ifdef HAVE_SYS_WAIT_H
69#include <sys/wait.h>
70#endif
71
72#if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H)
73#include <windows.h>
74#include <iphlpapi.h>
75#endif /* UB_ON_WINDOWS */
76
77/** create context functionality, but no pipes */
78static struct ub_ctx* ub_ctx_create_nopipe(void)
79{
80	struct ub_ctx* ctx;
81	unsigned int seed;
82#ifdef USE_WINSOCK
83	int r;
84	WSADATA wsa_data;
85#endif
86
87	log_init(NULL, 0, NULL); /* logs to stderr */
88	log_ident_set("libunbound");
89#ifdef USE_WINSOCK
90	if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
91		log_err("could not init winsock. WSAStartup: %s",
92			wsa_strerror(r));
93		return NULL;
94	}
95#endif
96	verbosity = 0; /* errors only */
97	checklock_start();
98	ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx));
99	if(!ctx) {
100		errno = ENOMEM;
101		return NULL;
102	}
103	alloc_init(&ctx->superalloc, NULL, 0);
104	seed = (unsigned int)time(NULL) ^ (unsigned int)getpid();
105	if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) {
106		seed = 0;
107		ub_randfree(ctx->seed_rnd);
108		free(ctx);
109		errno = ENOMEM;
110		return NULL;
111	}
112	seed = 0;
113	lock_basic_init(&ctx->qqpipe_lock);
114	lock_basic_init(&ctx->rrpipe_lock);
115	lock_basic_init(&ctx->cfglock);
116	ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
117	if(!ctx->env) {
118		ub_randfree(ctx->seed_rnd);
119		free(ctx);
120		errno = ENOMEM;
121		return NULL;
122	}
123	ctx->env->cfg = config_create_forlib();
124	if(!ctx->env->cfg) {
125		free(ctx->env);
126		ub_randfree(ctx->seed_rnd);
127		free(ctx);
128		errno = ENOMEM;
129		return NULL;
130	}
131	ctx->env->alloc = &ctx->superalloc;
132	ctx->env->worker = NULL;
133	ctx->env->need_to_validate = 0;
134	modstack_init(&ctx->mods);
135	rbtree_init(&ctx->queries, &context_query_cmp);
136	return ctx;
137}
138
139struct ub_ctx*
140ub_ctx_create(void)
141{
142	struct ub_ctx* ctx = ub_ctx_create_nopipe();
143	if(!ctx)
144		return NULL;
145	if((ctx->qq_pipe = tube_create()) == NULL) {
146		int e = errno;
147		ub_randfree(ctx->seed_rnd);
148		config_delete(ctx->env->cfg);
149		modstack_desetup(&ctx->mods, ctx->env);
150		free(ctx->env);
151		free(ctx);
152		errno = e;
153		return NULL;
154	}
155	if((ctx->rr_pipe = tube_create()) == NULL) {
156		int e = errno;
157		tube_delete(ctx->qq_pipe);
158		ub_randfree(ctx->seed_rnd);
159		config_delete(ctx->env->cfg);
160		modstack_desetup(&ctx->mods, ctx->env);
161		free(ctx->env);
162		free(ctx);
163		errno = e;
164		return NULL;
165	}
166	return ctx;
167}
168
169struct ub_ctx*
170ub_ctx_create_event(struct event_base* eb)
171{
172	struct ub_ctx* ctx = ub_ctx_create_nopipe();
173	if(!ctx)
174		return NULL;
175	/* no pipes, but we have the locks to make sure everything works */
176	ctx->created_bg = 0;
177	ctx->dothread = 1; /* the processing is in the same process,
178		makes ub_cancel and ub_ctx_delete do the right thing */
179	ctx->event_base = eb;
180	return ctx;
181}
182
183/** delete q */
184static void
185delq(rbnode_t* n, void* ATTR_UNUSED(arg))
186{
187	struct ctx_query* q = (struct ctx_query*)n;
188	context_query_delete(q);
189}
190
191/** stop the bg thread */
192static void ub_stop_bg(struct ub_ctx* ctx)
193{
194	/* stop the bg thread */
195	lock_basic_lock(&ctx->cfglock);
196	if(ctx->created_bg) {
197		uint8_t* msg;
198		uint32_t len;
199		uint32_t cmd = UB_LIBCMD_QUIT;
200		lock_basic_unlock(&ctx->cfglock);
201		lock_basic_lock(&ctx->qqpipe_lock);
202		(void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd,
203			(uint32_t)sizeof(cmd), 0);
204		lock_basic_unlock(&ctx->qqpipe_lock);
205		lock_basic_lock(&ctx->rrpipe_lock);
206		while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) {
207			/* discard all results except a quit confirm */
208			if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) {
209				free(msg);
210				break;
211			}
212			free(msg);
213		}
214		lock_basic_unlock(&ctx->rrpipe_lock);
215
216		/* if bg worker is a thread, wait for it to exit, so that all
217	 	 * resources are really gone. */
218		lock_basic_lock(&ctx->cfglock);
219		if(ctx->dothread) {
220			lock_basic_unlock(&ctx->cfglock);
221			ub_thread_join(ctx->bg_tid);
222		} else {
223			lock_basic_unlock(&ctx->cfglock);
224#ifndef UB_ON_WINDOWS
225			if(waitpid(ctx->bg_pid, NULL, 0) == -1) {
226				if(verbosity > 2)
227					log_err("waitpid: %s", strerror(errno));
228			}
229#endif
230		}
231	}
232	else {
233		lock_basic_unlock(&ctx->cfglock);
234	}
235}
236
237void
238ub_ctx_delete(struct ub_ctx* ctx)
239{
240	struct alloc_cache* a, *na;
241	int do_stop = 1;
242	if(!ctx) return;
243
244	/* see if bg thread is created and if threads have been killed */
245	/* no locks, because those may be held by terminated threads */
246	/* for processes the read pipe is closed and we see that on read */
247#ifdef HAVE_PTHREAD
248	if(ctx->created_bg && ctx->dothread) {
249		if(pthread_kill(ctx->bg_tid, 0) == ESRCH) {
250			/* thread has been killed */
251			do_stop = 0;
252		}
253	}
254#endif /* HAVE_PTHREAD */
255	if(do_stop)
256		ub_stop_bg(ctx);
257	libworker_delete_event(ctx->event_worker);
258
259	modstack_desetup(&ctx->mods, ctx->env);
260	a = ctx->alloc_list;
261	while(a) {
262		na = a->super;
263		a->super = &ctx->superalloc;
264		alloc_clear(a);
265		free(a);
266		a = na;
267	}
268	local_zones_delete(ctx->local_zones);
269	lock_basic_destroy(&ctx->qqpipe_lock);
270	lock_basic_destroy(&ctx->rrpipe_lock);
271	lock_basic_destroy(&ctx->cfglock);
272	tube_delete(ctx->qq_pipe);
273	tube_delete(ctx->rr_pipe);
274	if(ctx->env) {
275		slabhash_delete(ctx->env->msg_cache);
276		rrset_cache_delete(ctx->env->rrset_cache);
277		infra_delete(ctx->env->infra_cache);
278		config_delete(ctx->env->cfg);
279		free(ctx->env);
280	}
281	ub_randfree(ctx->seed_rnd);
282	alloc_clear(&ctx->superalloc);
283	traverse_postorder(&ctx->queries, delq, NULL);
284	free(ctx);
285#ifdef USE_WINSOCK
286	WSACleanup();
287#endif
288}
289
290int
291ub_ctx_set_option(struct ub_ctx* ctx, const char* opt, const char* val)
292{
293	lock_basic_lock(&ctx->cfglock);
294	if(ctx->finalized) {
295		lock_basic_unlock(&ctx->cfglock);
296		return UB_AFTERFINAL;
297	}
298	if(!config_set_option(ctx->env->cfg, opt, val)) {
299		lock_basic_unlock(&ctx->cfglock);
300		return UB_SYNTAX;
301	}
302	lock_basic_unlock(&ctx->cfglock);
303	return UB_NOERROR;
304}
305
306int
307ub_ctx_get_option(struct ub_ctx* ctx, const char* opt, char** str)
308{
309	int r;
310	lock_basic_lock(&ctx->cfglock);
311	r = config_get_option_collate(ctx->env->cfg, opt, str);
312	lock_basic_unlock(&ctx->cfglock);
313	if(r == 0) r = UB_NOERROR;
314	else if(r == 1) r = UB_SYNTAX;
315	else if(r == 2) r = UB_NOMEM;
316	return r;
317}
318
319int
320ub_ctx_config(struct ub_ctx* ctx, const char* fname)
321{
322	lock_basic_lock(&ctx->cfglock);
323	if(ctx->finalized) {
324		lock_basic_unlock(&ctx->cfglock);
325		return UB_AFTERFINAL;
326	}
327	if(!config_read(ctx->env->cfg, fname, NULL)) {
328		lock_basic_unlock(&ctx->cfglock);
329		return UB_SYNTAX;
330	}
331	lock_basic_unlock(&ctx->cfglock);
332	return UB_NOERROR;
333}
334
335int
336ub_ctx_add_ta(struct ub_ctx* ctx, const char* ta)
337{
338	char* dup = strdup(ta);
339	if(!dup) return UB_NOMEM;
340	lock_basic_lock(&ctx->cfglock);
341	if(ctx->finalized) {
342		lock_basic_unlock(&ctx->cfglock);
343		free(dup);
344		return UB_AFTERFINAL;
345	}
346	if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
347		lock_basic_unlock(&ctx->cfglock);
348		free(dup);
349		return UB_NOMEM;
350	}
351	lock_basic_unlock(&ctx->cfglock);
352	return UB_NOERROR;
353}
354
355int
356ub_ctx_add_ta_file(struct ub_ctx* ctx, const char* fname)
357{
358	char* dup = strdup(fname);
359	if(!dup) return UB_NOMEM;
360	lock_basic_lock(&ctx->cfglock);
361	if(ctx->finalized) {
362		lock_basic_unlock(&ctx->cfglock);
363		free(dup);
364		return UB_AFTERFINAL;
365	}
366	if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) {
367		lock_basic_unlock(&ctx->cfglock);
368		free(dup);
369		return UB_NOMEM;
370	}
371	lock_basic_unlock(&ctx->cfglock);
372	return UB_NOERROR;
373}
374
375int ub_ctx_add_ta_autr(struct ub_ctx* ctx, const char* fname)
376{
377	char* dup = strdup(fname);
378	if(!dup) return UB_NOMEM;
379	lock_basic_lock(&ctx->cfglock);
380	if(ctx->finalized) {
381		lock_basic_unlock(&ctx->cfglock);
382		free(dup);
383		return UB_AFTERFINAL;
384	}
385	if(!cfg_strlist_insert(&ctx->env->cfg->auto_trust_anchor_file_list,
386		dup)) {
387		lock_basic_unlock(&ctx->cfglock);
388		free(dup);
389		return UB_NOMEM;
390	}
391	lock_basic_unlock(&ctx->cfglock);
392	return UB_NOERROR;
393}
394
395int
396ub_ctx_trustedkeys(struct ub_ctx* ctx, const char* fname)
397{
398	char* dup = strdup(fname);
399	if(!dup) return UB_NOMEM;
400	lock_basic_lock(&ctx->cfglock);
401	if(ctx->finalized) {
402		lock_basic_unlock(&ctx->cfglock);
403		free(dup);
404		return UB_AFTERFINAL;
405	}
406	if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
407		lock_basic_unlock(&ctx->cfglock);
408		free(dup);
409		return UB_NOMEM;
410	}
411	lock_basic_unlock(&ctx->cfglock);
412	return UB_NOERROR;
413}
414
415int
416ub_ctx_debuglevel(struct ub_ctx* ctx, int d)
417{
418	lock_basic_lock(&ctx->cfglock);
419	verbosity = d;
420	ctx->env->cfg->verbosity = d;
421	lock_basic_unlock(&ctx->cfglock);
422	return UB_NOERROR;
423}
424
425int ub_ctx_debugout(struct ub_ctx* ctx, void* out)
426{
427	lock_basic_lock(&ctx->cfglock);
428	log_file((FILE*)out);
429	ctx->logfile_override = 1;
430	ctx->log_out = out;
431	lock_basic_unlock(&ctx->cfglock);
432	return UB_NOERROR;
433}
434
435int
436ub_ctx_async(struct ub_ctx* ctx, int dothread)
437{
438#ifdef THREADS_DISABLED
439	if(dothread) /* cannot do threading */
440		return UB_NOERROR;
441#endif
442	lock_basic_lock(&ctx->cfglock);
443	if(ctx->finalized) {
444		lock_basic_unlock(&ctx->cfglock);
445		return UB_AFTERFINAL;
446	}
447	ctx->dothread = dothread;
448	lock_basic_unlock(&ctx->cfglock);
449	return UB_NOERROR;
450}
451
452int
453ub_poll(struct ub_ctx* ctx)
454{
455	/* no need to hold lock while testing for readability. */
456	return tube_poll(ctx->rr_pipe);
457}
458
459int
460ub_fd(struct ub_ctx* ctx)
461{
462	return tube_read_fd(ctx->rr_pipe);
463}
464
465/** process answer from bg worker */
466static int
467process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
468	ub_callback_t* cb, void** cbarg, int* err,
469	struct ub_result** res)
470{
471	struct ctx_query* q;
472	if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
473		log_err("error: bad data from bg worker %d",
474			(int)context_serial_getcmd(msg, len));
475		return 0;
476	}
477
478	lock_basic_lock(&ctx->cfglock);
479	q = context_deserialize_answer(ctx, msg, len, err);
480	if(!q) {
481		lock_basic_unlock(&ctx->cfglock);
482		/* probably simply the lookup that failed, i.e.
483		 * response returned before cancel was sent out, so noerror */
484		return 1;
485	}
486	log_assert(q->async);
487
488	/* grab cb while locked */
489	if(q->cancelled) {
490		*cb = NULL;
491		*cbarg = NULL;
492	} else {
493		*cb = q->cb;
494		*cbarg = q->cb_arg;
495	}
496	if(*err) {
497		*res = NULL;
498		ub_resolve_free(q->res);
499	} else {
500		/* parse the message, extract rcode, fill result */
501		sldns_buffer* buf = sldns_buffer_new(q->msg_len);
502		struct regional* region = regional_create();
503		*res = q->res;
504		(*res)->rcode = LDNS_RCODE_SERVFAIL;
505		if(region && buf) {
506			sldns_buffer_clear(buf);
507			sldns_buffer_write(buf, q->msg, q->msg_len);
508			sldns_buffer_flip(buf);
509			libworker_enter_result(*res, buf, region,
510				q->msg_security);
511		}
512		(*res)->answer_packet = q->msg;
513		(*res)->answer_len = (int)q->msg_len;
514		q->msg = NULL;
515		sldns_buffer_free(buf);
516		regional_destroy(region);
517	}
518	q->res = NULL;
519	/* delete the q from list */
520	(void)rbtree_delete(&ctx->queries, q->node.key);
521	ctx->num_async--;
522	context_query_delete(q);
523	lock_basic_unlock(&ctx->cfglock);
524
525	if(*cb) return 2;
526	ub_resolve_free(*res);
527	return 1;
528}
529
530/** process answer from bg worker */
531static int
532process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len)
533{
534	int err;
535	ub_callback_t cb;
536	void* cbarg;
537	struct ub_result* res;
538	int r;
539
540	r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res);
541
542	/* no locks held while calling callback, so that library is
543	 * re-entrant. */
544	if(r == 2)
545		(*cb)(cbarg, err, res);
546
547	return r;
548}
549
550int
551ub_process(struct ub_ctx* ctx)
552{
553	int r;
554	uint8_t* msg;
555	uint32_t len;
556	while(1) {
557		msg = NULL;
558		lock_basic_lock(&ctx->rrpipe_lock);
559		r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
560		lock_basic_unlock(&ctx->rrpipe_lock);
561		if(r == 0)
562			return UB_PIPE;
563		else if(r == -1)
564			break;
565		if(!process_answer(ctx, msg, len)) {
566			free(msg);
567			return UB_PIPE;
568		}
569		free(msg);
570	}
571	return UB_NOERROR;
572}
573
574int
575ub_wait(struct ub_ctx* ctx)
576{
577	int err;
578	ub_callback_t cb;
579	void* cbarg;
580	struct ub_result* res;
581	int r;
582	uint8_t* msg;
583	uint32_t len;
584	/* this is basically the same loop as _process(), but with changes.
585	 * holds the rrpipe lock and waits with tube_wait */
586	while(1) {
587		lock_basic_lock(&ctx->rrpipe_lock);
588		lock_basic_lock(&ctx->cfglock);
589		if(ctx->num_async == 0) {
590			lock_basic_unlock(&ctx->cfglock);
591			lock_basic_unlock(&ctx->rrpipe_lock);
592			break;
593		}
594		lock_basic_unlock(&ctx->cfglock);
595
596		/* keep rrpipe locked, while
597		 * 	o waiting for pipe readable
598		 * 	o parsing message
599		 * 	o possibly decrementing num_async
600		 * do callback without lock
601		 */
602		r = tube_wait(ctx->rr_pipe);
603		if(r) {
604			r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
605			if(r == 0) {
606				lock_basic_unlock(&ctx->rrpipe_lock);
607				return UB_PIPE;
608			}
609			if(r == -1) {
610				lock_basic_unlock(&ctx->rrpipe_lock);
611				continue;
612			}
613			r = process_answer_detail(ctx, msg, len,
614				&cb, &cbarg, &err, &res);
615			lock_basic_unlock(&ctx->rrpipe_lock);
616			free(msg);
617			if(r == 0)
618				return UB_PIPE;
619			if(r == 2)
620				(*cb)(cbarg, err, res);
621		} else {
622			lock_basic_unlock(&ctx->rrpipe_lock);
623		}
624	}
625	return UB_NOERROR;
626}
627
628int
629ub_resolve(struct ub_ctx* ctx, const char* name, int rrtype,
630	int rrclass, struct ub_result** result)
631{
632	struct ctx_query* q;
633	int r;
634	*result = NULL;
635
636	lock_basic_lock(&ctx->cfglock);
637	if(!ctx->finalized) {
638		r = context_finalize(ctx);
639		if(r) {
640			lock_basic_unlock(&ctx->cfglock);
641			return r;
642		}
643	}
644	/* create new ctx_query and attempt to add to the list */
645	lock_basic_unlock(&ctx->cfglock);
646	q = context_new(ctx, name, rrtype, rrclass, NULL, NULL);
647	if(!q)
648		return UB_NOMEM;
649	/* become a resolver thread for a bit */
650
651	r = libworker_fg(ctx, q);
652	if(r) {
653		lock_basic_lock(&ctx->cfglock);
654		(void)rbtree_delete(&ctx->queries, q->node.key);
655		context_query_delete(q);
656		lock_basic_unlock(&ctx->cfglock);
657		return r;
658	}
659	q->res->answer_packet = q->msg;
660	q->res->answer_len = (int)q->msg_len;
661	q->msg = NULL;
662	*result = q->res;
663	q->res = NULL;
664
665	lock_basic_lock(&ctx->cfglock);
666	(void)rbtree_delete(&ctx->queries, q->node.key);
667	context_query_delete(q);
668	lock_basic_unlock(&ctx->cfglock);
669	return UB_NOERROR;
670}
671
672int
673ub_resolve_event(struct ub_ctx* ctx, const char* name, int rrtype,
674	int rrclass, void* mydata, ub_event_callback_t callback, int* async_id)
675{
676	struct ctx_query* q;
677	int r;
678
679	if(async_id)
680		*async_id = 0;
681	lock_basic_lock(&ctx->cfglock);
682	if(!ctx->finalized) {
683		int r = context_finalize(ctx);
684		if(r) {
685			lock_basic_unlock(&ctx->cfglock);
686			return r;
687		}
688	}
689	lock_basic_unlock(&ctx->cfglock);
690	if(!ctx->event_worker) {
691		ctx->event_worker = libworker_create_event(ctx,
692			ctx->event_base);
693		if(!ctx->event_worker) {
694			return UB_INITFAIL;
695		}
696	}
697
698	/* create new ctx_query and attempt to add to the list */
699	q = context_new(ctx, name, rrtype, rrclass, (ub_callback_t)callback,
700		mydata);
701	if(!q)
702		return UB_NOMEM;
703
704	/* attach to mesh */
705	if((r=libworker_attach_mesh(ctx, q, async_id)) != 0)
706		return r;
707	return UB_NOERROR;
708}
709
710
711int
712ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
713	int rrclass, void* mydata, ub_callback_t callback, int* async_id)
714{
715	struct ctx_query* q;
716	uint8_t* msg = NULL;
717	uint32_t len = 0;
718
719	if(async_id)
720		*async_id = 0;
721	lock_basic_lock(&ctx->cfglock);
722	if(!ctx->finalized) {
723		int r = context_finalize(ctx);
724		if(r) {
725			lock_basic_unlock(&ctx->cfglock);
726			return r;
727		}
728	}
729	if(!ctx->created_bg) {
730		int r;
731		ctx->created_bg = 1;
732		lock_basic_unlock(&ctx->cfglock);
733		r = libworker_bg(ctx);
734		if(r) {
735			lock_basic_lock(&ctx->cfglock);
736			ctx->created_bg = 0;
737			lock_basic_unlock(&ctx->cfglock);
738			return r;
739		}
740	} else {
741		lock_basic_unlock(&ctx->cfglock);
742	}
743
744	/* create new ctx_query and attempt to add to the list */
745	q = context_new(ctx, name, rrtype, rrclass, callback, mydata);
746	if(!q)
747		return UB_NOMEM;
748
749	/* write over pipe to background worker */
750	lock_basic_lock(&ctx->cfglock);
751	msg = context_serialize_new_query(q, &len);
752	if(!msg) {
753		(void)rbtree_delete(&ctx->queries, q->node.key);
754		ctx->num_async--;
755		context_query_delete(q);
756		lock_basic_unlock(&ctx->cfglock);
757		return UB_NOMEM;
758	}
759	if(async_id)
760		*async_id = q->querynum;
761	lock_basic_unlock(&ctx->cfglock);
762
763	lock_basic_lock(&ctx->qqpipe_lock);
764	if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
765		lock_basic_unlock(&ctx->qqpipe_lock);
766		free(msg);
767		return UB_PIPE;
768	}
769	lock_basic_unlock(&ctx->qqpipe_lock);
770	free(msg);
771	return UB_NOERROR;
772}
773
774int
775ub_cancel(struct ub_ctx* ctx, int async_id)
776{
777	struct ctx_query* q;
778	uint8_t* msg = NULL;
779	uint32_t len = 0;
780	lock_basic_lock(&ctx->cfglock);
781	q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id);
782	if(!q || !q->async) {
783		/* it is not there, so nothing to do */
784		lock_basic_unlock(&ctx->cfglock);
785		return UB_NOID;
786	}
787	log_assert(q->async);
788	q->cancelled = 1;
789
790	/* delete it */
791	if(!ctx->dothread) { /* if forked */
792		(void)rbtree_delete(&ctx->queries, q->node.key);
793		ctx->num_async--;
794		msg = context_serialize_cancel(q, &len);
795		context_query_delete(q);
796		lock_basic_unlock(&ctx->cfglock);
797		if(!msg) {
798			return UB_NOMEM;
799		}
800		/* send cancel to background worker */
801		lock_basic_lock(&ctx->qqpipe_lock);
802		if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
803			lock_basic_unlock(&ctx->qqpipe_lock);
804			free(msg);
805			return UB_PIPE;
806		}
807		lock_basic_unlock(&ctx->qqpipe_lock);
808		free(msg);
809	} else {
810		lock_basic_unlock(&ctx->cfglock);
811	}
812	return UB_NOERROR;
813}
814
815void
816ub_resolve_free(struct ub_result* result)
817{
818	char** p;
819	if(!result) return;
820	free(result->qname);
821	if(result->canonname != result->qname)
822		free(result->canonname);
823	if(result->data)
824		for(p = result->data; *p; p++)
825			free(*p);
826	free(result->data);
827	free(result->len);
828	free(result->answer_packet);
829	free(result->why_bogus);
830	free(result);
831}
832
833const char*
834ub_strerror(int err)
835{
836	switch(err) {
837		case UB_NOERROR: return "no error";
838		case UB_SOCKET: return "socket io error";
839		case UB_NOMEM: return "out of memory";
840		case UB_SYNTAX: return "syntax error";
841		case UB_SERVFAIL: return "server failure";
842		case UB_FORKFAIL: return "could not fork";
843		case UB_INITFAIL: return "initialization failure";
844		case UB_AFTERFINAL: return "setting change after finalize";
845		case UB_PIPE: return "error in pipe communication with async";
846		case UB_READFILE: return "error reading file";
847		case UB_NOID: return "error async_id does not exist";
848		default: return "unknown error";
849	}
850}
851
852int
853ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
854{
855	struct sockaddr_storage storage;
856	socklen_t stlen;
857	struct config_stub* s;
858	char* dupl;
859	lock_basic_lock(&ctx->cfglock);
860	if(ctx->finalized) {
861		lock_basic_unlock(&ctx->cfglock);
862		errno=EINVAL;
863		return UB_AFTERFINAL;
864	}
865	if(!addr) {
866		/* disable fwd mode - the root stub should be first. */
867		if(ctx->env->cfg->forwards &&
868			strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
869			s = ctx->env->cfg->forwards;
870			ctx->env->cfg->forwards = s->next;
871			s->next = NULL;
872			config_delstubs(s);
873		}
874		lock_basic_unlock(&ctx->cfglock);
875		return UB_NOERROR;
876	}
877	lock_basic_unlock(&ctx->cfglock);
878
879	/* check syntax for addr */
880	if(!extstrtoaddr(addr, &storage, &stlen)) {
881		errno=EINVAL;
882		return UB_SYNTAX;
883	}
884
885	/* it parses, add root stub in front of list */
886	lock_basic_lock(&ctx->cfglock);
887	if(!ctx->env->cfg->forwards ||
888		strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
889		s = calloc(1, sizeof(*s));
890		if(!s) {
891			lock_basic_unlock(&ctx->cfglock);
892			errno=ENOMEM;
893			return UB_NOMEM;
894		}
895		s->name = strdup(".");
896		if(!s->name) {
897			free(s);
898			lock_basic_unlock(&ctx->cfglock);
899			errno=ENOMEM;
900			return UB_NOMEM;
901		}
902		s->next = ctx->env->cfg->forwards;
903		ctx->env->cfg->forwards = s;
904	} else {
905		log_assert(ctx->env->cfg->forwards);
906		s = ctx->env->cfg->forwards;
907	}
908	dupl = strdup(addr);
909	if(!dupl) {
910		lock_basic_unlock(&ctx->cfglock);
911		errno=ENOMEM;
912		return UB_NOMEM;
913	}
914	if(!cfg_strlist_insert(&s->addrs, dupl)) {
915		free(dupl);
916		lock_basic_unlock(&ctx->cfglock);
917		errno=ENOMEM;
918		return UB_NOMEM;
919	}
920	lock_basic_unlock(&ctx->cfglock);
921	return UB_NOERROR;
922}
923
924int
925ub_ctx_resolvconf(struct ub_ctx* ctx, const char* fname)
926{
927	FILE* in;
928	int numserv = 0;
929	char buf[1024];
930	char* parse, *addr;
931	int r;
932
933	if(fname == NULL) {
934#if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H)
935		fname = "/etc/resolv.conf";
936#else
937		FIXED_INFO *info;
938		ULONG buflen = sizeof(*info);
939		IP_ADDR_STRING *ptr;
940
941		info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
942		if (info == NULL)
943			return UB_READFILE;
944
945		if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) {
946			free(info);
947			info = (FIXED_INFO *) malloc(buflen);
948			if (info == NULL)
949				return UB_READFILE;
950		}
951
952		if (GetNetworkParams(info, &buflen) == NO_ERROR) {
953			int retval=0;
954			ptr = &(info->DnsServerList);
955			while (ptr) {
956				numserv++;
957				if((retval=ub_ctx_set_fwd(ctx,
958					ptr->IpAddress.String))!=0) {
959					free(info);
960					return retval;
961				}
962				ptr = ptr->Next;
963			}
964			free(info);
965			if (numserv==0)
966				return UB_READFILE;
967			return UB_NOERROR;
968		}
969		free(info);
970		return UB_READFILE;
971#endif /* WINDOWS */
972	}
973	in = fopen(fname, "r");
974	if(!in) {
975		/* error in errno! perror(fname) */
976		return UB_READFILE;
977	}
978	while(fgets(buf, (int)sizeof(buf), in)) {
979		buf[sizeof(buf)-1] = 0;
980		parse=buf;
981		while(*parse == ' ' || *parse == '\t')
982			parse++;
983		if(strncmp(parse, "nameserver", 10) == 0) {
984			numserv++;
985			parse += 10; /* skip 'nameserver' */
986			/* skip whitespace */
987			while(*parse == ' ' || *parse == '\t')
988				parse++;
989			addr = parse;
990			/* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
991			while(isxdigit((unsigned char)*parse) || *parse=='.' || *parse==':')
992				parse++;
993			/* terminate after the address, remove newline */
994			*parse = 0;
995
996			if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
997				fclose(in);
998				return r;
999			}
1000		}
1001	}
1002	fclose(in);
1003	if(numserv == 0) {
1004		/* from resolv.conf(5) if none given, use localhost */
1005		return ub_ctx_set_fwd(ctx, "127.0.0.1");
1006	}
1007	return UB_NOERROR;
1008}
1009
1010int
1011ub_ctx_hosts(struct ub_ctx* ctx, const char* fname)
1012{
1013	FILE* in;
1014	char buf[1024], ldata[1024];
1015	char* parse, *addr, *name, *ins;
1016	lock_basic_lock(&ctx->cfglock);
1017	if(ctx->finalized) {
1018		lock_basic_unlock(&ctx->cfglock);
1019		errno=EINVAL;
1020		return UB_AFTERFINAL;
1021	}
1022	lock_basic_unlock(&ctx->cfglock);
1023	if(fname == NULL) {
1024#if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H)
1025		/*
1026		 * If this is Windows NT/XP/2K it's in
1027		 * %WINDIR%\system32\drivers\etc\hosts.
1028		 * If this is Windows 95/98/Me it's in %WINDIR%\hosts.
1029		 */
1030		name = getenv("WINDIR");
1031		if (name != NULL) {
1032			int retval=0;
1033			snprintf(buf, sizeof(buf), "%s%s", name,
1034				"\\system32\\drivers\\etc\\hosts");
1035			if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) {
1036				snprintf(buf, sizeof(buf), "%s%s", name,
1037					"\\hosts");
1038				retval=ub_ctx_hosts(ctx, buf);
1039			}
1040			return retval;
1041		}
1042		return UB_READFILE;
1043#else
1044		fname = "/etc/hosts";
1045#endif /* WIN32 */
1046	}
1047	in = fopen(fname, "r");
1048	if(!in) {
1049		/* error in errno! perror(fname) */
1050		return UB_READFILE;
1051	}
1052	while(fgets(buf, (int)sizeof(buf), in)) {
1053		buf[sizeof(buf)-1] = 0;
1054		parse=buf;
1055		while(*parse == ' ' || *parse == '\t')
1056			parse++;
1057		if(*parse == '#')
1058			continue; /* skip comment */
1059		/* format: <addr> spaces <name> spaces <name> ... */
1060		addr = parse;
1061		/* skip addr */
1062		while(isxdigit((unsigned char)*parse) || *parse == '.' || *parse == ':')
1063			parse++;
1064		if(*parse == '\r')
1065			parse++;
1066		if(*parse == '\n' || *parse == 0)
1067			continue;
1068		if(*parse == '%')
1069			continue; /* ignore macOSX fe80::1%lo0 localhost */
1070		if(*parse != ' ' && *parse != '\t') {
1071			/* must have whitespace after address */
1072			fclose(in);
1073			errno=EINVAL;
1074			return UB_SYNTAX;
1075		}
1076		*parse++ = 0; /* end delimiter for addr ... */
1077		/* go to names and add them */
1078		while(*parse) {
1079			while(*parse == ' ' || *parse == '\t' || *parse=='\n'
1080				|| *parse=='\r')
1081				parse++;
1082			if(*parse == 0 || *parse == '#')
1083				break;
1084			/* skip name, allows (too) many printable characters */
1085			name = parse;
1086			while('!' <= *parse && *parse <= '~')
1087				parse++;
1088			if(*parse)
1089				*parse++ = 0; /* end delimiter for name */
1090			snprintf(ldata, sizeof(ldata), "%s %s %s",
1091				name, str_is_ip6(addr)?"AAAA":"A", addr);
1092			ins = strdup(ldata);
1093			if(!ins) {
1094				/* out of memory */
1095				fclose(in);
1096				errno=ENOMEM;
1097				return UB_NOMEM;
1098			}
1099			lock_basic_lock(&ctx->cfglock);
1100			if(!cfg_strlist_insert(&ctx->env->cfg->local_data,
1101				ins)) {
1102				lock_basic_unlock(&ctx->cfglock);
1103				fclose(in);
1104				free(ins);
1105				errno=ENOMEM;
1106				return UB_NOMEM;
1107			}
1108			lock_basic_unlock(&ctx->cfglock);
1109		}
1110	}
1111	fclose(in);
1112	return UB_NOERROR;
1113}
1114
1115/** finalize the context, if not already finalized */
1116static int ub_ctx_finalize(struct ub_ctx* ctx)
1117{
1118	int res = 0;
1119	lock_basic_lock(&ctx->cfglock);
1120	if (!ctx->finalized) {
1121		res = context_finalize(ctx);
1122	}
1123	lock_basic_unlock(&ctx->cfglock);
1124	return res;
1125}
1126
1127/* Print local zones and RR data */
1128int ub_ctx_print_local_zones(struct ub_ctx* ctx)
1129{
1130	int res = ub_ctx_finalize(ctx);
1131	if (res) return res;
1132
1133	local_zones_print(ctx->local_zones);
1134
1135	return UB_NOERROR;
1136}
1137
1138/* Add a new zone */
1139int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name,
1140	const char *zone_type)
1141{
1142	enum localzone_type t;
1143	struct local_zone* z;
1144	uint8_t* nm;
1145	int nmlabs;
1146	size_t nmlen;
1147
1148	int res = ub_ctx_finalize(ctx);
1149	if (res) return res;
1150
1151	if(!local_zone_str2type(zone_type, &t)) {
1152		return UB_SYNTAX;
1153	}
1154
1155	if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
1156		return UB_SYNTAX;
1157	}
1158
1159	lock_rw_wrlock(&ctx->local_zones->lock);
1160	if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
1161		LDNS_RR_CLASS_IN))) {
1162		/* already present in tree */
1163		lock_rw_wrlock(&z->lock);
1164		z->type = t; /* update type anyway */
1165		lock_rw_unlock(&z->lock);
1166		lock_rw_unlock(&ctx->local_zones->lock);
1167		free(nm);
1168		return UB_NOERROR;
1169	}
1170	if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs,
1171		LDNS_RR_CLASS_IN, t)) {
1172		lock_rw_unlock(&ctx->local_zones->lock);
1173		return UB_NOMEM;
1174	}
1175	lock_rw_unlock(&ctx->local_zones->lock);
1176	return UB_NOERROR;
1177}
1178
1179/* Remove zone */
1180int ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name)
1181{
1182	struct local_zone* z;
1183	uint8_t* nm;
1184	int nmlabs;
1185	size_t nmlen;
1186
1187	int res = ub_ctx_finalize(ctx);
1188	if (res) return res;
1189
1190	if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
1191		return UB_SYNTAX;
1192	}
1193
1194	lock_rw_wrlock(&ctx->local_zones->lock);
1195	if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
1196		LDNS_RR_CLASS_IN))) {
1197		/* present in tree */
1198		local_zones_del_zone(ctx->local_zones, z);
1199	}
1200	lock_rw_unlock(&ctx->local_zones->lock);
1201	free(nm);
1202	return UB_NOERROR;
1203}
1204
1205/* Add new RR data */
1206int ub_ctx_data_add(struct ub_ctx* ctx, const char *data)
1207{
1208	int res = ub_ctx_finalize(ctx);
1209	if (res) return res;
1210
1211	res = local_zones_add_RR(ctx->local_zones, data);
1212	return (!res) ? UB_NOMEM : UB_NOERROR;
1213}
1214
1215/* Remove RR data */
1216int ub_ctx_data_remove(struct ub_ctx* ctx, const char *data)
1217{
1218	uint8_t* nm;
1219	int nmlabs;
1220	size_t nmlen;
1221	int res = ub_ctx_finalize(ctx);
1222	if (res) return res;
1223
1224	if(!parse_dname(data, &nm, &nmlen, &nmlabs))
1225		return UB_SYNTAX;
1226
1227	local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs,
1228		LDNS_RR_CLASS_IN);
1229
1230	free(nm);
1231	return UB_NOERROR;
1232}
1233
1234const char* ub_version(void)
1235{
1236	return PACKAGE_VERSION;
1237}
1238
1239int
1240ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
1241	if (!ctx || !ctx->event_base || !base) {
1242		return UB_INITFAIL;
1243	}
1244	if (ctx->event_base == base) {
1245		/* already set */
1246		return UB_NOERROR;
1247	}
1248
1249	lock_basic_lock(&ctx->cfglock);
1250	/* destroy the current worker - safe to pass in NULL */
1251	libworker_delete_event(ctx->event_worker);
1252	ctx->event_worker = NULL;
1253	ctx->event_base = base;
1254	ctx->created_bg = 0;
1255	ctx->dothread = 1;
1256	lock_basic_unlock(&ctx->cfglock);
1257	return UB_NOERROR;
1258}
1259