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