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