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