1 /**
2  *
3  * \file context.c
4  * @brief getdns context management functions
5  *
6  * Declarations taken from the getdns API description pseudo implementation.
7  *
8  */
9 
10 /*
11  * Copyright (c) 2013, NLnet Labs, Verisign, Inc.
12  * All rights reserved.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are met:
16  * * Redistributions of source code must retain the above copyright
17  *   notice, this list of conditions and the following disclaimer.
18  * * Redistributions in binary form must reproduce the above copyright
19  *   notice, this list of conditions and the following disclaimer in the
20  *   documentation and/or other materials provided with the distribution.
21  * * Neither the names of the copyright holders nor the
22  *   names of its contributors may be used to endorse or promote products
23  *   derived from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
28  * DISCLAIMED. IN NO EVENT SHALL Verisign, Inc. BE LIABLE FOR ANY
29  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
32  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #include "config.h"
38 #include "anchor.h"
39 
40 #ifndef USE_WINSOCK
41 #include <arpa/inet.h>
42 #include <sys/time.h>
43 #include <netdb.h>
44 #include <pwd.h>
45 #else
46 #include <winsock2.h>
47 #include <iphlpapi.h>
48 typedef unsigned short in_port_t;
49 
50 #include <stdio.h>
51 #include <windows.h>
52 #include <wincrypt.h>
53 #include <shlobj.h>
54 #endif
55 
56 #include <sys/stat.h>
57 #include <string.h>
58 #include <strings.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 
62 #include <assert.h>
63 #include <ctype.h>
64 #include <stdarg.h>
65 
66 #ifdef HAVE_PTHREAD
67 #include <pthread.h>
68 #endif
69 #include <stdbool.h>
70 
71 #ifdef HAVE_LIBUNBOUND
72 #include <unbound.h>
73 #endif
74 #include "debug.h"
75 #include "gldns/str2wire.h"
76 #include "gldns/wire2str.h"
77 #include "context.h"
78 #include "types-internal.h"
79 #include "util-internal.h"
80 #include "platform.h"
81 #include "dnssec.h"
82 #include "stub.h"
83 #include "list.h"
84 #include "dict.h"
85 #include "pubkey-pinning.h"
86 #include "const-info.h"
87 #include "tls.h"
88 
89 #define GETDNS_PORT_ZERO 0
90 #define GETDNS_PORT_DNS 53
91 #define GETDNS_PORT_DNS_OVER_TLS 853
92 #define GETDNS_STR_PORT_ZERO "0"
93 #define GETDNS_STR_PORT_DNS "53"
94 #define GETDNS_STR_PORT_DNS_OVER_TLS "853"
95 
96 #ifdef HAVE_PTHREAD
97 static pthread_mutex_t ssl_init_lock = PTHREAD_MUTEX_INITIALIZER;
98 #endif
99 static bool ssl_init=false;
100 
101 #ifdef HAVE_MDNS_SUPPORT
102 /*
103  * Forward declaration of MDNS context init and destroy function.
104  * We do this here instead of including mdns.h, in order to
105  * minimize dependencies.
106  */
107 void _getdns_mdns_context_init(struct getdns_context *context);
108 void _getdns_mdns_context_destroy(struct getdns_context *context);
109 #endif
110 
111 void *plain_mem_funcs_user_arg = MF_PLAIN;
112 
113 typedef struct host_name_addrs {
114 	_getdns_rbnode_t node;
115 	getdns_list *ipv4addrs;
116 	getdns_list *ipv6addrs;
117 	uint8_t host_name[];
118 } host_name_addrs;
119 
120 
121 /*  If changing these lists also remember to
122     change the value of GETDNS_UPSTREAM_TRANSPORTS */
123 static getdns_transport_list_t
124 getdns_upstream_transports[GETDNS_UPSTREAM_TRANSPORTS] = {
125 	GETDNS_TRANSPORT_TCP,
126 	GETDNS_TRANSPORT_TLS,
127 };
128 
129 static in_port_t
130 getdns_port_array[GETDNS_UPSTREAM_TRANSPORTS] = {
131 	GETDNS_PORT_DNS,
132 	GETDNS_PORT_DNS_OVER_TLS
133 };
134 
135 static char*
136 getdns_port_str_array[] = {
137 	GETDNS_STR_PORT_DNS,
138 	GETDNS_STR_PORT_DNS_OVER_TLS
139 };
140 
141 static const uint8_t no_suffixes[] = { 1, 0 };
142 
143 /* Private functions */
144 static getdns_return_t create_default_namespaces(struct getdns_context *context);
145 static getdns_return_t create_default_dns_transports(struct getdns_context *context);
146 static int transaction_id_cmp(const void *, const void *);
147 static void dispatch_updated(struct getdns_context *, uint16_t);
148 static void cancel_outstanding_requests(getdns_context*);
149 
150 /* unbound helpers */
151 #ifdef HAVE_LIBUNBOUND
152 static getdns_return_t rebuild_ub_ctx(struct getdns_context* context);
153 static void set_ub_string_opt(struct getdns_context *, char *, char *);
154 static void set_ub_number_opt(struct getdns_context *, char *, uint16_t);
155 static getdns_return_t set_ub_dns_transport(struct getdns_context*);
156 static void set_ub_limit_outstanding_queries(struct getdns_context*,
157     uint16_t);
158 static void set_ub_dnssec_allowed_skew(struct getdns_context*, uint32_t);
159 #endif
160 
161 /* Stuff to make it compile pedantically */
162 #define RETURN_IF_NULL(ptr, code) if(ptr == NULL) return code;
163 
164 static char *
_getdns_strdup2(const struct mem_funcs * mfs,const getdns_bindata * s)165 _getdns_strdup2(const struct mem_funcs *mfs, const getdns_bindata *s)
166 {
167     char *r;
168     if (!s || !(r = GETDNS_XMALLOC(*mfs, char, s->size + 1)))
169         return NULL;
170     else {
171 	r[s->size] = '\0';
172         return memcpy(r, s->data, s->size);
173     }
174 }
175 
176 static uint8_t*
upstream_addr(getdns_upstream * upstream)177 upstream_addr(getdns_upstream *upstream)
178 {
179 	return upstream->addr.ss_family == AF_INET
180 	    ? (void *)&((struct sockaddr_in*)&upstream->addr)->sin_addr
181 	    : (void *)&((struct sockaddr_in6*)&upstream->addr)->sin6_addr;
182 }
183 
184 static in_port_t
upstream_port(getdns_upstream * upstream)185 upstream_port(getdns_upstream *upstream)
186 {
187 	return ntohs(upstream->addr.ss_family == AF_INET
188 	     ? ((struct sockaddr_in *)&upstream->addr)->sin_port
189 	     : ((struct sockaddr_in6*)&upstream->addr)->sin6_port);
190 }
191 
destroy_local_host(_getdns_rbnode_t * node,void * arg)192 static void destroy_local_host(_getdns_rbnode_t * node, void *arg)
193 {
194 	getdns_context *context = (getdns_context *)arg;
195 	host_name_addrs *hnas = (host_name_addrs *)node;
196 	getdns_list_destroy(hnas->ipv4addrs);
197 	getdns_list_destroy(hnas->ipv6addrs);
198 	GETDNS_FREE(context->my_mf, hnas);
199 }
200 
201 /**
202  * Helper to get default lookup namespaces.
203  * TODO: Determine from OS
204  */
205 static getdns_return_t
create_default_namespaces(getdns_context * context)206 create_default_namespaces(getdns_context *context)
207 {
208 	if (!( context->namespaces
209 	     = GETDNS_XMALLOC(context->my_mf, getdns_namespace_t, 2)))
210 		return GETDNS_RETURN_MEMORY_ERROR;
211 
212 	context->namespaces[0] = GETDNS_NAMESPACE_LOCALNAMES;
213 	context->namespaces[1] = GETDNS_NAMESPACE_DNS;
214 	context->namespace_count = 2;
215 	return GETDNS_RETURN_GOOD;
216 }
217 
218 /**
219  * Helper to get default transports.
220  */
221 static getdns_return_t
create_default_dns_transports(getdns_context * context)222 create_default_dns_transports(getdns_context *context)
223 {
224 	if (!( context->dns_transports
225 	     = GETDNS_XMALLOC(context->my_mf, getdns_transport_list_t, 2)))
226 		return GETDNS_RETURN_MEMORY_ERROR;
227 
228 	context->dns_transports[0] = GETDNS_TRANSPORT_UDP;
229 	context->dns_transports[1] = GETDNS_TRANSPORT_TCP;
230 	context->dns_transport_count = 2;
231 
232 	return GETDNS_RETURN_GOOD;
233 }
234 
canonicalize_dname(uint8_t * dname)235 static inline void canonicalize_dname(uint8_t *dname)
236 {
237 	uint8_t *next_label;
238 
239 	while (*dname && !(*dname & 0xC0)) {
240 		next_label = dname + *dname + 1;
241 		dname += 1;
242 		while (dname < next_label) {
243 			*dname = (uint8_t)tolower((unsigned char)*dname);
244 			dname++;
245 		}
246 	}
247 }
248 
249 static int
canonical_dname_compare(register const uint8_t * d1,register const uint8_t * d2)250 canonical_dname_compare(register const uint8_t *d1, register const uint8_t *d2)
251 {
252 	register uint8_t lab1, lab2;
253 
254 	assert(d1 && d2);
255 
256 	lab1 = *d1++;
257 	lab2 = *d2++;
258 	while (lab1 != 0 || lab2 != 0) {
259 		/* compare label length */
260 		/* if one dname ends, it has labellength 0 */
261 		if (lab1 != lab2) {
262 			if (lab1 < lab2)
263 				return -1;
264 			return 1;
265 		}
266 		while (lab1--) {
267 			/* compare bytes first for speed */
268 			if (*d1 != *d2) {
269 				if (*d1 < *d2)
270 					return -1;
271 				return  1;
272 			}
273 			d1++;
274 			d2++;
275 		}
276 		/* next pair of labels. */
277 		lab1 = *d1++;
278 		lab2 = *d2++;
279 	}
280 	return 0;
281 }
282 
283 static int
local_host_cmp(const void * id1,const void * id2)284 local_host_cmp(const void *id1, const void *id2)
285 {
286 	return canonical_dname_compare(id1, id2);
287 }
288 
289 /** return 0 on success */
290 static getdns_return_t
add_local_host(getdns_context * context,getdns_dict * address,const char * str)291 add_local_host(getdns_context *context, getdns_dict *address, const char *str)
292 {
293 	uint8_t host_name[256];
294 	size_t host_name_len = sizeof(host_name);
295 	host_name_addrs *hnas;
296 	getdns_bindata *address_type;
297 	int hnas_found = 0;
298 	getdns_list **addrs;
299 	getdns_return_t r;
300 
301 	if (gldns_str2wire_dname_buf(str, host_name, &host_name_len))
302 		return GETDNS_RETURN_BAD_DOMAIN_NAME;
303 
304 	canonicalize_dname(host_name);
305 
306 	if (!(hnas = (host_name_addrs *)_getdns_rbtree_search(
307 	    &context->local_hosts, host_name))) {
308 
309 		if (!(hnas = (host_name_addrs *)GETDNS_XMALLOC(context->mf,
310 		    uint8_t, sizeof(host_name_addrs) + host_name_len)))
311 			return GETDNS_RETURN_MEMORY_ERROR;
312 
313 		hnas->ipv4addrs = NULL;
314 		hnas->ipv6addrs = NULL;
315 		(void)memcpy(hnas->host_name, host_name, host_name_len);
316 		hnas->node.key = &hnas->host_name;
317 
318 	} else
319 		hnas_found = 1;
320 
321 	if ((r = getdns_dict_get_bindata(address,"address_type",&address_type))
322 	||  address_type->size < 4
323 	||  !(addrs = address_type->data[3] == '4'? &hnas->ipv4addrs
324 	            : address_type->data[3] == '6'? &hnas->ipv4addrs : NULL)) {
325 
326 		if (!hnas_found) GETDNS_FREE(context->mf, hnas);
327 		return r ? r : GETDNS_RETURN_WRONG_TYPE_REQUESTED;
328 	}
329 	if (!*addrs && !(*addrs = getdns_list_create_with_context(context))) {
330 		if (!hnas_found) GETDNS_FREE(context->mf, hnas);
331 		return GETDNS_RETURN_MEMORY_ERROR;
332 	}
333 	if ((r = _getdns_list_append_this_dict(*addrs, address))) {
334 	       	if (!hnas_found) {
335 			getdns_list_destroy(*addrs);
336 			GETDNS_FREE(context->mf, hnas);
337 		}
338 		return r;
339 
340 	} else if (!hnas_found)
341 		(void)_getdns_rbtree_insert(&context->local_hosts, &hnas->node);
342 
343 	return GETDNS_RETURN_GOOD;
344 }
345 
346 static getdns_dict *
sockaddr_dict(const getdns_context * context,struct sockaddr * sa)347 sockaddr_dict(const getdns_context *context, struct sockaddr *sa)
348 {
349 	getdns_dict *address = getdns_dict_create_with_context(context);
350 	char addrstr[1024], *b;
351 	getdns_bindata bindata;
352 	uint16_t port;
353 
354 	if (!address)
355 		return NULL;
356 
357 	switch (sa->sa_family) {
358 	case AF_INET:
359 		if (getdns_dict_util_set_string(address,"address_type","IPv4"))
360 			break;
361 
362 		bindata.size = 4;
363 		bindata.data = (void *)&((struct sockaddr_in*)sa)->sin_addr;
364 		if ((getdns_dict_set_bindata(address,"address_data",&bindata)))
365 			break;
366 
367 		port = ntohs(((struct sockaddr_in *)sa)->sin_port);
368 		if (port != GETDNS_PORT_ZERO && port != GETDNS_PORT_DNS &&
369 		    getdns_dict_set_int(address, "port", (uint32_t)port))
370 			break;
371 
372 		return address;
373 
374 	case AF_INET6:
375 		if (getdns_dict_util_set_string(address,"address_type","IPv6"))
376 			break;
377 
378 		bindata.size = 16;
379 		bindata.data = (void *)&((struct sockaddr_in6*)sa)->sin6_addr;
380 		if ((getdns_dict_set_bindata(address,"address_data",&bindata)))
381 			break;
382 
383 		port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
384 		if (port != GETDNS_PORT_ZERO && port != GETDNS_PORT_DNS &&
385 		    getdns_dict_set_int(address, "port", (uint32_t)port))
386 			break;
387 
388 		/* Try to get scope_id too */
389 		if (getnameinfo(sa, sizeof(struct sockaddr_in6),
390 		    addrstr, sizeof(addrstr), NULL, 0, NI_NUMERICHOST))
391 			break;
392 		if ((b = strchr(addrstr, '%')) &&
393 		    getdns_dict_util_set_string(address, "scope_id", b+1))
394 			break;
395 
396 		return address;
397 	default:
398 		/* Unknown protocol */
399 		break;
400 	}
401 	getdns_dict_destroy(address);
402 	return NULL;
403 }
404 
405 static getdns_dict *
str_addr_dict(getdns_context * context,const char * str)406 str_addr_dict(getdns_context *context, const char *str)
407 {
408 	static struct addrinfo hints = { .ai_family = AF_UNSPEC
409 	                               , .ai_flags  = AI_NUMERICHOST };
410 	struct addrinfo *ai;
411 	getdns_dict *address;
412 
413 	if (getaddrinfo(str, NULL, &hints, &ai))
414 		return NULL;
415 	if (!ai)
416 		return NULL;
417 
418 	address = sockaddr_dict(context, ai->ai_addr);
419 	freeaddrinfo(ai);
420 
421 	return address;
422 }
423 
424 /**
425  * check a file for changes since the last check
426  * and refresh the current data if changes are detected
427  * @param context pointer to a previously created context to be used for this call
428  * @param fchg file to check
429  * @returns changes as OR'd list of GETDNS_FCHG_* values
430  * @returns GETDNS_FCHG_NONE if no changes
431  * @returns GETDNS_FCHG_ERRORS if problems (see fchg->errors for details)
432  */
433 static int
_getdns_filechg_check(struct filechg * fchg)434 _getdns_filechg_check(struct filechg *fchg)
435 {
436 	struct stat finfo;
437 
438 	if(fchg == NULL)
439 		return 0;
440 
441 	fchg->errors  = GETDNS_FCHG_NOERROR;
442 	fchg->changes = GETDNS_FCHG_NOCHANGES;
443 
444 	if(stat(fchg->fn, &finfo) != 0) {
445 		fchg->errors = errno;
446 		return GETDNS_FCHG_ERRORS;
447 	}
448 
449 	/* we want to consider a file that previously returned error for stat() as a
450 	   change */
451 
452 	if(fchg->prevstat.st_mtime != finfo.st_mtime)
453 		fchg->changes |= GETDNS_FCHG_MTIME;
454 	if(fchg->prevstat.st_ctime != finfo.st_ctime)
455 		fchg->changes |= GETDNS_FCHG_CTIME;
456 
457 	fchg->prevstat = finfo;
458 	return fchg->changes;
459 } /* filechg */
460 
461 getdns_return_t
getdns_context_set_hosts(getdns_context * context,const char * hosts)462 getdns_context_set_hosts(getdns_context *context, const char *hosts)
463 {
464 	/* enough space in buf for longest allowed domain name */
465 	char buf[2048];
466 	char *pos = buf, prev_c, *start_of_word = NULL;
467 	FILE *in;
468 	int start_of_line = 1;
469 	getdns_dict *address = NULL;
470 
471 	if (!context || !hosts)
472 		return GETDNS_RETURN_INVALID_PARAMETER;
473 
474 	if (!(in = fopen(hosts, "r")))
475 		return GETDNS_RETURN_IO_ERROR;
476 
477 	(void) strlcpy(context->fchg_hosts.fn, hosts, _GETDNS_PATH_MAX);
478 	(void) memset(&context->fchg_hosts.prevstat, 0, sizeof(struct stat));
479 	context->fchg_hosts.changes = GETDNS_FCHG_NOCHANGES;
480 	context->fchg_hosts.errors = GETDNS_FCHG_NOERROR;
481 	(void) _getdns_filechg_check(&context->fchg_hosts);
482 	_getdns_traverse_postorder(&context->local_hosts,
483 	    destroy_local_host, context);
484 	_getdns_rbtree_init(&context->local_hosts, local_host_cmp);
485 
486 	while (fgets(pos, (int)(sizeof(buf) - (pos - buf)), in)) {
487 		pos = buf;
488 		/* Break out of for to read more */
489 		for (;;) {
490 			/* Skip whitespace */
491 			while (*pos == ' '  || *pos == '\f'
492 			    || *pos == '\t' || *pos == '\v')
493 				pos++;
494 
495 			if (*pos == '\0') { /* End of read data */
496 				pos = buf;
497 				goto read_more;
498 
499 			} else if (*pos == '#' || *pos == '\r' || *pos == '\n')
500 				/* Comments or end of line */
501 				break; /* skip to next line */
502 
503 			assert(*pos && !isspace(*pos));
504 
505 			start_of_word = pos;
506 
507 			/* Search for end of word */
508 			while (*pos && !isspace(*pos))
509 				pos++;
510 
511 			/* '\0' before whitespace, so either the word did not
512 			 * fit, or we are at the end of the file.
513 			 */
514 			if (*pos == '\0') {
515 				if (start_of_word == buf) /* word too big */
516 					break; /* skip to next line */
517 
518 				/* Move word to fit in buffer */
519 				memmove(buf,start_of_word,pos - start_of_word);
520 				pos = buf + (pos - start_of_word);
521 				start_of_word = buf;
522 				*pos = '\0';
523 				goto read_more;
524 			}
525 			assert(isspace(*pos));
526 			prev_c = *pos;
527 			*pos = '\0';
528 			if (start_of_line) {
529 				start_of_line = 0;
530 				if (address)
531 					getdns_dict_destroy(address);
532 				if (!(address =
533 				    str_addr_dict(context, start_of_word)))
534 					/* Unparseable address */
535 					break; /* skip to next line */
536 			} else if (!add_local_host(context, address, start_of_word))
537 				address = NULL;
538 
539 			start_of_word = NULL;
540 			*pos = prev_c;
541 			/* process next word in buf */
542 		}
543 		/* skip to next line */
544 		while (*pos != '\r' && *pos != '\n')
545 			if (*pos)
546 				pos++;
547 			else if (!fgets((pos = buf), sizeof(buf), in))
548 				break; /* We're done */
549 		start_of_line = 1;
550 		if (address) {
551 			getdns_dict_destroy(address);
552 			address = NULL;
553 		}
554 		pos = buf;
555 read_more:	;
556 	}
557 	fclose(in);
558 	if (address) {
559 		/* One last name for this address? */
560 		if (start_of_word && !start_of_line)
561 			if (!add_local_host(context, address, start_of_word))
562 				address = NULL;
563 		getdns_dict_destroy(address);
564 	}
565 	return GETDNS_RETURN_GOOD;
566 }
567 
568 getdns_return_t
getdns_context_get_hosts(const getdns_context * context,const char ** hosts)569 getdns_context_get_hosts(const getdns_context *context, const char **hosts)
570 {
571 	if (!context || !hosts)
572 		return GETDNS_RETURN_INVALID_PARAMETER;
573 
574 	*hosts = *context->fchg_hosts.fn ? context->fchg_hosts.fn : NULL;
575 	return GETDNS_RETURN_GOOD;
576 }
577 
578 
579 static getdns_upstreams *
upstreams_create(getdns_context * context,size_t size)580 upstreams_create(getdns_context *context, size_t size)
581 {
582 	getdns_upstreams *r = (void *) GETDNS_XMALLOC(context->mf, char,
583 	    sizeof(getdns_upstreams) +
584 	    sizeof(getdns_upstream) * size);
585 
586 	if (r) {
587 		r->mf = context->mf;
588 		r->referenced = 1;
589 		r->count = 0;
590 		r->current_udp = 0;
591 		r->current_stateful = 0;
592 		r->max_backoff_value = context->max_backoff_value;
593 		r->tls_backoff_time = context->tls_backoff_time;
594 		r->tls_connection_retries = context->tls_connection_retries;
595 		r->log = context->log;
596 	}
597 	return r;
598 }
599 
600 
601 void
_getdns_upstreams_dereference(getdns_upstreams * upstreams)602 _getdns_upstreams_dereference(getdns_upstreams *upstreams)
603 {
604 	getdns_upstream *upstream;
605 	getdns_dns_req *dnsreq;
606 
607 	if (!upstreams || --upstreams->referenced > 0)
608 		return;
609 
610 	for ( upstream = upstreams->upstreams
611 	    ; upstreams->count
612 	    ; upstreams->count--, upstream++ ) {
613 
614 		sha256_pin_t *pin = upstream->tls_pubkey_pinset;
615 		if (upstream->loop && (   upstream->event.read_cb
616 		                       || upstream->event.write_cb
617 		                       || upstream->event.timeout_cb) ) {
618 
619 			GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
620 			upstream->event.read_cb = NULL;
621 			upstream->event.write_cb = NULL;
622 			upstream->event.timeout_cb = NULL;
623 		}
624 		if (upstream->loop &&  upstream->finished_event.timeout_cb) {
625 			GETDNS_CLEAR_EVENT(upstream->loop,
626 			    &upstream->finished_event);
627 			upstream->finished_event.timeout_cb = NULL;
628 		}
629 		while (upstream->finished_dnsreqs) {
630 			dnsreq = upstream->finished_dnsreqs;
631 			upstream->finished_dnsreqs = dnsreq->finished_next;
632 			if (!dnsreq->internal_cb) { /* Not part of chain */
633 				debug_req("Destroy    ", *dnsreq->netreqs);
634 				_getdns_context_cancel_request(dnsreq);
635 			}
636 		}
637 		if (upstream->tls_session != NULL)
638 			_getdns_tls_session_free(&upstreams->mf, upstream->tls_session);
639 
640 		if (upstream->tls_obj != NULL) {
641 			_getdns_tls_connection_shutdown(upstream->tls_obj);
642 			_getdns_tls_connection_free(&upstreams->mf, upstream->tls_obj);
643 		}
644 		if (upstream->fd != -1)
645 		{
646 			_getdns_closesocket(upstream->fd);
647 		}
648 		if (upstream->tcp.read_buf)
649 			GETDNS_FREE(upstreams->mf, upstream->tcp.read_buf);
650 		while (pin) {
651 			sha256_pin_t *nextpin = pin->next;
652 			GETDNS_FREE(upstreams->mf, pin);
653 			pin = nextpin;
654 		}
655 		upstream->tls_pubkey_pinset = NULL;
656 		if (upstream->tls_cipher_list)
657 			GETDNS_FREE(upstreams->mf, upstream->tls_cipher_list);
658 		if (upstream->tls_ciphersuites)
659 			GETDNS_FREE(upstreams->mf, upstream->tls_ciphersuites);
660 		if (upstream->tls_curves_list)
661 			GETDNS_FREE(upstreams->mf, upstream->tls_curves_list);
662 	}
663 	GETDNS_FREE(upstreams->mf, upstreams);
664 }
665 
666 static void
upstream_backoff(getdns_upstream * upstream)667 upstream_backoff(getdns_upstream *upstream) {
668 	upstream->conn_state = GETDNS_CONN_BACKOFF;
669 	/* Increase the backoff interval incrementally up to the tls_backoff_time*/
670 	if (upstream->conn_backoff_interval < upstream->upstreams->tls_backoff_time) {
671 		if (upstream->conn_backoff_interval < (UINT16_MAX-1)/2)
672 			upstream->conn_backoff_interval *= 2;
673 		else
674 			upstream->conn_backoff_interval = upstream->upstreams->tls_backoff_time;
675 	}
676 	if (upstream->conn_backoff_interval < upstream->upstreams->tls_backoff_time)
677 		upstream->conn_retry_time = time(NULL) + upstream->conn_backoff_interval;
678 	else
679 		upstream->conn_retry_time = time(NULL) + upstream->upstreams->tls_backoff_time;
680 	upstream->total_responses = 0;
681 	upstream->total_timeouts = 0;
682 	upstream->conn_completed = 0;
683 	upstream->conn_setup_failed = 0;
684 	upstream->conn_shutdowns = 0;
685 	upstream->conn_backoffs++;
686 	_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_NOTICE,
687 	    "%-40s : Upstream   : !Backing off %s on this upstream    - Will retry again in %ds at %s",
688 	            upstream->addr_str,
689 	            upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP",
690 	            upstream->conn_backoff_interval,
691 	            asctime(gmtime(&upstream->conn_retry_time)));
692 }
693 
694 static void
_getdns_upstream_reset(getdns_upstream * upstream)695 _getdns_upstream_reset(getdns_upstream *upstream)
696 {
697 	/* Back off connections that never got up service at all (probably no
698 	   TCP service or incompatible TLS version/cipher).
699 	   Leave choice between working upstreams to the stub.
700 	   This back-off should be time based for TLS according to RFC7858. For now,
701 	   use the same basis if we simply can't get TCP service either.*/
702 	/* [TLS1]TODO: This arbitrary logic at the moment - review and improve!*/
703 
704 	/*This is the configured number of retries to attempt*/
705 	uint16_t conn_retries = upstream->upstreams->tls_connection_retries;
706 
707 	if (upstream->conn_setup_failed >= conn_retries
708 
709 	    || ((int)upstream->conn_shutdowns >= conn_retries*GETDNS_TRANSPORT_FAIL_MULT
710 	     && upstream->total_responses == 0)
711 
712 	    || (upstream->conn_completed >= conn_retries &&
713 	     upstream->total_responses == 0 &&
714 	     upstream->total_timeouts > GETDNS_TRANSPORT_FAIL_MULT)) {
715 
716 		upstream_backoff(upstream);
717 	}
718 
719 	/* If we didn't backoff it would be nice to reset the conn_backoff_interval
720 	   if the upstream is working well again otherwise it would get stuck at the
721 	   tls_backoff_time forever... How about */
722 	if (upstream->conn_state != GETDNS_CONN_BACKOFF &&
723 	    upstream->responses_received > 1)
724 		upstream->conn_backoff_interval = 1;
725 
726 	// Reset per connection counters
727 	upstream->queries_sent = 0;
728 	upstream->responses_received = 0;
729 	upstream->responses_timeouts = 0;
730 	upstream->keepalive_timeout = 0;
731 	upstream->keepalive_shutdown = 0;
732 
733 	/* Now TLS stuff*/
734 	upstream->tls_auth_state = GETDNS_AUTH_NONE;
735 	if (upstream->event.ev && upstream->loop) {
736 		upstream->loop->vmt->clear(
737 		    upstream->loop, &upstream->event);
738 	}
739 	if (upstream->tls_obj != NULL) {
740 		_getdns_tls_connection_shutdown(upstream->tls_obj);
741 		_getdns_tls_connection_free(&upstream->upstreams->mf, upstream->tls_obj);
742 		upstream->tls_obj = NULL;
743 	}
744 	if (upstream->fd != -1) {
745 		_getdns_closesocket(upstream->fd);
746 		upstream->fd = -1;
747 	}
748 	/* Set connection ready for use again*/
749 	if (upstream->conn_state != GETDNS_CONN_BACKOFF)
750 		upstream->conn_state = GETDNS_CONN_CLOSED;
751 }
752 
753 void
_getdns_upstream_shutdown(getdns_upstream * upstream)754 _getdns_upstream_shutdown(getdns_upstream *upstream)
755 {
756 	/* Update total stats for the upstream.*/
757 	upstream->total_responses+=upstream->responses_received;
758 	upstream->total_timeouts+=upstream->responses_timeouts;
759 	/* Need the last auth state when using session resumption*/
760 	upstream->last_tls_auth_state = upstream->tls_auth_state;
761 	/* Keep track of the best auth state this upstream has had*/
762 	if (upstream->tls_auth_state > upstream->best_tls_auth_state)
763 		upstream->best_tls_auth_state = upstream->tls_auth_state;
764 	_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_DEBUG,
765 	    "%-40s : Conn closed: %s - Resps=%6d, Timeouts  =%6d, Curr_auth =%7s, Keepalive(ms)=%6d\n",
766 	             upstream->addr_str,
767 	             (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"),
768 	             (int)upstream->responses_received, (int)upstream->responses_timeouts,
769 	             _getdns_auth_str(upstream->tls_auth_state), (int)upstream->keepalive_timeout);
770 	_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_INFO,
771 	    "%-40s : Upstream   : %s - Resps=%6d, Timeouts  =%6d, Best_auth =%7s\n",
772 	             upstream->addr_str,
773 	             (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"),
774 	             (int)upstream->total_responses, (int)upstream->total_timeouts,
775 	             _getdns_auth_str(upstream->best_tls_auth_state));
776 	_getdns_upstream_log(upstream, GETDNS_LOG_UPSTREAM_STATS, GETDNS_LOG_INFO,
777 	    "%-40s : Upstream   : %s - Conns=%6d, Conn_fails=%6d, Conn_shuts=%7d, Backoffs     =%6d\n",
778 	             upstream->addr_str,
779 	             (upstream->transport == GETDNS_TRANSPORT_TLS ? "TLS" : "TCP"),
780 	             (int)upstream->conn_completed, (int)upstream->conn_setup_failed,
781 	             (int)upstream->conn_shutdowns, (int)upstream->conn_backoffs);
782 
783 	_getdns_upstream_reset(upstream);
784 }
785 
786 static int
tls_is_in_transports_list(getdns_context * context)787 tls_is_in_transports_list(getdns_context *context)
788 {
789 	size_t i;
790 
791 	for (i = 0; i< context->dns_transport_count;i++) {
792 		if (context->dns_transports[i] == GETDNS_TRANSPORT_TLS)
793 			return 1;
794 	}
795 	return 0;
796 }
797 
798 static int
tls_only_is_in_transports_list(getdns_context * context)799 tls_only_is_in_transports_list(getdns_context *context) {
800 	if (context->dns_transport_count != 1)
801 		return 0;
802 	if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS)
803 			return 1;
804 	return 0;
805 }
806 
807 
808 static int
net_req_query_id_cmp(const void * id1,const void * id2)809 net_req_query_id_cmp(const void *id1, const void *id2)
810 {
811 	/*
812 	 * old code was:
813 	 * return (intptr_t)id1 - (intptr_t)id2;
814 	 *but this is incorrect on 64 bit architectures.
815 	 */
816 	int ret = 0;
817 
818 	if (id1 != id2)
819 	{
820 		ret = ((intptr_t)id1 < (intptr_t)id2) ? -1 : 1;
821 	}
822 
823 	return ret;
824 }
825 
826 
827 static getdns_tsig_info const tsig_info[] = {
828 	  { GETDNS_NO_TSIG, NULL, 0, NULL, 0, 0, 0 }
829 	, { GETDNS_HMAC_MD5   , "hmac-md5.sig-alg.reg.int", 24
830 	       , (uint8_t *)"\x08hmac-md5\x07sig-alg\x03reg\x03int", 26, 10, 16 }
831 	, { GETDNS_NO_TSIG, NULL, 0, NULL, 0, 0, 0 }
832 	, { GETDNS_HMAC_SHA1  , "hmac-sha1"  ,  9
833 	       , (uint8_t *)"\x09hmac-sha1"  , 11, 10, 20 }
834 	, { GETDNS_HMAC_SHA224, "hmac-sha224", 11
835 	       , (uint8_t *)"\x0bhmac-sha224", 13, 14, 28 }
836 	, { GETDNS_HMAC_SHA256, "hmac-sha256", 11
837 	       , (uint8_t *)"\x0bhmac-sha256", 13, 16, 32 }
838 	, { GETDNS_HMAC_SHA384, "hmac-sha384", 11
839 	       , (uint8_t *)"\x0bhmac-sha384", 13, 24, 48 }
840 	, { GETDNS_HMAC_SHA512, "hmac-sha512", 11
841 	       , (uint8_t *)"\x0bhmac-sha512", 13, 32, 64 }
842 	, { GETDNS_HMAC_MD5   , "hmac-md5"   ,  8
843 	       , (uint8_t *)"\x08hmac-md5"   , 10, 10, 16 }
844 };
845 static size_t const n_tsig_infos =
846     sizeof(tsig_info) / sizeof(getdns_tsig_info);
847 
848 static getdns_tsig_info const * const last_tsig_info =
849     tsig_info + (sizeof(tsig_info) / sizeof(getdns_tsig_info));
850 
_getdns_get_tsig_info(getdns_tsig_algo tsig_alg)851 const getdns_tsig_info *_getdns_get_tsig_info(getdns_tsig_algo tsig_alg)
852 {
853 	return ((unsigned) tsig_alg > n_tsig_infos - 1)
854 	    || tsig_info[tsig_alg].alg == GETDNS_NO_TSIG ? NULL
855 	    : &tsig_info[tsig_alg];
856 }
857 
_getdns_get_tsig_algo(getdns_bindata * algo)858 static getdns_tsig_algo _getdns_get_tsig_algo(getdns_bindata *algo)
859 {
860 	const getdns_tsig_info *i;
861 
862 	if (!algo || algo->size == 0)
863 		return GETDNS_NO_TSIG;
864 
865 	if (algo->data[algo->size-1] != 0) {
866 		/* Unterminated string */
867 		for (i = tsig_info; i < last_tsig_info; i++)
868 			if ((algo->size == i->strlen_name ||
869 			     (algo->size - 1 == i->strlen_name &&
870 			      algo->data[algo->size - 1] == '.'
871 			     )
872 			    )&&
873 			    strncasecmp((const char *)algo->data, i->name,
874 			    i->strlen_name) == 0)
875 				return i->alg;
876 
877 	} else if (!_getdns_bindata_is_dname(algo)) {
878 		/* Terminated string */
879 		for (i = tsig_info; i < last_tsig_info; i++)
880 			if (algo->size - 1 == i->strlen_name &&
881 			    strncasecmp((const char *)algo->data, i->name,
882 			    i->strlen_name) == 0)
883 				return i->alg;
884 
885 	} else {
886 		/* fqdn, canonical_dname_compare is now safe to use! */
887 		for (i = tsig_info; i < last_tsig_info; i++)
888 			if (canonical_dname_compare(algo->data, i->dname) == 0)
889 				return i->alg;
890 	}
891 	return GETDNS_NO_TSIG;
892 }
893 
894 static void
upstream_init(getdns_upstream * upstream,getdns_upstreams * parent,struct addrinfo * ai)895 upstream_init(getdns_upstream *upstream,
896     getdns_upstreams *parent, struct addrinfo *ai)
897 {
898 	upstream->upstreams = parent;
899 
900 	upstream->addr_len = ai->ai_addrlen;
901 	(void) memcpy(&upstream->addr, ai->ai_addr, ai->ai_addrlen);
902 	inet_ntop(upstream->addr.ss_family, upstream_addr(upstream),
903 	          upstream->addr_str, INET6_ADDRSTRLEN);
904 
905 	/* How is this upstream doing on connections? */
906 	upstream->conn_completed = 0;
907 	upstream->conn_shutdowns = 0;
908 	upstream->conn_setup_failed = 0;
909 	upstream->conn_retry_time = 0;
910 	upstream->conn_backoff_interval = 1;
911 	upstream->conn_backoffs = 0;
912 	upstream->total_responses = 0;
913 	upstream->total_timeouts = 0;
914 	upstream->conn_state = GETDNS_CONN_CLOSED;
915 	upstream->queries_sent = 0;
916 	upstream->responses_received = 0;
917 	upstream->responses_timeouts = 0;
918 	upstream->keepalive_shutdown = 0;
919 	upstream->keepalive_timeout = 0;
920 	upstream->server_keepalive_received = 0;
921 	/* How is this upstream doing on UDP? */
922 	upstream->to_retry =  1;
923 	upstream->back_off =  1;
924 	upstream->udp_responses = 0;
925 	upstream->udp_timeouts = 0;
926 
927 	/* For sharing a socket to this upstream with TCP  */
928 	upstream->fd       = -1;
929 	upstream->tls_obj  = NULL;
930 	upstream->tls_session = NULL;
931 	upstream->tls_cipher_list = NULL;
932 	upstream->tls_ciphersuites = NULL;
933 	upstream->tls_curves_list = NULL;
934 	upstream->tls_min_version = (getdns_tls_version_t)0;
935 	upstream->tls_max_version = (getdns_tls_version_t)0;
936 	upstream->transport = GETDNS_TRANSPORT_TCP;
937 	upstream->tls_hs_state = GETDNS_HS_NONE;
938 	upstream->tls_auth_name[0] = '\0';
939 	upstream->tls_auth_state = GETDNS_AUTH_NONE;
940 	upstream->last_tls_auth_state = GETDNS_AUTH_NONE;
941 	upstream->best_tls_auth_state = GETDNS_AUTH_NONE;
942 	upstream->tls_pubkey_pinset = NULL;
943 	upstream->loop = NULL;
944 	(void) getdns_eventloop_event_init(
945 	    &upstream->event, upstream, NULL, NULL, NULL);
946 	(void) memset(&upstream->tcp, 0, sizeof(upstream->tcp));
947 
948 	upstream->write_queue = NULL;
949 	upstream->write_queue_last = NULL;
950 
951 	upstream->finished_dnsreqs = NULL;
952 	(void) getdns_eventloop_event_init(
953 	    &upstream->finished_event, upstream, NULL, NULL, NULL);
954 
955 	upstream->has_client_cookie = 0;
956 	upstream->has_prev_client_cookie = 0;
957 	upstream->has_server_cookie = 0;
958 
959 	upstream->tsig_alg  = GETDNS_NO_TSIG;
960 	upstream->tsig_dname_len = 0;
961 	upstream->tsig_size = 0;
962 
963 	/* Tracking of network requests on this socket */
964 	_getdns_rbtree_init(&upstream->netreq_by_query_id,
965 	    net_req_query_id_cmp);
966 }
967 
968 #ifdef USE_WINSOCK
969 
970 /*
971 Read the Windows search suffix and add to context
972 There may or may not be domains and suffixes so do not error if missing
973 */
get_dns_suffix_windows(getdns_list * suffix,char * domain)974 static int get_dns_suffix_windows(getdns_list *suffix, char* domain)
975 {
976     char *parse, *token, prev_ch;
977     char lszValue[255] = "";
978     char lszDomain[255] = "";
979     HKEY hKey;
980     LONG returnStatus;
981     DWORD dwType=REG_SZ;
982     DWORD dwSize=255;
983     returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
984                     "SYSTEM\\CurrentControlSet\\Services\\TcpIp\\Parameters",
985                      0,  KEY_READ, &hKey);
986     if (returnStatus != ERROR_SUCCESS)
987     {
988         /* try windows 9x/me */
989         returnStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
990                     "SYSTEM\\CurrentControlSet\\Services\\VxD\\MSTCP",
991                      0,  KEY_READ, &hKey);
992 
993     }
994     if (returnStatus == ERROR_SUCCESS)
995     {
996         returnStatus = RegQueryValueEx(hKey,
997              TEXT("SearchList"), 0, &dwType,(LPBYTE)&lszValue, &dwSize);
998         if (returnStatus == ERROR_SUCCESS)
999         {
1000            if ((strlen(lszValue)) > 0) {
1001            parse = lszValue;
1002            do {
1003                parse += strspn(parse, ",");
1004                token = parse + strcspn(parse, ",");
1005                prev_ch = *token;
1006                *token = 0;
1007                _getdns_list_append_string(suffix, parse);
1008 
1009                *token = prev_ch;
1010                parse = token;
1011            } while (*parse);
1012            }
1013 
1014         }
1015 
1016         dwSize = 255;
1017         returnStatus = RegQueryValueEx(hKey,
1018              TEXT("Domain"), 0, &dwType,(LPBYTE)&lszDomain, &dwSize);
1019         if (returnStatus == ERROR_SUCCESS)
1020         {
1021              strcpy_s(domain, dwSize, lszDomain);
1022         }
1023 
1024         RegCloseKey(hKey);
1025     } else {
1026         return 0; /* no DNS keys or suffixes */
1027     }
1028 
1029     return 1;
1030 }
1031 
1032 
1033 static getdns_return_t
set_os_defaults_windows(getdns_context * context)1034 set_os_defaults_windows(getdns_context *context)
1035 {
1036     char domain[1024] = "";
1037     size_t upstreams_limit = 10;
1038     struct addrinfo hints;
1039     struct addrinfo *result;
1040     getdns_list *suffix;
1041     getdns_upstream *upstream;
1042     size_t length;
1043     int s;
1044 	uint32_t info_err = 0;
1045 
1046     if (!(context->upstreams = upstreams_create(context, upstreams_limit)))
1047 	    return GETDNS_RETURN_MEMORY_ERROR;
1048 
1049     memset(&hints, 0, sizeof(struct addrinfo));
1050     hints.ai_family = AF_UNSPEC;      /* Allow IPv4 or IPv6 */
1051     hints.ai_socktype = 0;              /* Datagram socket */
1052     hints.ai_flags = AI_NUMERICHOST; /* No reverse name lookups */
1053     hints.ai_protocol = 0;              /* Any protocol */
1054     hints.ai_canonname = NULL;
1055     hints.ai_addr = NULL;
1056     hints.ai_next = NULL;
1057 
1058     FIXED_INFO *info;
1059     ULONG buflen = sizeof(*info);
1060     IP_ADDR_STRING *ptr = 0;
1061 
1062     info = (FIXED_INFO *)malloc(sizeof(FIXED_INFO));
1063     if (info == NULL)
1064 		return GETDNS_RETURN_MEMORY_ERROR;
1065 
1066 	if ((info_err = GetNetworkParams(info, &buflen)) == ERROR_BUFFER_OVERFLOW) {
1067 		free(info);
1068 		info = (FIXED_INFO *)malloc(buflen);
1069 		if (info == NULL)
1070 			return GETDNS_RETURN_GENERIC_ERROR;
1071 		info_err = GetNetworkParams(info, &buflen);
1072 	}
1073 
1074 	if (info_err == NO_ERROR) {
1075 		ptr = &info->DnsServerList;
1076 		*domain = 0;
1077 		while (ptr) {
1078 			size_t i;
1079 			for (i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) {
1080 				char *port_str = getdns_port_str_array[i];
1081 				if ((s = getaddrinfo(ptr->IpAddress.String, port_str, &hints, &result)))
1082 					continue;
1083 				if (!result)
1084 					continue;
1085 
1086 				upstream = &context->upstreams->
1087 					upstreams[context->upstreams->count++];
1088 				upstream_init(upstream, context->upstreams, result);
1089 				upstream->transport = getdns_upstream_transports[i];
1090 				freeaddrinfo(result);
1091 			}
1092 			ptr = ptr->Next;
1093 		}
1094 	}
1095 
1096 	if (info != NULL)
1097 		free(info);
1098 
1099     suffix = getdns_list_create_with_context(context);
1100 
1101     if (get_dns_suffix_windows(suffix, domain)) {
1102         (void) getdns_list_get_length(suffix, &length);
1103         if (*domain != 0) {
1104             _getdns_list_append_string(suffix, domain);
1105         }
1106         (void) getdns_list_get_length(suffix, &length);
1107         if (length > 0) {
1108             (void )getdns_context_set_suffix(context, suffix);
1109         }
1110     }
1111     getdns_list_destroy(suffix);
1112 
1113     return GETDNS_RETURN_GOOD;
1114 } /* set_os_defaults_windows */
1115 
1116 #else
1117 
1118 getdns_return_t
getdns_context_set_resolvconf(getdns_context * context,const char * resolvconf)1119 getdns_context_set_resolvconf(getdns_context *context, const char *resolvconf)
1120 {
1121 	FILE *in;
1122 	char line[1024], domain[1024];
1123 	char *parse, *token, prev_ch;
1124 	size_t upstream_count, length;
1125 	struct addrinfo hints;
1126 	struct addrinfo *result;
1127 	getdns_upstream *upstream;
1128 	getdns_list     *suffix;
1129 	int s;
1130 
1131 	if (!context || !resolvconf)
1132 		return GETDNS_RETURN_INVALID_PARAMETER;
1133 
1134 
1135 	(void) strlcpy( context->fchg_resolvconf.fn, resolvconf, _GETDNS_PATH_MAX);
1136 	(void) memset(&context->fchg_resolvconf.prevstat, 0, sizeof(struct stat));
1137 	context->fchg_resolvconf.changes = GETDNS_FCHG_NOCHANGES;
1138 	context->fchg_resolvconf.errors = GETDNS_FCHG_NOERROR;
1139 	(void) _getdns_filechg_check(&context->fchg_resolvconf);
1140 
1141 	if (!(in = fopen(context->fchg_resolvconf.fn, "r")))
1142 		return GETDNS_RETURN_IO_ERROR;
1143 
1144 	upstream_count = 0;
1145 	while (fgets(line, (int)sizeof(line), in))
1146 		if (strncmp(line, "nameserver", 10) == 0)
1147 			upstream_count++;
1148 	fclose(in);
1149 
1150 	suffix = getdns_list_create_with_context(context);
1151 	if (context->upstreams) {
1152 		_getdns_upstreams_dereference(context->upstreams);
1153 		context->upstreams = NULL;
1154 	}
1155 	if (!(context->upstreams = upstreams_create(
1156 	    context, upstream_count * GETDNS_UPSTREAM_TRANSPORTS))) {
1157 		return GETDNS_RETURN_MEMORY_ERROR;
1158 	}
1159 	if (!(in = fopen(context->fchg_resolvconf.fn, "r")))
1160 		return GETDNS_RETURN_IO_ERROR;
1161 
1162 	memset(&hints, 0, sizeof(struct addrinfo));
1163 	hints.ai_family    = AF_UNSPEC;      /* Allow IPv4 or IPv6 */
1164 	hints.ai_socktype  = 0;              /* Datagram socket */
1165 	hints.ai_flags     = AI_NUMERICHOST; /* No reverse name lookups */
1166 	hints.ai_protocol  = 0;              /* Any protocol */
1167 	hints.ai_canonname = NULL;
1168 	hints.ai_addr      = NULL;
1169 	hints.ai_next      = NULL;
1170 
1171 	*domain = 0;
1172 	while (fgets(line, (int)sizeof(line), in)) {
1173 		size_t i;
1174 
1175 		line[sizeof(line)-1] = 0;
1176 		/* parse = line + strspn(line, " \t"); */ /* No leading whitespace */
1177 		parse = line;
1178 
1179 		if (strncmp(parse, "domain", 6) == 0) {
1180 			parse += 6;
1181 			parse += strspn(parse, " \t");
1182 			if (*parse == 0 || *parse == '#') continue;
1183 			token = parse + strcspn(parse, " \t\r\n");
1184 			*token = 0;
1185 
1186 			(void) strlcpy(domain, parse, sizeof(domain));
1187 			continue;
1188 		}
1189 		if (strncmp(parse, "search", 6) == 0) {
1190 			parse += 6;
1191 			do {
1192 				parse += strspn(parse, " \t");
1193 				if (*parse == '#' || *parse == '\n') break;
1194 				token = parse + strcspn(parse, " \t\r\n");
1195 				prev_ch = *token;
1196 				*token = 0;
1197 
1198 				_getdns_list_append_string(suffix, parse);
1199 
1200 				*token = prev_ch;
1201 				parse = token;
1202 			} while (*parse);
1203 			continue;
1204 		}
1205 		if (strncmp(parse, "nameserver", 10) != 0)
1206 			continue;
1207 
1208 		parse += 10;
1209 		parse += strspn(parse, " \t");
1210 		if (*parse == 0 || *parse == '#') continue;
1211 		token = parse + strcspn(parse, " \t\r\n");
1212 		*token = 0;
1213 
1214 		for (i = 0; i < GETDNS_UPSTREAM_TRANSPORTS; i++) {
1215 			char *port_str = getdns_port_str_array[i];
1216 			if ((s = getaddrinfo(parse, port_str, &hints, &result)))
1217 				continue;
1218 			if (!result)
1219 				continue;
1220 
1221 			upstream = &context->upstreams->
1222 			    upstreams[context->upstreams->count++];
1223 			upstream_init(upstream, context->upstreams, result);
1224 			upstream->transport = getdns_upstream_transports[i];
1225 			freeaddrinfo(result);
1226 		}
1227 	}
1228 	fclose(in);
1229 
1230 	(void) getdns_list_get_length(suffix, &length);
1231 	if (length == 0 && *domain != 0)
1232 		_getdns_list_append_string(suffix, domain);
1233 	(void )getdns_context_set_suffix(context, suffix);
1234 	getdns_list_destroy(suffix);
1235 
1236 	dispatch_updated(context,
1237 		GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
1238 
1239 	return GETDNS_RETURN_GOOD;
1240 } /* set_os_defaults */
1241 #endif
1242 
1243 getdns_return_t
getdns_context_get_resolvconf(const getdns_context * context,const char ** resolvconf)1244 getdns_context_get_resolvconf(
1245     const getdns_context *context, const char **resolvconf)
1246 {
1247 	if (!context || !resolvconf)
1248 		return GETDNS_RETURN_INVALID_PARAMETER;
1249 
1250 	*resolvconf = *context->fchg_resolvconf.fn
1251 	            ?  context->fchg_resolvconf.fn : NULL;
1252 	return GETDNS_RETURN_GOOD;
1253 }
1254 
1255 
1256 /* compare of transaction ids in DESCENDING order
1257    so that 0 comes last
1258 */
1259 static int
transaction_id_cmp(const void * id1,const void * id2)1260 transaction_id_cmp(const void *id1, const void *id2)
1261 {
1262     if (id1 == NULL && id2 == NULL) {
1263         return 0;
1264     } else if (id1 == NULL && id2 != NULL) {
1265         return 1;
1266     } else if (id1 != NULL && id2 == NULL) {
1267         return -1;
1268     } else {
1269         getdns_transaction_t t1 =
1270             *((const getdns_transaction_t *) id1);
1271         getdns_transaction_t t2 =
1272             *((const getdns_transaction_t *) id2);
1273         if (t1 == t2) {
1274             return 0;
1275         } else if (t1 > t2) {
1276             return -1;
1277         } else {
1278             return 1;
1279         }
1280     }
1281 }
1282 
1283 static void
NULL_update_callback(getdns_context * context,getdns_context_code_t code,void * userarg)1284 NULL_update_callback(
1285     getdns_context *context, getdns_context_code_t code, void *userarg)
1286 { (void)context; (void)code; (void)userarg; }
1287 
1288 static int
netreq_expiry_cmp(const void * id1,const void * id2)1289 netreq_expiry_cmp(const void *id1, const void *id2)
1290 {
1291 	getdns_network_req *req1 = (getdns_network_req *)id1;
1292 	getdns_network_req *req2 = (getdns_network_req *)id2;
1293 
1294 	return req1->owner->expires < req2->owner->expires ? -1 :
1295 	       req1->owner->expires > req2->owner->expires ?  1 :
1296 	       req1 < req2 ? -1 :
1297 	       req1 > req2 ?  1 : 0;
1298 }
1299 
1300 void _getdns_check_expired_pending_netreqs(
1301     getdns_context *context, uint64_t *now_ms);
_getdns_check_expired_pending_netreqs_cb(void * arg)1302 static void _getdns_check_expired_pending_netreqs_cb(void *arg)
1303 {
1304 	uint64_t now_ms = 0;
1305 	_getdns_check_expired_pending_netreqs((getdns_context *)arg, &now_ms);
1306 }
1307 
1308 static char const * const _getdns_default_trust_anchors_url =
1309     "http://data.iana.org/root-anchors/root-anchors.xml";
1310 
1311 /* The ICANN CA fetched at 24 Sep 2010.  Valid to 2028 */
1312 static char const * const _getdns_default_trust_anchors_verify_CA =
1313 "-----BEGIN CERTIFICATE-----\n"
1314 "MIIDdzCCAl+gAwIBAgIBATANBgkqhkiG9w0BAQsFADBdMQ4wDAYDVQQKEwVJQ0FO\n"
1315 "TjEmMCQGA1UECxMdSUNBTk4gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxFjAUBgNV\n"
1316 "BAMTDUlDQU5OIFJvb3QgQ0ExCzAJBgNVBAYTAlVTMB4XDTA5MTIyMzA0MTkxMloX\n"
1317 "DTI5MTIxODA0MTkxMlowXTEOMAwGA1UEChMFSUNBTk4xJjAkBgNVBAsTHUlDQU5O\n"
1318 "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1JQ0FOTiBSb290IENB\n"
1319 "MQswCQYDVQQGEwJVUzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKDb\n"
1320 "cLhPNNqc1NB+u+oVvOnJESofYS9qub0/PXagmgr37pNublVThIzyLPGCJ8gPms9S\n"
1321 "G1TaKNIsMI7d+5IgMy3WyPEOECGIcfqEIktdR1YWfJufXcMReZwU4v/AdKzdOdfg\n"
1322 "ONiwc6r70duEr1IiqPbVm5T05l1e6D+HkAvHGnf1LtOPGs4CHQdpIUcy2kauAEy2\n"
1323 "paKcOcHASvbTHK7TbbvHGPB+7faAztABLoneErruEcumetcNfPMIjXKdv1V1E3C7\n"
1324 "MSJKy+jAqqQJqjZoQGB0necZgUMiUv7JK1IPQRM2CXJllcyJrm9WFxY0c1KjBO29\n"
1325 "iIKK69fcglKcBuFShUECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8B\n"
1326 "Af8EBAMCAf4wHQYDVR0OBBYEFLpS6UmDJIZSL8eZzfyNa2kITcBQMA0GCSqGSIb3\n"
1327 "DQEBCwUAA4IBAQAP8emCogqHny2UYFqywEuhLys7R9UKmYY4suzGO4nkbgfPFMfH\n"
1328 "6M+Zj6owwxlwueZt1j/IaCayoKU3QsrYYoDRolpILh+FPwx7wseUEV8ZKpWsoDoD\n"
1329 "2JFbLg2cfB8u/OlE4RYmcxxFSmXBg0yQ8/IoQt/bxOcEEhhiQ168H2yE5rxJMt9h\n"
1330 "15nu5JBSewrCkYqYYmaxyOC3WrVGfHZxVI7MpIFcGdvSb2a1uyuua8l0BKgk3ujF\n"
1331 "0/wsHNeP22qNyVO+XVBzrM8fk8BSUFuiT/6tZTYXRtEt5aKQZgXbKU5dUF3jT9qg\n"
1332 "j/Br5BZw3X/zd325TvnswzMC1+ljLzHnQGGk\n"
1333 "-----END CERTIFICATE-----\n";
1334 
1335 static char const * const _getdns_default_trust_anchors_verify_email =
1336     "dnssec@iana.org";
1337 
1338 /*
1339  * getdns_context_create
1340  *
1341  * Call this to initialize the context that is used in other getdns calls.
1342  */
1343 getdns_return_t
getdns_context_create_with_extended_memory_functions(getdns_context ** context,int set_from_os,void * userarg,void * (* malloc)(void * userarg,size_t),void * (* realloc)(void * userarg,void *,size_t),void (* free)(void * userarg,void *))1344 getdns_context_create_with_extended_memory_functions(
1345     getdns_context **context,
1346     int set_from_os,
1347     void *userarg,
1348     void *(*malloc)(void *userarg, size_t),
1349     void *(*realloc)(void *userarg, void *, size_t),
1350     void (*free)(void *userarg, void *)
1351     )
1352 {
1353 	getdns_return_t r;
1354 	struct getdns_context *result = NULL;
1355 	mf_union mf;
1356 	gldns_buffer gbuf;
1357 #ifdef USE_WINSOCK
1358 	WORD wVersionRequested;
1359 #endif
1360 
1361 	if (!context || !malloc || !realloc || !free)
1362 		return GETDNS_RETURN_INVALID_PARAMETER;
1363 
1364 	/** default init **/
1365 	mf.ext.malloc = malloc;
1366 	result = userarg == MF_PLAIN
1367 	    ? (*mf.pln.malloc)(         sizeof(struct getdns_context))
1368 	    : (*mf.ext.malloc)(userarg, sizeof(struct getdns_context));
1369 
1370 	if (!result)
1371 		return GETDNS_RETURN_MEMORY_ERROR;
1372 
1373 #ifdef USE_WINSOCK
1374 	/* We need to run WSAStartup() to be able to use getaddrinfo() */
1375 	wVersionRequested = MAKEWORD(2, 2);
1376 	if (WSAStartup(wVersionRequested, &result->wsaData)) {
1377 		r = GETDNS_RETURN_GENERIC_ERROR;
1378 		goto error;
1379 	}
1380 #endif
1381 	result->processing = 0;
1382 	result->destroying = 0;
1383 	result->my_mf.mf_arg         = userarg;
1384 	result->my_mf.mf.ext.malloc  = malloc;
1385 	result->my_mf.mf.ext.realloc = realloc;
1386 	result->my_mf.mf.ext.free    = free;
1387 
1388 	result->update_callback  = NULL;
1389 	result->update_callback2 = NULL_update_callback;
1390 	result->update_userarg   = NULL;
1391 
1392 	result->log.func    = NULL;
1393 	result->log.userarg = NULL;
1394 	result->log.system  = 0;
1395 	result->log.level   = GETDNS_LOG_ERR;
1396 
1397 	result->mf.mf_arg         = userarg;
1398 	result->mf.mf.ext.malloc  = malloc;
1399 	result->mf.mf.ext.realloc = realloc;
1400 	result->mf.mf.ext.free    = free;
1401 
1402 	result->resolution_type_set = 0;
1403 
1404 	_getdns_rbtree_init(&result->outbound_requests, transaction_id_cmp);
1405 	_getdns_rbtree_init(&result->local_hosts, local_host_cmp);
1406 	_getdns_rbtree_init(&result->pending_netreqs, netreq_expiry_cmp);
1407 	result->first_pending_netreq = NULL;
1408 	result->netreqs_in_flight = 0;
1409 	result->pending_timeout_event.userarg    = result;
1410 	result->pending_timeout_event.read_cb    = NULL;
1411 	result->pending_timeout_event.write_cb   = NULL;
1412 	result->pending_timeout_event.timeout_cb =
1413 	    _getdns_check_expired_pending_netreqs_cb;
1414 	result->pending_timeout_event.ev         = NULL;
1415 
1416 	result->server = NULL;
1417 
1418 #ifdef HAVE_LIBUNBOUND
1419 	result->resolution_type = GETDNS_RESOLUTION_RECURSING;
1420 #else
1421 	result->resolution_type = GETDNS_RESOLUTION_STUB;
1422 #endif
1423 	if ((r = create_default_namespaces(result)))
1424 		goto error;
1425 
1426 	result->timeout = 5000;
1427 	result->idle_timeout = 0;
1428 	result->follow_redirects = GETDNS_REDIRECTS_FOLLOW;
1429 	result->dns_root_servers = NULL;
1430 #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
1431 	result->root_servers_fn[0] = 0;
1432 #endif
1433 	result->append_name = GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST;
1434 	result->suffixes = no_suffixes;
1435 	result->suffixes_len = sizeof(no_suffixes);
1436 
1437 	result->trust_anchors_source = GETDNS_TASRC_NONE;
1438 	result->can_write_appdata = PROP_UNKNOWN;
1439 	result->trust_anchors_url = NULL;
1440 	result->trust_anchors_verify_email = NULL;
1441 	result->trust_anchors_verify_CA = NULL;
1442 	result->trust_anchors_backoff_time = 2500;
1443 	result->appdata_dir = NULL;
1444 	result->tls_ca_path = NULL;
1445 	result->tls_ca_file = NULL;
1446 	result->tls_cipher_list = NULL;
1447 	result->tls_ciphersuites = NULL;
1448 	result->tls_curves_list = NULL;
1449 	result->tls_min_version = GETDNS_TLS1_2;
1450 	result->tls_max_version = (getdns_tls_version_t)0;
1451 
1452 	(void) memset(&result->root_ksk, 0, sizeof(result->root_ksk));
1453 
1454 	(void) memset(&result->a, 0, sizeof(result->a));
1455 	(void) memset(&result->aaaa, 0, sizeof(result->aaaa));
1456 	result->a.fd = -1;
1457 	result->aaaa.fd = -1;
1458 
1459 	gldns_buffer_init_vfixed_frm_data(&gbuf, result->trust_anchors_spc
1460 	                                , sizeof(result->trust_anchors_spc));
1461 
1462 	if (!_getdns_parse_ta_file(NULL, &gbuf)) {
1463 		result->trust_anchors = NULL;
1464 		result->trust_anchors_len = 0;
1465 
1466 	} else if ((result->trust_anchors_len = gldns_buffer_position(&gbuf))
1467 		    > sizeof(result->trust_anchors_spc)) {
1468 
1469 		if ((result->trust_anchors = GETDNS_XMALLOC(
1470 		    result->mf, uint8_t, result->trust_anchors_len))) {
1471 
1472 			gldns_buffer_init_frm_data(&gbuf
1473 			                          , result->trust_anchors
1474 						  , result->trust_anchors_len);
1475 			if (!_getdns_parse_ta_file(NULL, &gbuf)) {
1476 				GETDNS_FREE(result->mf, result->trust_anchors);
1477 				result->trust_anchors = NULL;
1478 				result->trust_anchors_len = 0;
1479 			} else
1480 				result->trust_anchors_source = GETDNS_TASRC_ZONE;
1481 		}
1482 	} else {
1483 		result->trust_anchors = result->trust_anchors_spc;
1484 		result->trust_anchors_source = GETDNS_TASRC_ZONE;
1485 	}
1486 
1487 	result->upstreams = NULL;
1488 
1489 	result->edns_extended_rcode = 0;
1490 	result->edns_version = 0;
1491 	result->edns_do_bit = 0;
1492 	result->edns_client_subnet_private = 0;
1493 	result->tls_query_padding_blocksize = 1; /* default is to pad queries sensibly */
1494 	result->tls_ctx = NULL;
1495 
1496 	result->extension = &result->default_eventloop.loop;
1497 	_getdns_default_eventloop_init(&result->mf, &result->default_eventloop);
1498 	_getdns_default_eventloop_init(&result->mf, &result->sync_eventloop);
1499 
1500 	/* request extension defaults
1501 	 */
1502 	result->header = NULL;
1503 	result->add_opt_parameters = NULL;
1504 	result->add_warning_for_bad_dns = 0;
1505 	result->dnssec = 0;
1506 	result->dnssec_return_all_statuses = 0;
1507 	result->dnssec_return_full_validation_chain = 0;
1508 	result->dnssec_return_only_secure = 0;
1509 	result->dnssec_return_status = 0;
1510 	result->dnssec_return_validation_chain = 0;
1511 #ifdef DNSSEC_ROADBLOCK_AVOIDANCE
1512 	result->dnssec_roadblock_avoidance = 0;
1513 #endif
1514 	result->edns_cookies = 0;
1515 	result->return_api_information = 0;
1516 	result->return_both_v4_and_v6 = 0;
1517 	result->return_call_reporting = 0;
1518 	result->specify_class = GETDNS_RRCLASS_IN;
1519 
1520 	result->sys_ctxt  = NULL;
1521 	result->ta_notify = NULL;
1522 
1523 	/* state data used to detect changes to the system config files
1524 	 */
1525 	(void)memset(&result->fchg_resolvconf, 0, sizeof(struct filechg));
1526 	(void)memset(&result->fchg_hosts     , 0, sizeof(struct filechg));
1527 
1528 	result->dnssec_allowed_skew = 0;
1529 	result->edns_maximum_udp_payload_size = -1;
1530 	if ((r = create_default_dns_transports(result)))
1531 		goto error;
1532 	result->tls_auth = GETDNS_AUTHENTICATION_NONE;
1533 	result->tls_auth_min = GETDNS_AUTHENTICATION_NONE;
1534 	result->round_robin_upstreams = 0;
1535 	result->tls_backoff_time = 3600;
1536 	result->tls_connection_retries = 2;
1537 	result->limit_outstanding_queries = 0;
1538 	result->max_backoff_value = UDP_MAX_BACKOFF;
1539 
1540 	/* unbound context is initialized here */
1541 	/* Unbound needs SSL to be init'ed this early when TLS is used. However we
1542 	 * don't know that till later so we will have to do this every time. */
1543 
1544 #ifdef HAVE_PTHREAD
1545 	pthread_mutex_lock(&ssl_init_lock);
1546 #else
1547 	/* XXX implement Windows-style lock here */
1548 #endif
1549 	/* Only initialise SSL once and ideally in a thread-safe manner */
1550 	if (ssl_init == false) {
1551 		_getdns_tls_init();
1552 		ssl_init = true;
1553 	}
1554 #ifdef HAVE_PTHREAD
1555 	pthread_mutex_unlock(&ssl_init_lock);
1556 #else
1557 	/* XXX implement Windows-style unlock here */
1558 #endif
1559 #ifdef HAVE_LIBUNBOUND
1560 	result->unbound_ctx = NULL;
1561 	if ((r = rebuild_ub_ctx(result)))
1562 		goto error;
1563 #endif
1564 
1565 
1566 #ifdef HAVE_MDNS_SUPPORT
1567 	_getdns_mdns_context_init(result);
1568 #endif
1569 
1570 	// resolv.conf does not exist on Windows, handle differently
1571 #ifndef USE_WINSOCK
1572 	if ((set_from_os & 1)) {
1573 		(void) getdns_context_set_resolvconf(result, GETDNS_FN_RESOLVCONF);
1574 		(void) getdns_context_set_hosts(result, GETDNS_FN_HOSTS);
1575 	}
1576 #else
1577 	if ((set_from_os & 1) && (r = set_os_defaults_windows(result)))
1578 		goto error;
1579 #endif
1580 
1581 	*context = result;
1582 	return GETDNS_RETURN_GOOD;
1583 error:
1584 	getdns_context_destroy(result);
1585 	return r;
1586 } /* getdns_context_create_with_extended_memory_functions */
1587 
1588 /*
1589  * getdns_context_create
1590  *
1591  * Call this to initialize the context that is used in other getdns calls.
1592  */
1593 getdns_return_t
getdns_context_create_with_memory_functions(struct getdns_context ** context,int set_from_os,void * (* malloc)(size_t),void * (* realloc)(void *,size_t),void (* free)(void *))1594 getdns_context_create_with_memory_functions(struct getdns_context ** context,
1595     int set_from_os,
1596     void *(*malloc)(size_t),
1597     void *(*realloc)(void *, size_t),
1598     void (*free)(void *)
1599     )
1600 {
1601     mf_union mf;
1602     mf.pln.malloc = malloc;
1603     mf.pln.realloc = realloc;
1604     mf.pln.free = free;
1605     return getdns_context_create_with_extended_memory_functions(
1606         context, set_from_os, MF_PLAIN,
1607         mf.ext.malloc, mf.ext.realloc, mf.ext.free);
1608 }               /* getdns_context_create */
1609 
1610 /*
1611  * getdns_context_create
1612  *
1613  * Call this to initialize the context that is used in other getdns calls.
1614  */
1615 getdns_return_t
getdns_context_create(struct getdns_context ** context,int set_from_os)1616 getdns_context_create(struct getdns_context ** context, int set_from_os)
1617 {
1618     return getdns_context_create_with_memory_functions(context,
1619             set_from_os, malloc, realloc, free);
1620 }               /* getdns_context_create */
1621 
1622 /*
1623  * getdns_context_destroy
1624  *
1625  * Call this to dispose of resources associated with a context once you
1626  * are done with it.
1627  */
1628 void
getdns_context_destroy(struct getdns_context * context)1629 getdns_context_destroy(struct getdns_context *context)
1630 {
1631 	if (context == NULL)
1632 		return;
1633 
1634 	/*  If being destroyed during getdns callback, fail via assert */
1635 	assert(context->processing == 0);
1636 	if (context->destroying)
1637 		return;
1638 
1639 	context->destroying = 1;
1640 
1641 	if (context->sys_ctxt)
1642 		getdns_context_destroy(context->sys_ctxt);
1643 
1644 	/* cancel all outstanding requests */
1645 	cancel_outstanding_requests(context);
1646 
1647 	/* Destroy listening addresses */
1648 	(void) getdns_context_set_listen_addresses(context, NULL, NULL, NULL);
1649 
1650 	/* This needs to be done before cleaning the extension, because there
1651 	 * might be an idle_timeout schedules, which will not get unscheduled
1652 	 * with cancel_outstanding_requests.
1653 	 */
1654 	_getdns_upstreams_dereference(context->upstreams);
1655 
1656 	context->sync_eventloop.loop.vmt->cleanup(&context->sync_eventloop.loop);
1657 	context->extension->vmt->cleanup(context->extension);
1658 #ifdef HAVE_LIBUNBOUND
1659 	if (context->unbound_ctx)
1660 		ub_ctx_delete(context->unbound_ctx);
1661 #endif
1662 
1663 #ifdef HAVE_MDNS_SUPPORT
1664 	/*
1665 	 * Release all ressource allocated for MDNS.
1666 	 */
1667 	_getdns_mdns_context_destroy(context);
1668 #endif
1669 
1670 	if (context->namespaces)
1671 		GETDNS_FREE(context->my_mf, context->namespaces);
1672 
1673 	if (context->dns_transports)
1674 		GETDNS_FREE(context->my_mf, context->dns_transports);
1675 
1676 	if (context->tls_ctx)
1677 		_getdns_tls_context_free(&context->my_mf, context->tls_ctx);
1678 
1679 	getdns_list_destroy(context->dns_root_servers);
1680 
1681 #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
1682 	if (context->root_servers_fn[0])
1683 		unlink(context->root_servers_fn);
1684 #endif
1685 
1686 	if (context->suffixes && context->suffixes != no_suffixes)
1687 		GETDNS_FREE(context->mf, (void *)context->suffixes);
1688 
1689 	if (context->trust_anchors &&
1690 	    context->trust_anchors != context->trust_anchors_spc)
1691 		GETDNS_FREE(context->mf, context->trust_anchors);
1692 
1693 	_getdns_traverse_postorder(&context->local_hosts,
1694 	    destroy_local_host, context);
1695 
1696 	getdns_dict_destroy(context->header);
1697 	getdns_dict_destroy(context->add_opt_parameters);
1698 
1699 	if (context->trust_anchors_url)
1700 		GETDNS_FREE(context->mf, context->trust_anchors_url);
1701 	if (context->trust_anchors_verify_CA)
1702 		GETDNS_FREE( context->mf
1703 		           , context->trust_anchors_verify_CA);
1704 	if (context->trust_anchors_verify_email)
1705 		GETDNS_FREE( context->mf
1706 		           , context->trust_anchors_verify_email);
1707 	if (context->appdata_dir)
1708 		GETDNS_FREE(context->mf, context->appdata_dir);
1709 	if (context->tls_ca_path)
1710 		GETDNS_FREE(context->mf, context->tls_ca_path);
1711 	if (context->tls_ca_file)
1712 		GETDNS_FREE(context->mf, context->tls_ca_file);
1713 	if (context->tls_cipher_list)
1714 		GETDNS_FREE(context->mf, context->tls_cipher_list);
1715 	if (context->tls_ciphersuites)
1716 		GETDNS_FREE(context->mf, context->tls_ciphersuites);
1717 	if (context->tls_curves_list)
1718 		GETDNS_FREE(context->mf, context->tls_curves_list);
1719 
1720 #ifdef USE_WINSOCK
1721 	WSACleanup();
1722 #endif
1723 	GETDNS_FREE(context->my_mf, context);
1724 }               /* getdns_context_destroy */
1725 
1726 /*
1727  * getdns_context_set_context_update_callback
1728  *
1729  */
1730 getdns_return_t
getdns_context_set_context_update_callback(struct getdns_context * context,void (* value)(struct getdns_context * context,getdns_context_code_t changed_item))1731 getdns_context_set_context_update_callback(struct getdns_context *context,
1732     void (*value) (struct getdns_context *context,
1733                    getdns_context_code_t changed_item))
1734 {
1735     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
1736     context->update_callback = value;
1737     return GETDNS_RETURN_GOOD;
1738 }               /* getdns_context_set_context_update_callback */
1739 
1740 getdns_return_t
getdns_context_set_update_callback(getdns_context * context,void * userarg,void (* cb)(getdns_context *,getdns_context_code_t,void *))1741 getdns_context_set_update_callback(getdns_context *context, void *userarg,
1742     void (*cb)(getdns_context *, getdns_context_code_t, void *))
1743 {
1744 	if (!context) return GETDNS_RETURN_INVALID_PARAMETER;
1745 	context->update_userarg = userarg;
1746 	context->update_callback2 = cb ? cb : NULL_update_callback;
1747 	return GETDNS_RETURN_GOOD;
1748 }
1749 
1750 getdns_return_t
getdns_context_get_update_callback(const getdns_context * context,void ** userarg,void (** cb)(getdns_context *,getdns_context_code_t,void *))1751 getdns_context_get_update_callback(const getdns_context *context,
1752     void **userarg,
1753     void (**cb)(getdns_context *, getdns_context_code_t, void *))
1754 {
1755 	if (!context || !userarg || !cb)
1756 		return GETDNS_RETURN_INVALID_PARAMETER;
1757 
1758 	*userarg = context->update_userarg;
1759 	*cb = context->update_callback2;
1760 	return GETDNS_RETURN_GOOD;
1761 }
1762 
1763 getdns_return_t
getdns_context_set_logfunc(getdns_context * context,void * userarg,uint64_t system,getdns_loglevel_type level,getdns_logfunc_type log)1764 getdns_context_set_logfunc(getdns_context *context, void *userarg,
1765     uint64_t system, getdns_loglevel_type level, getdns_logfunc_type log)
1766 {
1767 	if (!context)
1768 		return GETDNS_RETURN_INVALID_PARAMETER;
1769 
1770 	context->log.func = log;
1771 	context->log.userarg = userarg;
1772 	context->log.system = system;
1773 	context->log.level = level;
1774 	if (context->upstreams) {
1775 		context->upstreams->log = context->log;
1776 	}
1777 	return GETDNS_RETURN_GOOD;
1778 }
1779 
1780 #ifdef HAVE_LIBUNBOUND
1781 /*
1782  * Helpers to set options on the unbound ctx
1783  */
1784 static void
set_ub_string_opt(struct getdns_context * ctx,char * opt,char * value)1785 set_ub_string_opt(struct getdns_context *ctx, char *opt, char *value)
1786 {
1787     if (ctx->unbound_ctx)
1788         ub_ctx_set_option(ctx->unbound_ctx, opt, value);
1789 }
1790 
1791 static void
set_ub_number_opt(struct getdns_context * ctx,char * opt,uint16_t value)1792 set_ub_number_opt(struct getdns_context *ctx, char *opt, uint16_t value)
1793 {
1794     char buffer[64];
1795     snprintf(buffer, 64, "%hu", value);
1796     set_ub_string_opt(ctx, opt, buffer);
1797 }
1798 
1799 static void
getdns_context_request_count_changed(getdns_context * context)1800 getdns_context_request_count_changed(getdns_context *context)
1801 {
1802 	size_t prev_count;
1803 
1804 	if (context->ub_event_scheduling) {
1805 		return;
1806 	}
1807 	context->ub_event_scheduling++;
1808 	do {
1809 		prev_count = context->outbound_requests.count;
1810 		DEBUG_SCHED("getdns_context_request_count_changed(%d)\n",
1811 		    (int) context->outbound_requests.count);
1812 		if (context->outbound_requests.count && ! context->ub_event.ev){
1813 			DEBUG_SCHED("gc_request_count_changed "
1814 			    "-> ub schedule(el_ev = %p, el_ev->ev = %p)\n",
1815 			    (void *)&context->ub_event, (void *)context->ub_event.ev);
1816 #ifndef USE_WINSOCK
1817 #ifdef HAVE_UNBOUND_EVENT_API
1818 			if (!_getdns_ub_loop_enabled(&context->ub_loop))
1819 #endif
1820 				context->extension->vmt->schedule(
1821 				    context->extension,
1822 				    ub_fd(context->unbound_ctx),
1823 				    TIMEOUT_FOREVER, &context->ub_event);
1824 #endif
1825 		} else if (! context->outbound_requests.count &&
1826 		    context->ub_event.ev) {
1827 			DEBUG_SCHED("gc_request_count_changed "
1828 			    "-> ub clear(el_ev = %p, el_ev->ev = %p)\n",
1829 			    (void *)&context->ub_event, (void *)context->ub_event.ev);
1830 
1831 #ifndef USE_WINSOCK
1832 #ifdef HAVE_UNBOUND_EVENT_API
1833 			if (!_getdns_ub_loop_enabled(&context->ub_loop))
1834 #endif
1835 				context->extension->vmt->clear(
1836 				    context->extension, &context->ub_event);
1837 #endif
1838 		}
1839 	} while (prev_count != context->outbound_requests.count);
1840 	context->ub_event_scheduling--;
1841 }
1842 
1843 void
_getdns_context_ub_read_cb(void * userarg)1844 _getdns_context_ub_read_cb(void *userarg)
1845 {
1846 	getdns_context *context = (getdns_context *)userarg;
1847 
1848 	/* getdns_context_process_async, but without reinvoking an eventloop
1849 	 * (with context->extension->vmt->run*), because we are already
1850 	 * called from a running eventloop.
1851 	 */
1852 	if (ub_poll(context->unbound_ctx))
1853 		(void) ub_process(context->unbound_ctx);
1854 
1855 	/* No need to handle timeouts. They are handled by the extension. */
1856 
1857 	getdns_context_request_count_changed(context);
1858 }
1859 
1860 static getdns_return_t
rebuild_ub_ctx(struct getdns_context * context)1861 rebuild_ub_ctx(struct getdns_context* context) {
1862 	if (context->unbound_ctx != NULL) {
1863 		/* cancel all requests and delete */
1864 		cancel_outstanding_requests(context);
1865 		ub_ctx_delete(context->unbound_ctx);
1866 		context->unbound_ctx = NULL;
1867 	}
1868 	/* setup */
1869 #ifdef HAVE_UNBOUND_EVENT_API
1870 	_getdns_ub_loop_init(&context->ub_loop, &context->mf, context->extension);
1871 	if (_getdns_ub_loop_enabled(&context->ub_loop)) {
1872 		context->unbound_ctx = ub_ctx_create_ub_event(&context->ub_loop.super);
1873 	} else {
1874 #endif
1875 		context->unbound_ctx = ub_ctx_create();
1876 		(void) ub_ctx_async(context->unbound_ctx, 1);
1877 #ifdef HAVE_UNBOUND_EVENT_API
1878 	}
1879 #endif
1880 	context->unbound_ta_set = 0;
1881 	if (!context->unbound_ctx)
1882 		return GETDNS_RETURN_MEMORY_ERROR;
1883 
1884 #ifdef HAVE_UNBOUND_EVENT_API
1885         ub_ctx_set_option(context->unbound_ctx,
1886 	    "target-fetch-policy:", "0 0 0 0 0");
1887 #endif
1888 	set_ub_dnssec_allowed_skew(context,
1889 	    context->dnssec_allowed_skew);
1890     	set_ub_number_opt(context, "edns-buffer-size:",
1891 	    context->edns_maximum_udp_payload_size);
1892 	set_ub_dns_transport(context);
1893 
1894 	context->ub_event.userarg    = context;
1895 	context->ub_event.read_cb    = _getdns_context_ub_read_cb;
1896 	context->ub_event.write_cb   = NULL;
1897 	context->ub_event.timeout_cb = NULL;
1898 	context->ub_event.ev         = NULL;
1899 	context->ub_event_scheduling = 0;
1900 
1901 	return GETDNS_RETURN_GOOD;
1902 }
1903 #else
1904 #define set_ub_string_opt(ctx, opt, value) do {} while (0)
1905 #define set_ub_number_opt(ctx, opt, value) do {} while (0)
1906 #define getdns_context_request_count_changed(context) do {} while (0)
1907 #endif
1908 
1909 /**
1910  * Helper to dispatch the updated callback
1911  */
1912 static void
dispatch_updated(struct getdns_context * context,uint16_t item)1913 dispatch_updated(struct getdns_context *context, uint16_t item)
1914 {
1915 	if (context->update_callback2 != NULL_update_callback)
1916 		context->update_callback2(
1917 		    context, item, context->update_userarg);
1918 
1919     if (context->update_callback) {
1920         context->update_callback(context, item);
1921     }
1922 }
1923 
1924 /*
1925  * getdns_context_set_resolution_type
1926  *
1927  */
1928 getdns_return_t
getdns_context_set_resolution_type(struct getdns_context * context,getdns_resolution_t value)1929 getdns_context_set_resolution_type(struct getdns_context *context,
1930     getdns_resolution_t value)
1931 {
1932     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
1933     if (value != GETDNS_RESOLUTION_STUB && value != GETDNS_RESOLUTION_RECURSING) {
1934         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
1935     }
1936 #ifndef HAVE_LIBUNBOUND
1937     if (value == GETDNS_RESOLUTION_RECURSING)
1938 	    return GETDNS_RETURN_NOT_IMPLEMENTED;
1939 #endif
1940 #ifndef STUB_NATIVE_DNSSEC
1941     if (context->resolution_type_set != 0) {
1942         /* already setup */
1943         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
1944     }
1945 #endif
1946     context->resolution_type = value;
1947 
1948     dispatch_updated(context, GETDNS_CONTEXT_CODE_RESOLUTION_TYPE);
1949 
1950     return GETDNS_RETURN_GOOD;
1951 }               /* getdns_context_set_resolution_type */
1952 
1953 /*
1954  * getdns_context_set_namespaces
1955  *
1956  */
1957 getdns_return_t
getdns_context_set_namespaces(getdns_context * context,size_t namespace_count,const getdns_namespace_t * namespaces)1958 getdns_context_set_namespaces(getdns_context *context,
1959     size_t namespace_count, const getdns_namespace_t *namespaces)
1960 {
1961 	size_t i;
1962 	getdns_return_t r = GETDNS_RETURN_GOOD;
1963 
1964 	if (!context)
1965 		return GETDNS_RETURN_INVALID_PARAMETER;
1966 
1967 	if (namespace_count == 0 || namespaces == NULL)
1968 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
1969 
1970 	for (i = 0; i < namespace_count; i++) {
1971 		if (namespaces[i] == GETDNS_NAMESPACE_NETBIOS ||
1972 #ifndef HAVE_MDNS_SUPPORT
1973 			namespaces[i] == GETDNS_NAMESPACE_MDNS ||
1974 #endif
1975 		    namespaces[i] == GETDNS_NAMESPACE_NIS)
1976 			r = GETDNS_RETURN_NOT_IMPLEMENTED;
1977 
1978 		else if (namespaces[i] != GETDNS_NAMESPACE_DNS &&
1979 #ifdef HAVE_MDNS_SUPPORT
1980 			namespaces[i] != GETDNS_NAMESPACE_MDNS &&
1981 #endif
1982 		    namespaces[i] != GETDNS_NAMESPACE_LOCALNAMES )
1983 			return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
1984 	}
1985 	GETDNS_FREE(context->my_mf, context->namespaces);
1986 
1987 	/** duplicate **/
1988 	context->namespaces = GETDNS_XMALLOC(
1989 	    context->my_mf, getdns_namespace_t, namespace_count);
1990 	(void) memcpy(context->namespaces, namespaces,
1991 	    namespace_count * sizeof(getdns_namespace_t));
1992 	context->namespace_count = namespace_count;
1993 
1994 	dispatch_updated(context, GETDNS_CONTEXT_CODE_NAMESPACES);
1995 
1996 	return r;
1997 }               /* getdns_context_set_namespaces */
1998 
1999 static getdns_return_t
getdns_set_base_dns_transports(getdns_context * context,size_t transport_count,getdns_transport_list_t * transports)2000 getdns_set_base_dns_transports(
2001     getdns_context *context, size_t transport_count, getdns_transport_list_t *transports)
2002 {
2003 	size_t i;
2004 	getdns_transport_list_t *new_transports;
2005 
2006 	RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2007 	if (transport_count == 0 || !transports)
2008 		return GETDNS_RETURN_INVALID_PARAMETER;
2009 
2010 	/* Check for valid transports and that they are used only once*/
2011 	int u=0,t=0,l=0;
2012 	for(i=0; i<transport_count; i++)
2013 	{
2014 		switch (transports[i]) {
2015 			case GETDNS_TRANSPORT_UDP:       u++; break;
2016 			case GETDNS_TRANSPORT_TCP:       t++; break;
2017 			case GETDNS_TRANSPORT_TLS:       l++; break;
2018 			default: return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2019 		}
2020 	}
2021 	if ( u>1 || t>1 || l>1)
2022 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2023 
2024 	if (!(new_transports = GETDNS_XMALLOC(context->my_mf,
2025 		getdns_transport_list_t, transport_count)))
2026 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2027 
2028 	if (context->dns_transports)
2029 		GETDNS_FREE(context->my_mf, context->dns_transports);
2030 
2031 	/** duplicate **/
2032 	context->dns_transports = new_transports;
2033 	memcpy(context->dns_transports, transports,
2034 	    transport_count * sizeof(getdns_transport_list_t));
2035 	context->dns_transport_count = transport_count;
2036 
2037 	return GETDNS_RETURN_GOOD;
2038 }
2039 
2040 static getdns_return_t
set_ub_dns_transport(struct getdns_context * context)2041 set_ub_dns_transport(struct getdns_context* context) {
2042 	int fallback;
2043 	size_t i;
2044 
2045     /* These mappings are not exact because Unbound is configured differently,
2046        so just map as close as possible. Not all options can be supported.*/
2047     switch (context->dns_transports[0]) {
2048         case GETDNS_TRANSPORT_UDP:
2049             set_ub_string_opt(context, "do-udp:", "yes");
2050             if (context->dns_transport_count > 1
2051 	        && context->dns_transports[1] == GETDNS_TRANSPORT_TCP)
2052                 set_ub_string_opt(context, "do-tcp:", "yes");
2053             else
2054                 set_ub_string_opt(context, "do-tcp:", "no");
2055             break;
2056         case GETDNS_TRANSPORT_TCP:
2057             set_ub_string_opt(context, "do-udp:", "no");
2058             set_ub_string_opt(context, "do-tcp:", "yes");
2059             break;
2060         case GETDNS_TRANSPORT_TLS:
2061             set_ub_string_opt(context, "do-udp:", "no");
2062             set_ub_string_opt(context, "do-tcp:", "yes");
2063             /* Find out if there is a fallback available. */
2064             fallback = 0;
2065             for (i = 1; i < context->dns_transport_count; i++) {
2066                 if (context->dns_transports[i] == GETDNS_TRANSPORT_TCP) {
2067                     fallback = 1;
2068                     break;
2069                 }
2070                 else if (context->dns_transports[i] == GETDNS_TRANSPORT_UDP) {
2071                     set_ub_string_opt(context, "do-udp:", "yes");
2072                     set_ub_string_opt(context, "do-tcp:", "no");
2073                     fallback = 1;
2074                     break;
2075                 }
2076             }
2077             if (fallback == 0)
2078                 /* Use TLS if it is the only thing.*/
2079                 set_ub_string_opt(context, "ssl-upstream:", "yes");
2080             break;
2081        default:
2082            return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2083         }
2084     return GETDNS_RETURN_GOOD;
2085 }
2086 
2087 /*
2088  * getdns_context_set_dns_transport
2089  *
2090  */
2091 getdns_return_t
getdns_context_set_dns_transport(getdns_context * context,getdns_transport_t value)2092 getdns_context_set_dns_transport(
2093     getdns_context *context, getdns_transport_t value)
2094 {
2095 	size_t count = 2;
2096 	getdns_transport_list_t *new_transports;
2097 
2098 	RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2099 
2100 	if (value == GETDNS_TRANSPORT_UDP_ONLY ||
2101 	    value == GETDNS_TRANSPORT_TCP_ONLY ||
2102 	    value == GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN ||
2103 	    value == GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN)
2104 	    count = 1;
2105 
2106 	if (!(new_transports = GETDNS_XMALLOC(
2107 	       context->my_mf, getdns_transport_list_t, count)))
2108 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2109 
2110 	if (context->dns_transports)
2111 		GETDNS_FREE(context->my_mf, context->dns_transports);
2112 
2113 	context->dns_transport_count = count;
2114 	context->dns_transports = new_transports;
2115 
2116 	switch ((int)value) {
2117 	    case GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP:
2118 	        context->dns_transports[0] = GETDNS_TRANSPORT_UDP;
2119 	        context->dns_transports[1] = GETDNS_TRANSPORT_TCP;
2120 	        break;
2121 	    case GETDNS_TRANSPORT_UDP_ONLY:
2122 	        context->dns_transports[0] = GETDNS_TRANSPORT_UDP;
2123 	        break;
2124 	    case GETDNS_TRANSPORT_TCP_ONLY:
2125 	    case GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN:
2126 	        context->dns_transports[0] = GETDNS_TRANSPORT_TCP;
2127 	        break;
2128 	    case GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN:
2129 	        context->dns_transports[0] = GETDNS_TRANSPORT_TLS;
2130 	        break;
2131 	    case GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN:
2132 	        context->dns_transports[0] = GETDNS_TRANSPORT_TLS;
2133 	        context->dns_transports[1] = GETDNS_TRANSPORT_TCP;
2134 	       break;
2135 	   default:
2136 	       return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2137 	}
2138 	/* Note that the call below does not have any effect in unbound after the
2139 	 * ctx is finalised so for recursive mode or stub + dnssec only the first
2140 	 * transport specified on the first query is used.
2141 	 * However the method returns success as otherwise the transport could not
2142 	 * be reset for stub mode.
2143 	 * Also, not all transport options supported in libunbound yet */
2144 	if (set_ub_dns_transport(context) != GETDNS_RETURN_GOOD) {
2145 	    return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2146 	}
2147 	dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT);
2148 	return GETDNS_RETURN_GOOD;
2149 }
2150 
2151 /*
2152  * getdns_context_set_dns_transport_list
2153  *
2154  */
2155 getdns_return_t
getdns_context_set_dns_transport_list(getdns_context * context,size_t transport_count,getdns_transport_list_t * transports)2156 getdns_context_set_dns_transport_list(getdns_context *context,
2157     size_t transport_count, getdns_transport_list_t *transports)
2158 {
2159     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2160     if (getdns_set_base_dns_transports(context, transport_count, transports) != GETDNS_RETURN_GOOD)
2161         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2162     /* Note that the call below does not have any effect in unbound after the
2163      * ctx is finalised so for recursive mode or stub + dnssec only the first
2164      * transport specified on the first query is used.
2165      * However the method returns success as otherwise the transport could not
2166      * be reset for stub mode.
2167      * Also, not all transport options supported in libunbound yet */
2168     if (set_ub_dns_transport(context) != GETDNS_RETURN_GOOD) {
2169         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2170     }
2171     dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_TRANSPORT);
2172     return GETDNS_RETURN_GOOD;
2173 }               /* getdns_context_set_dns_transport_list */
2174 
2175 /*
2176  * getdns_context_set_tls_authentication
2177  *
2178  */
2179 getdns_return_t
getdns_context_set_tls_authentication(getdns_context * context,getdns_tls_authentication_t value)2180 getdns_context_set_tls_authentication(getdns_context *context,
2181                                       getdns_tls_authentication_t value)
2182 {
2183     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2184     if (value != GETDNS_AUTHENTICATION_NONE &&
2185         value != GETDNS_AUTHENTICATION_REQUIRED) {
2186         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2187     }
2188     context->tls_auth = value;
2189 
2190     dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_AUTHENTICATION);
2191 
2192     return GETDNS_RETURN_GOOD;
2193 }               /* getdns_context_set_tls_authentication_list */
2194 
2195 /*
2196  * getdns_context_set_round_robin_upstreams
2197  *
2198  */
2199 getdns_return_t
getdns_context_set_round_robin_upstreams(getdns_context * context,uint8_t value)2200 getdns_context_set_round_robin_upstreams(getdns_context *context, uint8_t value)
2201 {
2202     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2203     /* only allow 0 or 1 */
2204     if (value != 0 && value != 1) {
2205         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2206     }
2207 
2208     context->round_robin_upstreams = value;
2209 
2210     dispatch_updated(context, GETDNS_CONTEXT_CODE_ROUND_ROBIN_UPSTREAMS);
2211 
2212     return GETDNS_RETURN_GOOD;
2213 }               /* getdns_context_set_round_robin_upstreams */
2214 
2215 /**
2216  * Set the maximum number of messages that can be sent to other upstreams
2217  * before the upstream which has previously timed out will be tried again.
2218  * @see getdns_context_get_max_backoff_value
2219  * @param[in] context  The context to configure
2220  * @param[in[ value    Number of messages sent to other upstreams before
2221  *                     retrying the upstream which had timed out.
2222  * @return GETDNS_RETURN_GOOD on success
2223  * @return GETDNS_RETURN_INVALID_PARAMETER if context is null.
2224  */
2225 getdns_return_t
getdns_context_set_max_backoff_value(getdns_context * context,uint16_t value)2226 getdns_context_set_max_backoff_value(getdns_context *context, uint16_t value)
2227 {
2228     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2229 
2230     context->max_backoff_value = value;
2231 
2232     dispatch_updated(context, GETDNS_CONTEXT_CODE_MAX_BACKOFF_VALUE);
2233 
2234     return GETDNS_RETURN_GOOD;
2235 }               /* getdns_context_set_max_backoff_value */
2236 
2237 /*
2238  * getdns_context_set_tls_backoff_time
2239  *
2240  */
2241 getdns_return_t
getdns_context_set_tls_backoff_time(getdns_context * context,uint16_t value)2242 getdns_context_set_tls_backoff_time(getdns_context *context, uint16_t value)
2243 {
2244     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2245     /* Value is in seconds. Should we have a lower limit? 1 second?*/
2246     context->tls_backoff_time = value;
2247 
2248     dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_BACKOFF_TIME);
2249 
2250     return GETDNS_RETURN_GOOD;
2251 }               /* getdns_context_set_tls_backoff_time */
2252 
2253 /*
2254  * getdns_context_set_tls_connection_retries
2255  *
2256  */
2257 getdns_return_t
getdns_context_set_tls_connection_retries(getdns_context * context,uint16_t value)2258 getdns_context_set_tls_connection_retries(getdns_context *context, uint16_t value)
2259 {
2260     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2261     /* Should we put a sensible upper limit on this? 10?*/
2262     // if (value > 10) {
2263     //     return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2264     // }
2265 
2266     context->tls_connection_retries = value;
2267 
2268     dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CONNECTION_RETRIES);
2269 
2270     return GETDNS_RETURN_GOOD;
2271 }               /* getdns_context_set_tls_connection retries */
2272 
2273 #ifdef HAVE_LIBUNBOUND
2274 static void
set_ub_limit_outstanding_queries(getdns_context * context,uint16_t value)2275 set_ub_limit_outstanding_queries(getdns_context* context, uint16_t value) {
2276     /* num-queries-per-thread */
2277     set_ub_number_opt(context, "num-queries-per-thread:", value);
2278 }
2279 #endif
2280 /*
2281  * getdns_context_set_limit_outstanding_queries
2282  *
2283  */
2284 getdns_return_t
getdns_context_set_limit_outstanding_queries(struct getdns_context * context,uint16_t limit)2285 getdns_context_set_limit_outstanding_queries(struct getdns_context *context,
2286     uint16_t limit)
2287 {
2288     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2289 #ifdef HAVE_LIBUNBOUND
2290     set_ub_limit_outstanding_queries(context, limit);
2291 #endif
2292     if (limit != context->limit_outstanding_queries) {
2293         context->limit_outstanding_queries = limit;
2294         dispatch_updated(context,
2295             GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES);
2296     }
2297 
2298     return GETDNS_RETURN_GOOD;
2299 }               /* getdns_context_set_limit_outstanding_queries */
2300 
2301 /*
2302  * getdns_context_set_timeout
2303  *
2304  */
2305 getdns_return_t
getdns_context_set_timeout(struct getdns_context * context,uint64_t timeout)2306 getdns_context_set_timeout(struct getdns_context *context, uint64_t timeout)
2307 {
2308     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2309 
2310     if (timeout == 0) {
2311         return GETDNS_RETURN_INVALID_PARAMETER;
2312     }
2313 
2314     context->timeout = timeout;
2315 
2316     dispatch_updated(context, GETDNS_CONTEXT_CODE_TIMEOUT);
2317 
2318     return GETDNS_RETURN_GOOD;
2319 }               /* getdns_context_set_timeout */
2320 
2321 /*
2322  * getdns_context_set_idle_timeout
2323  *
2324  */
2325 getdns_return_t
getdns_context_set_idle_timeout(getdns_context * context,uint64_t timeout)2326 getdns_context_set_idle_timeout(getdns_context *context, uint64_t timeout)
2327 {
2328 	size_t i;
2329 
2330 	if (!context)
2331 		return GETDNS_RETURN_INVALID_PARAMETER;
2332 
2333 	/* Shuold we enforce maximum based on edns-tcp-keepalive spec? */
2334 	/* 0 should be allowed as that is the default.*/
2335 
2336 	context->idle_timeout = timeout;
2337 
2338 	dispatch_updated(context, GETDNS_CONTEXT_CODE_IDLE_TIMEOUT);
2339 
2340 	if (timeout)
2341 		return GETDNS_RETURN_GOOD;
2342 
2343 	/* If timeout == 0, call scheduled idle timeout events */
2344 	for (i = 0; i < context->upstreams->count; i++) {
2345 		getdns_upstream *upstream =
2346 		    &context->upstreams->upstreams[i];
2347 
2348 		if (!upstream->event.ev ||
2349 		    !upstream->event.timeout_cb ||
2350 		     upstream->event.read_cb ||
2351 		     upstream->event.write_cb)
2352 			continue;
2353 
2354 		GETDNS_CLEAR_EVENT(upstream->loop, &upstream->event);
2355 		upstream->event.timeout_cb(upstream->event.userarg);
2356 	}
2357 	return GETDNS_RETURN_GOOD;
2358 }               /* getdns_context_set_timeout */
2359 
2360 
2361 /*
2362  * getdns_context_set_follow_redirects
2363  *
2364  */
2365 getdns_return_t
getdns_context_set_follow_redirects(getdns_context * context,getdns_redirects_t value)2366 getdns_context_set_follow_redirects(
2367     getdns_context *context, getdns_redirects_t value)
2368 {
2369 	if (!context)
2370 		return GETDNS_RETURN_INVALID_PARAMETER;
2371 
2372 	if (value != GETDNS_REDIRECTS_FOLLOW &&
2373 	    value != GETDNS_REDIRECTS_DO_NOT_FOLLOW)
2374 		return GETDNS_RETURN_INVALID_PARAMETER;
2375 
2376 	context->follow_redirects = value;
2377 
2378 	dispatch_updated(context, GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS);
2379 
2380 	return GETDNS_RETURN_GOOD;
2381 }               /* getdns_context_set_follow_redirects */
2382 
2383 /*
2384  * getdns_context_set_dns_root_servers
2385  *
2386  */
2387 getdns_return_t
getdns_context_set_dns_root_servers(getdns_context * context,getdns_list * addresses)2388 getdns_context_set_dns_root_servers(
2389     getdns_context *context, getdns_list *addresses)
2390 {
2391 #ifdef HAVE_LIBUNBOUND
2392 #  ifndef HAVE_UB_CTX_SET_STUB
2393 	char tmpfn[FILENAME_MAX] = P_tmpdir "/getdns-root-dns-servers-XXXXXX";
2394 	FILE *fh;
2395 	int fd;
2396 	size_t dst_len;
2397 #  endif
2398 	size_t i;
2399 	getdns_dict *rr_dict;
2400 	getdns_return_t r = GETDNS_RETURN_GOOD;
2401 	getdns_bindata *addr_bd;
2402 	char dst[2048];
2403 #endif
2404 	getdns_list *newlist;
2405 
2406 	if (!context)
2407 		return GETDNS_RETURN_INVALID_PARAMETER;
2408 
2409 	if (!addresses) {
2410 #ifdef HAVE_LIBUNBOUND
2411 		if (ub_ctx_set_option(
2412 		    context->unbound_ctx, "root-hints:", ""))
2413 			return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2414 #endif
2415 		if (context->dns_root_servers)
2416 			getdns_list_destroy(context->dns_root_servers);
2417 		context->dns_root_servers = NULL;
2418 
2419 #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
2420 		if (context->root_servers_fn[0])
2421 			unlink(context->root_servers_fn);
2422 		context->root_servers_fn[0] = 0;
2423 #endif
2424 		dispatch_updated(
2425 		    context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS);
2426 		return GETDNS_RETURN_GOOD;
2427 	}
2428 
2429 #ifdef HAVE_LIBUNBOUND
2430 #  ifdef HAVE_UB_CTX_SET_STUB
2431 	for (i=0; !r; i++) {
2432 		if (!(r = getdns_list_get_bindata(addresses, i, &addr_bd)))
2433 			/* success! */
2434 			;
2435 
2436 		else if ((r = getdns_list_get_dict(addresses, i, &rr_dict)))
2437 			/* Not a bindata, not a dict? ERROR! */
2438 			break;
2439 
2440 		else if (getdns_dict_get_bindata(
2441 		    rr_dict, "address_data", &addr_bd) &&
2442 		    getdns_dict_get_bindata(
2443 		    rr_dict, "/rdata/ipv4_address", &addr_bd) &&
2444 		    getdns_dict_get_bindata(
2445 		    rr_dict, "/rdata/ipv6_address", &addr_bd))
2446 
2447 		       	/* Not a parsable address,
2448 			 * pass because we allow root.hint's files as input
2449 			 */
2450 			continue;
2451 
2452 		if (addr_bd->size == 16 &&
2453 		    inet_ntop(AF_INET6, addr_bd->data, dst, sizeof(dst))) {
2454 
2455 			if (ub_ctx_set_stub(context->unbound_ctx,".",dst,1)) {
2456 				return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2457 			}
2458 
2459 		} else if (addr_bd->size == 4 &&
2460 		    inet_ntop(AF_INET, addr_bd->data, dst, sizeof(dst))) {
2461 			if (ub_ctx_set_stub(context->unbound_ctx,".",dst,1)) {
2462 				return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2463 			}
2464 		}
2465 	}
2466 #  else
2467 	if ((fd = mkstemp(tmpfn)) < 0)
2468 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2469 
2470 	if (!(fh = fdopen(fd, "w")))
2471 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2472 	for (i=0; !r; i++) {
2473 		dst_len = sizeof(dst);
2474 		if (!(r = getdns_list_get_bindata(addresses, i, &addr_bd)))
2475 			/* success! */
2476 			;
2477 
2478 		else if ((r = getdns_list_get_dict(addresses, i, &rr_dict)))
2479 			/* Not a bindata, not a dict? ERROR! */
2480 			break;
2481 
2482 		else if (!getdns_rr_dict2str_buf(rr_dict, dst, &dst_len)) {
2483 
2484 			fprintf(fh, "%s", dst);
2485 			continue;
2486 
2487 		} else if (getdns_dict_get_bindata(
2488 		    rr_dict, "address_data", &addr_bd) &&
2489 		    getdns_dict_get_bindata(
2490 		    rr_dict, "/rdata/ipv4_address", &addr_bd) &&
2491 		    getdns_dict_get_bindata(
2492 		    rr_dict, "/rdata/ipv6_address", &addr_bd))
2493 
2494 		       	/* Not a parsable address,
2495 			 * pass because we allow root.hint's files as input
2496 			 */
2497 			continue;
2498 
2499 		if (addr_bd->size == 16 &&
2500 		    inet_ntop(AF_INET6, addr_bd->data, dst, sizeof(dst)))
2501 
2502 			fprintf(fh,". NS %"PRIsz".root-servers.getdnsapi.net.\n"
2503 			    "%"PRIsz".root-servers.getdnsapi.net. AAAA %s\n",
2504 			    i, i, dst);
2505 
2506 		else if (addr_bd->size == 4 &&
2507 		    inet_ntop(AF_INET, addr_bd->data, dst, sizeof(dst)))
2508 
2509 			fprintf(fh,". NS %"PRIsz".root-servers.getdnsapi.net.\n"
2510 			    "%"PRIsz".root-servers.getdnsapi.net. A %s\n",
2511 			    i, i, dst);
2512 	}
2513 	fclose(fh);
2514 	if (ub_ctx_set_option(
2515 	    context->unbound_ctx, "root-hints:", tmpfn)) {
2516 		unlink(tmpfn);
2517 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2518 	}
2519 #  endif
2520 #endif
2521 	if (_getdns_list_copy(addresses, &newlist)) {
2522 #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
2523 		unlink(tmpfn);
2524 #endif
2525 		return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2526 	}
2527 	if (context->dns_root_servers)
2528 		getdns_list_destroy(context->dns_root_servers);
2529 	context->dns_root_servers = newlist;
2530 
2531 #if defined(HAVE_LIBUNBOUND) && !defined(HAVE_UB_CTX_SET_STUB)
2532 	if (context->root_servers_fn[0])
2533 		unlink(context->root_servers_fn);
2534 	(void) memcpy(context->root_servers_fn, tmpfn, strlen(tmpfn));
2535 #endif
2536 
2537 	dispatch_updated(context, GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS);
2538 	return GETDNS_RETURN_GOOD;
2539 }               /* getdns_context_set_dns_root_servers */
2540 
2541 /*
2542  * getdns_context_set_append_name
2543  *
2544  */
2545 getdns_return_t
getdns_context_set_append_name(getdns_context * context,getdns_append_name_t value)2546 getdns_context_set_append_name(
2547     getdns_context *context, getdns_append_name_t value)
2548 {
2549 	if (!context)
2550 		return GETDNS_RETURN_INVALID_PARAMETER;
2551 
2552 	switch ((int)value) {
2553 	case GETDNS_APPEND_NAME_ALWAYS:
2554 	case GETDNS_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE:
2555 	case GETDNS_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE:
2556 	case GETDNS_APPEND_NAME_NEVER:
2557 	case GETDNS_APPEND_NAME_TO_SINGLE_LABEL_FIRST:
2558 		context->append_name = value;
2559 		dispatch_updated(context, GETDNS_CONTEXT_CODE_APPEND_NAME);
2560 		return GETDNS_RETURN_GOOD;
2561 	}
2562 	return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
2563 }               /* getdns_context_set_append_name */
2564 
2565 /*
2566  * getdns_context_set_suffix
2567  *
2568  */
2569 getdns_return_t
getdns_context_set_suffix(getdns_context * context,getdns_list * value)2570 getdns_context_set_suffix(getdns_context *context, getdns_list *value)
2571 {
2572 	getdns_return_t r;
2573 	size_t i;
2574 	gldns_buffer gbuf;
2575 	uint8_t buf_spc[1024], *suffixes = NULL;
2576 	size_t suffixes_len = 0;
2577 	uint8_t dname[256];
2578 	size_t dname_len;
2579 	char name_spc[1025], *name;
2580 	getdns_bindata *bindata;
2581 
2582 	if (!context)
2583 		return GETDNS_RETURN_INVALID_PARAMETER;
2584 
2585 	if (value == NULL) {
2586 		if (context->suffixes && context->suffixes != no_suffixes)
2587 			GETDNS_FREE(context->mf, (void *)context->suffixes);
2588 
2589 		context->suffixes = no_suffixes;
2590 		context->suffixes_len = sizeof(no_suffixes);
2591 		return GETDNS_RETURN_GOOD;
2592 	}
2593 	gldns_buffer_init_vfixed_frm_data(&gbuf, buf_spc, sizeof(buf_spc));
2594 	for (;;) {
2595 		for ( i = 0
2596 		    ; !(r = getdns_list_get_bindata(value, i, &bindata))
2597 		    ; i++) {
2598 
2599 			if (bindata->size == 0 || bindata->size >= sizeof(name_spc))
2600 				continue;
2601 
2602 			if (bindata->data[bindata->size-1] != 0) {
2603 				/* Unterminated string */
2604 				(void) memcpy(name_spc, bindata->data, bindata->size);
2605 				name_spc[bindata->size] = 0;
2606 				name = name_spc;
2607 			} else
2608 				/* Terminated string */
2609 				name = (char *)bindata->data;
2610 
2611 			dname_len = sizeof(dname);
2612 			if (gldns_str2wire_dname_buf(name, dname, &dname_len))
2613 				return GETDNS_RETURN_GENERIC_ERROR;
2614 
2615 			gldns_buffer_write_u8(&gbuf, (uint8_t) dname_len);
2616 			gldns_buffer_write(&gbuf, dname, dname_len);
2617 		}
2618 		if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM)
2619 			r = GETDNS_RETURN_GOOD;
2620 		else
2621 			break;
2622 
2623 		gldns_buffer_write_u8(&gbuf, 1);
2624 		gldns_buffer_write_u8(&gbuf, 0);
2625 
2626 		if (gldns_buffer_begin(&gbuf) != buf_spc)
2627 			break;
2628 
2629 		suffixes_len = gldns_buffer_position(&gbuf);
2630 		if (!(suffixes = GETDNS_XMALLOC(
2631 		    context->mf, uint8_t, suffixes_len))) {
2632 			r = GETDNS_RETURN_MEMORY_ERROR;
2633 			break;
2634 		}
2635 		if (suffixes_len <= gldns_buffer_limit(&gbuf)) {
2636 			(void) memcpy (suffixes, buf_spc, suffixes_len);
2637 			break;
2638 		}
2639 		gldns_buffer_init_frm_data(&gbuf, suffixes, suffixes_len);
2640 	}
2641 	if (r) {
2642 		if (gldns_buffer_begin(&gbuf) != buf_spc)
2643 			GETDNS_FREE(context->mf, suffixes);
2644 		return r;
2645 	}
2646 	if (context->suffixes && context->suffixes != no_suffixes)
2647 		GETDNS_FREE(context->mf, (void *)context->suffixes);
2648 
2649 	context->suffixes = suffixes;
2650 	context->suffixes_len = suffixes_len;
2651 
2652 	dispatch_updated(context, GETDNS_CONTEXT_CODE_SUFFIX);
2653 	return GETDNS_RETURN_GOOD;
2654 }               /* getdns_context_set_suffix */
2655 
2656 /*
2657  * getdns_context_set_dnssec_trust_anchors
2658  *
2659  */
2660 getdns_return_t
getdns_context_set_dnssec_trust_anchors(getdns_context * context,getdns_list * value)2661 getdns_context_set_dnssec_trust_anchors(
2662     getdns_context *context, getdns_list *value)
2663 {
2664 	RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2665 
2666 	if (context->trust_anchors &&
2667 	    context->trust_anchors != context->trust_anchors_spc)
2668 		GETDNS_FREE(context->mf, context->trust_anchors);
2669 
2670 	if (value) {
2671 		context->trust_anchors_len = sizeof(context->trust_anchors_spc);
2672 		context->trust_anchors = _getdns_list2wire(value,
2673 		    context->trust_anchors_spc, &context->trust_anchors_len,
2674 		    &context->mf);
2675 		context->trust_anchors_source = GETDNS_TASRC_APP;
2676 	} else {
2677 		context->trust_anchors = NULL;
2678 		context->trust_anchors_len = 0;
2679 		context->trust_anchors_source = GETDNS_TASRC_NONE;
2680 	}
2681 	dispatch_updated(context, GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS);
2682 	return GETDNS_RETURN_GOOD;
2683 }               /* getdns_context_set_dnssec_trust_anchors */
2684 
2685 #ifdef HAVE_LIBUNBOUND
2686 static void
set_ub_dnssec_allowed_skew(struct getdns_context * context,uint32_t value)2687 set_ub_dnssec_allowed_skew(struct getdns_context* context, uint32_t value) {
2688     set_ub_number_opt(context, "val-sig-skew-min:", value);
2689     set_ub_number_opt(context, "val-sig-skew-max:", value);
2690 }
2691 #endif
2692 /*
2693  * getdns_context_set_dnssec_allowed_skew
2694  *
2695  */
2696 getdns_return_t
getdns_context_set_dnssec_allowed_skew(struct getdns_context * context,uint32_t value)2697 getdns_context_set_dnssec_allowed_skew(struct getdns_context *context,
2698     uint32_t value)
2699 {
2700     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2701 #ifdef HAVE_LIBUNBOUND
2702     set_ub_dnssec_allowed_skew(context, value);
2703 #endif
2704     if (value != context->dnssec_allowed_skew) {
2705         context->dnssec_allowed_skew = value;
2706         dispatch_updated(context, GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW);
2707     }
2708 
2709     return GETDNS_RETURN_GOOD;
2710 }               /* getdns_context_set_dnssec_allowed_skew */
2711 
2712 /*
2713  * getdns_context_set_upstream_recursive_servers
2714  *
2715  */
2716 getdns_return_t
getdns_context_set_upstream_recursive_servers(struct getdns_context * context,struct getdns_list * upstream_list)2717 getdns_context_set_upstream_recursive_servers(struct getdns_context *context,
2718     struct getdns_list *upstream_list)
2719 {
2720 	getdns_return_t r;
2721 	size_t count = 0;
2722 	size_t i;
2723 	getdns_upstreams *upstreams;
2724 	char addrstr[1024], portstr[1024], *eos;
2725 	struct addrinfo hints;
2726 
2727 	RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
2728 
2729 	if (  !upstream_list
2730 	   || (r = getdns_list_get_length(upstream_list, &count))
2731 	   || count == 0) {
2732 		_getdns_upstreams_dereference(context->upstreams);
2733 		context->upstreams = NULL;
2734 		dispatch_updated(context,
2735 			GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
2736 	}
2737 	memset(&hints, 0, sizeof(struct addrinfo));
2738 	hints.ai_family    = AF_UNSPEC;      /* Allow IPv4 or IPv6 */
2739 	hints.ai_socktype  = 0;              /* Datagram socket */
2740 	hints.ai_flags     = AI_NUMERICHOST; /* No reverse name lookups */
2741 	hints.ai_protocol  = 0;              /* Any protocol */
2742 	hints.ai_canonname = NULL;
2743 	hints.ai_addr      = NULL;
2744 	hints.ai_next      = NULL;
2745 
2746 	upstreams = upstreams_create(
2747 	    context, count * GETDNS_UPSTREAM_TRANSPORTS);
2748 	for (i = 0; i < count; i++) {
2749 		getdns_dict    *dict;
2750 		getdns_bindata *address_type;
2751 		getdns_bindata *address_data;
2752 		getdns_bindata *tls_auth_name;
2753 		struct sockaddr_storage  addr;
2754 
2755 		getdns_bindata  *scope_id;
2756 		getdns_upstream *upstream;
2757 
2758 		getdns_bindata  *tsig_alg_name, *tsig_name, *tsig_key;
2759 		getdns_tsig_algo tsig_alg;
2760 		char             tsig_name_str[1024];
2761 		uint8_t          tsig_dname_spc[256], *tsig_dname;
2762 		size_t           tsig_dname_len;
2763 
2764 		size_t           j;
2765 
2766 		if ((r = getdns_list_get_dict(upstream_list, i, &dict))) {
2767 			dict = NULL;
2768 
2769 			if ((r = getdns_list_get_bindata(
2770 			    upstream_list, i, &address_data)))
2771 				goto error;
2772 
2773 			if (address_data->size == 4)
2774 				addr.ss_family = AF_INET;
2775 			else if (address_data->size == 16)
2776 				addr.ss_family = AF_INET6;
2777 			else	goto invalid_parameter;
2778 
2779 		} else if ((r = getdns_dict_get_bindata(
2780 		    dict, "address_type",&address_type))) {
2781 			/* Just address_data is also okay */
2782 			if ((r = getdns_dict_get_bindata(
2783 			    dict, "address_data", &address_data)))
2784 				goto error;
2785 
2786 			if (address_data->size == 4)
2787 				addr.ss_family = AF_INET;
2788 			else if (address_data->size == 16)
2789 				addr.ss_family = AF_INET6;
2790 			else	goto invalid_parameter;
2791 
2792 		} else {
2793 			if (address_type->size < 4)
2794 				goto invalid_parameter;
2795 			else if (!strncmp((char*)address_type->data,"IPv4",4))
2796 				addr.ss_family = AF_INET;
2797 			else if (!strncmp((char*)address_type->data,"IPv6",4))
2798 				addr.ss_family = AF_INET6;
2799 			else	goto invalid_parameter;
2800 
2801 			if ((r = getdns_dict_get_bindata(
2802 			    dict, "address_data", &address_data)))
2803 				goto error;
2804 			if ((addr.ss_family == AF_INET &&
2805 			     address_data->size != 4) ||
2806 			    (addr.ss_family == AF_INET6 &&
2807 			     address_data->size != 16))
2808 				goto invalid_parameter;
2809 		}
2810 		if (inet_ntop(addr.ss_family, address_data->data,
2811 		    addrstr, 1024) == NULL)
2812 			goto invalid_parameter;
2813 
2814 		if (dict && getdns_dict_get_bindata(dict,"scope_id",&scope_id)
2815 		    == GETDNS_RETURN_GOOD) {
2816 			if (strlen(addrstr) + scope_id->size > 1022)
2817 				goto invalid_parameter;
2818 			eos = &addrstr[strlen(addrstr)];
2819 			*eos++ = '%';
2820 			(void) memcpy(eos, scope_id->data, scope_id->size);
2821 			eos[scope_id->size] = 0;
2822 		}
2823 
2824 		tsig_alg_name = tsig_name = tsig_key = NULL;
2825 		tsig_dname = NULL;
2826 		tsig_dname_len = 0;
2827 
2828 		if (dict && getdns_dict_get_bindata(dict,
2829 		    "tsig_algorithm", &tsig_alg_name) == GETDNS_RETURN_GOOD)
2830 			tsig_alg = _getdns_get_tsig_algo(tsig_alg_name);
2831 		else
2832 			tsig_alg = GETDNS_HMAC_MD5;
2833 
2834 		if (!dict)
2835 			tsig_alg = GETDNS_NO_TSIG; /* No name, no TSIG */
2836 
2837 		else if (getdns_dict_get_bindata(
2838 		    dict, "tsig_name", &tsig_name))
2839 			tsig_alg = GETDNS_NO_TSIG; /* No name, no TSIG */
2840 
2841 		else if (tsig_name->size == 0)
2842 			tsig_alg = GETDNS_NO_TSIG;
2843 
2844 		else if (tsig_name->data[tsig_name->size - 1] != 0) {
2845 			/* Unterminated string */
2846 			if (tsig_name->size >= sizeof(tsig_name_str) - 1)
2847 				tsig_alg = GETDNS_NO_TSIG;
2848 			else {
2849 				(void) memcpy(tsig_name_str, tsig_name->data
2850 				                           , tsig_name->size);
2851 				tsig_name_str[tsig_name->size] = 0;
2852 
2853 				tsig_dname_len = sizeof(tsig_dname_spc);
2854 				if (gldns_str2wire_dname_buf(tsig_name_str,
2855 				    tsig_dname_spc, &tsig_dname_len))
2856 					tsig_alg = GETDNS_NO_TSIG;
2857 				else
2858 					tsig_dname = tsig_dname_spc;
2859 			}
2860 		} else if (!_getdns_bindata_is_dname(tsig_name)) {
2861 			/* Terminated string */
2862 			tsig_dname_len = sizeof(tsig_dname_spc);
2863 			if (gldns_str2wire_dname_buf(tsig_name_str,
2864 			    tsig_dname_spc, &tsig_dname_len))
2865 				tsig_alg = GETDNS_NO_TSIG;
2866 			else
2867 				tsig_dname = tsig_dname_spc;
2868 
2869 		} else if (tsig_name->size > sizeof(tsig_dname_spc))
2870 			tsig_alg = GETDNS_NO_TSIG;
2871 
2872 		else {
2873 			/* fqdn */
2874 			tsig_dname = memcpy(tsig_dname_spc, tsig_name->data
2875 			                                  , tsig_name->size);
2876 			tsig_dname_len = tsig_name->size;
2877 		}
2878 		if (dict && getdns_dict_get_bindata(
2879 		    dict, "tsig_secret", &tsig_key))
2880 			tsig_alg = GETDNS_NO_TSIG; /* No key, no TSIG */
2881 
2882 		/* Don't check TSIG length contraints here.
2883 		 * Let the upstream decide what is secure enough.
2884 		 */
2885 
2886 		/* Loop to create upstreams as needed*/
2887 		for (j = 0; j < GETDNS_UPSTREAM_TRANSPORTS; j++) {
2888 			uint32_t port;
2889 			struct addrinfo *ai;
2890 			port = getdns_port_array[j];
2891 			if (port == GETDNS_PORT_ZERO)
2892 				continue;
2893 
2894 			if (getdns_upstream_transports[j] != GETDNS_TRANSPORT_TLS) {
2895 				if (dict)
2896 					(void) getdns_dict_get_int(dict, "port", &port);
2897 			} else {
2898 				if (dict)
2899 					(void) getdns_dict_get_int(dict, "tls_port", &port);
2900 			}
2901 			(void) snprintf(portstr, 1024, "%d", (int)port);
2902 
2903 			if (getaddrinfo(addrstr, portstr, &hints, &ai))
2904 				goto invalid_parameter;
2905 			if (!ai)
2906 				continue;
2907 
2908 			/* TODO[TLS]: Should probably check that the upstream doesn't
2909 			 * already exist (in case user has specified TLS port explicitly and
2910 			 * to prevent duplicates) */
2911 
2912 			upstream = &upstreams->upstreams[upstreams->count];
2913 			upstream->addr.ss_family = addr.ss_family;
2914 			upstream_init(upstream, upstreams, ai);
2915 			upstream->transport = getdns_upstream_transports[j];
2916 			if (dict && getdns_upstream_transports[j] == GETDNS_TRANSPORT_TLS) {
2917 				getdns_list *pubkey_pinset = NULL;
2918 				getdns_bindata *tls_cipher_list = NULL;
2919 				getdns_bindata *tls_ciphersuites = NULL;
2920 				getdns_bindata *tls_curves_list = NULL;
2921 				uint32_t        tls_version;
2922 				/* Missing support in TLS library is
2923 				 * detected and reported during connection setup.
2924 				 */
2925 
2926 				if ((r = getdns_dict_get_bindata(
2927 				    dict, "tls_auth_name", &tls_auth_name)) == GETDNS_RETURN_GOOD) {
2928 
2929 					if (tls_auth_name->size >= sizeof(upstream->tls_auth_name)) {
2930 						/* tls_auth_name's are
2931 						 * domain names in presentation
2932 						 * format and, taking escaping
2933 						 * into account, should not
2934 						 * be larger than 1024 bytes.
2935 						 */
2936 						freeaddrinfo(ai);
2937 						goto invalid_parameter;
2938 					}
2939 					memcpy(upstream->tls_auth_name,
2940 					       (char *)tls_auth_name->data,
2941 						tls_auth_name->size);
2942 					upstream->tls_auth_name
2943 					    [tls_auth_name->size] = '\0';
2944 				}
2945 				if ((r = getdns_dict_get_list(dict, "tls_pubkey_pinset",
2946 							      &pubkey_pinset)) == GETDNS_RETURN_GOOD) {
2947 			   /* TODO: what if the user supplies tls_pubkey_pinset with
2948 			    * something other than a list? */
2949 					r = _getdns_get_pubkey_pinset_from_list(pubkey_pinset,
2950 										&(upstreams->mf),
2951 										&(upstream->tls_pubkey_pinset));
2952 					if (r != GETDNS_RETURN_GOOD) {
2953 						freeaddrinfo(ai);
2954 						goto invalid_parameter;
2955 					}
2956 				}
2957 				(void) getdns_dict_get_bindata(
2958 				    dict, "tls_cipher_list", &tls_cipher_list);
2959 				upstream->tls_cipher_list = tls_cipher_list
2960 				    ? _getdns_strdup2(&upstreams->mf
2961 				                     , tls_cipher_list)
2962 				    : NULL;
2963 				(void) getdns_dict_get_bindata(
2964 				    dict, "tls_ciphersuites", &tls_ciphersuites);
2965 				upstream->tls_ciphersuites = tls_ciphersuites
2966 				    ? _getdns_strdup2(&upstreams->mf
2967 				                     , tls_ciphersuites)
2968 				    : NULL;
2969 				(void) getdns_dict_get_bindata(
2970 				    dict, "tls_curves_list", &tls_curves_list);
2971 				if (tls_curves_list) {
2972 					upstream->tls_curves_list =
2973 					    _getdns_strdup2(&upstreams->mf
2974 					                   , tls_curves_list);
2975 				} else
2976 					upstream->tls_curves_list = NULL;
2977 				if (!getdns_dict_get_int(
2978 				    dict, "tls_min_version", &tls_version))
2979 					upstream->tls_min_version = tls_version;
2980 				if (!getdns_dict_get_int(
2981 				    dict, "tls_max_version", &tls_version))
2982 					upstream->tls_max_version = tls_version;
2983 			}
2984 			if ((upstream->tsig_alg = tsig_alg)) {
2985 				if (tsig_name) {
2986 					(void) memcpy(upstream->tsig_dname,
2987 					    tsig_dname, tsig_dname_len);
2988 					upstream->tsig_dname_len =
2989 						tsig_dname_len;
2990 				} else
2991 					upstream->tsig_dname_len = 0;
2992 
2993 				if (tsig_key) {
2994 					(void) memcpy(upstream->tsig_key,
2995 					    tsig_key->data, tsig_key->size);
2996 					upstream->tsig_size = tsig_key->size;
2997 				} else
2998 					upstream->tsig_size = 0;
2999 			} else {
3000 				upstream->tsig_dname_len = 0;
3001 				upstream->tsig_size = 0;
3002 			}
3003 			upstreams->count++;
3004 			freeaddrinfo(ai);
3005 		}
3006 	}
3007 	_getdns_upstreams_dereference(context->upstreams);
3008 	context->upstreams = upstreams;
3009 	dispatch_updated(context,
3010 		GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS);
3011 
3012 	return GETDNS_RETURN_GOOD;
3013 
3014 invalid_parameter:
3015 	_getdns_upstreams_dereference(upstreams);
3016 	return GETDNS_RETURN_INVALID_PARAMETER;
3017 error:
3018 	_getdns_upstreams_dereference(upstreams);
3019 	return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
3020 } /* getdns_context_set_upstream_recursive_servers */
3021 
3022 
3023 /*
3024  * getdns_context_unset_edns_maximum_udp_payload_size
3025  *
3026  */
3027 getdns_return_t
getdns_context_unset_edns_maximum_udp_payload_size(getdns_context * context)3028 getdns_context_unset_edns_maximum_udp_payload_size(getdns_context *context)
3029 {
3030 	if (!context)
3031 		return GETDNS_RETURN_INVALID_PARAMETER;
3032 
3033 #ifdef HAVE_LIBUNBOUND
3034     	set_ub_number_opt(context, "edns-buffer-size:", 4096);
3035 #endif
3036 	if (context->edns_maximum_udp_payload_size != -1) {
3037 		context->edns_maximum_udp_payload_size = -1;
3038 		dispatch_updated(context,
3039 		    GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE);
3040 	}
3041 	return GETDNS_RETURN_GOOD;
3042 }               /* getdns_context_set_edns_maximum_udp_payload_size */
3043 
3044 /*
3045  * getdns_context_set_edns_maximum_udp_payload_size
3046  *
3047  */
3048 getdns_return_t
getdns_context_set_edns_maximum_udp_payload_size(struct getdns_context * context,uint16_t value)3049 getdns_context_set_edns_maximum_udp_payload_size(struct getdns_context *context,
3050     uint16_t value)
3051 {
3052 	if (!context)
3053 		return GETDNS_RETURN_INVALID_PARAMETER;
3054 
3055 #ifdef HAVE_LIBUNBOUND
3056     	set_ub_number_opt(context, "edns-buffer-size:", value);
3057 #endif
3058 	if (value != context->edns_maximum_udp_payload_size) {
3059 		context->edns_maximum_udp_payload_size = value;
3060 		dispatch_updated(context,
3061 		    GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE);
3062 	}
3063 	return GETDNS_RETURN_GOOD;
3064 }               /* getdns_context_set_edns_maximum_udp_payload_size */
3065 
3066 /*
3067  * getdns_context_set_edns_extended_rcode
3068  *
3069  */
3070 getdns_return_t
getdns_context_set_edns_extended_rcode(struct getdns_context * context,uint8_t value)3071 getdns_context_set_edns_extended_rcode(struct getdns_context *context, uint8_t value)
3072 {
3073     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3074     context->edns_extended_rcode = value;
3075 
3076     dispatch_updated(context, GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE);
3077 
3078     return GETDNS_RETURN_GOOD;
3079 }               /* getdns_context_set_edns_extended_rcode */
3080 
3081 /*
3082  * getdns_context_set_edns_version
3083  *
3084  */
3085 getdns_return_t
getdns_context_set_edns_version(struct getdns_context * context,uint8_t value)3086 getdns_context_set_edns_version(struct getdns_context *context, uint8_t value)
3087 {
3088     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3089     context->edns_version = value;
3090 
3091     dispatch_updated(context, GETDNS_CONTEXT_CODE_EDNS_VERSION);
3092 
3093     return GETDNS_RETURN_GOOD;
3094 }               /* getdns_context_set_edns_version */
3095 
3096 /*
3097  * getdns_context_set_edns_do_bit
3098  *
3099  */
3100 getdns_return_t
getdns_context_set_edns_do_bit(struct getdns_context * context,uint8_t value)3101 getdns_context_set_edns_do_bit(struct getdns_context *context, uint8_t value)
3102 {
3103     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3104     /* only allow 1 */
3105     if (value != 0 && value != 1) {
3106         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
3107     }
3108 
3109     context->edns_do_bit = value;
3110 
3111     dispatch_updated(context, GETDNS_CONTEXT_CODE_EDNS_DO_BIT);
3112 
3113     return GETDNS_RETURN_GOOD;
3114 }               /* getdns_context_set_edns_do_bit */
3115 
3116 /*
3117  * getdns_context_set_edns_client_subnet_private
3118  *
3119  */
3120 getdns_return_t
getdns_context_set_edns_client_subnet_private(struct getdns_context * context,uint8_t value)3121 getdns_context_set_edns_client_subnet_private(struct getdns_context *context, uint8_t value)
3122 {
3123     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3124     /* only allow 1 */
3125     if (value != 0 && value != 1) {
3126         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
3127     }
3128 
3129     context->edns_client_subnet_private = value;
3130 
3131     dispatch_updated(context, GETDNS_CONTEXT_CODE_EDNS_CLIENT_SUBNET_PRIVATE);
3132 
3133     return GETDNS_RETURN_GOOD;
3134 }               /* getdns_context_set_edns_client_subnet_private */
3135 
3136 /*
3137  * getdns_context_set_tls_query_padding_blocksize
3138  *
3139  */
3140 getdns_return_t
getdns_context_set_tls_query_padding_blocksize(struct getdns_context * context,uint16_t value)3141 getdns_context_set_tls_query_padding_blocksize(struct getdns_context *context, uint16_t value)
3142 {
3143     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3144     /* only allow values between 0 and MAXIMUM_UPSTREAM_OPTION_SPACE - 4
3145        (4 is for the overhead of the option itself) */
3146     if (value > MAXIMUM_UPSTREAM_OPTION_SPACE - 4) {
3147         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
3148     }
3149 
3150     context->tls_query_padding_blocksize = value;
3151 
3152     dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_QUERY_PADDING_BLOCKSIZE);
3153 
3154     return GETDNS_RETURN_GOOD;
3155 }               /* getdns_context_set_tls_query_padding_blocksize */
3156 /*
3157  * getdns_context_set_extended_memory_functions
3158  *
3159  */
3160 getdns_return_t
getdns_context_set_extended_memory_functions(struct getdns_context * context,void * userarg,void * (* malloc)(void * userarg,size_t),void * (* realloc)(void * userarg,void *,size_t),void (* free)(void * userarg,void *))3161 getdns_context_set_extended_memory_functions(
3162     struct getdns_context *context,
3163     void *userarg,
3164     void *(*malloc) (void *userarg, size_t),
3165     void *(*realloc) (void *userarg, void *, size_t),
3166     void (*free) (void *userarg, void *)
3167     )
3168 {
3169     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3170     if (!malloc || !realloc || !free)
3171         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
3172 
3173     context->mf.mf_arg         = userarg;
3174     context->mf.mf.ext.malloc  = malloc;
3175     context->mf.mf.ext.realloc = realloc;
3176     context->mf.mf.ext.free    = free;
3177 
3178     dispatch_updated(context, GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS);
3179 
3180     return GETDNS_RETURN_GOOD;
3181 } /* getdns_context_set_extended_memory_functions*/
3182 
3183 
3184 /*
3185  * getdns_context_set_memory_functions
3186  *
3187  */
3188 getdns_return_t
getdns_context_set_memory_functions(struct getdns_context * context,void * (* malloc)(size_t),void * (* realloc)(void *,size_t),void (* free)(void *))3189 getdns_context_set_memory_functions(struct getdns_context *context,
3190     void *(*malloc) (size_t),
3191     void *(*realloc) (void *, size_t),
3192     void (*free) (void *)
3193     )
3194 {
3195     mf_union mf;
3196     mf.pln.malloc = malloc;
3197     mf.pln.realloc = realloc;
3198     mf.pln.free = free;
3199     return getdns_context_set_extended_memory_functions(
3200         context, MF_PLAIN, mf.ext.malloc, mf.ext.realloc, mf.ext.free);
3201 } /* getdns_context_set_memory_functions*/
3202 
3203 void
_getdns_context_track_outbound_request(getdns_dns_req * dnsreq)3204 _getdns_context_track_outbound_request(getdns_dns_req *dnsreq)
3205 {
3206 	/* Called only by getdns_general_ns() after successful allocation */
3207 	assert(dnsreq);
3208 
3209 	dnsreq->node.key = &(dnsreq->trans_id);
3210 	if (_getdns_rbtree_insert(
3211 	    &dnsreq->context->outbound_requests, &dnsreq->node))
3212 		getdns_context_request_count_changed(dnsreq->context);
3213 }
3214 
3215 void
_getdns_context_clear_outbound_request(getdns_dns_req * dnsreq)3216 _getdns_context_clear_outbound_request(getdns_dns_req *dnsreq)
3217 {
3218     	if (!dnsreq) return;
3219 
3220 	if (dnsreq->loop && dnsreq->loop->vmt && dnsreq->timeout.timeout_cb) {
3221 		dnsreq->loop->vmt->clear(dnsreq->loop, &dnsreq->timeout);
3222 		dnsreq->timeout.timeout_cb = NULL;
3223 	}
3224 	/* delete the node from the tree */
3225 	if (_getdns_rbtree_delete(
3226 	    &dnsreq->context->outbound_requests, &dnsreq->trans_id))
3227 		getdns_context_request_count_changed(dnsreq->context);
3228 
3229 	if (dnsreq->chain)
3230 		_getdns_cancel_validation_chain(dnsreq);
3231 }
3232 
3233 void
_getdns_context_cancel_request(getdns_dns_req * dnsreq)3234 _getdns_context_cancel_request(getdns_dns_req *dnsreq)
3235 {
3236 	getdns_network_req *netreq, **netreq_p;
3237 
3238 	DEBUG_SCHED("%s(%p)\n", __FUNC__, (void *)dnsreq);
3239 	if (!dnsreq) return;
3240 
3241 	_getdns_context_clear_outbound_request(dnsreq);
3242 
3243 	/* cancel network requests */
3244 	for (netreq_p = dnsreq->netreqs; (netreq = *netreq_p); netreq_p++)
3245 #ifdef HAVE_LIBUNBOUND
3246 		if (netreq->unbound_id != -1) {
3247 			ub_cancel(dnsreq->context->unbound_ctx,
3248 			    netreq->unbound_id);
3249 			netreq->unbound_id = -1;
3250 		} else
3251 #endif
3252 			_getdns_cancel_stub_request(netreq);
3253 
3254 	/* clean up */
3255 	_getdns_dns_req_free(dnsreq);
3256 }
3257 
3258 /*
3259  * getdns_cancel_callback
3260  *
3261  */
3262 getdns_return_t
getdns_cancel_callback(getdns_context * context,getdns_transaction_t transaction_id)3263 getdns_cancel_callback(getdns_context *context,
3264     getdns_transaction_t transaction_id)
3265 {
3266 	getdns_dns_req *dnsreq;
3267 
3268 	if (!context)
3269 		return GETDNS_RETURN_INVALID_PARAMETER;
3270 
3271 	/* delete the node from the tree */
3272 	if (!(dnsreq = (getdns_dns_req *)_getdns_rbtree_delete(
3273 	    &context->outbound_requests, &transaction_id)))
3274 		return GETDNS_RETURN_UNKNOWN_TRANSACTION;
3275 
3276 	getdns_context_request_count_changed(context);
3277 
3278 	debug_req("CB Cancel  ", *dnsreq->netreqs);
3279 	if (dnsreq->user_callback) {
3280 		dnsreq->context->processing = 1;
3281 		dnsreq->user_callback(dnsreq->context, GETDNS_CALLBACK_CANCEL,
3282 		    NULL, dnsreq->user_pointer, dnsreq->trans_id);
3283 		dnsreq->context->processing = 0;
3284 	}
3285 	if (!dnsreq->internal_cb) { /* Not part of chain */
3286 		debug_req("Destroy    ", *dnsreq->netreqs);
3287 		_getdns_context_cancel_request(dnsreq);
3288 	}
3289 	return GETDNS_RETURN_GOOD;
3290 } /* getdns_cancel_callback */
3291 
3292 void
_getdns_context_request_timed_out(getdns_dns_req * dnsreq)3293 _getdns_context_request_timed_out(getdns_dns_req *dnsreq)
3294 {
3295 	DEBUG_SCHED("%s(%p)\n", __FUNC__, (void *)dnsreq);
3296 
3297 	debug_req("CB Timeout ", *dnsreq->netreqs);
3298 	if (dnsreq->user_callback) {
3299 		dnsreq->context->processing = 1;
3300 		dnsreq->user_callback(dnsreq->context, GETDNS_CALLBACK_TIMEOUT,
3301 		    _getdns_create_getdns_response(dnsreq),
3302 		     dnsreq->user_pointer, dnsreq->trans_id);
3303 		dnsreq->context->processing = 0;
3304 	}
3305 	_getdns_context_cancel_request(dnsreq);
3306 }
3307 
3308 static void
accumulate_outstanding_transactions(_getdns_rbnode_t * node,void * arg)3309 accumulate_outstanding_transactions(_getdns_rbnode_t *node, void* arg)
3310 {
3311 	*(*(getdns_transaction_t**)arg)++ = ((getdns_dns_req*)node)->trans_id;
3312 }
3313 
3314 static void
cancel_outstanding_requests(getdns_context * context)3315 cancel_outstanding_requests(getdns_context* context)
3316 {
3317 	getdns_transaction_t *trans_ids, *tids_a, *tids_i;
3318 
3319 	if (context->outbound_requests.count == 0)
3320 		return;
3321 
3322 	tids_i = tids_a = trans_ids = GETDNS_XMALLOC(context->my_mf,
3323 	    getdns_transaction_t, context->outbound_requests.count);
3324 
3325 	_getdns_traverse_postorder(&context->outbound_requests,
3326 	    accumulate_outstanding_transactions, &tids_a);
3327 
3328 	while (tids_i < tids_a) {
3329 
3330 		/* We have to cancel by transaction_id because we do not know
3331 		 * what happens when the user_callback is called.  It might
3332 		 * delete getdns_dns_req's that were scheduled to be canceled.
3333 		 * The extra lookup with transaction_id makes sure we do not
3334 		 * access freed memory.
3335 		 */
3336 		(void) getdns_cancel_callback(context, *tids_i++);
3337 	}
3338 	GETDNS_FREE(context->my_mf, trans_ids);
3339 }
3340 
3341 #ifndef STUB_NATIVE_DNSSEC
3342 
3343 static uint32_t *
upstream_scope_id(getdns_upstream * upstream)3344 upstream_scope_id(getdns_upstream *upstream)
3345 {
3346 	return upstream->addr.ss_family == AF_INET ? NULL
3347 	    : (upstream_addr(upstream)[0] == 0xFE &&
3348 	       (upstream_addr(upstream)[1] & 0xC0) == 0x80 ?
3349 	       &((struct sockaddr_in6*)&upstream->addr)->sin6_scope_id : NULL);
3350 }
3351 
3352 static void
upstream_ntop_buf(getdns_upstream * upstream,char * buf,size_t len)3353 upstream_ntop_buf(getdns_upstream *upstream, char *buf, size_t len)
3354 {
3355 	/* Also possible but prints scope_id by name (nor parsed by unbound)
3356 	 *
3357 	 * getnameinfo((struct sockaddr *)&upstream->addr, upstream->addr_len,
3358 	 *     buf, len, NULL, 0, NI_NUMERICHOST)
3359 	 */
3360 	(void) inet_ntop(upstream->addr.ss_family, upstream_addr(upstream),
3361 	    buf, len);
3362 	if (upstream_scope_id(upstream))
3363 		(void) snprintf(buf + strlen(buf), len - strlen(buf),
3364 		    "%%%d", (int)*upstream_scope_id(upstream));
3365 	else if (upstream_port(upstream) != GETDNS_PORT_DNS && upstream_port(upstream) != GETDNS_PORT_ZERO)
3366 		(void) snprintf(buf + strlen(buf), len - strlen(buf),
3367 		    "@%d", (int)upstream_port(upstream));
3368 }
3369 
3370 static getdns_return_t
ub_setup_stub(struct ub_ctx * ctx,getdns_context * context)3371 ub_setup_stub(struct ub_ctx *ctx, getdns_context *context)
3372 {
3373 	getdns_return_t r = GETDNS_RETURN_GOOD;
3374 	size_t i;
3375 	getdns_upstream *upstream;
3376 	char addr[1024];
3377 	getdns_upstreams *upstreams = context->upstreams;
3378 	int r;
3379 
3380 	if ((r = ub_ctx_set_fwd(ctx, NULL))) {
3381 		_getdns_log(&context->log
3382 		    , GETDNS_LOG_SYS_STUB, GETDNS_LOG_WARNING
3383 		    , "%s: %s (%s)\n"
3384 		    , STUB_DEBUG_SETUP
3385 		    , "Error while clearing forwarding modus on unbound context"
3386 		    , ub_strerror(r));
3387 	}
3388 	for (i = 0; i < upstreams->count; i++) {
3389 		upstream = &upstreams->upstreams[i];
3390 		/* [TLS]: Use only the TLS subset of upstreams when TLS is the
3391 		 * only thing used. All other cases must currently fallback to
3392 		 * TCP for libunbound.*/
3393 		if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS &&
3394 		    context->dns_transport_count ==1 &&
3395 			upstream->transport !=  GETDNS_TRANSPORT_TLS)
3396 				continue;
3397 		upstream_ntop_buf(upstream, addr, 1024);
3398 		if ((r = ub_ctx_set_fwd(ctx, addr))) {
3399 			_getdns_log(&context->log
3400 			    , GETDNS_LOG_SYS_STUB, GETDNS_LOG_WARNING
3401 			    , "%s: %s '%s' (%s)\n"
3402 			    , STUB_DEBUG_SETUP
3403 			    , "Error while setting up unbound context for "
3404 			      "forwarding to"
3405 			    , addr
3406 			    , ub_strerror(r));
3407 		}
3408 	}
3409 
3410 	/* Allow lookups of:
3411 	 */
3412 	/* - localhost */
3413 	(void)ub_ctx_zone_remove(ctx, "localhost.");
3414 
3415 	/* - reverse IPv4 loopback */
3416 	(void)ub_ctx_zone_remove(ctx, "127.in-addr.arpa.");
3417 
3418 	/* - reverse IPv6 loopback */
3419 	(void)ub_ctx_zone_remove(ctx, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0."
3420 	                              "0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.");
3421 
3422 	/* - reverse RFC1918 local use zones */
3423 	(void)ub_ctx_zone_remove(ctx, "10.in-addr.arpa.");
3424 	(void)ub_ctx_zone_remove(ctx, "16.172.in-addr.arpa.");
3425 	(void)ub_ctx_zone_remove(ctx, "17.172.in-addr.arpa.");
3426 	(void)ub_ctx_zone_remove(ctx, "18.172.in-addr.arpa.");
3427 	(void)ub_ctx_zone_remove(ctx, "19.172.in-addr.arpa.");
3428 	(void)ub_ctx_zone_remove(ctx, "20.172.in-addr.arpa.");
3429 	(void)ub_ctx_zone_remove(ctx, "21.172.in-addr.arpa.");
3430 	(void)ub_ctx_zone_remove(ctx, "22.172.in-addr.arpa.");
3431 	(void)ub_ctx_zone_remove(ctx, "23.172.in-addr.arpa.");
3432 	(void)ub_ctx_zone_remove(ctx, "24.172.in-addr.arpa.");
3433 	(void)ub_ctx_zone_remove(ctx, "25.172.in-addr.arpa.");
3434 	(void)ub_ctx_zone_remove(ctx, "26.172.in-addr.arpa.");
3435 	(void)ub_ctx_zone_remove(ctx, "27.172.in-addr.arpa.");
3436 	(void)ub_ctx_zone_remove(ctx, "28.172.in-addr.arpa.");
3437 	(void)ub_ctx_zone_remove(ctx, "29.172.in-addr.arpa.");
3438 	(void)ub_ctx_zone_remove(ctx, "30.172.in-addr.arpa.");
3439 	(void)ub_ctx_zone_remove(ctx, "31.172.in-addr.arpa.");
3440 	(void)ub_ctx_zone_remove(ctx, "168.192.in-addr.arpa.");
3441 
3442 	/* - reverse RFC3330 IP4 this, link-local, testnet and broadcast */
3443 	(void)ub_ctx_zone_remove(ctx, "0.in-addr.arpa.");
3444 	(void)ub_ctx_zone_remove(ctx, "254.169.in-addr.arpa.");
3445 	(void)ub_ctx_zone_remove(ctx, "2.0.192.in-addr.arpa.");
3446 	(void)ub_ctx_zone_remove(ctx, "100.51.198.in-addr.arpa.");
3447 	(void)ub_ctx_zone_remove(ctx, "113.0.203.in-addr.arpa.");
3448 	(void)ub_ctx_zone_remove(ctx, "255.255.255.255.in-addr.arpa.");
3449 
3450 	/* - reverse RFC4291 IP6 unspecified */
3451 	(void)ub_ctx_zone_remove(ctx, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0."
3452 	                              "0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.");
3453 
3454 	/* - reverse RFC4193 IPv6 Locally Assigned Local Addresses */
3455 	(void)ub_ctx_zone_remove(ctx, "D.F.ip6.arpa.");
3456 
3457 	/* - reverse RFC4291 IPv6 Link Local Addresses */
3458 	(void)ub_ctx_zone_remove(ctx, "8.E.F.ip6.arpa.");
3459 	(void)ub_ctx_zone_remove(ctx, "9.E.F.ip6.arpa.");
3460 	(void)ub_ctx_zone_remove(ctx, "A.E.F.ip6.arpa.");
3461 	(void)ub_ctx_zone_remove(ctx, "B.E.F.ip6.arpa.");
3462 
3463 	/* - reverse IPv6 Example Prefix */
3464 	(void)ub_ctx_zone_remove(ctx, "8.B.D.0.1.0.0.2.ip6.arpa.");
3465 
3466 	return r;
3467 }
3468 #endif
3469 
3470 
3471 #ifdef HAVE_LIBUNBOUND
3472 static getdns_return_t
ub_setup_recursing(struct ub_ctx * ctx,getdns_context * context)3473 ub_setup_recursing(struct ub_ctx *ctx, getdns_context *context)
3474 {
3475 	_getdns_rr_iter rr_spc, *rr;
3476 	char ta_str[8192];
3477 	int r;
3478 
3479 	if ((r = ub_ctx_set_fwd(ctx, NULL))) {
3480 		_getdns_log(&context->log
3481 		    , GETDNS_LOG_SYS_RECURSING, GETDNS_LOG_WARNING
3482 		    , "%s: %s (%s)\n"
3483 		    , STUB_DEBUG_SETUP
3484 		    , "Error while clearing forwarding modus on unbound context"
3485 		    , ub_strerror(r));
3486 	}
3487 	if (!context->unbound_ta_set && context->trust_anchors) {
3488 		for ( rr = _getdns_rr_iter_init( &rr_spc
3489 		                               , context->trust_anchors
3490 		                               , context->trust_anchors_len)
3491 		    ; rr ; rr = _getdns_rr_iter_next(rr) ) {
3492 
3493 			(void) gldns_wire2str_rr_buf((UNCONST_UINT8_p)rr->pos,
3494 			    rr->nxt - rr->pos, ta_str, sizeof(ta_str));
3495 			if ((r = ub_ctx_add_ta(ctx, ta_str))) {
3496 				_getdns_log(&context->log
3497 				    , GETDNS_LOG_SYS_RECURSING
3498 				    , GETDNS_LOG_WARNING
3499 				    , "%s: %s '%s' (%s)\n"
3500 				    , STUB_DEBUG_SETUP
3501 				    , "Error while equiping unbound context "
3502 				      "with trust anchor"
3503 				    , ta_str
3504 				    , ub_strerror(r));
3505 			}
3506 		}
3507 		context->unbound_ta_set = 1;
3508 	}
3509 	return GETDNS_RETURN_GOOD;
3510 }
3511 #endif
3512 
3513 static getdns_return_t
_getdns_ns_dns_setup(struct getdns_context * context)3514 _getdns_ns_dns_setup(struct getdns_context *context)
3515 {
3516 	assert(context);
3517 
3518 	switch (context->resolution_type) {
3519 	case GETDNS_RESOLUTION_STUB:
3520 		if (!context->upstreams || !context->upstreams->count) {
3521 			_getdns_log(&context->log
3522 			    , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR
3523 			    , "%s: %s\n"
3524 			    , STUB_DEBUG_SETUP
3525 			    , "Stub resolution requested, but no upstreams "
3526 			      "configured");
3527 			return GETDNS_RETURN_BAD_CONTEXT;
3528 		}
3529 #ifdef STUB_NATIVE_DNSSEC
3530 # ifdef DNSSEC_ROADBLOCK_AVOIDANCE
3531 #  ifdef HAVE_LIBUNBOUND
3532 		return ub_setup_recursing(context->unbound_ctx, context);
3533 #  else
3534 		/* Return NOT_IMPLEMENTED on query with an
3535 		 * roadblock avoidance extension.
3536 		 */
3537 		return GETDNS_RETURN_GOOD;
3538 #  endif
3539 # else
3540 		return GETDNS_RETURN_GOOD;
3541 # endif
3542 #else
3543 		return ub_setup_stub(context->unbound_ctx, context);
3544 #endif
3545 
3546 	case GETDNS_RESOLUTION_RECURSING:
3547 #ifdef HAVE_LIBUNBOUND
3548 		return ub_setup_recursing(context->unbound_ctx, context);
3549 #else
3550 		return GETDNS_RETURN_NOT_IMPLEMENTED;
3551 #endif
3552 	}
3553 	_getdns_log(&context->log
3554 	    , GETDNS_LOG_SYS_RESOLVING
3555 	    , GETDNS_LOG_ERR
3556 	    , "%s: %s (%d)\n", STUB_DEBUG_SETUP
3557 	    , "Unknown resolution type: "
3558 	    , context->resolution_type);
3559 	return GETDNS_RETURN_BAD_CONTEXT;
3560 }
3561 
3562 getdns_return_t
_getdns_context_prepare_for_resolution(getdns_context * context)3563 _getdns_context_prepare_for_resolution(getdns_context *context)
3564 {
3565 	getdns_return_t r;
3566 
3567 	assert(context);
3568 	if (context->destroying)
3569 		return GETDNS_RETURN_BAD_CONTEXT;
3570 
3571 	/* Transport can in theory be set per query in stub mode */
3572 	if (context->resolution_type == GETDNS_RESOLUTION_STUB &&
3573 	    tls_is_in_transports_list(context) == 1) {
3574 		/* Check minimum require authentication level*/
3575 		if (tls_only_is_in_transports_list(context) == 1 &&
3576 		    context->tls_auth == GETDNS_AUTHENTICATION_REQUIRED) {
3577 			context->tls_auth_min = GETDNS_AUTHENTICATION_REQUIRED;
3578 			/* TODO: If no auth data provided for any upstream,
3579 			 * fail here
3580 			 */
3581 		}
3582 		else {
3583 			context->tls_auth_min = GETDNS_AUTHENTICATION_NONE;
3584 		}
3585 
3586 		if (context->tls_ctx == NULL) {
3587 			context->tls_ctx = _getdns_tls_context_new(&context->my_mf, &context->log);
3588 			if (context->tls_ctx == NULL)
3589 				return GETDNS_RETURN_BAD_CONTEXT;
3590 
3591 			r = _getdns_tls_context_set_min_max_tls_version(context->tls_ctx, context->tls_min_version, context->tls_max_version);
3592 			if (r) {
3593 				_getdns_tls_context_free(&context->my_mf, context->tls_ctx);
3594 				context->tls_ctx = NULL;
3595 				return r;
3596 			}
3597 
3598 			/* Be strict and only use the cipher suites recommended in RFC7525
3599 			   Unless we later fallback to opportunistic. */
3600 			r = _getdns_tls_context_set_cipher_list(context->tls_ctx, context->tls_cipher_list);
3601 			if (!r)
3602 				r = _getdns_tls_context_set_cipher_suites(context->tls_ctx, context->tls_ciphersuites);
3603 			if (!r && context->tls_curves_list)
3604 				r = _getdns_tls_context_set_curves_list(context->tls_ctx, context->tls_curves_list);
3605 			if (r) {
3606 				_getdns_tls_context_free(&context->my_mf, context->tls_ctx);
3607 				context->tls_ctx = NULL;
3608 				return r;
3609 			}
3610 
3611 			/* For strict authentication, we must have local root certs available
3612 		       Set up is done only when the tls_ctx is created (per getdns_context)*/
3613 			if (_getdns_tls_context_set_ca(context->tls_ctx, context->tls_ca_file, context->tls_ca_path)) {
3614 				if (context->tls_auth_min == GETDNS_AUTHENTICATION_REQUIRED) {
3615 					_getdns_log(&context->log
3616 					    , GETDNS_LOG_SYS_STUB
3617 					    , GETDNS_LOG_DEBUG
3618 					    , "%s: %s\n"
3619 					    , STUB_DEBUG_SETUP_TLS
3620 					    , "Authentication is needed but no "
3621 					      "verify location could be loaded");
3622 					_getdns_tls_context_free(&context->my_mf, context->tls_ctx);
3623 					context->tls_ctx = NULL;
3624 					return GETDNS_RETURN_BAD_CONTEXT;
3625 				}
3626 			}
3627 			_getdns_tls_context_pinset_init(context->tls_ctx);
3628 		}
3629 	}
3630 
3631 	/* Block use of TLS ONLY in recursive mode as it won't work */
3632     /* Note: If TLS is used in recursive mode this will try TLS on port
3633      * 53 so it is blocked here. */
3634 	if (context->resolution_type == GETDNS_RESOLUTION_RECURSING &&
3635 	    tls_only_is_in_transports_list(context) == 1) {
3636 		_getdns_log(&context->log
3637 		    , GETDNS_LOG_SYS_STUB, GETDNS_LOG_ERR
3638 		    , "%s: %s\n"
3639 		    , STUB_DEBUG_SETUP_TLS
3640 		    , "TLS only transport is not supported for the recursing "
3641 		      "resolution type");
3642 		_getdns_tls_context_free(&context->my_mf, context->tls_ctx);
3643 		context->tls_ctx = NULL;
3644 		return GETDNS_RETURN_NOT_IMPLEMENTED;
3645 	}
3646 	if (context->resolution_type_set == context->resolution_type)
3647         	/* already set and no config changes
3648 		 * have caused this to be bad.
3649 		 */
3650 		return GETDNS_RETURN_GOOD;
3651 
3652 	/* TODO: respect namespace order (unbound always uses local first if cfg
3653 	 * the spec calls for us to treat the namespace list as ordered
3654 	 * so we need to respect that order
3655 	 */
3656 	r = _getdns_ns_dns_setup(context);
3657 	if (r == GETDNS_RETURN_GOOD)
3658 		context->resolution_type_set = context->resolution_type;
3659 	return r;
3660 } /* _getdns_context_prepare_for_resolution */
3661 
3662 static char *
_getdns_strdup(const struct mem_funcs * mfs,const char * s)3663 _getdns_strdup(const struct mem_funcs *mfs, const char *s)
3664 {
3665     size_t sz;
3666     char *r;
3667     if (!s || !(r = GETDNS_XMALLOC(*mfs, char, (sz = strlen(s) + 1))))
3668         return NULL;
3669     else
3670         return memcpy(r, s, sz);
3671 }
3672 
3673 static uint8_t _getdns_bindata_nodata[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
3674 
3675 struct getdns_bindata *
_getdns_bindata_copy(struct mem_funcs * mfs,size_t size,const uint8_t * data)3676 _getdns_bindata_copy(struct mem_funcs *mfs, size_t size, const uint8_t *data)
3677 {
3678 	/* Don't know why, but nodata allows
3679 	 * empty bindatas with the python bindings
3680 	 */
3681 	struct getdns_bindata *dst;
3682 
3683 	if (!(dst = GETDNS_MALLOC(*mfs, struct getdns_bindata)))
3684 		return NULL;
3685 
3686 	if ((dst->size = size)) {
3687 		dst->data = GETDNS_XMALLOC(*mfs, uint8_t, size);
3688 		if (!dst->data) {
3689 			GETDNS_FREE(*mfs, dst);
3690 			return NULL;
3691 		}
3692 		(void) memcpy(dst->data, data, size);
3693 	} else {
3694 		dst->data = _getdns_bindata_nodata;
3695 	}
3696 	return dst;
3697 }
3698 
3699 void
_getdns_bindata_destroy(struct mem_funcs * mfs,struct getdns_bindata * bindata)3700 _getdns_bindata_destroy(struct mem_funcs *mfs,
3701     struct getdns_bindata *bindata)
3702 {
3703 	if (!bindata)
3704 		return;
3705 
3706 	if (bindata->data && bindata->data != _getdns_bindata_nodata)
3707 		GETDNS_FREE(*mfs, bindata->data);
3708 	GETDNS_FREE(*mfs, bindata);
3709 }
3710 
3711 /* TODO: Remove next_timeout argument from getdns_context_get_num_pending_requests
3712  */
3713 uint32_t
getdns_context_get_num_pending_requests(const getdns_context * context,struct timeval * next_timeout)3714 getdns_context_get_num_pending_requests(const getdns_context* context,
3715     struct timeval* next_timeout)
3716 {
3717 	(void)next_timeout;
3718 
3719 	if (!context)
3720 		return GETDNS_RETURN_INVALID_PARAMETER;
3721 
3722 	if (context->outbound_requests.count)
3723 		context->extension->vmt->run_once(context->extension, 0);
3724 
3725 	return context->outbound_requests.count;
3726 }
3727 
3728 /* process async reqs */
3729 getdns_return_t
getdns_context_process_async(getdns_context * context)3730 getdns_context_process_async(getdns_context *context)
3731 {
3732 	if (!context)
3733 		return GETDNS_RETURN_INVALID_PARAMETER;
3734 
3735 	context->extension->vmt->run_once(context->extension, 0);
3736 	return GETDNS_RETURN_GOOD;
3737 }
3738 
3739 void
getdns_context_run(getdns_context * context)3740 getdns_context_run(getdns_context *context)
3741 {
3742 	context->extension->vmt->run(context->extension);
3743 }
3744 
3745 getdns_return_t
getdns_context_detach_eventloop(struct getdns_context * context)3746 getdns_context_detach_eventloop(struct getdns_context* context)
3747 {
3748 	RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
3749 
3750 	/* When called from within a callback, do not execute pending
3751 	 * context destroys.
3752 	 * The (other) callback handler will handle it.
3753 	 *
3754 	 * ( because callbacks occur in cancel_outstanding_requests,
3755 	 *   and they may destroy the context )
3756 	 */
3757 	/* cancel all outstanding requests */
3758 	cancel_outstanding_requests(context);
3759 	context->extension->vmt->cleanup(context->extension);
3760 	context->extension = &context->default_eventloop.loop;
3761 	_getdns_default_eventloop_init(&context->mf, &context->default_eventloop);
3762 #ifdef HAVE_UNBOUND_EVENT_API
3763 	if (_getdns_ub_loop_enabled(&context->ub_loop))
3764 		context->ub_loop.extension = context->extension;
3765 #endif
3766 	return GETDNS_RETURN_GOOD;
3767 }
3768 
3769 getdns_return_t
getdns_context_set_eventloop(getdns_context * context,getdns_eventloop * loop)3770 getdns_context_set_eventloop(getdns_context* context, getdns_eventloop* loop)
3771 {
3772 	if (!context || !loop)
3773 		return GETDNS_RETURN_INVALID_PARAMETER;
3774 
3775 	if (context->extension) {
3776 		cancel_outstanding_requests(context);
3777 		context->extension->vmt->cleanup(context->extension);
3778 	}
3779 	context->extension = loop;
3780 #ifdef HAVE_UNBOUND_EVENT_API
3781 	if (_getdns_ub_loop_enabled(&context->ub_loop))
3782 		context->ub_loop.extension = loop;
3783 #endif
3784 	return GETDNS_RETURN_GOOD;
3785 }
3786 
3787 getdns_return_t
getdns_context_get_eventloop(const getdns_context * context,getdns_eventloop ** loop)3788 getdns_context_get_eventloop(
3789     const getdns_context *context, getdns_eventloop **loop)
3790 {
3791 	if (!context || !loop)
3792 		return GETDNS_RETURN_INVALID_PARAMETER;
3793 
3794 	if (!context->extension)
3795 		return GETDNS_RETURN_GENERIC_ERROR;
3796 	else
3797 		*loop = context->extension;
3798 
3799 	return GETDNS_RETURN_GOOD;
3800 }
3801 
3802 static size_t _getdns_get_appdata(const getdns_context *context, char *path);
3803 static getdns_dict*
_get_context_settings(const getdns_context * context)3804 _get_context_settings(const getdns_context* context)
3805 {
3806 	getdns_dict *result = getdns_dict_create_with_context(context);
3807 	getdns_list *list;
3808 	size_t       i;
3809 	const char  *str_value;
3810 	char         appdata_dir[_GETDNS_PATH_MAX] = "";
3811 
3812 	if (!result)
3813 		return NULL;
3814 
3815 	/* int fields */
3816 	/* the timeouts are stored as uint64, but the value maximum used in
3817 	   practice is 6553500ms, so we just trim the value to be on the safe side. */
3818 	if (   getdns_dict_set_int(result, "timeout",
3819 	                           (context->timeout > 0xFFFFFFFFull) ? 0xFFFFFFFF: (uint32_t) context->timeout)
3820 	    || getdns_dict_set_int(result, "idle_timeout",
3821 	                           (context->idle_timeout > 0xFFFFFFFFull) ? 0xFFFFFFFF : (uint32_t) context->idle_timeout)
3822 	    || getdns_dict_set_int(result, "limit_outstanding_queries",
3823 	                           context->limit_outstanding_queries)
3824             || getdns_dict_set_int(result, "dnssec_allowed_skew",
3825 	                           context->dnssec_allowed_skew)
3826 	    || getdns_dict_set_int(result, "follow_redirects",
3827 	                           context->follow_redirects)
3828 	    || (  context->edns_maximum_udp_payload_size != -1
3829 	       && getdns_dict_set_int(result, "edns_maximum_udp_payload_size",
3830 	                              context->edns_maximum_udp_payload_size))
3831 	    || getdns_dict_set_int(result, "edns_client_subnet_private",
3832 	                           context->edns_client_subnet_private)
3833 	    || getdns_dict_set_int(result, "edns_extended_rcode",
3834 	                           context->edns_extended_rcode)
3835 	    || getdns_dict_set_int(result, "edns_version",
3836 	                           context->edns_version)
3837 	    || getdns_dict_set_int(result, "edns_do_bit",
3838 	                           context->edns_do_bit)
3839 	    || getdns_dict_set_int(result, "append_name",
3840 	                           context->append_name)
3841 	    || getdns_dict_set_int(result, "tls_authentication",
3842 	                           context->tls_auth)
3843 	    || getdns_dict_set_int(result, "round_robin_upstreams",
3844 	                           context->round_robin_upstreams)
3845 	    || getdns_dict_set_int(result, "max_backoff_value",
3846 	                           context->max_backoff_value)
3847 	    || getdns_dict_set_int(result, "tls_backoff_time",
3848 	                           context->tls_backoff_time)
3849 	    || getdns_dict_set_int(result, "tls_connection_retries",
3850 	                           context->tls_connection_retries)
3851 	    || getdns_dict_set_int(result, "tls_query_padding_blocksize",
3852 	                           context->tls_query_padding_blocksize)
3853 	    || getdns_dict_set_int(result, "resolution_type",
3854 	                           context->resolution_type)
3855 	    || getdns_dict_set_int(result, "trust_anchors_backoff_time",
3856 	                           context->trust_anchors_backoff_time)
3857 	    )
3858 		goto error;
3859 
3860 	/* list fields */
3861 	if (getdns_context_get_suffix(context, &list))
3862 		goto error;
3863 
3864 	if (_getdns_dict_set_this_list(result, "suffix", list)) {
3865 		getdns_list_destroy(list);
3866 		goto error;
3867 	}
3868 	if (getdns_context_get_upstream_recursive_servers(context, &list))
3869 		goto error;
3870 
3871 	if (_getdns_dict_set_this_list(
3872 	    result, "upstream_recursive_servers", list)) {
3873 		getdns_list_destroy(list);
3874 		goto error;
3875 	}
3876 	if (getdns_context_get_dnssec_trust_anchors(context, &list))
3877 		; /* pass */
3878 
3879 	else if (list && _getdns_dict_set_this_list(
3880 	    result, "dnssec_trust_anchors", list)) {
3881 		getdns_list_destroy(list);
3882 		goto error;
3883 	}
3884 	if (context->dns_transport_count > 0) {
3885 		/* create a namespace list */
3886 		if (!(list = getdns_list_create_with_context(context)))
3887 			goto error;
3888 
3889 		for (i = 0; i < context->dns_transport_count; ++i) {
3890 			if (getdns_list_set_int(list, i,
3891 			    context->dns_transports[i])) {
3892 				getdns_list_destroy(list);
3893 				goto error;
3894 			}
3895 		}
3896 		if (_getdns_dict_set_this_list(
3897 		    result, "dns_transport_list", list)) {
3898 			getdns_list_destroy(list);
3899 			goto error;
3900 		}
3901 	}
3902 	if (context->namespace_count > 0) {
3903         /* create a namespace list */
3904 		if (!(list = getdns_list_create_with_context(context)))
3905 			goto error;
3906 
3907 		for (i = 0; i < context->namespace_count; ++i) {
3908 			if (getdns_list_set_int(list, i,
3909 			    context->namespaces[i])) {
3910 				getdns_list_destroy(list);
3911 				goto error;
3912 			}
3913 		}
3914 		if (_getdns_dict_set_this_list(result, "namespaces", list)) {
3915 			getdns_list_destroy(list);
3916 			return NULL;
3917 		}
3918 	}
3919 	(void) _getdns_get_appdata(context, appdata_dir);
3920 	(void) getdns_dict_util_set_string(result, "appdata_dir", appdata_dir);
3921 	if (!getdns_context_get_trust_anchors_url(context, &str_value) && str_value)
3922 		(void) getdns_dict_util_set_string(result, "trust_anchors_url", str_value);
3923 	if (!getdns_context_get_trust_anchors_verify_CA(context, &str_value) && str_value)
3924 		(void) getdns_dict_util_set_string(result, "trust_anchors_verify_CA", str_value);
3925 	if (!getdns_context_get_trust_anchors_verify_email(context, &str_value) && str_value)
3926 		(void) getdns_dict_util_set_string(result, "trust_anchors_verify_email", str_value);
3927 	if (!getdns_context_get_resolvconf(context, &str_value) && str_value)
3928 		(void) getdns_dict_util_set_string(result, "resolvconf", str_value);
3929 	if (!getdns_context_get_hosts(context, &str_value) && str_value)
3930 		(void) getdns_dict_util_set_string(result, "hosts", str_value);
3931 	if (!getdns_context_get_tls_ca_path(context, &str_value) && str_value)
3932 		(void) getdns_dict_util_set_string(result, "tls_ca_path", str_value);
3933 	if (!getdns_context_get_tls_ca_file(context, &str_value) && str_value)
3934 		(void) getdns_dict_util_set_string(result, "tls_ca_file", str_value);
3935 	if (!getdns_context_get_tls_cipher_list(context, &str_value) && str_value)
3936 		(void) getdns_dict_util_set_string(result, "tls_cipher_list", str_value);
3937 	if (!getdns_context_get_tls_ciphersuites(context, &str_value) && str_value)
3938 		(void) getdns_dict_util_set_string(result, "tls_ciphersuites", str_value);
3939 	if (!getdns_context_get_tls_curves_list(context, &str_value) && str_value)
3940 		(void) getdns_dict_util_set_string(result, "tls_curves_list", str_value);
3941 	if (context->tls_min_version)
3942 		(void) getdns_dict_set_int( result, "tls_min_version"
3943 		                          , context->tls_min_version);
3944 	if (context->tls_max_version)
3945 		(void) getdns_dict_set_int( result, "tls_max_version"
3946 		                          , context->tls_max_version);
3947 
3948 	/* Default settings for extensions */
3949 	(void)getdns_dict_set_int(
3950 	    result, "add_warning_for_bad_dns",
3951 	    context->add_warning_for_bad_dns ? GETDNS_EXTENSION_TRUE
3952 	                                     : GETDNS_EXTENSION_FALSE);
3953 	(void)getdns_dict_set_int(
3954 	    result, "dnssec_return_all_statuses",
3955 	    context->dnssec_return_all_statuses ? GETDNS_EXTENSION_TRUE
3956 	                                        : GETDNS_EXTENSION_FALSE);
3957 	(void)getdns_dict_set_int(
3958 	    result, "dnssec_return_full_validation_chain",
3959 	    context->dnssec_return_full_validation_chain ? GETDNS_EXTENSION_TRUE
3960 	                                                 : GETDNS_EXTENSION_FALSE);
3961 	(void)getdns_dict_set_int(
3962 	    result, "dnssec",
3963 	    context->dnssec ? GETDNS_EXTENSION_TRUE : GETDNS_EXTENSION_FALSE);
3964 
3965 	(void)getdns_dict_set_int(
3966 	    result, "dnssec_return_only_secure",
3967 	    context->dnssec_return_only_secure ? GETDNS_EXTENSION_TRUE
3968 	                                       : GETDNS_EXTENSION_FALSE);
3969 	(void)getdns_dict_set_int(
3970 	    result, "dnssec_return_status",
3971 	    context->dnssec_return_status ? GETDNS_EXTENSION_TRUE
3972 	                                  : GETDNS_EXTENSION_FALSE);
3973 	(void)getdns_dict_set_int(
3974 	    result, "dnssec_return_validation_chain",
3975 	    context->dnssec_return_validation_chain ? GETDNS_EXTENSION_TRUE
3976 	                                            : GETDNS_EXTENSION_FALSE);
3977 
3978 #if defined(DNSSEC_ROADBLOCK_AVOIDANCE) && defined(HAVE_LIBUNBOUND)
3979 	(void)getdns_dict_set_int(
3980 	    result, "dnssec_roadblock_avoidance",
3981 	    context->dnssec_roadblock_avoidance ? GETDNS_EXTENSION_TRUE
3982 	                                        : GETDNS_EXTENSION_FALSE);
3983 #endif
3984 #ifdef EDNS_COOKIES
3985 	(void)getdns_dict_set_int(
3986 	    result, "edns_cookies",
3987 	    context->edns_cookies ? GETDNS_EXTENSION_TRUE
3988 	                          : GETDNS_EXTENSION_FALSE);
3989 #endif
3990 	(void)getdns_dict_set_int(
3991 	    result, "return_both_v4_and_v6",
3992 	    context->return_both_v4_and_v6 ? GETDNS_EXTENSION_TRUE
3993 	                                   : GETDNS_EXTENSION_FALSE);
3994 	(void)getdns_dict_set_int(
3995 	    result, "return_call_reporting",
3996 	    context->return_call_reporting ? GETDNS_EXTENSION_TRUE
3997 	                                   : GETDNS_EXTENSION_FALSE);
3998 	(void)getdns_dict_set_int(result, "specify_class",
3999 	    (uint32_t)context->specify_class);
4000 
4001 	if (context->add_opt_parameters)
4002 		(void)getdns_dict_set_dict(
4003 		    result, "add_opt_parameters", context->add_opt_parameters);
4004 
4005 	if (context->header)
4006 		(void)getdns_dict_set_dict(
4007 		    result, "header", context->add_opt_parameters);
4008 
4009 	return result;
4010 error:
4011 	getdns_dict_destroy(result);
4012 	return NULL;
4013 }
4014 
4015 getdns_dict*
getdns_context_get_api_information(const getdns_context * context)4016 getdns_context_get_api_information(const getdns_context* context)
4017 {
4018 	getdns_dict* result;
4019 	getdns_dict* settings;
4020 
4021 	if ((result = getdns_dict_create_with_context(context))
4022 
4023 	    && ! getdns_dict_util_set_string(
4024 	    result, "version_string", GETDNS_VERSION)
4025 
4026 	    && ! getdns_dict_set_int(
4027 	    result, "version_number", getdns_get_version_number())
4028 
4029 	    && ! getdns_dict_util_set_string(
4030 	    result, "api_version_string", getdns_get_api_version())
4031 
4032 	    && ! getdns_dict_set_int(
4033 	    result, "api_version_number", getdns_get_api_version_number())
4034 
4035 	    && ! getdns_dict_util_set_string(
4036 	    result, "implementation_string", PACKAGE_URL)
4037 
4038 	    && ! getdns_dict_util_set_string(
4039 	    result, "compilation_comment", GETDNS_COMPILATION_COMMENT)
4040 
4041 	    && ! getdns_dict_util_set_string(
4042 	    result, "default_trust_anchor_location", TRUST_ANCHOR_FILE)
4043 
4044 	    && ! getdns_dict_util_set_string(
4045 	    result, "default_resolvconf_location", GETDNS_FN_RESOLVCONF)
4046 
4047 	    && ! getdns_dict_util_set_string(
4048 	    result, "default_hosts_location", GETDNS_FN_HOSTS)
4049 
4050 	    && ! _getdns_tls_get_api_information(result)
4051 
4052 	    && ! getdns_dict_set_int(
4053 	    result, "resolution_type", context->resolution_type)
4054 
4055 	    && (settings = _get_context_settings(context))) {
4056 
4057 		if (!_getdns_dict_set_this_dict(result,"all_context",settings))
4058 			return result;
4059 
4060 		getdns_dict_destroy(settings);
4061 	}
4062 	getdns_dict_destroy(result);
4063 	return NULL;
4064 }
4065 
4066 getdns_return_t
getdns_context_set_return_dnssec_status(getdns_context * context,int enabled)4067 getdns_context_set_return_dnssec_status(getdns_context* context, int enabled) {
4068     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
4069     if (enabled != GETDNS_EXTENSION_TRUE &&
4070         enabled != GETDNS_EXTENSION_FALSE) {
4071         return GETDNS_RETURN_INVALID_PARAMETER;
4072     }
4073     context->dnssec_return_status = enabled == GETDNS_EXTENSION_TRUE;
4074     return GETDNS_RETURN_GOOD;
4075 }
4076 
4077 getdns_return_t
getdns_context_set_use_threads(getdns_context * context,int use_threads)4078 getdns_context_set_use_threads(getdns_context* context, int use_threads) {
4079     RETURN_IF_NULL(context, GETDNS_RETURN_INVALID_PARAMETER);
4080     int r = 0;
4081     if (context->resolution_type_set != 0) {
4082         /* already setup */
4083         return GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
4084     }
4085 #ifdef HAVE_LIBUNBOUND
4086     if (use_threads)
4087         r = ub_ctx_async(context->unbound_ctx, 1);
4088     else
4089         r = ub_ctx_async(context->unbound_ctx, 0);
4090 #else
4091     (void)use_threads;
4092 #endif
4093     return r == 0 ? GETDNS_RETURN_GOOD : GETDNS_RETURN_CONTEXT_UPDATE_FAIL;
4094 }
4095 
4096 getdns_return_t
_getdns_context_local_namespace_resolve(getdns_dns_req * dnsreq,getdns_dict ** response)4097 _getdns_context_local_namespace_resolve(
4098     getdns_dns_req *dnsreq, getdns_dict **response)
4099 {
4100 	getdns_context  *context = dnsreq->context;
4101 	host_name_addrs *hnas;
4102 	uint8_t lookup[256];
4103 	getdns_list    empty_list = { 0, 0, NULL, { NULL, {{ NULL,NULL,NULL}}}};
4104 	getdns_bindata bindata;
4105 	getdns_list   *jaa;
4106 	size_t         i;
4107 	getdns_dict   *addr;
4108 	int ipv4 = dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_A ||
4109 	    (dnsreq->netreqs[1] &&
4110 	     dnsreq->netreqs[1]->request_type == GETDNS_RRTYPE_A);
4111 	int ipv6 = dnsreq->netreqs[0]->request_type == GETDNS_RRTYPE_AAAA ||
4112 	    (dnsreq->netreqs[1] &&
4113 	     dnsreq->netreqs[1]->request_type == GETDNS_RRTYPE_AAAA);
4114 	getdns_return_t r;
4115 
4116 	if (!ipv4 && !ipv6)
4117 		return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
4118 
4119 	/*Do the lookup*/
4120 	(void)memcpy(lookup, dnsreq->name, dnsreq->name_len);
4121 	canonicalize_dname(lookup);
4122 
4123 	if (!(hnas = (host_name_addrs *)
4124 	    _getdns_rbtree_search(&context->local_hosts, lookup)))
4125 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
4126 
4127 	if (!hnas->ipv4addrs && (!ipv6 || !hnas->ipv6addrs))
4128 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
4129 
4130 	if (!hnas->ipv6addrs && (!ipv4 || !hnas->ipv4addrs))
4131 		return GETDNS_RETURN_NO_SUCH_DICT_NAME;
4132 
4133 	if (!(*response = getdns_dict_create_with_context(context)))
4134 		return GETDNS_RETURN_MEMORY_ERROR;
4135 
4136 	bindata.size = dnsreq->name_len;
4137 	bindata.data = dnsreq->name;
4138 	if ((r = getdns_dict_set_bindata(*response,"canonical_name",&bindata)))
4139 		goto error;
4140 
4141 	empty_list.mf = context->mf;
4142 	if ((r = getdns_dict_set_list(*response, "replies_full", &empty_list)))
4143 		goto error;
4144 
4145 	if ((r = getdns_dict_set_list(*response, "replies_tree", &empty_list)))
4146 		goto error;
4147 
4148 	if ((r=getdns_dict_set_int(*response,"status",GETDNS_RESPSTATUS_GOOD)))
4149 		goto error;
4150 
4151 	if (!ipv4 || !hnas->ipv4addrs) {
4152 		if ((r = getdns_dict_set_list(*response,
4153 		    "just_address_answers", hnas->ipv6addrs)))
4154 			goto error;
4155 		return GETDNS_RETURN_GOOD;
4156 	} else if (!ipv6 || !hnas->ipv6addrs) {
4157 		if ((r = getdns_dict_set_list(*response,
4158 		    "just_address_answers", hnas->ipv4addrs)))
4159 			goto error;
4160 		return GETDNS_RETURN_GOOD;
4161 	}
4162 	if (!(jaa = getdns_list_create_with_context(context))) {
4163 		r = GETDNS_RETURN_MEMORY_ERROR;
4164 		goto error;
4165 	}
4166 
4167 	for (i = 0; !getdns_list_get_dict(hnas->ipv4addrs, i, &addr); i++)
4168 		if ((r = _getdns_list_append_dict(jaa, addr)))
4169 			break;
4170 	for (i = 0; !getdns_list_get_dict(hnas->ipv6addrs, i, &addr); i++)
4171 		if ((r = _getdns_list_append_dict(jaa, addr)))
4172 			break;
4173 	if (!(r = _getdns_dict_set_this_list(*response, "just_address_answers", jaa)))
4174 		return GETDNS_RETURN_GOOD;
4175 	else
4176 		getdns_list_destroy(jaa);
4177 error:
4178 	getdns_dict_destroy(*response);
4179 	return r;
4180 }
4181 
4182 struct mem_funcs *
priv_getdns_context_mf(getdns_context * context)4183 priv_getdns_context_mf(getdns_context *context)
4184 {
4185 	return &context->mf;
4186 }
4187 
4188 /** begin getters **/
4189 
4190 #define CONTEXT_GETTER2(NAME,TYPE,VALUE) \
4191     getdns_return_t \
4192     getdns_context_get_ ## NAME ( \
4193         const getdns_context *context, TYPE *value) \
4194     { if (!context || !value)	return GETDNS_RETURN_INVALID_PARAMETER \
4195     ; *value = context-> VALUE;	return GETDNS_RETURN_GOOD; }
4196 
4197 #define CONTEXT_GETTER(NAME,TYPE) CONTEXT_GETTER2(NAME,TYPE,NAME)
4198 
CONTEXT_GETTER(resolution_type,getdns_resolution_t)4199 CONTEXT_GETTER(resolution_type, getdns_resolution_t)
4200 
4201 getdns_return_t
4202 getdns_context_get_namespaces(const getdns_context *context,
4203     size_t* namespace_count, getdns_namespace_t **namespaces)
4204 {
4205 	if (!context || !namespace_count || !namespaces)
4206 		return GETDNS_RETURN_INVALID_PARAMETER;
4207 	*namespace_count = context->namespace_count;
4208 	if (!context->namespace_count) {
4209 		*namespaces = NULL;
4210 		return GETDNS_RETURN_GOOD;
4211 	}
4212 	// use normal malloc here so users can do normal free
4213 	*namespaces = malloc(
4214 	    context->namespace_count * sizeof(getdns_namespace_t));
4215 	memcpy(*namespaces, context->namespaces,
4216 	    context->namespace_count * sizeof(getdns_namespace_t));
4217 	return GETDNS_RETURN_GOOD;
4218 }
4219 
4220 getdns_return_t
getdns_context_get_dns_transport(const getdns_context * context,getdns_transport_t * value)4221 getdns_context_get_dns_transport(
4222     const getdns_context *context, getdns_transport_t* value)
4223 {
4224 	if (!context || !value)
4225 		return GETDNS_RETURN_INVALID_PARAMETER;
4226 
4227 	if (context->dns_transport_count == 0)
4228 		return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
4229 
4230 	/* Best effort mapping for backwards compatibility*/
4231 	if (context->dns_transports[0] == GETDNS_TRANSPORT_UDP) {
4232 		if (context->dns_transport_count == 1)
4233 			*value = GETDNS_TRANSPORT_UDP_ONLY;
4234 		else if (context->dns_transport_count == 2
4235 		     &&  context->dns_transports[1] == GETDNS_TRANSPORT_TCP)
4236 			*value = GETDNS_TRANSPORT_UDP_FIRST_AND_FALL_BACK_TO_TCP;
4237 		else
4238 			return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
4239 	}
4240 	if (context->dns_transports[0] == GETDNS_TRANSPORT_TCP) {
4241 		if (context->dns_transport_count == 1)
4242 			*value = GETDNS_TRANSPORT_TCP_ONLY_KEEP_CONNECTIONS_OPEN;
4243 	}
4244 	if (context->dns_transports[0] == GETDNS_TRANSPORT_TLS) {
4245 		if (context->dns_transport_count == 1)
4246 			*value = GETDNS_TRANSPORT_TLS_ONLY_KEEP_CONNECTIONS_OPEN;
4247 		else if (context->dns_transport_count == 2
4248 		     &&  context->dns_transports[1] == GETDNS_TRANSPORT_TCP)
4249 			*value = GETDNS_TRANSPORT_TLS_FIRST_AND_FALL_BACK_TO_TCP_KEEP_CONNECTIONS_OPEN;
4250 		else
4251 			return GETDNS_RETURN_WRONG_TYPE_REQUESTED;
4252 	}
4253 	return GETDNS_RETURN_GOOD;
4254 }
4255 
4256 getdns_return_t
getdns_context_get_dns_transport_list(const getdns_context * context,size_t * transport_count,getdns_transport_list_t ** transports)4257 getdns_context_get_dns_transport_list(const getdns_context *context,
4258     size_t* transport_count, getdns_transport_list_t **transports)
4259 {
4260 	if (!context || !transport_count || !transports)
4261 		return GETDNS_RETURN_INVALID_PARAMETER;
4262 	*transport_count = context->dns_transport_count;
4263 	if (!context->dns_transport_count) {
4264 		*transports = NULL;
4265 		return GETDNS_RETURN_GOOD;
4266 	}
4267 	// use normal malloc here so users can do normal free
4268 	*transports = malloc(
4269 	    context->dns_transport_count * sizeof(getdns_transport_list_t));
4270 	memcpy(*transports, context->dns_transports,
4271 	    context->dns_transport_count * sizeof(getdns_transport_list_t));
4272 	return GETDNS_RETURN_GOOD;
4273 }
4274 
CONTEXT_GETTER2(tls_authentication,getdns_tls_authentication_t,tls_auth)4275 CONTEXT_GETTER2(tls_authentication, getdns_tls_authentication_t, tls_auth)
4276 CONTEXT_GETTER(round_robin_upstreams      , uint8_t)
4277 CONTEXT_GETTER(max_backoff_value          , uint16_t)
4278 CONTEXT_GETTER(tls_backoff_time           , uint16_t)
4279 CONTEXT_GETTER(tls_connection_retries     , uint16_t)
4280 CONTEXT_GETTER(limit_outstanding_queries  , uint16_t)
4281 CONTEXT_GETTER(timeout                    , uint64_t)
4282 CONTEXT_GETTER(idle_timeout               , uint64_t)
4283 CONTEXT_GETTER(follow_redirects           , getdns_redirects_t)
4284 
4285 getdns_return_t
4286 getdns_context_get_dns_root_servers(
4287     const getdns_context *context, getdns_list **value)
4288 {
4289 	if (!context || !value) return GETDNS_RETURN_INVALID_PARAMETER;
4290 	if (context->dns_root_servers)
4291 		return _getdns_list_copy(context->dns_root_servers, value);
4292 	*value = NULL;
4293 	return GETDNS_RETURN_GOOD;
4294 }
4295 
CONTEXT_GETTER(append_name,getdns_append_name_t)4296 CONTEXT_GETTER(append_name                , getdns_append_name_t)
4297 
4298 getdns_return_t
4299 getdns_context_get_suffix(const getdns_context *context, getdns_list **value)
4300 {
4301 	size_t dname_len;
4302 	const uint8_t *dname;
4303 	char name[1024];
4304 	getdns_return_t r = GETDNS_RETURN_GOOD;
4305 	getdns_list *list;
4306 
4307 	if (!context || !value)
4308 		return GETDNS_RETURN_INVALID_PARAMETER;
4309 
4310 	if (!(list = getdns_list_create_with_context(context)))
4311 		return GETDNS_RETURN_MEMORY_ERROR;
4312 
4313 	assert(context->suffixes);
4314 	dname_len = context->suffixes[0];
4315 	dname = context->suffixes + 1;
4316 	while (dname_len && *dname) {
4317 		if (! gldns_wire2str_dname_buf((UNCONST_UINT8_p)
4318 		    dname, dname_len, name, sizeof(name))) {
4319 			r = GETDNS_RETURN_GENERIC_ERROR;
4320 			break;
4321 		}
4322 		if ((r = _getdns_list_append_string(list, name)))
4323 			break;
4324 		dname += dname_len;
4325 		dname_len = *dname++;
4326 	}
4327 	if (r)
4328 		getdns_list_destroy(list);
4329 	else
4330 		*value = list;
4331 
4332 	return r;
4333 }
4334 
4335 getdns_return_t
getdns_context_get_dnssec_trust_anchors(const getdns_context * context,getdns_list ** value)4336 getdns_context_get_dnssec_trust_anchors(
4337     const getdns_context *context, getdns_list **value)
4338 {
4339 	if (!context || !value) return GETDNS_RETURN_INVALID_PARAMETER;
4340 
4341 	if (context->trust_anchors) {
4342 		if ((*value = getdns_list_create_with_context(context)))
4343 			_getdns_wire2list( context->trust_anchors
4344 			                 , context->trust_anchors_len
4345 			                 , *value);
4346 		else
4347 			return GETDNS_RETURN_MEMORY_ERROR;
4348 	} else
4349 		*value = NULL;
4350 
4351 	return GETDNS_RETURN_GOOD;
4352 }
4353 
4354 getdns_return_t
getdns_context_get_dnssec_allowed_skew(const getdns_context * context,uint32_t * value)4355 getdns_context_get_dnssec_allowed_skew(
4356     const getdns_context *context, uint32_t* value)
4357 {
4358 	if (!context || !value) return GETDNS_RETURN_INVALID_PARAMETER;
4359 	*value = context->dnssec_allowed_skew;
4360 	return GETDNS_RETURN_GOOD;
4361 }
4362 
4363 getdns_return_t
getdns_context_get_upstream_recursive_servers(const getdns_context * context,getdns_list ** upstreams_r)4364 getdns_context_get_upstream_recursive_servers(
4365     const getdns_context *context, getdns_list **upstreams_r)
4366 {
4367 	size_t i;
4368 	getdns_list *upstreams;
4369 	getdns_return_t r;
4370 
4371 	if (!context || !upstreams_r)
4372 		return GETDNS_RETURN_INVALID_PARAMETER;
4373 
4374 	if (!(upstreams = getdns_list_create_with_context(context)))
4375 		return GETDNS_RETURN_MEMORY_ERROR;
4376 
4377 	if (!context->upstreams || context->upstreams->count == 0) {
4378 		*upstreams_r = upstreams;
4379 		return GETDNS_RETURN_GOOD;
4380 	}
4381 	r = GETDNS_RETURN_GOOD;
4382 	i = 0;
4383 	while (!r && i < context->upstreams->count) {
4384 		size_t j;
4385 		getdns_dict *d;
4386 		getdns_upstream  *upstream = &context->upstreams->upstreams[i];
4387 		getdns_bindata    bindata;
4388 		const getdns_tsig_info *tsig_info;
4389 
4390 		if (!(d =
4391 		    sockaddr_dict(context, (struct sockaddr*)&upstream->addr))) {
4392 			r = GETDNS_RETURN_MEMORY_ERROR;
4393 			break;
4394 		}
4395 		if (upstream->tsig_alg) {
4396 			tsig_info = _getdns_get_tsig_info(upstream->tsig_alg);
4397 
4398 			if ((r = _getdns_dict_set_const_bindata(
4399 			    d, "tsig_algorithm",
4400 			    tsig_info->dname_len, tsig_info->dname)))
4401 				break;
4402 
4403 			if (upstream->tsig_dname_len) {
4404 				bindata.data = upstream->tsig_dname;
4405 				bindata.size = upstream->tsig_dname_len;
4406 				if ((r = getdns_dict_set_bindata(
4407 				    d, "tsig_name", &bindata)))
4408 					break;
4409 			}
4410 			if (upstream->tsig_size) {
4411 				bindata.data = upstream->tsig_key;
4412 				bindata.size = upstream->tsig_size;
4413 				if ((r = getdns_dict_set_bindata(
4414 				    d, "tsig_secret", &bindata)))
4415 					break;
4416 			}
4417 		}
4418 		for ( j = 1, i++
4419 		    ; j < GETDNS_UPSTREAM_TRANSPORTS &&
4420 		      i < context->upstreams->count
4421 		    ; j++, i++) {
4422 
4423 			upstream = &context->upstreams->upstreams[i];
4424 
4425 			if (upstream->transport == GETDNS_TRANSPORT_UDP &&
4426 			    upstream_port(upstream) != getdns_port_array[j] &&
4427 			    (r = getdns_dict_set_int(d, "port",
4428 			    (uint32_t)upstream_port(upstream))))
4429 				break;
4430 
4431 			if (upstream->transport == GETDNS_TRANSPORT_TLS) {
4432 				if (upstream_port(upstream) != getdns_port_array[j] &&
4433 					(r = getdns_dict_set_int(d, "tls_port",
4434 								   (uint32_t) upstream_port(upstream))))
4435 					break;
4436 				if (upstream->tls_auth_name[0] != '\0' &&
4437 				    (r = getdns_dict_util_set_string(d,
4438 				                                     "tls_auth_name",
4439 				                                     upstream->tls_auth_name)))
4440 					break;
4441 				if (upstream->tls_pubkey_pinset) {
4442 					getdns_list *pins = NULL;
4443 					if ((_getdns_get_pubkey_pinset_list(context,
4444 									   upstream->tls_pubkey_pinset,
4445 									   &pins) == GETDNS_RETURN_GOOD) &&
4446 						(r = _getdns_dict_set_this_list(d, "tls_pubkey_pinset", pins))) {
4447 						getdns_list_destroy(pins);
4448 						break;
4449 					}
4450 				}
4451 				if (upstream->tls_cipher_list) {
4452 					(void) getdns_dict_util_set_string(
4453 					    d, "tls_cipher_list",
4454 					    upstream->tls_cipher_list);
4455 				}
4456 				if (upstream->tls_ciphersuites) {
4457 					(void) getdns_dict_util_set_string(
4458 					    d, "tls_ciphersuites",
4459 					    upstream->tls_ciphersuites);
4460 				}
4461 				if (upstream->tls_curves_list) {
4462 					(void) getdns_dict_util_set_string(
4463 					    d, "tls_curves_list",
4464 					    upstream->tls_curves_list);
4465 				}
4466 				if (upstream->tls_min_version) {
4467 					(void) getdns_dict_set_int(
4468 					    d, "tls_min_version",
4469 					    upstream->tls_min_version);
4470 				}
4471 				if (upstream->tls_max_version) {
4472 					(void) getdns_dict_set_int(
4473 					    d, "tls_max_version",
4474 					    upstream->tls_max_version);
4475 				}
4476 			}
4477 		}
4478 		if (!r)
4479 			if (!(r = _getdns_list_append_this_dict(upstreams, d)))
4480 				d = NULL;
4481 		getdns_dict_destroy(d);
4482         }
4483         if (r)
4484 		getdns_list_destroy(upstreams);
4485 	else
4486 		*upstreams_r = upstreams;
4487 	return r;
4488 }
4489 
4490 getdns_return_t
getdns_context_get_edns_maximum_udp_payload_size(const getdns_context * context,uint16_t * value)4491 getdns_context_get_edns_maximum_udp_payload_size(
4492     const getdns_context *context, uint16_t* value)
4493 {
4494 	if (!context || !value) return GETDNS_RETURN_INVALID_PARAMETER;
4495 	*value = context->edns_maximum_udp_payload_size == -1 ? 0
4496 	       : context->edns_maximum_udp_payload_size;
4497 	return GETDNS_RETURN_GOOD;
4498 }
4499 
CONTEXT_GETTER(edns_extended_rcode,uint8_t)4500 CONTEXT_GETTER(edns_extended_rcode        , uint8_t)
4501 CONTEXT_GETTER(edns_version               , uint8_t)
4502 CONTEXT_GETTER(edns_do_bit                , uint8_t)
4503 CONTEXT_GETTER(edns_client_subnet_private , uint8_t)
4504 CONTEXT_GETTER(tls_query_padding_blocksize, uint16_t)
4505 
4506 static int _streq(const getdns_bindata *name, const char *str)
4507 {
4508 	if (strlen(str) != name->size)
4509 		return 0;
4510 	else	return strncmp((const char *)name->data, str, name->size) == 0;
4511 }
4512 
_get_list_or_read_file(const getdns_dict * config_dict,const char * setting,getdns_list ** r_list,int * destroy_list)4513 static getdns_return_t _get_list_or_read_file(const getdns_dict *config_dict,
4514     const char *setting, getdns_list **r_list, int *destroy_list)
4515 {
4516 	getdns_bindata *fn_bd;
4517 	char fn[FILENAME_MAX];
4518 	FILE *fh;
4519 	getdns_return_t r;
4520 
4521 	assert(r_list);
4522 	assert(destroy_list);
4523 
4524 	*destroy_list = 0;
4525 	if (!(r = getdns_dict_get_list(config_dict, setting, r_list)))
4526 		return GETDNS_RETURN_GOOD;
4527 
4528 	else if ((r = getdns_dict_get_bindata(config_dict, setting, &fn_bd)))
4529 		return r;
4530 
4531 	else if (fn_bd->size >= FILENAME_MAX)
4532 		return GETDNS_RETURN_INVALID_PARAMETER;
4533 
4534 	(void)memcpy(fn, fn_bd->data, fn_bd->size);
4535 	fn[fn_bd->size] = 0;
4536 
4537 	if (!(fh = fopen(fn, "r")))
4538 		return GETDNS_RETURN_GENERIC_ERROR;
4539 
4540 	if (!(r = getdns_fp2rr_list(fh, r_list, NULL, 3600)))
4541 		*destroy_list = 1;
4542 
4543 	fclose(fh);
4544 	return r;
4545 }
4546 
4547 #define CONTEXT_SETTING_INT(X) \
4548 	} else 	if (_streq(setting, #X)) { \
4549 		if (!(r = getdns_dict_get_int(config_dict, #X , &n))) \
4550 			r = getdns_context_set_ ## X (context, n);
4551 
4552 #define CONTEXT_SETTING_LIST(X) \
4553 	} else 	if (_streq(setting, #X)) { \
4554 		if (!(r = getdns_dict_get_list(config_dict, #X , &list))) \
4555 			r = getdns_context_set_ ## X (context, list);
4556 
4557 #define CONTEXT_SETTING_LIST_OR_ZONEFILE(X) \
4558 	} else if (_streq(setting, #X)) { \
4559 		if (!(r = _get_list_or_read_file( \
4560 		    config_dict, #X , &list, &destroy_list))) \
4561 			r = getdns_context_set_ ## X(context, list); \
4562 		if (destroy_list) getdns_list_destroy(list);
4563 
4564 #define CONTEXT_SETTING_ARRAY(X, T) \
4565 	} else 	if (_streq(setting, #X )) { \
4566 		if (!(r = getdns_dict_get_list(config_dict, #X , &list)) && \
4567 		    !(r =  getdns_list_get_length(list, &count))) { \
4568 			for (i=0; i<count && i<(sizeof(X)/sizeof(*X)); i++) { \
4569 				if ((r = getdns_list_get_int(list, i, &n))) \
4570 					break; \
4571 				X[i] = (getdns_ ## T ## _t)n; \
4572 			} \
4573 			r = getdns_context_set_ ##X (context, i, X); \
4574 		}
4575 
4576 #define EXTENSION_SETTING_BOOL(X) \
4577 	} else if (_streq(setting, #X )) { \
4578 		if (!(r = getdns_dict_get_int(config_dict, #X , &n))) { \
4579 			if (n == GETDNS_EXTENSION_TRUE) context->X  = 1; \
4580 			else if (n == GETDNS_EXTENSION_FALSE) context->X = 0; \
4581 			else r = GETDNS_RETURN_INVALID_PARAMETER; \
4582 		}
4583 
4584 #define CONTEXT_SETTING_STRING(X) \
4585 	} else if (_streq(setting, #X )) { \
4586 		if (!(r = getdns_dict_get_bindata(config_dict, #X , &bd))) { \
4587 			if (bd->size < sizeof(str_buf)) { \
4588 				(void) memcpy(str_buf, (char *)bd->data, bd->size); \
4589 				str_buf[bd->size] = '\0'; \
4590 				r = getdns_context_set_ ## X( \
4591 				    context, str_buf); \
4592 			} else if ((tmp_str = _getdns_strdup2(&context->mf, bd))) { \
4593 				r = getdns_context_set_ ## X( \
4594 				    context, tmp_str); \
4595 				GETDNS_FREE(context->mf, tmp_str); \
4596 			} else \
4597 				r = GETDNS_RETURN_MEMORY_ERROR; \
4598 		}
4599 
4600 static getdns_return_t
_getdns_context_config_setting(getdns_context * context,const getdns_dict * config_dict,const getdns_bindata * setting)4601 _getdns_context_config_setting(getdns_context *context,
4602     const getdns_dict *config_dict, const getdns_bindata *setting)
4603 {
4604 	getdns_return_t r = GETDNS_RETURN_GOOD;
4605 	getdns_dict *dict;
4606 	getdns_list *list;
4607 	getdns_namespace_t namespaces[100];
4608 	getdns_transport_list_t dns_transport_list[100];
4609 	size_t count, i;
4610 	uint32_t n;
4611 	getdns_bindata *bd;
4612 	int destroy_list = 0;
4613 	char str_buf[1024], *tmp_str;
4614 
4615 	if (_streq(setting, "all_context")) {
4616 		if (!(r = getdns_dict_get_dict(config_dict, "all_context", &dict)))
4617 			r = getdns_context_config(context, dict);
4618 
4619 	CONTEXT_SETTING_INT(resolution_type)
4620 	CONTEXT_SETTING_ARRAY(namespaces, namespace)
4621 	CONTEXT_SETTING_INT(dns_transport)
4622 	CONTEXT_SETTING_ARRAY(dns_transport_list, transport_list)
4623 	CONTEXT_SETTING_INT(idle_timeout)
4624 	CONTEXT_SETTING_INT(limit_outstanding_queries)
4625 	CONTEXT_SETTING_INT(timeout)
4626 	CONTEXT_SETTING_INT(follow_redirects)
4627 	CONTEXT_SETTING_LIST_OR_ZONEFILE(dns_root_servers)
4628 	CONTEXT_SETTING_INT(append_name)
4629 	CONTEXT_SETTING_LIST(suffix)
4630 	CONTEXT_SETTING_LIST_OR_ZONEFILE(dnssec_trust_anchors)
4631 	CONTEXT_SETTING_INT(dnssec_allowed_skew)
4632 	CONTEXT_SETTING_LIST(upstream_recursive_servers)
4633 	CONTEXT_SETTING_INT(edns_maximum_udp_payload_size)
4634 	CONTEXT_SETTING_INT(edns_extended_rcode)
4635 	CONTEXT_SETTING_INT(edns_version)
4636 	CONTEXT_SETTING_INT(edns_do_bit)
4637 
4638 	/***************************************/
4639 	/****                               ****/
4640 	/****  Unofficial context settings  ****/
4641 	/****                               ****/
4642 	/***************************************/
4643 
4644 	CONTEXT_SETTING_INT(edns_client_subnet_private)
4645 	CONTEXT_SETTING_INT(tls_authentication)
4646 	CONTEXT_SETTING_INT(round_robin_upstreams)
4647 	CONTEXT_SETTING_INT(tls_backoff_time)
4648 	CONTEXT_SETTING_INT(tls_connection_retries)
4649 	CONTEXT_SETTING_INT(tls_query_padding_blocksize)
4650 	CONTEXT_SETTING_STRING(trust_anchors_url)
4651 	CONTEXT_SETTING_STRING(trust_anchors_verify_CA)
4652 	CONTEXT_SETTING_STRING(trust_anchors_verify_email)
4653 	CONTEXT_SETTING_INT(trust_anchors_backoff_time)
4654 	CONTEXT_SETTING_STRING(appdata_dir)
4655 #ifndef USE_WINSOCK
4656 	CONTEXT_SETTING_STRING(resolvconf)
4657 #endif
4658 	CONTEXT_SETTING_STRING(hosts)
4659 	CONTEXT_SETTING_STRING(tls_ca_path)
4660 	CONTEXT_SETTING_STRING(tls_ca_file)
4661 	CONTEXT_SETTING_STRING(tls_cipher_list)
4662 	CONTEXT_SETTING_STRING(tls_ciphersuites)
4663 	CONTEXT_SETTING_STRING(tls_curves_list)
4664 	CONTEXT_SETTING_INT(tls_min_version)
4665 	CONTEXT_SETTING_INT(tls_max_version)
4666 
4667 	/**************************************/
4668 	/****                              ****/
4669 	/****  Default extensions setting  ****/
4670 	/****                              ****/
4671 	/**************************************/
4672 	EXTENSION_SETTING_BOOL(add_warning_for_bad_dns)
4673 	EXTENSION_SETTING_BOOL(dnssec)
4674 	EXTENSION_SETTING_BOOL(dnssec_return_all_statuses)
4675 	EXTENSION_SETTING_BOOL(dnssec_return_full_validation_chain)
4676 	EXTENSION_SETTING_BOOL(dnssec_return_only_secure)
4677 	EXTENSION_SETTING_BOOL(dnssec_return_status)
4678 	EXTENSION_SETTING_BOOL(dnssec_return_validation_chain)
4679 #if defined(DNSSEC_ROADBLOCK_AVOIDANCE) && defined(HAVE_LIBUNBOUND)
4680 	EXTENSION_SETTING_BOOL(dnssec_roadblock_avoidance)
4681 #endif
4682 #ifdef EDNS_COOKIES
4683 	EXTENSION_SETTING_BOOL(edns_cookies)
4684 #endif
4685 	EXTENSION_SETTING_BOOL(return_api_information)
4686 	EXTENSION_SETTING_BOOL(return_both_v4_and_v6)
4687 	EXTENSION_SETTING_BOOL(return_call_reporting)
4688 
4689 	} else if (_streq(setting, "add_opt_parameters")) {
4690 		if (!(r = getdns_dict_get_dict(config_dict, "add_opt_parameters" , &dict))) {
4691 			if (context->add_opt_parameters)
4692 				getdns_dict_destroy(context->add_opt_parameters);
4693 			context->add_opt_parameters = NULL;
4694 			r = _getdns_dict_copy(dict, &context->add_opt_parameters);
4695 		}
4696 
4697 	} else if (_streq(setting, "header")) {
4698 		if (!(r = getdns_dict_get_dict(config_dict, "header" , &dict))) {
4699 			if (context->header)
4700 				getdns_dict_destroy(context->header);
4701 			if (!(context->header =
4702 			    getdns_dict_create_with_context(context)))
4703 				r = GETDNS_RETURN_MEMORY_ERROR;
4704 			else	r = getdns_dict_set_dict(
4705 			    context->header, "header", dict);
4706 		}
4707 
4708 	} else if (_streq(setting, "specify_class")) {
4709 		if (!(r = getdns_dict_get_int(
4710 		    config_dict, "specify_class" , &n)))
4711 			context->specify_class = (uint16_t)n;
4712 
4713 
4714 	/************************************/
4715 	/****                            ****/
4716 	/****  Ignored context settings  ****/
4717 	/****                            ****/
4718 	/************************************/
4719 	} else if (!_streq(setting, "implementation_string")
4720 	    && !_streq(setting, "version_string")
4721 	    && !_streq(setting, "version_number")
4722 	    && !_streq(setting, "api_version_string")
4723 	    && !_streq(setting, "api_version_number")
4724 	    && !_streq(setting, "trust_anchor_file")
4725 	    && !_streq(setting, "default_trust_anchor_location")
4726 	    && !_streq(setting, "default_resolvconf_location")
4727 	    && !_streq(setting, "default_hosts_location")
4728 	    && !_streq(setting, "compilation_comment")
4729 	    && !_streq(setting, "openssl_build_version_number")
4730 	    && !_streq(setting, "openssl_version_number")
4731 	    && !_streq(setting, "openssl_version_string")
4732 	    && !_streq(setting, "openssl_cflags")
4733 	    && !_streq(setting, "openssl_built_on")
4734 	    && !_streq(setting, "openssl_platform")
4735 	    && !_streq(setting, "openssl_dir")
4736 	    && !_streq(setting, "openssl_engines_dir")
4737 	    ) {
4738 		r = GETDNS_RETURN_NOT_IMPLEMENTED;
4739 	}
4740 	return r;
4741 }
4742 
4743 getdns_return_t
getdns_context_config(getdns_context * context,const getdns_dict * config_dict)4744 getdns_context_config(getdns_context *context, const getdns_dict *config_dict)
4745 {
4746 	getdns_list *settings;
4747 	getdns_return_t r;
4748 	getdns_bindata *setting;
4749 	size_t i;
4750 
4751 	if ((r = getdns_dict_get_names(config_dict, &settings)))
4752 		return r;
4753 
4754 	for (i = 0; !(r = getdns_list_get_bindata(settings,i,&setting)); i++) {
4755 		if ((r = _getdns_context_config_setting(
4756 		    context, config_dict, setting)))
4757 			break;
4758 	}
4759 	if (r == GETDNS_RETURN_NO_SUCH_LIST_ITEM)
4760 		r = GETDNS_RETURN_GOOD;
4761 
4762 	getdns_list_destroy(settings);
4763 	return r;
4764 }
4765 
_getdns_get_appdata(const getdns_context * context,char * path)4766 static size_t _getdns_get_appdata(const getdns_context *context, char *path)
4767 {
4768 	size_t len = 0;
4769 
4770 #ifdef USE_WINSOCK
4771 # define SLASHTOK '\\'
4772 # define APPDATA_SUBDIR "getdns"
4773 
4774 	if (context->appdata_dir) {
4775 		(void) strcpy(path, context->appdata_dir);
4776 		len = strlen(path);
4777 
4778 	} else if (! SUCCEEDED(SHGetFolderPath(NULL,
4779 	    CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
4780 		_getdns_log(&context->log
4781 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_NOTICE
4782 			   , "Could not get %%AppData%% directory\n");
4783 
4784 	else if ((len = strlen(path))
4785 			+ sizeof(APPDATA_SUBDIR) + 2 >= _GETDNS_PATH_MAX)
4786 		_getdns_log(&context->log
4787 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4788 		           , "Path name for appdata directory too long\n");
4789 #else
4790 # define SLASHTOK '/'
4791 # define APPDATA_SUBDIR ".getdns"
4792 	struct passwd *p = getpwuid(getuid());
4793 	char *home = NULL;
4794 
4795 	if (context->appdata_dir) {
4796 		(void) strcpy(path, context->appdata_dir);
4797 		len = strlen(path);
4798 
4799 	} else if (!(home = p ? p->pw_dir : getenv("HOME")))
4800 		_getdns_log(&context->log
4801 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_NOTICE
4802 		           , "Unable to determine home directory location\n");
4803 
4804 	else if ((len = strlen(home)) + sizeof(APPDATA_SUBDIR) + 2 >= _GETDNS_PATH_MAX)
4805 		_getdns_log(&context->log
4806 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4807 		           , "Path name for appdata directory too long\n");
4808 
4809 	else if (!strcpy(path, home))
4810 		; /* strcpy returns path always */
4811 #endif
4812 	else {
4813 		if (len == 0 || (  path[len - 1] != '/'
4814 		                && path[len - 1] != '\\')) {
4815 			path[len++] = SLASHTOK;
4816 			path[len  ] = '\0';
4817 		}
4818 		(void) strcpy(path + len, APPDATA_SUBDIR);
4819 		len += sizeof(APPDATA_SUBDIR) - 1;
4820 	}
4821 	if (len) {
4822 		if (path[len - 1] == '/' || path[len - 1] == '\\') {
4823 			path[--len] = '\0';
4824 		}
4825 		if (0 >
4826 #ifdef USE_WINSOCK
4827 		    mkdir(path)
4828 #else
4829 		    mkdir(path, 0755)
4830 #endif
4831 		    && errno != EEXIST)
4832 			_getdns_log(&context->log
4833 				   , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4834 				   , "mkdir(\"%s\") failed: %s\n"
4835 				   , path, _getdns_errnostr());
4836 		else {
4837 			path[len++] = SLASHTOK;
4838 			path[len  ] = '\0';
4839 			return len;
4840 		}
4841 	}
4842 	path[0] = '\0';
4843 	return 0;
4844 }
4845 
_getdns_context_get_priv_fp(const getdns_context * context,const char * fn)4846 FILE *_getdns_context_get_priv_fp(
4847     const getdns_context *context, const char *fn)
4848 {
4849 	char path[_GETDNS_PATH_MAX];
4850 	FILE *f = NULL;
4851 	size_t len = _getdns_get_appdata(context, path);
4852 
4853 	if (len + strlen(fn) >= sizeof(path))
4854 		_getdns_log(&context->log
4855 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4856 		           , "Path name for appdata directory too long\n");
4857 
4858 
4859 	else if (!strcpy(path + len, fn))
4860 		; /* strcpy returns path + len always */
4861 
4862 	else if (!(f = fopen(path, "r")))
4863 		_getdns_log(&context->log
4864 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_INFO
4865 		           , "Error opening \"%s\": %s\n"
4866 			   , path, _getdns_errnostr());
4867 	return f;
4868 }
4869 
_getdns_context_get_priv_file(const getdns_context * context,const char * fn,uint8_t * buf,size_t buf_len,size_t * file_sz)4870 uint8_t *_getdns_context_get_priv_file(const getdns_context *context,
4871     const char *fn, uint8_t *buf, size_t buf_len, size_t *file_sz)
4872 {
4873 	FILE *f = NULL;
4874 
4875 	if (!(f = _getdns_context_get_priv_fp(context, fn)))
4876 		; /* pass */
4877 
4878 	else if ((*file_sz = fread(buf, 1, buf_len, f)) < (buf_len  - 1) && feof(f)) {
4879 		buf[*file_sz] = 0;
4880 		(void) fclose(f);
4881 		return buf;
4882 	}
4883 	else if (fseek(f, 0, SEEK_END) < 0)
4884 		_getdns_log(&context->log
4885 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4886 		           , "Error determining size of \"%s\": %s\n"
4887 			   , fn, _getdns_errnostr());
4888 
4889 	else if (!(buf = GETDNS_XMALLOC(
4890 	    context->mf, uint8_t, (buf_len = ftell(f) + 1))))
4891 		_getdns_log(&context->log
4892 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4893 		           , "Error allocating %d bytes of memory for \"%s\"\n"
4894 			   , (int)buf_len, fn);
4895 
4896 	else {
4897 		rewind(f);
4898 		if ((*file_sz = fread(buf, 1, buf_len, f)) >= buf_len || !feof(f)) {
4899 			GETDNS_FREE(context->mf, buf);
4900 			_getdns_log(&context->log
4901 				   , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4902 				   , "Error reding \"%s\": %s\n"
4903 				   , fn, _getdns_errnostr());
4904 		}
4905 		else {
4906 			buf[*file_sz] = 0;
4907 			(void) fclose(f);
4908 			return buf;
4909 		}
4910 	}
4911 	if (f)
4912 		(void) fclose(f);
4913 	return NULL;
4914 }
4915 
4916 
_getdns_context_write_priv_file(getdns_context * context,const char * fn,getdns_bindata * content)4917 int _getdns_context_write_priv_file(getdns_context *context,
4918     const char *fn, getdns_bindata *content)
4919 {
4920 	char path[_GETDNS_PATH_MAX], tmpfn[_GETDNS_PATH_MAX];
4921 	int fd = -1;
4922 	FILE *f = NULL;
4923 	size_t len = _getdns_get_appdata(context, path);
4924 
4925 	if (len + 6          >= sizeof(tmpfn)
4926 	     ||  len + strlen(fn) >= sizeof(path))
4927 		_getdns_log(&context->log
4928 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4929 		           , "Application data filename \"%s\" too long\n"
4930 			   , fn);
4931 
4932 	else if (snprintf(tmpfn, sizeof(tmpfn), "%sXXXXXX", path) < 0)
4933 		_getdns_log(&context->log
4934 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4935 		           , "Error creating temporary file template \"%s\"\n"
4936 			   , tmpfn);
4937 
4938 	else if (!strcpy(path + len, fn))
4939 		; /* strcpy returns path + len always */
4940 
4941 	else if ((fd = mkstemp(tmpfn)) < 0)
4942 		_getdns_log(&context->log
4943 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_INFO
4944 		           , "Could not create temporary file \"%s\": %s\n"
4945 			   , tmpfn, _getdns_errnostr());
4946 
4947 	else if (!(f = fdopen(fd, "w")))
4948 		_getdns_log(&context->log
4949 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4950 		           , "Error opening temporary file \"%s\": %s\n"
4951 			   , tmpfn, _getdns_errnostr());
4952 
4953 	else if (fwrite(content->data, 1, content->size, f) < content->size)
4954 		_getdns_log(&context->log
4955 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4956 		           , "Error writing to temporary file \"%s\": %s\n"
4957 			   , tmpfn, _getdns_errnostr());
4958 
4959 	else if (fclose(f) < 0)
4960 		_getdns_log(&context->log
4961 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4962 		           , "Error closing temporary file \"%s\": %s\n"
4963 			   , tmpfn, _getdns_errnostr());
4964 
4965 	else if (rename(tmpfn, path) < 0)
4966 		_getdns_log(&context->log
4967 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
4968 		           , "Error renaming temporary file \"%s\" to \"%s\""
4969 			     ": %s\n", tmpfn, path, _getdns_errnostr());
4970 	else {
4971 		context->can_write_appdata = PROP_ABLE;
4972 		return 1;
4973 	}
4974 	if (f)
4975 		(void) fclose(f);
4976 
4977 	else if (fd >= 0)
4978 		(void) close(fd);
4979 
4980 	context->can_write_appdata = PROP_UNABLE;
4981 	context->trust_anchors_backoff_expiry =
4982 	    _getdns_get_now_ms() + context->trust_anchors_backoff_time;
4983 	return 0;
4984 }
4985 
_getdns_context_can_write_appdata(getdns_context * context)4986 int _getdns_context_can_write_appdata(getdns_context *context)
4987 {
4988 	char test_fn[30], path[_GETDNS_PATH_MAX];
4989 	size_t len;
4990 	getdns_bindata test_content = { 4, (void *)"TEST" };
4991 
4992 	if (context->can_write_appdata == PROP_ABLE)
4993 		return 1;
4994 
4995 	else if (context->can_write_appdata == PROP_UNABLE) {
4996 		if (_getdns_ms_until_expiry(
4997 		    context->trust_anchors_backoff_expiry) > 0)
4998 			return 0;
4999 		context->can_write_appdata = PROP_UNKNOWN;
5000 	}
5001 	(void) snprintf( test_fn, sizeof(test_fn)
5002 	               , "write-test-%d.tmp", arc4random());
5003 
5004 	if (!_getdns_context_write_priv_file(context, test_fn, &test_content))
5005 		return 0;
5006 
5007 	len = _getdns_get_appdata(context, path);
5008 
5009 	if (len + strlen(test_fn) >= sizeof(path))
5010 		_getdns_log(&context->log
5011 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5012 		           , "Application data too long \"%s\" + \"%s\"\n"
5013 			   , path, test_fn);
5014 
5015 	else if (!strcpy(path + len, test_fn))
5016 		; /* strcpy returns path + len always */
5017 
5018 	else if (unlink(path) < 0)
5019 		_getdns_log(&context->log
5020 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5021 		           , "Error unlinking write test file: \"%s\": %s\n"
5022 			   , path, _getdns_errnostr());
5023 	return 1;
5024 }
5025 
5026 getdns_return_t
getdns_context_set_trust_anchors_url(getdns_context * context,const char * url)5027 getdns_context_set_trust_anchors_url(
5028     getdns_context *context, const char *url)
5029 {
5030 	const char *path;
5031 	size_t path_len;
5032 
5033 	if (!context)
5034 		return GETDNS_RETURN_INVALID_PARAMETER;
5035 
5036 	if (url) {
5037 		if (! ((url[0] == 'h' || url[0] == 'H')
5038 		    && (url[1] == 't' || url[1] == 'T')
5039 		    && (url[2] == 't' || url[2] == 'T')
5040 		    && (url[3] == 'p' || url[3] == 'P')
5041 		    &&  url[4] == ':' && url[5] == '/' && url[6] == '/'
5042 		    && (path = strchr(url + 7, '/'))))
5043 			return GETDNS_RETURN_NOT_IMPLEMENTED;
5044 
5045 		path_len = strlen(path);
5046 		if (! ( path_len >= 5
5047 		    &&    path[path_len - 4] == '.'
5048 		    && (  path[path_len - 3] == 'x'
5049 		       || path[path_len - 3] == 'X')
5050 		    && (  path[path_len - 2] == 'm'
5051 		       || path[path_len - 2] == 'M')
5052 		    && (  path[path_len - 1] == 'l'
5053 		       || path[path_len - 1] == 'L')))
5054 			return GETDNS_RETURN_NOT_IMPLEMENTED;
5055 	}
5056 	if (context->trust_anchors_url)
5057 		GETDNS_FREE(context->mf, context->trust_anchors_url);
5058 	context->trust_anchors_url = _getdns_strdup(&context->mf, url);
5059 
5060 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TRUST_ANCHORS_URL);
5061 	return GETDNS_RETURN_GOOD;
5062 }
5063 
5064 getdns_return_t
getdns_context_get_trust_anchors_url(const getdns_context * context,const char ** url)5065 getdns_context_get_trust_anchors_url(
5066     const getdns_context *context, const char **url)
5067 {
5068 	if (!context || !url)
5069 		return GETDNS_RETURN_INVALID_PARAMETER;
5070 
5071 	*url = context && context->trust_anchors_url
5072 	     ?            context->trust_anchors_url
5073 	     :     _getdns_default_trust_anchors_url;
5074 	return GETDNS_RETURN_GOOD;
5075 }
5076 
5077 getdns_return_t
getdns_context_set_trust_anchors_verify_CA(getdns_context * context,const char * verify_CA)5078 getdns_context_set_trust_anchors_verify_CA(
5079     getdns_context *context, const char *verify_CA)
5080 {
5081 	if (!context)
5082 		return GETDNS_RETURN_INVALID_PARAMETER;
5083 
5084 	if (context->trust_anchors_verify_CA)
5085 		GETDNS_FREE(context->mf, context->trust_anchors_verify_CA);
5086 	context->trust_anchors_verify_CA =
5087 	    _getdns_strdup(&context->mf, verify_CA);
5088 
5089 	dispatch_updated( context
5090 	                , GETDNS_CONTEXT_CODE_TRUST_ANCHORS_VERIFY_CA);
5091 	return GETDNS_RETURN_GOOD;
5092 }
5093 
5094 getdns_return_t
getdns_context_get_trust_anchors_verify_CA(const getdns_context * context,const char ** verify_CA)5095 getdns_context_get_trust_anchors_verify_CA(
5096     const getdns_context *context, const char **verify_CA)
5097 {
5098 	if (!verify_CA)
5099 		return GETDNS_RETURN_INVALID_PARAMETER;
5100 
5101 	*verify_CA = context && context->trust_anchors_verify_CA
5102 	           ?            context->trust_anchors_verify_CA
5103 	           :     _getdns_default_trust_anchors_verify_CA;
5104 	return GETDNS_RETURN_GOOD;
5105 }
5106 
5107 getdns_return_t
getdns_context_set_trust_anchors_verify_email(getdns_context * context,const char * verify_email)5108 getdns_context_set_trust_anchors_verify_email(
5109     getdns_context *context, const char *verify_email)
5110 {
5111 	if (!context)
5112 		return GETDNS_RETURN_INVALID_PARAMETER;
5113 
5114 	if (context->trust_anchors_verify_email)
5115 		GETDNS_FREE(context->mf, context->trust_anchors_verify_email);
5116 	context->trust_anchors_verify_email =
5117 	    _getdns_strdup(&context->mf, verify_email);
5118 
5119 	dispatch_updated( context
5120 	                , GETDNS_CONTEXT_CODE_TRUST_ANCHORS_VERIFY_EMAIL);
5121 	return GETDNS_RETURN_GOOD;
5122 }
5123 
5124 getdns_return_t
getdns_context_get_trust_anchors_verify_email(const getdns_context * context,const char ** verify_email)5125 getdns_context_get_trust_anchors_verify_email(
5126     const getdns_context *context, const char **verify_email)
5127 {
5128 	if (!verify_email)
5129 		return GETDNS_RETURN_INVALID_PARAMETER;
5130 
5131 	*verify_email = context && context->trust_anchors_verify_email
5132 	              ?            context->trust_anchors_verify_email
5133 		      :     _getdns_default_trust_anchors_verify_email;
5134 	return GETDNS_RETURN_GOOD;
5135 }
5136 
5137 getdns_return_t
getdns_context_set_trust_anchors_backoff_time(getdns_context * context,uint64_t backoff_time)5138 getdns_context_set_trust_anchors_backoff_time(
5139     getdns_context *context, uint64_t backoff_time)
5140 {
5141 	if (!context)
5142 		return GETDNS_RETURN_INVALID_PARAMETER;
5143 
5144 	context->trust_anchors_backoff_time = backoff_time;
5145 	if (context->trust_anchors_source == GETDNS_TASRC_FAILED)
5146 		context->trust_anchors_source = GETDNS_TASRC_NONE;
5147 	dispatch_updated( context
5148 	                , GETDNS_CONTEXT_CODE_TRUST_ANCHORS_BACKOFF_TIME);
5149 	return GETDNS_RETURN_GOOD;
5150 }
5151 
CONTEXT_GETTER(trust_anchors_backoff_time,uint64_t)5152 CONTEXT_GETTER(trust_anchors_backoff_time , uint64_t)
5153 
5154 getdns_return_t
5155 getdns_context_set_appdata_dir(
5156     getdns_context *context, const char *appdata_dir)
5157 {
5158 	if (!context)
5159 		return GETDNS_RETURN_INVALID_PARAMETER;
5160 
5161 	if (context->appdata_dir)
5162 		GETDNS_FREE(context->mf, context->appdata_dir);
5163 	context->appdata_dir = _getdns_strdup(&context->mf, appdata_dir);
5164 
5165 	dispatch_updated(context, GETDNS_CONTEXT_CODE_APPDATA_DIR);
5166 	return GETDNS_RETURN_GOOD;
5167 }
5168 
_getdns_context_get_sys_ctxt(getdns_context * context,getdns_eventloop * loop)5169 getdns_context *_getdns_context_get_sys_ctxt(
5170     getdns_context *context, getdns_eventloop *loop)
5171 {
5172 	getdns_return_t r;
5173 
5174 	if (context->sys_ctxt)
5175 		return context->sys_ctxt;
5176 
5177 	if ((r = getdns_context_create_with_extended_memory_functions(
5178 	   &context->sys_ctxt, 1, context->mf.mf_arg,
5179 	    context->mf.mf.ext.malloc, context->mf.mf.ext.realloc,
5180 	    context->mf.mf.ext.free)))
5181 		_getdns_log(&context->log
5182 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5183 		           , "Could not create system context: %s\n"
5184 			    , getdns_get_errorstr_by_id(r));
5185 #ifndef USE_WINSOCK
5186 	else if (*context->fchg_resolvconf.fn &&
5187 	    (r = getdns_context_set_resolvconf(
5188 	    context->sys_ctxt, context->fchg_resolvconf.fn)))
5189 		_getdns_log(&context->log
5190 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5191 		           , "Could not initialize system context with "
5192 			     "resolvconf \"%s\": %s\n"
5193 			   , context->fchg_resolvconf.fn
5194 			   , getdns_get_errorstr_by_id(r));
5195 #endif
5196 	else if (*context->fchg_hosts.fn &&
5197 	    (r = getdns_context_set_hosts(
5198 	    context->sys_ctxt, context->fchg_hosts.fn)))
5199 		_getdns_log(&context->log
5200 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5201 		           , "Could not initialize system context with "
5202 			     "hosts \"%s\": %s\n"
5203 			   , context->fchg_hosts.fn
5204 			   , getdns_get_errorstr_by_id(r));
5205 
5206 	else if ((r = getdns_context_set_eventloop(
5207 	    context->sys_ctxt, loop)))
5208 		_getdns_log(&context->log
5209 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5210 		           , "Could not configure %ssynchronous loop "
5211 			     "with system context: %s\n"
5212 			    , ( loop == &context->sync_eventloop.loop
5213 			      ? "" : "a" )
5214 			    , getdns_get_errorstr_by_id(r));
5215 
5216 	else if ((r = getdns_context_set_resolution_type(
5217 	    context->sys_ctxt, GETDNS_RESOLUTION_STUB)))
5218 		_getdns_log(&context->log
5219 		           , GETDNS_LOG_SYS_ANCHOR, GETDNS_LOG_ERR
5220 		           , "Could not configure system context for "
5221 			     "stub resolver: %s\n"
5222 			    , getdns_get_errorstr_by_id(r));
5223 	else
5224 		return context->sys_ctxt;
5225 
5226 	getdns_context_destroy(context->sys_ctxt);
5227 	context->sys_ctxt = NULL;
5228 	return NULL;
5229 }
5230 
5231 getdns_return_t
getdns_context_set_tls_ca_path(getdns_context * context,const char * tls_ca_path)5232 getdns_context_set_tls_ca_path(getdns_context *context, const char *tls_ca_path)
5233 {
5234 	if (!context || !tls_ca_path)
5235 		return GETDNS_RETURN_INVALID_PARAMETER;
5236 	if (context->tls_ca_path)
5237 		GETDNS_FREE(context->mf, context->tls_ca_path);
5238 	context->tls_ca_path = _getdns_strdup(&context->mf, tls_ca_path);
5239 
5240 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CA_PATH);
5241 	return GETDNS_RETURN_GOOD;
5242 }
5243 
CONTEXT_GETTER(tls_ca_path,const char *)5244 CONTEXT_GETTER(tls_ca_path                , const char *)
5245 
5246 getdns_return_t
5247 getdns_context_set_tls_ca_file(getdns_context *context, const char *tls_ca_file)
5248 {
5249 	if (!context || !tls_ca_file)
5250 		return GETDNS_RETURN_INVALID_PARAMETER;
5251 	if (context->tls_ca_file)
5252 		GETDNS_FREE(context->mf, context->tls_ca_file);
5253 	context->tls_ca_file = _getdns_strdup(&context->mf, tls_ca_file);
5254 
5255 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CA_FILE);
5256 	return GETDNS_RETURN_GOOD;
5257 }
5258 
CONTEXT_GETTER(tls_ca_file,const char *)5259 CONTEXT_GETTER(tls_ca_file                , const char *)
5260 
5261 getdns_return_t
5262 getdns_context_set_tls_cipher_list(
5263     getdns_context *context, const char *tls_cipher_list)
5264 {
5265 	if (!context)
5266 		return GETDNS_RETURN_INVALID_PARAMETER;
5267 	if (context->tls_cipher_list)
5268 		GETDNS_FREE(context->mf, context->tls_cipher_list);
5269 	context->tls_cipher_list = tls_cipher_list
5270 	                         ? _getdns_strdup(&context->mf, tls_cipher_list)
5271 	                         : NULL;
5272 
5273 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST);
5274 	return GETDNS_RETURN_GOOD;
5275 }
5276 
5277 getdns_return_t
getdns_context_get_tls_cipher_list(const getdns_context * context,const char ** tls_cipher_list)5278 getdns_context_get_tls_cipher_list(
5279     const getdns_context *context, const char **tls_cipher_list)
5280 {
5281 	if (!context || !tls_cipher_list)
5282 		return GETDNS_RETURN_INVALID_PARAMETER;
5283 
5284 	*tls_cipher_list = context->tls_cipher_list
5285 	                 ? context->tls_cipher_list
5286 			 : _getdns_tls_context_get_default_cipher_list();
5287 	return GETDNS_RETURN_GOOD;
5288 }
5289 
5290 getdns_return_t
getdns_context_set_tls_ciphersuites(getdns_context * context,const char * tls_ciphersuites)5291 getdns_context_set_tls_ciphersuites(
5292     getdns_context *context, const char *tls_ciphersuites)
5293 {
5294 	if (!context)
5295 		return GETDNS_RETURN_INVALID_PARAMETER;
5296 	if (context->tls_ciphersuites)
5297 		GETDNS_FREE(context->mf, context->tls_ciphersuites);
5298 	context->tls_ciphersuites = tls_ciphersuites
5299 	                         ? _getdns_strdup(&context->mf, tls_ciphersuites)
5300 	                         : NULL;
5301 
5302 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CIPHERSUITES);
5303 	return GETDNS_RETURN_GOOD;
5304 }
5305 
5306 getdns_return_t
getdns_context_get_tls_ciphersuites(const getdns_context * context,const char ** tls_ciphersuites)5307 getdns_context_get_tls_ciphersuites(
5308     const getdns_context *context, const char **tls_ciphersuites)
5309 {
5310 	if (!context || !tls_ciphersuites)
5311 		return GETDNS_RETURN_INVALID_PARAMETER;
5312 
5313 	*tls_ciphersuites = context->tls_ciphersuites
5314 	                 ? context->tls_ciphersuites
5315 			 : _getdns_tls_context_get_default_cipher_suites();
5316 	return GETDNS_RETURN_GOOD;
5317 }
5318 
5319 getdns_return_t
getdns_context_set_tls_curves_list(getdns_context * context,const char * tls_curves_list)5320 getdns_context_set_tls_curves_list(
5321     getdns_context *context, const char *tls_curves_list)
5322 {
5323 	if (!context)
5324 		return GETDNS_RETURN_INVALID_PARAMETER;
5325 #if HAVE_TLS_CTX_CURVES_LIST
5326 	if (context->tls_curves_list)
5327 		GETDNS_FREE(context->mf, context->tls_curves_list);
5328 	context->tls_curves_list = tls_curves_list
5329 	                         ? _getdns_strdup(&context->mf, tls_curves_list)
5330 	                         : NULL;
5331 
5332 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_CIPHER_LIST);
5333 	return GETDNS_RETURN_GOOD;
5334 #else
5335 	(void)tls_curves_list;
5336 	return GETDNS_RETURN_NOT_IMPLEMENTED;
5337 #endif
5338 }
5339 
CONTEXT_GETTER(tls_curves_list,const char *)5340 CONTEXT_GETTER(tls_curves_list            , const char *)
5341 
5342 getdns_return_t
5343 getdns_context_set_tls_min_version(
5344     getdns_context *context, getdns_tls_version_t tls_min_version)
5345 {
5346 	if (!context)
5347 		return GETDNS_RETURN_INVALID_PARAMETER;
5348 	context->tls_min_version = tls_min_version;
5349 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_MIN_VERSION);
5350 	return GETDNS_RETURN_GOOD;
5351 }
5352 
CONTEXT_GETTER(tls_min_version,getdns_tls_version_t)5353 CONTEXT_GETTER(tls_min_version            , getdns_tls_version_t)
5354 
5355 getdns_return_t
5356 getdns_context_set_tls_max_version(
5357     getdns_context *context, getdns_tls_version_t tls_max_version)
5358 {
5359 	if (!context)
5360 		return GETDNS_RETURN_INVALID_PARAMETER;
5361 	context->tls_max_version = tls_max_version;
5362 	dispatch_updated(context, GETDNS_CONTEXT_CODE_TLS_MAX_VERSION);
5363 	return GETDNS_RETURN_GOOD;
5364 }
5365 
5366 CONTEXT_GETTER(tls_max_version            , getdns_tls_version_t)
5367 
5368 /* context.c */
5369