Annotation of src/usr.bin/dig/dighost.c, Revision 1.16
1.1 florian 1: /*
2: * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3: *
4: * Permission to use, copy, modify, and/or distribute this software for any
5: * purpose with or without fee is hereby granted, provided that the above
6: * copyright notice and this permission notice appear in all copies.
7: *
8: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14: * PERFORMANCE OF THIS SOFTWARE.
15: */
16:
1.16 ! jung 17: /* $Id: dighost.c,v 1.15 2020/02/23 08:55:43 florian Exp $ */
1.1 florian 18:
19: /*! \file
20: * \note
21: * Notice to programmers: Do not use this code as an example of how to
22: * use the ISC library to perform DNS lookups. Dig and Host both operate
23: * on the request level, since they allow fine-tuning of output and are
24: * intended as debugging tools. As a result, they perform many of the
25: * functions which could be better handled using the dns_resolver
26: * functions in most applications.
27: */
28:
29: #include <sys/socket.h>
30: #include <limits.h>
31: #include <locale.h>
32: #include <netdb.h>
1.6 florian 33: #include <resolv.h>
1.1 florian 34: #include <stdlib.h>
35: #include <string.h>
36:
37: #include <dns/byaddr.h>
38: #include <dns/fixedname.h>
39: #include <dns/log.h>
40: #include <dns/message.h>
41: #include <dns/name.h>
42: #include <dns/rdata.h>
43: #include <dns/rdataclass.h>
44: #include <dns/rdatalist.h>
45: #include <dns/rdataset.h>
46: #include "rdatastruct.h"
47: #include <dns/rdatatype.h>
48: #include <dns/result.h>
49: #include <dns/tsig.h>
50:
51: #include <dst/dst.h>
52: #include <dst/result.h>
53:
54: #include <isc/app.h>
55: #include <isc/base64.h>
56: #include <isc/hex.h>
57: #include <isc/log.h>
58: #include <isc/netaddr.h>
59: #include <isc/parseint.h>
60: #include <isc/result.h>
61: #include <isc/safe.h>
62: #include <isc/serial.h>
63: #include <isc/sockaddr.h>
64: #include <isc/task.h>
65: #include <isc/timer.h>
66: #include <isc/types.h>
67: #include <isc/util.h>
68:
69: #include <isccfg/namedconf.h>
70: #include <lwres/lwres.h>
71:
72: #include "dig.h"
73:
74: static lwres_conf_t lwconfdata;
75: static lwres_conf_t *lwconf = &lwconfdata;
76:
77: dig_lookuplist_t lookup_list;
78: dig_serverlist_t server_list;
1.5 florian 79: dig_serverlist_t root_hints_server_list;
1.1 florian 80: dig_searchlistlist_t search_list;
81:
82: isc_boolean_t
83: check_ra = ISC_FALSE,
84: have_ipv4 = ISC_TRUE,
85: have_ipv6 = ISC_TRUE,
86: specified_source = ISC_FALSE,
87: free_now = ISC_FALSE,
88: cancel_now = ISC_FALSE,
89: usesearch = ISC_FALSE,
90: showsearch = ISC_FALSE,
91: qr = ISC_FALSE,
92: is_dst_up = ISC_FALSE,
93: keep_open = ISC_FALSE;
94: in_port_t port = 53;
95: unsigned int timeout = 0;
96: unsigned int extrabytes;
97: isc_log_t *lctx = NULL;
98: isc_taskmgr_t *taskmgr = NULL;
99: isc_task_t *global_task = NULL;
100: isc_timermgr_t *timermgr = NULL;
101: isc_socketmgr_t *socketmgr = NULL;
102: isc_sockaddr_t bind_address;
103: isc_sockaddr_t bind_any;
104: int sendcount = 0;
105: int recvcount = 0;
106: int sockcount = 0;
107: int ndots = -1;
108: int tries = 3;
109: int lookup_counter = 0;
110:
111: static char sitvalue[256];
112:
113: isc_socket_t *keep = NULL;
114: isc_sockaddr_t keepaddr;
115:
1.5 florian 116: static const struct {
117: const char *ns;
118: const int af;
119: } root_hints[] = {
120: { "198.41.0.4", AF_INET }, /* a.root-servers.net */
121: { "2001:503:ba3e::2:30", AF_INET6 }, /* a.root-servers.net */
122: { "199.9.14.201", AF_INET }, /* b.root-servers.net */
123: { "2001:500:200::b", AF_INET6 }, /* b.root-servers.net */
124: { "192.33.4.12", AF_INET }, /* c.root-servers.net */
125: { "2001:500:2::c", AF_INET6 }, /* c.root-servers.net */
126: { "199.7.91.13", AF_INET }, /* d.root-servers.net */
127: { "2001:500:2d::d", AF_INET6 }, /* d.root-servers.net */
128: { "192.203.230.10", AF_INET }, /* e.root-servers.net */
129: { "2001:500:a8::e", AF_INET6 }, /* e.root-servers.net */
130: { "192.5.5.241", AF_INET }, /* f.root-servers.net */
131: { "2001:500:2f::f", AF_INET6 }, /* f.root-servers.net */
132: { "192.112.36.4", AF_INET }, /* g.root-servers.net */
133: { "2001:500:12::d0d", AF_INET6 }, /* g.root-servers.net */
134: { "198.97.190.53", AF_INET }, /* h.root-servers.net */
135: { "2001:500:1::53", AF_INET6 }, /* h.root-servers.net */
136: { "192.36.148.17", AF_INET }, /* i.root-servers.net */
137: { "2001:7fe::53", AF_INET6 }, /* i.root-servers.net */
138: { "192.58.128.30", AF_INET }, /* j.root-servers.net */
139: { "2001:503:c27::2:30", AF_INET6 }, /* j.root-servers.net */
140: { "193.0.14.129", AF_INET }, /* k.root-servers.net */
141: { "2001:7fd::1", AF_INET6 }, /* k.root-servers.net */
142: { "199.7.83.42", AF_INET }, /* l.root-servers.net */
143: { "2001:500:9f::42", AF_INET6 }, /* l.root-servers.net */
144: { "202.12.27.33", AF_INET }, /* m.root-servers.net */
145: { "2001:dc3::35", AF_INET6 } /* m.root-servers.net */
146: };
147:
1.1 florian 148: /*%
149: * Exit Codes:
150: *
151: *\li 0 Everything went well, including things like NXDOMAIN
152: *\li 1 Usage error
153: *\li 7 Got too many RR's or Names
154: *\li 8 Couldn't open batch file
155: *\li 9 No reply from server
156: *\li 10 Internal error
157: */
158: int exitcode = 0;
159: int fatalexit = 0;
160: char keynametext[MXNAME];
161: char keyfile[MXNAME] = "";
162: char keysecret[MXNAME] = "";
163: unsigned char cookie_secret[33];
164: unsigned char cookie[8];
165: dns_name_t *hmacname = NULL;
166: unsigned int digestbits = 0;
167: isc_buffer_t *namebuf = NULL;
168: dns_tsigkey_t *tsigkey = NULL;
169: isc_boolean_t validated = ISC_TRUE;
170: isc_boolean_t debugging = ISC_FALSE;
171: isc_boolean_t debugtiming = ISC_FALSE;
172: char *progname = NULL;
173: dig_lookup_t *current_lookup = NULL;
174:
175: #define DIG_MAX_ADDRESSES 20
176:
177: /* dynamic callbacks */
178:
179: isc_result_t
180: (*dighost_printmessage)(dig_query_t *query, dns_message_t *msg,
181: isc_boolean_t headers);
182:
183: void
184: (*dighost_received)(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query);
185:
186: void
187: (*dighost_trying)(char *frm, dig_lookup_t *lookup);
188:
189: void
190: (*dighost_shutdown)(void);
191:
192: /* forward declarations */
193:
194: static void
195: cancel_lookup(dig_lookup_t *lookup);
196:
197: static void
198: recv_done(isc_task_t *task, isc_event_t *event);
199:
200: static void
201: send_udp(dig_query_t *query);
202:
203: static void
204: connect_timeout(isc_task_t *task, isc_event_t *event);
205:
206: static void
207: launch_next_query(dig_query_t *query, isc_boolean_t include_question);
208:
209: static void
210: check_next_lookup(dig_lookup_t *lookup);
211:
212: static isc_boolean_t
213: next_origin(dig_lookup_t *oldlookup);
214:
215: char *
216: next_token(char **stringp, const char *delim) {
217: char *res;
218:
219: do {
220: res = strsep(stringp, delim);
221: if (res == NULL)
222: break;
223: } while (*res == '\0');
224: return (res);
225: }
226:
227: static int
228: count_dots(char *string) {
229: char *s;
230: int i = 0;
231:
232: s = string;
233: while (*s != '\0') {
234: if (*s == '.')
235: i++;
236: s++;
237: }
238: return (i);
239: }
240:
241: static void
242: hex_dump(isc_buffer_t *b) {
243: unsigned int len, i;
244: isc_region_t r;
245:
246: isc_buffer_usedregion(b, &r);
247:
248: printf("%u bytes\n", r.length);
249: for (len = 0; len < r.length; len++) {
250: printf("%02x ", r.base[len]);
251: if (len % 16 == 15) {
252: fputs(" ", stdout);
253: for (i = len - 15; i <= len; i++) {
254: if (r.base[i] >= '!' && r.base[i] <= '}')
255: putchar(r.base[i]);
256: else
257: putchar('.');
258: }
259: printf("\n");
260: }
261: }
262: if (len % 16 != 0) {
263: for (i = len; (i % 16) != 0; i++)
264: fputs(" ", stdout);
265: fputs(" ", stdout);
266: for (i = ((len>>4)<<4); i < len; i++) {
267: if (r.base[i] >= '!' && r.base[i] <= '}')
268: putchar(r.base[i]);
269: else
270: putchar('.');
271: }
272: printf("\n");
273: }
274: }
275:
276: /*%
277: * Append 'len' bytes of 'text' at '*p', failing with
278: * ISC_R_NOSPACE if that would advance p past 'end'.
279: */
280: static isc_result_t
281: append(const char *text, size_t len, char **p, char *end) {
282: if (*p + len > end)
283: return (ISC_R_NOSPACE);
284: memmove(*p, text, len);
285: *p += len;
286: return (ISC_R_SUCCESS);
287: }
288:
289: static isc_result_t
290: reverse_octets(const char *in, char **p, char *end) {
291: const char *dot = strchr(in, '.');
292: size_t len;
293: if (dot != NULL) {
294: isc_result_t result;
295: result = reverse_octets(dot + 1, p, end);
296: if (result != ISC_R_SUCCESS)
297: return (result);
298: result = append(".", 1, p, end);
299: if (result != ISC_R_SUCCESS)
300: return (result);
301: len = (int) (dot - in);
302: } else {
303: len = (int) strlen(in);
304: }
305: return (append(in, len, p, end));
306: }
307:
308: isc_result_t
309: get_reverse(char *reverse, size_t len, char *value, isc_boolean_t ip6_int,
310: isc_boolean_t strict)
311: {
312: int r;
313: isc_result_t result;
314: isc_netaddr_t addr;
315:
316: addr.family = AF_INET6;
317: r = inet_pton(AF_INET6, value, &addr.type.in6);
318: if (r > 0) {
319: /* This is a valid IPv6 address. */
320: dns_fixedname_t fname;
321: dns_name_t *name;
322: unsigned int options = 0;
323:
324: if (ip6_int)
325: options |= DNS_BYADDROPT_IPV6INT;
326: dns_fixedname_init(&fname);
327: name = dns_fixedname_name(&fname);
328: result = dns_byaddr_createptrname2(&addr, options, name);
329: if (result != ISC_R_SUCCESS)
330: return (result);
331: dns_name_format(name, reverse, (unsigned int)len);
332: return (ISC_R_SUCCESS);
333: } else {
334: /*
335: * Not a valid IPv6 address. Assume IPv4.
336: * If 'strict' is not set, construct the
337: * in-addr.arpa name by blindly reversing
338: * octets whether or not they look like integers,
339: * so that this can be used for RFC2317 names
340: * and such.
341: */
342: char *p = reverse;
343: char *end = reverse + len;
344: if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1)
345: return (DNS_R_BADDOTTEDQUAD);
346: result = reverse_octets(value, &p, end);
347: if (result != ISC_R_SUCCESS)
348: return (result);
349: /* Append .in-addr.arpa. and a terminating NUL. */
350: result = append(".in-addr.arpa.", 15, &p, end);
351: if (result != ISC_R_SUCCESS)
352: return (result);
353: return (ISC_R_SUCCESS);
354: }
355: }
356:
357: void
358: fatal(const char *format, ...) {
359: va_list args;
360:
361: fflush(stdout);
362: fprintf(stderr, "%s: ", progname);
363: va_start(args, format);
364: vfprintf(stderr, format, args);
365: va_end(args);
366: fprintf(stderr, "\n");
367: if (exitcode < 10)
368: exitcode = 10;
369: if (fatalexit != 0)
370: exitcode = fatalexit;
371: exit(exitcode);
372: }
373:
374: void
375: debug(const char *format, ...) {
376: va_list args;
1.8 florian 377: struct timespec t;
1.1 florian 378:
379: if (debugging) {
380: fflush(stdout);
381: if (debugtiming) {
1.13 florian 382: clock_gettime(CLOCK_MONOTONIC, &t);
1.8 florian 383: fprintf(stderr, "%lld.%06ld: ", t.tv_sec, t.tv_nsec /
384: 1000);
1.1 florian 385: }
386: va_start(args, format);
387: vfprintf(stderr, format, args);
388: va_end(args);
389: fprintf(stderr, "\n");
390: }
391: }
392:
393: void
394: check_result(isc_result_t result, const char *msg) {
395: if (result != ISC_R_SUCCESS) {
396: fatal("%s: %s", msg, isc_result_totext(result));
397: }
398: }
399:
400: /*%
401: * Create a server structure, which is part of the lookup structure.
402: * This is little more than a linked list of servers to query in hopes
403: * of finding the answer the user is looking for
404: */
405: dig_server_t *
406: make_server(const char *servname, const char *userarg) {
407: dig_server_t *srv;
408:
409: REQUIRE(servname != NULL);
410:
411: debug("make_server(%s)", servname);
412: srv = malloc(sizeof(struct dig_server));
413: if (srv == NULL)
414: fatal("memory allocation failure in %s:%d",
415: __FILE__, __LINE__);
416: strlcpy(srv->servername, servname, MXNAME);
417: strlcpy(srv->userarg, userarg, MXNAME);
418: ISC_LINK_INIT(srv, link);
419: return (srv);
420: }
421:
422: static int
423: addr2af(int lwresaddrtype)
424: {
425: int af = 0;
426:
427: switch (lwresaddrtype) {
428: case LWRES_ADDRTYPE_V4:
429: af = AF_INET;
430: break;
431:
432: case LWRES_ADDRTYPE_V6:
433: af = AF_INET6;
434: break;
435: }
436:
437: return (af);
438: }
439:
440: /*%
441: * Create a copy of the server list from the lwres configuration structure.
442: * The dest list must have already had ISC_LIST_INIT applied.
443: */
444: static void
445: copy_server_list(lwres_conf_t *confdata, dig_serverlist_t *dest) {
446: dig_server_t *newsrv;
447: char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") +
448: sizeof("%4000000000")];
449: int af;
450: int i;
451:
452: debug("copy_server_list()");
453: for (i = 0; i < confdata->nsnext; i++) {
454: af = addr2af(confdata->nameservers[i].family);
455:
456: if (af == AF_INET && !have_ipv4)
457: continue;
458: if (af == AF_INET6 && !have_ipv6)
459: continue;
460:
461: inet_ntop(af, confdata->nameservers[i].address,
462: tmp, sizeof(tmp));
463: if (af == AF_INET6 && confdata->nameservers[i].zone != 0) {
464: char buf[sizeof("%4000000000")];
465: snprintf(buf, sizeof(buf), "%%%u",
466: confdata->nameservers[i].zone);
467: strlcat(tmp, buf, sizeof(tmp));
468: }
469: newsrv = make_server(tmp, tmp);
470: ISC_LINK_INIT(newsrv, link);
471: ISC_LIST_ENQUEUE(*dest, newsrv, link);
472: }
473: }
474:
475: void
476: flush_server_list(void) {
477: dig_server_t *s, *ps;
478:
479: debug("flush_server_list()");
480: s = ISC_LIST_HEAD(server_list);
481: while (s != NULL) {
482: ps = s;
483: s = ISC_LIST_NEXT(s, link);
484: ISC_LIST_DEQUEUE(server_list, ps, link);
485: free(ps);
486: }
487: }
488:
489: /* this used to be bind9_getaddresses from lib/bind9 */
490: static isc_result_t
491: get_addresses(const char *hostname, in_port_t dstport,
492: isc_sockaddr_t *addrs, int addrsize, int *addrcount)
493: {
494: struct addrinfo *ai = NULL, *tmpai, hints;
495: int result, i;
496:
497: REQUIRE(hostname != NULL);
498: REQUIRE(addrs != NULL);
499: REQUIRE(addrcount != NULL);
500: REQUIRE(addrsize > 0);
501:
502: memset(&hints, 0, sizeof(hints));
503: if (!have_ipv6)
504: hints.ai_family = PF_INET;
505: else if (!have_ipv4)
506: hints.ai_family = PF_INET6;
507: else {
508: hints.ai_family = PF_UNSPEC;
509: hints.ai_flags = AI_ADDRCONFIG;
510: }
511: hints.ai_socktype = SOCK_STREAM;
512:
513: result = getaddrinfo(hostname, NULL, &hints, &ai);
514: switch (result) {
515: case 0:
516: break;
517: case EAI_NONAME:
518: case EAI_NODATA:
519: return (ISC_R_NOTFOUND);
520: default:
521: return (ISC_R_FAILURE);
522: }
523: for (tmpai = ai, i = 0;
524: tmpai != NULL && i < addrsize;
525: tmpai = tmpai->ai_next)
526: {
527: if (tmpai->ai_family != AF_INET &&
528: tmpai->ai_family != AF_INET6)
529: continue;
530: if (tmpai->ai_family == AF_INET) {
531: struct sockaddr_in *sin;
532: sin = (struct sockaddr_in *)tmpai->ai_addr;
533: isc_sockaddr_fromin(&addrs[i], &sin->sin_addr, dstport);
534: } else {
535: struct sockaddr_in6 *sin6;
536: sin6 = (struct sockaddr_in6 *)tmpai->ai_addr;
537: isc_sockaddr_fromin6(&addrs[i], &sin6->sin6_addr,
538: dstport);
539: }
540: i++;
541:
542: }
543: freeaddrinfo(ai);
544: *addrcount = i;
545: if (*addrcount == 0)
546: return (ISC_R_NOTFOUND);
547: else
548: return (ISC_R_SUCCESS);
549: }
550:
551: void
552: set_nameserver(char *opt) {
553: isc_result_t result;
554: isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
555: isc_netaddr_t netaddr;
556: int count, i;
557: dig_server_t *srv;
558: char tmp[ISC_NETADDR_FORMATSIZE];
559:
560: if (opt == NULL)
561: return;
562:
563: result = get_addresses(opt, 0, sockaddrs,
564: DIG_MAX_ADDRESSES, &count);
565: if (result != ISC_R_SUCCESS)
566: fatal("couldn't get address for '%s': %s",
567: opt, isc_result_totext(result));
568:
569: flush_server_list();
570:
571: for (i = 0; i < count; i++) {
572: isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
573: isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
574: srv = make_server(tmp, opt);
575: if (srv == NULL)
576: fatal("memory allocation failure");
577: ISC_LIST_APPEND(server_list, srv, link);
578: }
579: }
580:
581: static isc_result_t
582: add_nameserver(lwres_conf_t *confdata, const char *addr, int af) {
583:
584: int i = confdata->nsnext;
585:
586: if (confdata->nsnext >= LWRES_CONFMAXNAMESERVERS)
587: return (ISC_R_FAILURE);
588:
589: switch (af) {
590: case AF_INET:
591: confdata->nameservers[i].family = LWRES_ADDRTYPE_V4;
1.3 florian 592: confdata->nameservers[i].length = sizeof(struct in_addr);
1.1 florian 593: break;
594: case AF_INET6:
595: confdata->nameservers[i].family = LWRES_ADDRTYPE_V6;
1.3 florian 596: confdata->nameservers[i].length = sizeof(struct in6_addr);
1.1 florian 597: break;
598: default:
599: return (ISC_R_FAILURE);
600: }
601:
602: if (inet_pton(af, addr, &confdata->nameservers[i].address) == 1) {
603: confdata->nsnext++;
604: return (ISC_R_SUCCESS);
605: }
606: return (ISC_R_FAILURE);
607: }
608:
609: /*%
610: * Produce a cloned server list. The dest list must have already had
611: * ISC_LIST_INIT applied.
612: */
613: void
614: clone_server_list(dig_serverlist_t src, dig_serverlist_t *dest) {
615: dig_server_t *srv, *newsrv;
616:
617: debug("clone_server_list()");
618: srv = ISC_LIST_HEAD(src);
619: while (srv != NULL) {
620: newsrv = make_server(srv->servername, srv->userarg);
621: ISC_LINK_INIT(newsrv, link);
622: ISC_LIST_ENQUEUE(*dest, newsrv, link);
623: srv = ISC_LIST_NEXT(srv, link);
624: }
625: }
626:
627: /*%
628: * Create an empty lookup structure, which holds all the information needed
629: * to get an answer to a user's question. This structure contains two
630: * linked lists: the server list (servers to query) and the query list
631: * (outstanding queries which have been made to the listed servers).
632: */
633: dig_lookup_t *
634: make_empty_lookup(void) {
635: dig_lookup_t *looknew;
636:
637: debug("make_empty_lookup()");
638:
639: INSIST(!free_now);
640:
641: looknew = malloc(sizeof(struct dig_lookup));
642: if (looknew == NULL)
643: fatal("memory allocation failure in %s:%d",
644: __FILE__, __LINE__);
645: looknew->pending = ISC_TRUE;
646: looknew->textname[0] = 0;
647: looknew->cmdline[0] = 0;
648: looknew->rdtype = dns_rdatatype_a;
649: looknew->qrdtype = dns_rdatatype_a;
650: looknew->rdclass = dns_rdataclass_in;
651: looknew->rdtypeset = ISC_FALSE;
652: looknew->rdclassset = ISC_FALSE;
653: looknew->sendspace = NULL;
654: looknew->sendmsg = NULL;
655: looknew->name = NULL;
656: looknew->oname = NULL;
657: looknew->xfr_q = NULL;
658: looknew->current_query = NULL;
659: looknew->doing_xfr = ISC_FALSE;
660: looknew->ixfr_serial = 0;
661: looknew->trace = ISC_FALSE;
662: looknew->trace_root = ISC_FALSE;
663: looknew->identify = ISC_FALSE;
664: looknew->identify_previous_line = ISC_FALSE;
665: looknew->ignore = ISC_FALSE;
666: looknew->servfail_stops = ISC_TRUE;
667: looknew->besteffort = ISC_TRUE;
668: looknew->dnssec = ISC_FALSE;
669: looknew->ednsflags = 0;
670: looknew->opcode = dns_opcode_query;
671: looknew->expire = ISC_FALSE;
672: looknew->nsid = ISC_FALSE;
673: looknew->idnout = ISC_FALSE;
674: looknew->sit = ISC_FALSE;
675: looknew->udpsize = 0;
676: looknew->edns = -1;
677: looknew->recurse = ISC_TRUE;
678: looknew->aaonly = ISC_FALSE;
679: looknew->adflag = ISC_FALSE;
680: looknew->cdflag = ISC_FALSE;
681: looknew->ns_search_only = ISC_FALSE;
682: looknew->origin = NULL;
683: looknew->tsigctx = NULL;
684: looknew->querysig = NULL;
685: looknew->retries = tries;
686: looknew->nsfound = 0;
687: looknew->tcp_mode = ISC_FALSE;
688: looknew->tcp_mode_set = ISC_FALSE;
689: looknew->ip6_int = ISC_FALSE;
690: looknew->comments = ISC_TRUE;
691: looknew->stats = ISC_TRUE;
692: looknew->section_question = ISC_TRUE;
693: looknew->section_answer = ISC_TRUE;
694: looknew->section_authority = ISC_TRUE;
695: looknew->section_additional = ISC_TRUE;
696: looknew->new_search = ISC_FALSE;
697: looknew->done_as_is = ISC_FALSE;
698: looknew->need_search = ISC_FALSE;
699: looknew->ecs_addr = NULL;
700: looknew->sitvalue = NULL;
701: looknew->ednsopts = NULL;
702: looknew->ednsoptscnt = 0;
703: looknew->ednsneg = ISC_FALSE;
704: looknew->eoferr = 0;
705: dns_fixedname_init(&looknew->fdomain);
706: ISC_LINK_INIT(looknew, link);
707: ISC_LIST_INIT(looknew->q);
708: ISC_LIST_INIT(looknew->connecting);
709: ISC_LIST_INIT(looknew->my_server_list);
710: return (looknew);
711: }
712:
713: #define EDNSOPT_OPTIONS 100U
714:
715: static void
716: cloneopts(dig_lookup_t *looknew, dig_lookup_t *lookold) {
717: size_t len = sizeof(looknew->ednsopts[0]) * EDNSOPT_OPTIONS;
718: size_t i;
719: looknew->ednsopts = malloc(len);
720: if (looknew->ednsopts == NULL)
721: fatal("out of memory");
722: for (i = 0; i < EDNSOPT_OPTIONS; i++) {
723: looknew->ednsopts[i].code = 0;
724: looknew->ednsopts[i].length = 0;
725: looknew->ednsopts[i].value = NULL;
726: }
727: looknew->ednsoptscnt = 0;
728: if (lookold == NULL || lookold->ednsopts == NULL)
729: return;
730:
731: for (i = 0; i < lookold->ednsoptscnt; i++) {
732: len = lookold->ednsopts[i].length;
733: if (len != 0) {
734: INSIST(lookold->ednsopts[i].value != NULL);
735: looknew->ednsopts[i].value =
736: malloc(len);
737: if (looknew->ednsopts[i].value == NULL)
738: fatal("out of memory");
739: memmove(looknew->ednsopts[i].value,
740: lookold->ednsopts[i].value, len);
741: }
742: looknew->ednsopts[i].code = lookold->ednsopts[i].code;
743: looknew->ednsopts[i].length = len;
744: }
745: looknew->ednsoptscnt = lookold->ednsoptscnt;
746: }
747:
748: /*%
749: * Clone a lookup, perhaps copying the server list. This does not clone
750: * the query list, since it will be regenerated by the setup_lookup()
751: * function, nor does it queue up the new lookup for processing.
752: * Caution: If you don't clone the servers, you MUST clone the server
753: * list separately from somewhere else, or construct it by hand.
754: */
755: dig_lookup_t *
756: clone_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
757: dig_lookup_t *looknew;
758:
759: debug("clone_lookup()");
760:
761: INSIST(!free_now);
762:
763: looknew = make_empty_lookup();
764: INSIST(looknew != NULL);
765: strlcpy(looknew->textname, lookold->textname, MXNAME);
766: strlcpy(looknew->cmdline, lookold->cmdline, MXNAME);
767: looknew->textname[MXNAME-1] = 0;
768: looknew->rdtype = lookold->rdtype;
769: looknew->qrdtype = lookold->qrdtype;
770: looknew->rdclass = lookold->rdclass;
771: looknew->rdtypeset = lookold->rdtypeset;
772: looknew->rdclassset = lookold->rdclassset;
773: looknew->doing_xfr = lookold->doing_xfr;
774: looknew->ixfr_serial = lookold->ixfr_serial;
775: looknew->trace = lookold->trace;
776: looknew->trace_root = lookold->trace_root;
777: looknew->identify = lookold->identify;
778: looknew->identify_previous_line = lookold->identify_previous_line;
779: looknew->ignore = lookold->ignore;
780: looknew->servfail_stops = lookold->servfail_stops;
781: looknew->besteffort = lookold->besteffort;
782: looknew->dnssec = lookold->dnssec;
783: looknew->ednsflags = lookold->ednsflags;
784: looknew->opcode = lookold->opcode;
785: looknew->expire = lookold->expire;
786: looknew->nsid = lookold->nsid;
787: looknew->sit = lookold->sit;
788: looknew->sitvalue = lookold->sitvalue;
789: if (lookold->ednsopts != NULL) {
790: cloneopts(looknew, lookold);
791: } else {
792: looknew->ednsopts = NULL;
793: looknew->ednsoptscnt = 0;
794: }
795: looknew->ednsneg = lookold->ednsneg;
796: looknew->idnout = lookold->idnout;
797: looknew->udpsize = lookold->udpsize;
798: looknew->edns = lookold->edns;
799: looknew->recurse = lookold->recurse;
800: looknew->aaonly = lookold->aaonly;
801: looknew->adflag = lookold->adflag;
802: looknew->cdflag = lookold->cdflag;
803: looknew->ns_search_only = lookold->ns_search_only;
804: looknew->tcp_mode = lookold->tcp_mode;
805: looknew->tcp_mode_set = lookold->tcp_mode_set;
806: looknew->comments = lookold->comments;
807: looknew->stats = lookold->stats;
808: looknew->section_question = lookold->section_question;
809: looknew->section_answer = lookold->section_answer;
810: looknew->section_authority = lookold->section_authority;
811: looknew->section_additional = lookold->section_additional;
812: looknew->origin = lookold->origin;
813: looknew->retries = lookold->retries;
814: looknew->tsigctx = NULL;
815: looknew->need_search = lookold->need_search;
816: looknew->done_as_is = lookold->done_as_is;
817: looknew->eoferr = lookold->eoferr;
818:
819: if (lookold->ecs_addr != NULL) {
820: size_t len = sizeof(isc_sockaddr_t);
821: looknew->ecs_addr = malloc(len);
822: if (looknew->ecs_addr == NULL)
823: fatal("out of memory");
824: memmove(looknew->ecs_addr, lookold->ecs_addr, len);
825: }
826:
827: dns_name_copy(dns_fixedname_name(&lookold->fdomain),
828: dns_fixedname_name(&looknew->fdomain), NULL);
829:
830: if (servers)
831: clone_server_list(lookold->my_server_list,
832: &looknew->my_server_list);
833: return (looknew);
834: }
835:
836: /*%
837: * Requeue a lookup for further processing, perhaps copying the server
838: * list. The new lookup structure is returned to the caller, and is
839: * queued for processing. If servers are not cloned in the requeue, they
840: * must be added before allowing the current event to complete, since the
841: * completion of the event may result in the next entry on the lookup
842: * queue getting run.
843: */
844: dig_lookup_t *
845: requeue_lookup(dig_lookup_t *lookold, isc_boolean_t servers) {
846: dig_lookup_t *looknew;
847:
848: debug("requeue_lookup()");
849:
850: lookup_counter++;
851: if (lookup_counter > LOOKUP_LIMIT)
852: fatal("too many lookups");
853:
854: looknew = clone_lookup(lookold, servers);
855: INSIST(looknew != NULL);
856:
857: debug("before insertion, init@%p -> %p, new@%p -> %p",
858: lookold, lookold->link.next, looknew, looknew->link.next);
859: ISC_LIST_PREPEND(lookup_list, looknew, link);
860: debug("after insertion, init -> %p, new = %p, new -> %p",
861: lookold, looknew, looknew->link.next);
862: return (looknew);
863: }
864:
865: void
866: setup_text_key(void) {
867: isc_result_t result;
868: dns_name_t keyname;
869: isc_buffer_t secretbuf;
870: unsigned int secretsize;
871: unsigned char *secretstore;
872:
873: debug("setup_text_key()");
874: result = isc_buffer_allocate(&namebuf, MXNAME);
875: check_result(result, "isc_buffer_allocate");
876: dns_name_init(&keyname, NULL);
877: check_result(result, "dns_name_init");
878: isc_buffer_putstr(namebuf, keynametext);
879: secretsize = (unsigned int) strlen(keysecret) * 3 / 4;
880: secretstore = malloc(secretsize);
881: if (secretstore == NULL)
882: fatal("memory allocation failure in %s:%d",
883: __FILE__, __LINE__);
884: isc_buffer_init(&secretbuf, secretstore, secretsize);
885: result = isc_base64_decodestring(keysecret, &secretbuf);
886: if (result != ISC_R_SUCCESS)
887: goto failure;
888:
889: secretsize = isc_buffer_usedlength(&secretbuf);
890:
891: if (hmacname == NULL) {
892: result = DST_R_UNSUPPORTEDALG;
893: goto failure;
894: }
895:
896: result = dns_name_fromtext(&keyname, namebuf, dns_rootname, 0, namebuf);
897: if (result != ISC_R_SUCCESS)
898: goto failure;
899:
900: result = dns_tsigkey_create(&keyname, hmacname, secretstore,
901: (int)secretsize, ISC_FALSE, NULL, 0, 0,
902: &tsigkey);
903: failure:
904: if (result != ISC_R_SUCCESS)
905: printf(";; Couldn't create key %s: %s\n",
906: keynametext, isc_result_totext(result));
907: else
908: dst_key_setbits(tsigkey->key, digestbits);
909:
910: free(secretstore);
911: dns_name_invalidate(&keyname);
912: isc_buffer_free(&namebuf);
913: }
914:
915: static isc_result_t
916: parse_uint_helper(uint32_t *uip, const char *value, uint32_t max,
917: const char *desc, int base) {
918: uint32_t n;
919: isc_result_t result = isc_parse_uint32(&n, value, base);
920: if (result == ISC_R_SUCCESS && n > max)
921: result = ISC_R_RANGE;
922: if (result != ISC_R_SUCCESS) {
923: printf("invalid %s '%s': %s\n", desc,
924: value, isc_result_totext(result));
925: return (result);
926: }
927: *uip = n;
928: return (ISC_R_SUCCESS);
929: }
930:
931: isc_result_t
932: parse_uint(uint32_t *uip, const char *value, uint32_t max,
933: const char *desc) {
934: return (parse_uint_helper(uip, value, max, desc, 10));
935: }
936:
937: isc_result_t
938: parse_xint(uint32_t *uip, const char *value, uint32_t max,
939: const char *desc) {
940: return (parse_uint_helper(uip, value, max, desc, 0));
941: }
942:
943: static uint32_t
944: parse_bits(char *arg, const char *desc, uint32_t max) {
945: isc_result_t result;
946: uint32_t tmp;
947:
948: result = parse_uint(&tmp, arg, max, desc);
949: if (result != ISC_R_SUCCESS)
950: fatal("couldn't parse digest bits");
951: tmp = (tmp + 7) & ~0x7U;
952: return (tmp);
953: }
954:
955: isc_result_t
956: parse_netprefix(isc_sockaddr_t **sap, const char *value) {
957: isc_result_t result = ISC_R_SUCCESS;
958: isc_sockaddr_t *sa = NULL;
959: struct in_addr in4;
960: struct in6_addr in6;
961: uint32_t prefix_length = 0xffffffff;
962: char *slash = NULL;
963: isc_boolean_t parsed = ISC_FALSE;
964: isc_boolean_t prefix_parsed = ISC_FALSE;
965: char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
966:
967: REQUIRE(sap != NULL && *sap == NULL);
968:
969: if (strlcpy(buf, value, sizeof(buf)) >= sizeof(buf))
970: fatal("invalid prefix '%s'\n", value);
971:
972: sa = malloc(sizeof(*sa));
973: if (sa == NULL)
974: fatal("out of memory");
975: memset(sa, 0, sizeof(*sa));
976:
977: if (strcmp(buf, "0") == 0) {
978: sa->type.sa.sa_family = AF_UNSPEC;
979: prefix_length = 0;
980: goto done;
981: }
982:
983: slash = strchr(buf, '/');
984: if (slash != NULL) {
985: *slash = '\0';
986: result = isc_parse_uint32(&prefix_length, slash + 1, 10);
987: if (result != ISC_R_SUCCESS) {
988: fatal("invalid prefix length in '%s': %s\n",
989: value, isc_result_totext(result));
990: }
991: prefix_parsed = ISC_TRUE;
992: }
993:
994: if (inet_pton(AF_INET6, buf, &in6) == 1) {
995: parsed = ISC_TRUE;
996: isc_sockaddr_fromin6(sa, &in6, 0);
997: if (prefix_length > 128)
998: prefix_length = 128;
999: } else if (inet_pton(AF_INET, buf, &in4) == 1) {
1000: parsed = ISC_TRUE;
1001: isc_sockaddr_fromin(sa, &in4, 0);
1002: if (prefix_length > 32)
1003: prefix_length = 32;
1004: } else if (prefix_parsed) {
1005: int i;
1006:
1007: for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
1008: strlcat(buf, ".0", sizeof(buf));
1009: if (inet_pton(AF_INET, buf, &in4) == 1) {
1010: parsed = ISC_TRUE;
1011: isc_sockaddr_fromin(sa, &in4, 0);
1012: break;
1013: }
1014: }
1015:
1016: if (prefix_length > 32)
1017: prefix_length = 32;
1018: }
1019:
1020: if (!parsed)
1021: fatal("invalid address '%s'", value);
1022:
1023: done:
1024: sa->length = prefix_length;
1025: *sap = sa;
1026:
1027: return (ISC_R_SUCCESS);
1028: }
1029:
1030: /*
1031: * Parse HMAC algorithm specification
1032: */
1033: void
1034: parse_hmac(const char *hmac) {
1035: char buf[20];
1036: size_t len;
1037:
1038: REQUIRE(hmac != NULL);
1039:
1040: len = strlen(hmac);
1041: if (len >= sizeof(buf))
1042: fatal("unknown key type '%.*s'", (int)len, hmac);
1043: strlcpy(buf, hmac, sizeof(buf));
1044:
1045: digestbits = 0;
1046:
1047: if (strcasecmp(buf, "hmac-sha1") == 0) {
1048: hmacname = DNS_TSIG_HMACSHA1_NAME;
1049: digestbits = 0;
1050: } else if (strncasecmp(buf, "hmac-sha1-", 10) == 0) {
1051: hmacname = DNS_TSIG_HMACSHA1_NAME;
1052: digestbits = parse_bits(&buf[10], "digest-bits [0..160]", 160);
1053: } else if (strcasecmp(buf, "hmac-sha224") == 0) {
1054: hmacname = DNS_TSIG_HMACSHA224_NAME;
1055: } else if (strncasecmp(buf, "hmac-sha224-", 12) == 0) {
1056: hmacname = DNS_TSIG_HMACSHA224_NAME;
1057: digestbits = parse_bits(&buf[12], "digest-bits [0..224]", 224);
1058: } else if (strcasecmp(buf, "hmac-sha256") == 0) {
1059: hmacname = DNS_TSIG_HMACSHA256_NAME;
1060: } else if (strncasecmp(buf, "hmac-sha256-", 12) == 0) {
1061: hmacname = DNS_TSIG_HMACSHA256_NAME;
1062: digestbits = parse_bits(&buf[12], "digest-bits [0..256]", 256);
1063: } else if (strcasecmp(buf, "hmac-sha384") == 0) {
1064: hmacname = DNS_TSIG_HMACSHA384_NAME;
1065: } else if (strncasecmp(buf, "hmac-sha384-", 12) == 0) {
1066: hmacname = DNS_TSIG_HMACSHA384_NAME;
1067: digestbits = parse_bits(&buf[12], "digest-bits [0..384]", 384);
1068: } else if (strcasecmp(buf, "hmac-sha512") == 0) {
1069: hmacname = DNS_TSIG_HMACSHA512_NAME;
1070: } else if (strncasecmp(buf, "hmac-sha512-", 12) == 0) {
1071: hmacname = DNS_TSIG_HMACSHA512_NAME;
1072: digestbits = parse_bits(&buf[12], "digest-bits [0..512]", 512);
1073: } else {
1074: fprintf(stderr, ";; Warning, ignoring "
1075: "invalid TSIG algorithm %s\n", buf);
1076: }
1077: }
1078:
1079: /*
1080: * Get a key from a named.conf format keyfile
1081: */
1082: static isc_result_t
1083: read_confkey(void) {
1084: cfg_parser_t *pctx = NULL;
1085: cfg_obj_t *file = NULL;
1086: const cfg_obj_t *keyobj = NULL;
1087: const cfg_obj_t *secretobj = NULL;
1088: const cfg_obj_t *algorithmobj = NULL;
1089: const char *keyname;
1090: const char *secretstr;
1091: const char *algorithm;
1092: isc_result_t result;
1093:
1094: result = cfg_parser_create(NULL, &pctx);
1095: if (result != ISC_R_SUCCESS)
1096: goto cleanup;
1097:
1098: result = cfg_parse_file(pctx, keyfile, &cfg_type_sessionkey,
1099: &file);
1100: if (result != ISC_R_SUCCESS)
1101: goto cleanup;
1102:
1103: result = cfg_map_get(file, "key", &keyobj);
1104: if (result != ISC_R_SUCCESS)
1105: goto cleanup;
1106:
1107: (void) cfg_map_get(keyobj, "secret", &secretobj);
1108: (void) cfg_map_get(keyobj, "algorithm", &algorithmobj);
1109: if (secretobj == NULL || algorithmobj == NULL)
1110: fatal("key must have algorithm and secret");
1111:
1112: keyname = cfg_obj_asstring(cfg_map_getname(keyobj));
1113: secretstr = cfg_obj_asstring(secretobj);
1114: algorithm = cfg_obj_asstring(algorithmobj);
1115:
1116: strlcpy(keynametext, keyname, sizeof(keynametext));
1117: strlcpy(keysecret, secretstr, sizeof(keysecret));
1118: parse_hmac(algorithm);
1119: setup_text_key();
1120:
1121: cleanup:
1122: if (pctx != NULL) {
1123: if (file != NULL)
1124: cfg_obj_destroy(pctx, &file);
1125: cfg_parser_destroy(&pctx);
1126: }
1127:
1128: return (result);
1129: }
1130:
1131: void
1132: setup_file_key(void) {
1133: isc_result_t result;
1134:
1135: debug("setup_file_key()");
1136:
1.12 florian 1137: /* Try reading the key as a session.key keyfile */
1138: result = read_confkey();
1.1 florian 1139:
1.12 florian 1140: if (result != ISC_R_SUCCESS)
1.1 florian 1141: fprintf(stderr, "Couldn't read key from %s: %s\n",
1142: keyfile, isc_result_totext(result));
1143: }
1144:
1145: static dig_searchlist_t *
1146: make_searchlist_entry(char *domain) {
1147: dig_searchlist_t *search;
1148: search = malloc(sizeof(*search));
1149: if (search == NULL)
1150: fatal("memory allocation failure in %s:%d",
1151: __FILE__, __LINE__);
1152: strlcpy(search->origin, domain, MXNAME);
1153: search->origin[MXNAME-1] = 0;
1154: ISC_LINK_INIT(search, link);
1155: return (search);
1156: }
1157:
1158: static void
1159: clear_searchlist(void) {
1160: dig_searchlist_t *search;
1161: while ((search = ISC_LIST_HEAD(search_list)) != NULL) {
1162: ISC_LIST_UNLINK(search_list, search, link);
1163: free(search);
1164: }
1165: }
1166:
1167: static void
1168: create_search_list(lwres_conf_t *confdata) {
1169: int i;
1170: dig_searchlist_t *search;
1171:
1172: debug("create_search_list()");
1173: clear_searchlist();
1174:
1175: for (i = 0; i < confdata->searchnxt; i++) {
1176: search = make_searchlist_entry(confdata->search[i]);
1177: ISC_LIST_APPEND(search_list, search, link);
1178: }
1179: }
1180:
1181: /*%
1182: * Setup the system as a whole, reading key information and resolv.conf
1183: * settings.
1184: */
1185: void
1186: setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only) {
1187: dig_searchlist_t *domain = NULL;
1188: lwres_result_t lwresult;
1189: int lwresflags = 0;
1190:
1191: debug("setup_system()");
1192:
1193: if (ipv4only) {
1194: if (have_ipv4) {
1195: isc_net_disableipv6();
1196: have_ipv6 = ISC_FALSE;
1197: } else {
1198: fatal("can't find IPv4 networking");
1199: }
1200: }
1201:
1202: if (ipv6only) {
1203: if (have_ipv6) {
1204: isc_net_disableipv4();
1205: have_ipv4 = ISC_FALSE;
1206: } else {
1207: fatal("can't find IPv6 networking");
1208: }
1209: }
1210:
1211: if (have_ipv4)
1212: lwresflags |= LWRES_USEIPV4;
1213: if (have_ipv6)
1214: lwresflags |= LWRES_USEIPV6;
1215: lwres_conf_init(lwconf, lwresflags);
1216:
1.6 florian 1217: lwresult = lwres_conf_parse(lwconf, _PATH_RESCONF);
1.1 florian 1218: if (lwresult != LWRES_R_SUCCESS && lwresult != LWRES_R_NOTFOUND)
1.6 florian 1219: fatal("parse of %s failed", _PATH_RESCONF);
1.1 florian 1220:
1221: /* Make the search list */
1222: if (lwconf->searchnxt > 0)
1223: create_search_list(lwconf);
1224: else { /* No search list. Use the domain name if any */
1225: if (lwconf->domainname != NULL) {
1226: domain = make_searchlist_entry(lwconf->domainname);
1227: ISC_LIST_APPEND(search_list, domain, link);
1228: domain = NULL;
1229: }
1230: }
1231:
1232: if (ndots == -1) {
1233: ndots = lwconf->ndots;
1234: debug("ndots is %d.", ndots);
1235: }
1236:
1237: /* If user doesn't specify server use nameservers from resolv.conf. */
1238: if (ISC_LIST_EMPTY(server_list))
1239: copy_server_list(lwconf, &server_list);
1240:
1241: /* If we don't find a nameserver fall back to localhost */
1242: if (ISC_LIST_EMPTY(server_list)) {
1243: if (have_ipv4) {
1244: lwresult = add_nameserver(lwconf, "127.0.0.1", AF_INET);
1245: if (lwresult != ISC_R_SUCCESS)
1246: fatal("add_nameserver failed");
1247: }
1248: if (have_ipv6) {
1249: lwresult = add_nameserver(lwconf, "::1", AF_INET6);
1250: if (lwresult != ISC_R_SUCCESS)
1251: fatal("add_nameserver failed");
1252: }
1253:
1254: copy_server_list(lwconf, &server_list);
1255: }
1256:
1257: if (keyfile[0] != 0)
1258: setup_file_key();
1259: else if (keysecret[0] != 0)
1260: setup_text_key();
1261: arc4random_buf(cookie_secret, sizeof(cookie_secret));
1262: }
1263:
1264: /*%
1265: * Override the search list derived from resolv.conf by 'domain'.
1266: */
1267: void
1268: set_search_domain(char *domain) {
1269: dig_searchlist_t *search;
1270:
1271: clear_searchlist();
1272: search = make_searchlist_entry(domain);
1273: ISC_LIST_APPEND(search_list, search, link);
1274: }
1275:
1276: /*%
1277: * Setup the ISC and DNS libraries for use by the system.
1278: */
1279: void
1280: setup_libs(void) {
1281: isc_result_t result;
1282: isc_logconfig_t *logconfig = NULL;
1283:
1284: debug("setup_libs()");
1285:
1286: dns_result_register();
1287:
1288: result = isc_log_create(&lctx, &logconfig);
1289: check_result(result, "isc_log_create");
1290:
1291: isc_log_setcontext(lctx);
1292: dns_log_init(lctx);
1293: dns_log_setcontext(lctx);
1294:
1295: result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
1296: check_result(result, "isc_log_usechannel");
1297:
1298: isc_log_setdebuglevel(lctx, 0);
1299:
1300: result = isc_taskmgr_create(1, 0, &taskmgr);
1301: check_result(result, "isc_taskmgr_create");
1302:
1303: result = isc_task_create(taskmgr, 0, &global_task);
1304: check_result(result, "isc_task_create");
1305: isc_task_setname(global_task, "dig", NULL);
1306:
1307: result = isc_timermgr_create(&timermgr);
1308: check_result(result, "isc_timermgr_create");
1309:
1310: result = isc_socketmgr_create(&socketmgr);
1311: check_result(result, "isc_socketmgr_create");
1312:
1313: check_result(result, "isc_entropy_create");
1314:
1315: result = dst_lib_init();
1316: check_result(result, "dst_lib_init");
1317: is_dst_up = ISC_TRUE;
1318: }
1319:
1320: typedef struct dig_ednsoptname {
1321: uint32_t code;
1322: const char *name;
1323: } dig_ednsoptname_t;
1324:
1325: dig_ednsoptname_t optnames[] = {
1326: { 3, "NSID" }, /* RFC 5001 */
1327: { 5, "DAU" }, /* RFC 6975 */
1328: { 6, "DHU" }, /* RFC 6975 */
1329: { 7, "N3U" }, /* RFC 6975 */
1330: { 8, "ECS" }, /* RFC 7871 */
1331: { 9, "EXPIRE" }, /* RFC 7314 */
1332: { 10, "COOKIE" }, /* RFC 7873 */
1333: { 11, "KEEPALIVE" }, /* RFC 7828 */
1334: { 12, "PADDING" }, /* RFC 7830 */
1335: { 12, "PAD" }, /* shorthand */
1336: { 13, "CHAIN" }, /* RFC 7901 */
1337: { 14, "KEY-TAG" }, /* RFC 8145 */
1338: { 26946, "DEVICEID" }, /* Brian Hartvigsen */
1339: };
1340:
1341: #define N_EDNS_OPTNAMES (sizeof(optnames) / sizeof(optnames[0]))
1342:
1343: void
1344: save_opt(dig_lookup_t *lookup, char *code, char *value) {
1345: isc_result_t result;
1346: uint32_t num = 0;
1347: isc_buffer_t b;
1348: isc_boolean_t found = ISC_FALSE;
1349: unsigned int i;
1350:
1351: if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS)
1352: fatal("too many ednsopts");
1353:
1354: for (i = 0; i < N_EDNS_OPTNAMES; i++) {
1355: if (strcasecmp(code, optnames[i].name) == 0) {
1356: num = optnames[i].code;
1357: found = ISC_TRUE;
1358: break;
1359: }
1360: }
1361:
1362: if (!found) {
1363: result = parse_uint(&num, code, 65535, "ednsopt");
1364: if (result != ISC_R_SUCCESS)
1365: fatal("bad edns code point: %s", code);
1366: }
1367:
1368: if (lookup->ednsopts == NULL) {
1369: cloneopts(lookup, NULL);
1370: }
1371:
1372: if (lookup->ednsopts[lookup->ednsoptscnt].value != NULL)
1373: free(lookup->ednsopts[lookup->ednsoptscnt].value);
1374:
1375: lookup->ednsopts[lookup->ednsoptscnt].code = num;
1376: lookup->ednsopts[lookup->ednsoptscnt].length = 0;
1377: lookup->ednsopts[lookup->ednsoptscnt].value = NULL;
1378:
1379: if (value != NULL) {
1380: char *buf;
1381: buf = malloc(strlen(value)/2 + 1);
1382: if (buf == NULL)
1383: fatal("out of memory");
1384: isc_buffer_init(&b, buf, (unsigned int) strlen(value)/2 + 1);
1385: result = isc_hex_decodestring(value, &b);
1386: check_result(result, "isc_hex_decodestring");
1387: lookup->ednsopts[lookup->ednsoptscnt].value =
1388: isc_buffer_base(&b);
1389: lookup->ednsopts[lookup->ednsoptscnt].length =
1390: isc_buffer_usedlength(&b);
1391: }
1392:
1393: lookup->ednsoptscnt++;
1394: }
1395:
1396: /*%
1397: * Add EDNS0 option record to a message. Currently, the only supported
1398: * options are UDP buffer size, the DO bit, and EDNS options
1399: * (e.g., NSID, SIT, client-subnet)
1400: */
1401: static void
1402: add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns,
1403: unsigned int flags, dns_ednsopt_t *opts, size_t count)
1404: {
1405: dns_rdataset_t *rdataset = NULL;
1406: isc_result_t result;
1407:
1408: debug("add_opt()");
1409: result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
1410: opts, count);
1411: check_result(result, "dns_message_buildopt");
1412: result = dns_message_setopt(msg, rdataset);
1413: check_result(result, "dns_message_setopt");
1414: }
1415:
1416: /*%
1417: * Add a question section to a message, asking for the specified name,
1418: * type, and class.
1419: */
1420: static void
1421: add_question(dns_message_t *message, dns_name_t *name,
1422: dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
1423: {
1424: dns_rdataset_t *rdataset;
1425: isc_result_t result;
1426:
1427: debug("add_question()");
1428: rdataset = NULL;
1429: result = dns_message_gettemprdataset(message, &rdataset);
1430: check_result(result, "dns_message_gettemprdataset()");
1431: dns_rdataset_makequestion(rdataset, rdclass, rdtype);
1432: ISC_LIST_APPEND(name->list, rdataset, link);
1433: }
1434:
1435: /*%
1436: * Check if we're done with all the queued lookups, which is true iff
1437: * all sockets, sends, and recvs are accounted for (counters == 0),
1438: * and the lookup list is empty.
1439: * If we are done, pass control back out to dighost_shutdown() (which is
1440: * part of dig.c, host.c, or nslookup.c) to either shutdown the system as
1441: * a whole or reseed the lookup list.
1442: */
1443: static void
1444: check_if_done(void) {
1445: debug("check_if_done()");
1446: debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
1447: if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
1448: sendcount == 0) {
1449: INSIST(sockcount == 0);
1450: INSIST(recvcount == 0);
1451: debug("shutting down");
1452: dighost_shutdown();
1453: }
1454: }
1455:
1456: /*%
1457: * Clear out a query when we're done with it. WARNING: This routine
1458: * WILL invalidate the query pointer.
1459: */
1460: static void
1461: clear_query(dig_query_t *query) {
1462: dig_lookup_t *lookup;
1463:
1464: REQUIRE(query != NULL);
1465:
1466: debug("clear_query(%p)", query);
1467:
1468: if (query->timer != NULL)
1469: isc_timer_detach(&query->timer);
1470: lookup = query->lookup;
1471:
1472: if (lookup->current_query == query)
1473: lookup->current_query = NULL;
1474:
1475: if (ISC_LINK_LINKED(query, link))
1476: ISC_LIST_UNLINK(lookup->q, query, link);
1477: if (ISC_LINK_LINKED(query, clink))
1478: ISC_LIST_UNLINK(lookup->connecting, query, clink);
1479: if (ISC_LINK_LINKED(&query->recvbuf, link))
1480: ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf,
1481: link);
1482: if (ISC_LINK_LINKED(&query->lengthbuf, link))
1483: ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf,
1484: link);
1485: INSIST(query->recvspace != NULL);
1486:
1487: if (query->sock != NULL) {
1488: isc_socket_detach(&query->sock);
1489: sockcount--;
1490: debug("sockcount=%d", sockcount);
1491: }
1492: free(query->recvspace);
1493: isc_buffer_invalidate(&query->recvbuf);
1494: isc_buffer_invalidate(&query->lengthbuf);
1495: if (query->waiting_senddone)
1496: query->pending_free = ISC_TRUE;
1497: else
1498: free(query);
1499: }
1500:
1501: /*%
1502: * Try and clear out a lookup if we're done with it. Return ISC_TRUE if
1503: * the lookup was successfully cleared. If ISC_TRUE is returned, the
1504: * lookup pointer has been invalidated.
1505: */
1506: static isc_boolean_t
1507: try_clear_lookup(dig_lookup_t *lookup) {
1508: dig_query_t *q;
1509:
1510: REQUIRE(lookup != NULL);
1511:
1512: debug("try_clear_lookup(%p)", lookup);
1513:
1514: if (ISC_LIST_HEAD(lookup->q) != NULL ||
1515: ISC_LIST_HEAD(lookup->connecting) != NULL)
1516: {
1517: if (debugging) {
1518: q = ISC_LIST_HEAD(lookup->q);
1519: while (q != NULL) {
1520: debug("query to %s still pending", q->servname);
1521: q = ISC_LIST_NEXT(q, link);
1522: }
1523:
1524: q = ISC_LIST_HEAD(lookup->connecting);
1525: while (q != NULL) {
1526: debug("query to %s still connecting",
1527: q->servname);
1528: q = ISC_LIST_NEXT(q, clink);
1529: }
1530: }
1531: return (ISC_FALSE);
1532: }
1533:
1534: /*
1535: * At this point, we know there are no queries on the lookup,
1536: * so can make it go away also.
1537: */
1538: destroy_lookup(lookup);
1539: return (ISC_TRUE);
1540: }
1541:
1542: void
1543: destroy_lookup(dig_lookup_t *lookup) {
1544: dig_server_t *s;
1545: void *ptr;
1546:
1547: debug("destroy");
1548: s = ISC_LIST_HEAD(lookup->my_server_list);
1549: while (s != NULL) {
1550: debug("freeing server %p belonging to %p", s, lookup);
1551: ptr = s;
1552: s = ISC_LIST_NEXT(s, link);
1553: ISC_LIST_DEQUEUE(lookup->my_server_list,
1554: (dig_server_t *)ptr, link);
1555: free(ptr);
1556: }
1557: if (lookup->sendmsg != NULL)
1558: dns_message_destroy(&lookup->sendmsg);
1559: if (lookup->querysig != NULL) {
1560: debug("freeing buffer %p", lookup->querysig);
1561: isc_buffer_free(&lookup->querysig);
1562: }
1563: if (lookup->sendspace != NULL)
1564: free(lookup->sendspace);
1565:
1566: if (lookup->tsigctx != NULL)
1567: dst_context_destroy(&lookup->tsigctx);
1568:
1569: if (lookup->ecs_addr != NULL)
1570: free(lookup->ecs_addr);
1571:
1572: if (lookup->ednsopts != NULL) {
1573: size_t i;
1574: for (i = 0; i < EDNSOPT_OPTIONS; i++) {
1575: if (lookup->ednsopts[i].value != NULL)
1576: free(lookup->ednsopts[i].value);
1577: }
1578: free(lookup->ednsopts);
1579: }
1580:
1581: free(lookup);
1582: }
1583:
1584: /*%
1585: * If we can, start the next lookup in the queue running.
1586: * This assumes that the lookup on the head of the queue hasn't been
1587: * started yet. It also removes the lookup from the head of the queue,
1588: * setting the current_lookup pointer pointing to it.
1589: */
1590: void
1591: start_lookup(void) {
1592: debug("start_lookup()");
1593: if (cancel_now)
1594: return;
1595:
1596: /*
1597: * If there's a current lookup running, we really shouldn't get
1598: * here.
1599: */
1600: INSIST(current_lookup == NULL);
1601:
1602: current_lookup = ISC_LIST_HEAD(lookup_list);
1603: /*
1604: * Put the current lookup somewhere so cancel_all can find it
1605: */
1606: if (current_lookup != NULL) {
1607: ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
1608: if (setup_lookup(current_lookup))
1609: do_lookup(current_lookup);
1610: else if (next_origin(current_lookup))
1611: check_next_lookup(current_lookup);
1612: } else {
1613: check_if_done();
1614: }
1615: }
1616:
1617: /*%
1618: * If we can, clear the current lookup and start the next one running.
1619: * This calls try_clear_lookup, so may invalidate the lookup pointer.
1620: */
1621: static void
1622: check_next_lookup(dig_lookup_t *lookup) {
1623:
1624: INSIST(!free_now);
1625:
1626: debug("check_next_lookup(%p)", lookup);
1627:
1628: if (ISC_LIST_HEAD(lookup->q) != NULL) {
1629: debug("still have a worker");
1630: return;
1631: }
1632: if (try_clear_lookup(lookup)) {
1633: current_lookup = NULL;
1634: start_lookup();
1635: }
1636: }
1637:
1638: /*%
1639: * Create and queue a new lookup as a followup to the current lookup,
1640: * based on the supplied message and section. This is used in trace and
1641: * name server search modes to start a new lookup using servers from
1642: * NS records in a reply. Returns the number of followup lookups made.
1643: */
1644: static int
1645: followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section)
1646: {
1647: dig_lookup_t *lookup = NULL;
1648: dig_server_t *srv = NULL;
1649: dns_rdataset_t *rdataset = NULL;
1650: dns_rdata_t rdata = DNS_RDATA_INIT;
1651: dns_name_t *name = NULL;
1652: isc_result_t result;
1653: isc_boolean_t success = ISC_FALSE;
1654: int numLookups = 0;
1655: int num;
1656: isc_result_t lresult, addresses_result;
1657: char bad_namestr[DNS_NAME_FORMATSIZE];
1658: dns_name_t *domain;
1659: isc_boolean_t horizontal = ISC_FALSE, bad = ISC_FALSE;
1660:
1661: INSIST(!free_now);
1662:
1663: debug("following up %s", query->lookup->textname);
1664:
1665: addresses_result = ISC_R_SUCCESS;
1666: bad_namestr[0] = '\0';
1667: for (result = dns_message_firstname(msg, section);
1668: result == ISC_R_SUCCESS;
1669: result = dns_message_nextname(msg, section)) {
1670: name = NULL;
1671: dns_message_currentname(msg, section, &name);
1672:
1673: if (section == DNS_SECTION_AUTHORITY) {
1674: rdataset = NULL;
1675: result = dns_message_findtype(name, dns_rdatatype_soa,
1676: 0, &rdataset);
1677: if (result == ISC_R_SUCCESS)
1678: return (0);
1679: }
1680: rdataset = NULL;
1681: result = dns_message_findtype(name, dns_rdatatype_ns, 0,
1682: &rdataset);
1683: if (result != ISC_R_SUCCESS)
1684: continue;
1685:
1686: debug("found NS set");
1687:
1688: if (query->lookup->trace && !query->lookup->trace_root) {
1689: dns_namereln_t namereln;
1690: unsigned int nlabels;
1691: int order;
1692:
1693: domain = dns_fixedname_name(&query->lookup->fdomain);
1694: namereln = dns_name_fullcompare(name, domain,
1695: &order, &nlabels);
1696: if (namereln == dns_namereln_equal) {
1697: if (!horizontal)
1698: printf(";; BAD (HORIZONTAL) REFERRAL\n");
1699: horizontal = ISC_TRUE;
1700: } else if (namereln != dns_namereln_subdomain) {
1701: if (!bad)
1702: printf(";; BAD REFERRAL\n");
1703: bad = ISC_TRUE;
1704: continue;
1705: }
1706: }
1707:
1708: for (result = dns_rdataset_first(rdataset);
1709: result == ISC_R_SUCCESS;
1710: result = dns_rdataset_next(rdataset)) {
1711: char namestr[DNS_NAME_FORMATSIZE];
1712: dns_rdata_ns_t ns;
1713:
1714: if (query->lookup->trace_root &&
1715: query->lookup->nsfound >= MXSERV)
1716: break;
1717:
1718: dns_rdataset_current(rdataset, &rdata);
1719:
1720: query->lookup->nsfound++;
1721: result = dns_rdata_tostruct(&rdata, &ns);
1722: check_result(result, "dns_rdata_tostruct");
1723: dns_name_format(&ns.name, namestr, sizeof(namestr));
1724: dns_rdata_freestruct(&ns);
1725:
1726: /* Initialize lookup if we've not yet */
1727: debug("found NS %s", namestr);
1728: if (!success) {
1729: success = ISC_TRUE;
1730: lookup_counter++;
1731: lookup = requeue_lookup(query->lookup,
1732: ISC_FALSE);
1733: cancel_lookup(query->lookup);
1734: lookup->doing_xfr = ISC_FALSE;
1735: if (!lookup->trace_root &&
1736: section == DNS_SECTION_ANSWER)
1737: lookup->trace = ISC_FALSE;
1738: else
1739: lookup->trace = query->lookup->trace;
1740: lookup->ns_search_only =
1741: query->lookup->ns_search_only;
1742: lookup->trace_root = ISC_FALSE;
1743: if (lookup->ns_search_only)
1744: lookup->recurse = ISC_FALSE;
1745: domain = dns_fixedname_name(&lookup->fdomain);
1746: dns_name_copy(name, domain, NULL);
1747: }
1748: debug("adding server %s", namestr);
1749: num = getaddresses(lookup, namestr, &lresult);
1750: if (lresult != ISC_R_SUCCESS) {
1751: printf("couldn't get address for '%s': %s\n",
1752: namestr, isc_result_totext(lresult));
1753: if (addresses_result == ISC_R_SUCCESS) {
1754: addresses_result = lresult;
1755: strlcpy(bad_namestr, namestr,
1756: sizeof(bad_namestr));
1757: }
1758: }
1759: numLookups += num;
1760: dns_rdata_reset(&rdata);
1761: }
1762: }
1763: if (numLookups == 0 && addresses_result != ISC_R_SUCCESS) {
1764: fatal("couldn't get address for '%s': %s",
1765: bad_namestr, isc_result_totext(result));
1766: }
1767:
1768: if (lookup == NULL &&
1769: section == DNS_SECTION_ANSWER &&
1770: (query->lookup->trace || query->lookup->ns_search_only))
1771: return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY));
1772:
1773: /*
1774: * Randomize the order the nameserver will be tried.
1775: */
1776: if (numLookups > 1) {
1777: uint32_t i, j;
1778: dig_serverlist_t my_server_list;
1779: dig_server_t *next;
1780:
1781: ISC_LIST_INIT(my_server_list);
1782:
1783: i = numLookups;
1784: for (srv = ISC_LIST_HEAD(lookup->my_server_list);
1785: srv != NULL;
1786: srv = ISC_LIST_HEAD(lookup->my_server_list)) {
1787: INSIST(i > 0);
1788: j = arc4random_uniform(i);
1789: next = ISC_LIST_NEXT(srv, link);
1790: while (j-- > 0 && next != NULL) {
1791: srv = next;
1792: next = ISC_LIST_NEXT(srv, link);
1793: }
1794: ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
1795: ISC_LIST_APPEND(my_server_list, srv, link);
1796: i--;
1797: }
1798: ISC_LIST_APPENDLIST(lookup->my_server_list,
1799: my_server_list, link);
1800: }
1801:
1802: return (numLookups);
1803: }
1804:
1805: /*%
1806: * Create and queue a new lookup using the next origin from the search
1807: * list, read in setup_system().
1808: *
1809: * Return ISC_TRUE iff there was another searchlist entry.
1810: */
1811: static isc_boolean_t
1812: next_origin(dig_lookup_t *oldlookup) {
1813: dig_lookup_t *newlookup;
1814: dig_searchlist_t *search;
1815: dns_fixedname_t fixed;
1816: dns_name_t *name;
1817: isc_result_t result;
1818:
1819: INSIST(!free_now);
1820:
1821: debug("next_origin()");
1822: debug("following up %s", oldlookup->textname);
1823:
1824: if (!usesearch)
1825: /*
1826: * We're not using a search list, so don't even think
1827: * about finding the next entry.
1828: */
1829: return (ISC_FALSE);
1830:
1831: /*
1832: * Check for a absolute name or ndots being met.
1833: */
1834: dns_fixedname_init(&fixed);
1835: name = dns_fixedname_name(&fixed);
1836: result = dns_name_fromstring2(name, oldlookup->textname, NULL, 0);
1837: if (result == ISC_R_SUCCESS &&
1838: (dns_name_isabsolute(name) ||
1839: (int)dns_name_countlabels(name) > ndots))
1840: return (ISC_FALSE);
1841:
1842: if (oldlookup->origin == NULL && !oldlookup->need_search)
1843: /*
1844: * Then we just did rootorg; there's nothing left.
1845: */
1846: return (ISC_FALSE);
1847: if (oldlookup->origin == NULL && oldlookup->need_search) {
1848: newlookup = requeue_lookup(oldlookup, ISC_TRUE);
1849: newlookup->origin = ISC_LIST_HEAD(search_list);
1850: newlookup->need_search = ISC_FALSE;
1851: } else {
1852: search = ISC_LIST_NEXT(oldlookup->origin, link);
1853: if (search == NULL && oldlookup->done_as_is)
1854: return (ISC_FALSE);
1855: newlookup = requeue_lookup(oldlookup, ISC_TRUE);
1856: newlookup->origin = search;
1857: }
1858: cancel_lookup(oldlookup);
1859: return (ISC_TRUE);
1860: }
1861:
1862: /*%
1863: * Insert an SOA record into the sendmessage in a lookup. Used for
1864: * creating IXFR queries.
1865: */
1866: static void
1867: insert_soa(dig_lookup_t *lookup) {
1868: isc_result_t result;
1869: dns_rdata_soa_t soa;
1870: dns_rdata_t *rdata = NULL;
1871: dns_rdatalist_t *rdatalist = NULL;
1872: dns_rdataset_t *rdataset = NULL;
1873: dns_name_t *soaname = NULL;
1874:
1875: debug("insert_soa()");
1876: soa.serial = lookup->ixfr_serial;
1877: soa.refresh = 0;
1878: soa.retry = 0;
1879: soa.expire = 0;
1880: soa.minimum = 0;
1881: soa.common.rdclass = lookup->rdclass;
1882: soa.common.rdtype = dns_rdatatype_soa;
1883:
1884: dns_name_init(&soa.origin, NULL);
1885: dns_name_init(&soa.contact, NULL);
1886:
1887: dns_name_clone(dns_rootname, &soa.origin);
1888: dns_name_clone(dns_rootname, &soa.contact);
1889:
1890: isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
1891: sizeof(lookup->rdatastore));
1892:
1893: result = dns_message_gettemprdata(lookup->sendmsg, &rdata);
1894: check_result(result, "dns_message_gettemprdata");
1895:
1896: result = dns_rdata_fromstruct(rdata, lookup->rdclass,
1897: dns_rdatatype_soa, &soa,
1898: &lookup->rdatabuf);
1899: check_result(result, "isc_rdata_fromstruct");
1900:
1901: result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
1902: check_result(result, "dns_message_gettemprdatalist");
1903:
1904: result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
1905: check_result(result, "dns_message_gettemprdataset");
1906:
1907: dns_rdatalist_init(rdatalist);
1908: rdatalist->type = dns_rdatatype_soa;
1909: rdatalist->rdclass = lookup->rdclass;
1910: ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1911:
1912: dns_rdatalist_tordataset(rdatalist, rdataset);
1913:
1914: result = dns_message_gettempname(lookup->sendmsg, &soaname);
1915: check_result(result, "dns_message_gettempname");
1916: dns_name_init(soaname, NULL);
1917: dns_name_clone(lookup->name, soaname);
1918: ISC_LIST_INIT(soaname->list);
1919: ISC_LIST_APPEND(soaname->list, rdataset, link);
1920: dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
1921: }
1922:
1923: static void
1924: compute_cookie(unsigned char *clientcookie, size_t len) {
1925: /* XXXMPA need to fix, should be per server. */
1926: INSIST(len >= 8U);
1927: memmove(clientcookie, cookie_secret, 8);
1928: }
1929:
1.5 florian 1930: #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
1931: static void
1.14 jung 1932: populate_root_hints(void)
1.5 florian 1933: {
1934: dig_server_t *newsrv;
1935: size_t i;
1936:
1937: if (!ISC_LIST_EMPTY(root_hints_server_list))
1938: return;
1939:
1940: for (i = 0; i < nitems(root_hints); i++) {
1941: if (!have_ipv4 && root_hints[i].af == AF_INET)
1942: continue;
1943: if (!have_ipv6 && root_hints[i].af == AF_INET6)
1944: continue;
1945: newsrv = make_server(root_hints[i].ns, root_hints[i].ns);
1946: ISC_LINK_INIT(newsrv, link);
1947: ISC_LIST_ENQUEUE(root_hints_server_list, newsrv, link);
1948: }
1949: }
1950: #undef nitems
1951:
1.1 florian 1952: /*%
1953: * Setup the supplied lookup structure, making it ready to start sending
1954: * queries to servers. Create and initialize the message to be sent as
1955: * well as the query structures and buffer space for the replies. If the
1956: * server list is empty, clone it from the system default list.
1957: */
1958: isc_boolean_t
1959: setup_lookup(dig_lookup_t *lookup) {
1960: isc_result_t result;
1961: uint32_t id;
1962: unsigned int len;
1963: dig_server_t *serv;
1964: dig_query_t *query;
1965: isc_buffer_t b;
1966: dns_compress_t cctx;
1967: char store[MXNAME];
1968: char ecsbuf[20];
1969: char sitbuf[256];
1970:
1971: REQUIRE(lookup != NULL);
1972: INSIST(!free_now);
1973:
1974: debug("setup_lookup(%p)", lookup);
1975:
1976: result = dns_message_create(DNS_MESSAGE_INTENTRENDER,
1977: &lookup->sendmsg);
1978: check_result(result, "dns_message_create");
1979:
1980: if (lookup->new_search) {
1981: debug("resetting lookup counter.");
1982: lookup_counter = 0;
1983: }
1984:
1985: if (ISC_LIST_EMPTY(lookup->my_server_list)) {
1.5 florian 1986: if (lookup->trace && lookup->trace_root) {
1987: populate_root_hints();
1988: clone_server_list(root_hints_server_list,
1989: &lookup->my_server_list);
1990: } else {
1991: debug("cloning server list");
1992: clone_server_list(server_list,
1993: &lookup->my_server_list);
1994: }
1.1 florian 1995: }
1996: result = dns_message_gettempname(lookup->sendmsg, &lookup->name);
1997: check_result(result, "dns_message_gettempname");
1998: dns_name_init(lookup->name, NULL);
1999:
2000: isc_buffer_init(&lookup->namebuf, lookup->name_space,
2001: sizeof(lookup->name_space));
2002: isc_buffer_init(&lookup->onamebuf, lookup->oname_space,
2003: sizeof(lookup->oname_space));
2004:
2005: /*
2006: * If the name has too many dots, force the origin to be NULL
2007: * (which produces an absolute lookup). Otherwise, take the origin
2008: * we have if there's one in the struct already. If it's NULL,
2009: * take the first entry in the searchlist iff either usesearch
2010: * is TRUE or we got a domain line in the resolv.conf file.
2011: */
2012: if (lookup->new_search) {
2013: if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
2014: lookup->origin = NULL; /* Force abs lookup */
2015: lookup->done_as_is = ISC_TRUE;
2016: lookup->need_search = usesearch;
2017: } else if (lookup->origin == NULL && usesearch) {
2018: lookup->origin = ISC_LIST_HEAD(search_list);
2019: lookup->need_search = ISC_FALSE;
2020: }
2021: }
2022:
2023: if (lookup->origin != NULL) {
2024: debug("trying origin %s", lookup->origin->origin);
2025: result = dns_message_gettempname(lookup->sendmsg,
2026: &lookup->oname);
2027: check_result(result, "dns_message_gettempname");
2028: dns_name_init(lookup->oname, NULL);
2029: /* XXX Helper funct to conv char* to name? */
2030: len = (unsigned int) strlen(lookup->origin->origin);
2031: isc_buffer_init(&b, lookup->origin->origin, len);
2032: isc_buffer_add(&b, len);
2033: result = dns_name_fromtext(lookup->oname, &b, dns_rootname,
2034: 0, &lookup->onamebuf);
2035: if (result != ISC_R_SUCCESS) {
2036: dns_message_puttempname(lookup->sendmsg,
2037: &lookup->name);
2038: dns_message_puttempname(lookup->sendmsg,
2039: &lookup->oname);
2040: fatal("'%s' is not in legal name syntax (%s)",
2041: lookup->origin->origin,
2042: isc_result_totext(result));
2043: }
2044: if (lookup->trace && lookup->trace_root) {
2045: dns_name_clone(dns_rootname, lookup->name);
2046: } else {
2047: dns_fixedname_t fixed;
2048: dns_name_t *name;
2049:
2050: dns_fixedname_init(&fixed);
2051: name = dns_fixedname_name(&fixed);
2052: len = (unsigned int) strlen(lookup->textname);
2053: isc_buffer_init(&b, lookup->textname, len);
2054: isc_buffer_add(&b, len);
2055: result = dns_name_fromtext(name, &b, NULL, 0, NULL);
2056: if (result == ISC_R_SUCCESS &&
2057: !dns_name_isabsolute(name))
2058: result = dns_name_concatenate(name,
2059: lookup->oname,
2060: lookup->name,
2061: &lookup->namebuf);
2062: else if (result == ISC_R_SUCCESS)
2063: result = dns_name_copy(name, lookup->name,
2064: &lookup->namebuf);
2065: if (result != ISC_R_SUCCESS) {
2066: dns_message_puttempname(lookup->sendmsg,
2067: &lookup->name);
2068: dns_message_puttempname(lookup->sendmsg,
2069: &lookup->oname);
2070: if (result == DNS_R_NAMETOOLONG)
2071: return (ISC_FALSE);
2072: fatal("'%s' is not in legal name syntax (%s)",
2073: lookup->textname,
2074: isc_result_totext(result));
2075: }
2076: }
2077: dns_message_puttempname(lookup->sendmsg, &lookup->oname);
2078: } else
2079: {
2080: debug("using root origin");
2081: if (lookup->trace && lookup->trace_root)
2082: dns_name_clone(dns_rootname, lookup->name);
2083: else {
2084: len = (unsigned int) strlen(lookup->textname);
2085: isc_buffer_init(&b, lookup->textname, len);
2086: isc_buffer_add(&b, len);
2087: result = dns_name_fromtext(lookup->name, &b,
2088: dns_rootname, 0,
2089: &lookup->namebuf);
2090: }
2091: if (result != ISC_R_SUCCESS) {
2092: dns_message_puttempname(lookup->sendmsg,
2093: &lookup->name);
2094: fatal("'%s' is not a legal name "
2095: "(%s)", lookup->textname,
2096: isc_result_totext(result));
2097: }
2098: }
2099: dns_name_format(lookup->name, store, sizeof(store));
2100: dighost_trying(store, lookup);
2101: INSIST(dns_name_isabsolute(lookup->name));
2102:
2103: id = arc4random();
2104: lookup->sendmsg->id = (unsigned short)id & 0xFFFF;
2105: lookup->sendmsg->opcode = lookup->opcode;
2106: lookup->msgcounter = 0;
2107: /*
2108: * If this is a trace request, completely disallow recursion, since
2109: * it's meaningless for traces.
2110: */
2111: if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root))
2112: lookup->recurse = ISC_FALSE;
2113:
2114: if (lookup->recurse &&
2115: lookup->rdtype != dns_rdatatype_axfr &&
2116: lookup->rdtype != dns_rdatatype_ixfr) {
2117: debug("recursive query");
2118: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
2119: }
2120:
2121: /* XXX aaflag */
2122: if (lookup->aaonly) {
2123: debug("AA query");
2124: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
2125: }
2126:
2127: if (lookup->adflag) {
2128: debug("AD query");
2129: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
2130: }
2131:
2132: if (lookup->cdflag) {
2133: debug("CD query");
2134: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
2135: }
2136:
2137: dns_message_addname(lookup->sendmsg, lookup->name,
2138: DNS_SECTION_QUESTION);
2139:
2140: if (lookup->trace && lookup->trace_root) {
2141: lookup->qrdtype = lookup->rdtype;
2142: lookup->rdtype = dns_rdatatype_ns;
2143: }
2144:
2145: if ((lookup->rdtype == dns_rdatatype_axfr) ||
2146: (lookup->rdtype == dns_rdatatype_ixfr)) {
2147: /*
2148: * Force TCP mode if we're doing an axfr.
2149: */
2150: if (lookup->rdtype == dns_rdatatype_axfr) {
2151: lookup->doing_xfr = ISC_TRUE;
2152: lookup->tcp_mode = ISC_TRUE;
2153: } else if (lookup->tcp_mode) {
2154: lookup->doing_xfr = ISC_TRUE;
2155: }
2156: }
2157:
2158: add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
2159: lookup->rdtype);
2160:
2161: /* add_soa */
2162: if (lookup->rdtype == dns_rdatatype_ixfr)
2163: insert_soa(lookup);
2164:
2165: /* XXX Insist this? */
2166: lookup->tsigctx = NULL;
2167: lookup->querysig = NULL;
2168: if (tsigkey != NULL) {
2169: debug("initializing keys");
2170: result = dns_message_settsigkey(lookup->sendmsg, tsigkey);
2171: check_result(result, "dns_message_settsigkey");
2172: }
2173:
2174: lookup->sendspace = malloc(COMMSIZE);
2175: if (lookup->sendspace == NULL)
2176: fatal("memory allocation failure");
2177:
2178: result = dns_compress_init(&cctx, -1);
2179: check_result(result, "dns_compress_init");
2180:
2181: debug("starting to render the message");
2182: isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
2183: result = dns_message_renderbegin(lookup->sendmsg, &cctx,
2184: &lookup->renderbuf);
2185: check_result(result, "dns_message_renderbegin");
2186: if (lookup->udpsize > 0 || lookup->dnssec ||
2187: lookup->edns > -1 || lookup->ecs_addr != NULL)
2188: {
2189: #define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS)
2190: dns_ednsopt_t opts[MAXOPTS];
2191: unsigned int flags;
2192: unsigned int i = 0;
2193:
2194: if (lookup->udpsize == 0)
2195: lookup->udpsize = 4096;
2196: if (lookup->edns < 0)
2197: lookup->edns = 0;
2198:
2199: if (lookup->nsid) {
2200: INSIST(i < MAXOPTS);
2201: opts[i].code = DNS_OPT_NSID;
2202: opts[i].length = 0;
2203: opts[i].value = NULL;
2204: i++;
2205: }
2206:
2207: if (lookup->ecs_addr != NULL) {
2208: uint8_t addr[16];
2209: uint16_t family;
2210: uint32_t plen;
2211: struct sockaddr *sa;
2212: struct sockaddr_in *sin;
2213: struct sockaddr_in6 *sin6;
2214: size_t addrl;
2215:
2216: sa = &lookup->ecs_addr->type.sa;
2217: plen = lookup->ecs_addr->length;
2218:
2219: /* Round up prefix len to a multiple of 8 */
2220: addrl = (plen + 7) / 8;
2221:
2222: INSIST(i < MAXOPTS);
2223: opts[i].code = DNS_OPT_CLIENT_SUBNET;
2224: opts[i].length = (uint16_t) addrl + 4;
2225: check_result(result, "isc_buffer_allocate");
2226:
2227: /*
2228: * XXXMUKS: According to RFC7871, "If there is
2229: * no ADDRESS set, i.e., SOURCE PREFIX-LENGTH is
2230: * set to 0, then FAMILY SHOULD be set to the
2231: * transport over which the query is sent."
2232: *
2233: * However, at this point we don't know what
2234: * transport(s) we'll be using, so we can't
2235: * set the value now. For now, we're using
2236: * IPv4 as the default the +subnet option
2237: * used an IPv4 prefix, or for +subnet=0,
2238: * and IPv6 if the +subnet option used an
2239: * IPv6 prefix.
2240: *
2241: * (For future work: preserve the offset into
2242: * the buffer where the family field is;
2243: * that way we can update it in send_udp()
2244: * or send_tcp_connect() once we know
2245: * what it outght to be.)
2246: */
2247: switch (sa->sa_family) {
2248: case AF_UNSPEC:
2249: INSIST(plen == 0);
2250: family = 1;
2251: break;
2252: case AF_INET:
2253: INSIST(plen <= 32);
2254: family = 1;
2255: sin = (struct sockaddr_in *) sa;
2256: memmove(addr, &sin->sin_addr, addrl);
2257: break;
2258: case AF_INET6:
2259: INSIST(plen <= 128);
2260: family = 2;
2261: sin6 = (struct sockaddr_in6 *) sa;
2262: memmove(addr, &sin6->sin6_addr, addrl);
2263: break;
2264: default:
2265: INSIST(0);
2266: }
2267:
2268: isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
2269: /* family */
2270: isc_buffer_putuint16(&b, family);
2271: /* source prefix-length */
2272: isc_buffer_putuint8(&b, plen);
2273: /* scope prefix-length */
2274: isc_buffer_putuint8(&b, 0);
2275:
2276: /* address */
2277: if (addrl > 0) {
2278: /* Mask off last address byte */
2279: if ((plen % 8) != 0)
2280: addr[addrl - 1] &=
2281: ~0U << (8 - (plen % 8));
2282: isc_buffer_putmem(&b, addr,
2283: (unsigned)addrl);
2284: }
2285:
2286: opts[i].value = (uint8_t *) ecsbuf;
2287: i++;
2288: }
2289:
2290: if (lookup->sit) {
2291: INSIST(i < MAXOPTS);
2292: opts[i].code = DNS_OPT_COOKIE;
2293: if (lookup->sitvalue != NULL) {
2294: isc_buffer_init(&b, sitbuf, sizeof(sitbuf));
2295: result = isc_hex_decodestring(lookup->sitvalue,
2296: &b);
2297: check_result(result, "isc_hex_decodestring");
2298: opts[i].value = isc_buffer_base(&b);
2299: opts[i].length = isc_buffer_usedlength(&b);
2300: } else {
2301: compute_cookie(cookie, sizeof(cookie));
2302: opts[i].length = 8;
2303: opts[i].value = cookie;
2304: }
2305: i++;
2306: }
2307:
2308: if (lookup->expire) {
2309: INSIST(i < MAXOPTS);
2310: opts[i].code = DNS_OPT_EXPIRE;
2311: opts[i].length = 0;
2312: opts[i].value = NULL;
2313: i++;
2314: }
2315:
2316: if (lookup->ednsoptscnt != 0) {
2317: INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
2318: memmove(&opts[i], lookup->ednsopts,
2319: sizeof(dns_ednsopt_t) * lookup->ednsoptscnt);
2320: i += lookup->ednsoptscnt;
2321: }
2322:
2323: flags = lookup->ednsflags;
2324: flags &= ~DNS_MESSAGEEXTFLAG_DO;
2325: if (lookup->dnssec)
2326: flags |= DNS_MESSAGEEXTFLAG_DO;
2327: add_opt(lookup->sendmsg, lookup->udpsize,
2328: lookup->edns, flags, opts, i);
2329: }
2330:
2331: result = dns_message_rendersection(lookup->sendmsg,
1.15 florian 2332: DNS_SECTION_QUESTION);
1.1 florian 2333: check_result(result, "dns_message_rendersection");
2334: result = dns_message_rendersection(lookup->sendmsg,
1.15 florian 2335: DNS_SECTION_AUTHORITY);
1.1 florian 2336: check_result(result, "dns_message_rendersection");
2337: result = dns_message_renderend(lookup->sendmsg);
2338: check_result(result, "dns_message_renderend");
2339: debug("done rendering");
2340:
2341: dns_compress_invalidate(&cctx);
2342:
2343: /*
2344: * Force TCP mode if the request is larger than 512 bytes.
2345: */
2346: if (isc_buffer_usedlength(&lookup->renderbuf) > 512)
2347: lookup->tcp_mode = ISC_TRUE;
2348:
2349: lookup->pending = ISC_FALSE;
2350:
2351: for (serv = ISC_LIST_HEAD(lookup->my_server_list);
2352: serv != NULL;
2353: serv = ISC_LIST_NEXT(serv, link)) {
2354: query = malloc(sizeof(dig_query_t));
2355: if (query == NULL)
2356: fatal("memory allocation failure in %s:%d",
2357: __FILE__, __LINE__);
2358: debug("create query %p linked to lookup %p",
2359: query, lookup);
2360: query->lookup = lookup;
2361: query->timer = NULL;
2362: query->waiting_connect = ISC_FALSE;
2363: query->waiting_senddone = ISC_FALSE;
2364: query->pending_free = ISC_FALSE;
2365: query->recv_made = ISC_FALSE;
2366: query->first_pass = ISC_TRUE;
2367: query->first_soa_rcvd = ISC_FALSE;
2368: query->second_rr_rcvd = ISC_FALSE;
2369: query->first_repeat_rcvd = ISC_FALSE;
2370: query->warn_id = ISC_TRUE;
2371: query->timedout = ISC_FALSE;
2372: query->first_rr_serial = 0;
2373: query->second_rr_serial = 0;
2374: query->servname = serv->servername;
2375: query->userarg = serv->userarg;
2376: query->rr_count = 0;
2377: query->msg_count = 0;
2378: query->byte_count = 0;
2379: query->ixfr_axfr = ISC_FALSE;
2380: ISC_LIST_INIT(query->recvlist);
2381: ISC_LIST_INIT(query->lengthlist);
2382: query->sock = NULL;
2383: query->recvspace = malloc(COMMSIZE);
2384: if (query->recvspace == NULL)
2385: fatal("memory allocation failure");
2386:
2387: isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
2388: isc_buffer_init(&query->lengthbuf, query->lengthspace, 2);
2389: isc_buffer_init(&query->slbuf, query->slspace, 2);
2390: query->sendbuf = lookup->renderbuf;
2391:
2392: ISC_LINK_INIT(query, clink);
2393: ISC_LINK_INIT(query, link);
2394: ISC_LIST_ENQUEUE(lookup->q, query, link);
2395: }
2396:
2397: /* XXX qrflag, print_query, etc... */
2398: if (!ISC_LIST_EMPTY(lookup->q) && qr) {
2399: extrabytes = 0;
2400: dighost_printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg,
2401: ISC_TRUE);
2402: }
2403: return (ISC_TRUE);
2404: }
2405:
2406: /*%
2407: * Event handler for send completion. Track send counter, and clear out
2408: * the query if the send was canceled.
2409: */
2410: static void
2411: send_done(isc_task_t *_task, isc_event_t *event) {
2412: isc_socketevent_t *sevent = (isc_socketevent_t *)event;
2413: isc_buffer_t *b = NULL;
2414: dig_query_t *query, *next;
2415: dig_lookup_t *l;
2416:
2417: REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
2418:
2419: UNUSED(_task);
2420:
2421: debug("send_done()");
2422: sendcount--;
2423: debug("sendcount=%d", sendcount);
2424: INSIST(sendcount >= 0);
2425:
2426: for (b = ISC_LIST_HEAD(sevent->bufferlist);
2427: b != NULL;
2428: b = ISC_LIST_HEAD(sevent->bufferlist)) {
2429: ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2430: free(b);
2431: }
2432:
2433: query = event->ev_arg;
2434: query->waiting_senddone = ISC_FALSE;
2435: l = query->lookup;
2436:
2437: if (l->ns_search_only && !l->trace_root && !l->tcp_mode) {
2438: debug("sending next, since searching");
2439: next = ISC_LIST_NEXT(query, link);
2440: if (next != NULL)
2441: send_udp(next);
2442: }
2443:
2444: isc_event_free(&event);
2445:
2446: if (query->pending_free)
2447: free(query);
2448:
2449: check_if_done();
2450: }
2451:
2452: /*%
2453: * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding
2454: * IO sockets. The cancel handlers should take care of cleaning up the
2455: * query and lookup structures
2456: */
2457: static void
2458: cancel_lookup(dig_lookup_t *lookup) {
2459: dig_query_t *query, *next;
2460:
2461: debug("cancel_lookup()");
2462: query = ISC_LIST_HEAD(lookup->q);
2463: while (query != NULL) {
2464: next = ISC_LIST_NEXT(query, link);
2465: if (query->sock != NULL) {
2466: isc_socket_cancel(query->sock, global_task,
2467: ISC_SOCKCANCEL_ALL);
2468: check_if_done();
2469: } else {
2470: clear_query(query);
2471: }
2472: query = next;
2473: }
2474: lookup->pending = ISC_FALSE;
2475: lookup->retries = 0;
2476: }
2477:
2478: static void
2479: bringup_timer(dig_query_t *query, unsigned int default_timeout) {
2480: dig_lookup_t *l;
2481: unsigned int local_timeout;
2482: isc_result_t result;
2483:
2484: debug("bringup_timer()");
2485: /*
2486: * If the timer already exists, that means we're calling this
2487: * a second time (for a retry). Don't need to recreate it,
2488: * just reset it.
2489: */
2490: l = query->lookup;
2491: if (ISC_LINK_LINKED(query, link) && ISC_LIST_NEXT(query, link) != NULL)
2492: local_timeout = SERVER_TIMEOUT;
2493: else {
2494: if (timeout == 0)
2495: local_timeout = default_timeout;
2496: else
2497: local_timeout = timeout;
2498: }
2499: debug("have local timeout of %d", local_timeout);
1.9 florian 2500: l->interval.tv_sec = local_timeout;
2501: l->interval.tv_nsec = 0;
1.1 florian 2502: if (query->timer != NULL)
2503: isc_timer_detach(&query->timer);
1.7 florian 2504: result = isc_timer_create(timermgr,
1.1 florian 2505: &l->interval, global_task, connect_timeout,
2506: query, &query->timer);
2507: check_result(result, "isc_timer_create");
2508: }
2509:
2510: static void
2511: force_timeout(dig_query_t *query) {
2512: isc_event_t *event;
2513:
2514: debug("force_timeout ()");
2515: event = isc_event_allocate(query, ISC_TIMEREVENT_IDLE,
2516: connect_timeout, query,
2517: sizeof(isc_event_t));
2518: if (event == NULL) {
2519: fatal("isc_event_allocate: %s",
2520: isc_result_totext(ISC_R_NOMEMORY));
2521: }
2522: isc_task_send(global_task, &event);
2523:
2524: /*
2525: * The timer may have expired if, for example, get_address() takes
2526: * long time and the timer was running on a different thread.
2527: * We need to cancel the possible timeout event not to confuse
2528: * ourselves due to the duplicate events.
2529: */
2530: if (query->timer != NULL)
2531: isc_timer_detach(&query->timer);
2532: }
2533:
2534:
2535: static void
2536: connect_done(isc_task_t *task, isc_event_t *event);
2537:
2538: /*%
2539: * Unlike send_udp, this can't be called multiple times with the same
2540: * query. When we retry TCP, we requeue the whole lookup, which should
2541: * start anew.
2542: */
2543: static void
2544: send_tcp_connect(dig_query_t *query) {
2545: isc_result_t result;
2546: dig_query_t *next;
2547: dig_lookup_t *l;
2548:
2549: debug("send_tcp_connect(%p)", query);
2550:
2551: l = query->lookup;
2552: query->waiting_connect = ISC_TRUE;
2553: query->lookup->current_query = query;
2554: result = get_address(query->servname, port, &query->sockaddr);
2555: if (result != ISC_R_SUCCESS) {
2556: /*
2557: * This servname doesn't have an address. Try the next server
2558: * by triggering an immediate 'timeout' (we lie, but the effect
2559: * is the same).
2560: */
2561: force_timeout(query);
2562: return;
2563: }
2564:
2565: if (specified_source &&
2566: (isc_sockaddr_pf(&query->sockaddr) !=
2567: isc_sockaddr_pf(&bind_address))) {
2568: printf(";; Skipping server %s, incompatible "
2569: "address family\n", query->servname);
2570: query->waiting_connect = ISC_FALSE;
2571: if (ISC_LINK_LINKED(query, link))
2572: next = ISC_LIST_NEXT(query, link);
2573: else
2574: next = NULL;
2575: l = query->lookup;
2576: clear_query(query);
2577: if (next == NULL) {
2578: printf(";; No acceptable nameservers\n");
2579: check_next_lookup(l);
2580: return;
2581: }
2582: send_tcp_connect(next);
2583: return;
2584: }
2585:
2586: INSIST(query->sock == NULL);
2587:
2588: if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) {
2589: sockcount++;
2590: isc_socket_attach(keep, &query->sock);
2591: query->waiting_connect = ISC_FALSE;
2592: launch_next_query(query, ISC_TRUE);
2593: goto search;
2594: }
2595:
2596: result = isc_socket_create(socketmgr,
2597: isc_sockaddr_pf(&query->sockaddr),
2598: isc_sockettype_tcp, &query->sock);
2599: check_result(result, "isc_socket_create");
2600: sockcount++;
2601: debug("sockcount=%d", sockcount);
2602: if (specified_source)
2603: result = isc_socket_bind(query->sock, &bind_address,
2604: ISC_SOCKET_REUSEADDRESS);
2605: else {
2606: if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
2607: have_ipv4)
2608: isc_sockaddr_any(&bind_any);
2609: else
2610: isc_sockaddr_any6(&bind_any);
2611: result = isc_socket_bind(query->sock, &bind_any, 0);
2612: }
2613: check_result(result, "isc_socket_bind");
2614: bringup_timer(query, TCP_TIMEOUT);
2615: result = isc_socket_connect(query->sock, &query->sockaddr,
2616: global_task, connect_done, query);
2617: check_result(result, "isc_socket_connect");
2618: search:
2619: /*
2620: * If we're at the endgame of a nameserver search, we need to
2621: * immediately bring up all the queries. Do it here.
2622: */
2623: if (l->ns_search_only && !l->trace_root) {
2624: debug("sending next, since searching");
2625: if (ISC_LINK_LINKED(query, link)) {
2626: next = ISC_LIST_NEXT(query, link);
2627: ISC_LIST_DEQUEUE(l->q, query, link);
2628: } else
2629: next = NULL;
2630: ISC_LIST_ENQUEUE(l->connecting, query, clink);
2631: if (next != NULL)
2632: send_tcp_connect(next);
2633: }
2634: }
2635:
2636: static isc_buffer_t *
2637: clone_buffer(isc_buffer_t *source) {
2638: isc_buffer_t *buffer;
2639: buffer = malloc(sizeof(*buffer));
2640: if (buffer == NULL)
2641: fatal("memory allocation failure in %s:%d",
2642: __FILE__, __LINE__);
2643: *buffer = *source;
2644: return (buffer);
2645: }
2646:
2647: /*%
2648: * Send a UDP packet to the remote nameserver, possible starting the
2649: * recv action as well. Also make sure that the timer is running and
2650: * is properly reset.
2651: */
2652: static void
2653: send_udp(dig_query_t *query) {
2654: dig_lookup_t *l = NULL;
2655: isc_result_t result;
2656: isc_buffer_t *sendbuf;
2657:
2658: debug("send_udp(%p)", query);
2659:
2660: l = query->lookup;
2661: bringup_timer(query, UDP_TIMEOUT);
2662: l->current_query = query;
2663: debug("working on lookup %p, query %p", query->lookup, query);
2664: if (!query->recv_made) {
2665: /* XXX Check the sense of this, need assertion? */
2666: query->waiting_connect = ISC_FALSE;
2667: result = get_address(query->servname, port, &query->sockaddr);
2668: if (result != ISC_R_SUCCESS) {
2669: /* This servname doesn't have an address. */
2670: force_timeout(query);
2671: return;
2672: }
2673:
2674: result = isc_socket_create(socketmgr,
2675: isc_sockaddr_pf(&query->sockaddr),
2676: isc_sockettype_udp, &query->sock);
2677: check_result(result, "isc_socket_create");
2678: sockcount++;
2679: debug("sockcount=%d", sockcount);
2680: if (specified_source) {
2681: result = isc_socket_bind(query->sock, &bind_address,
2682: ISC_SOCKET_REUSEADDRESS);
2683: } else {
2684: isc_sockaddr_anyofpf(&bind_any,
2685: isc_sockaddr_pf(&query->sockaddr));
2686: result = isc_socket_bind(query->sock, &bind_any, 0);
2687: }
2688: check_result(result, "isc_socket_bind");
2689:
2690: query->recv_made = ISC_TRUE;
2691: ISC_LINK_INIT(&query->recvbuf, link);
2692: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,
2693: link);
2694: debug("recving with lookup=%p, query=%p, sock=%p",
2695: query->lookup, query, query->sock);
2696: result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2697: global_task, recv_done, query);
2698: check_result(result, "isc_socket_recvv");
2699: recvcount++;
2700: debug("recvcount=%d", recvcount);
2701: }
2702: ISC_LIST_INIT(query->sendlist);
2703: sendbuf = clone_buffer(&query->sendbuf);
2704: ISC_LIST_ENQUEUE(query->sendlist, sendbuf, link);
2705: debug("sending a request");
1.13 florian 2706: clock_gettime(CLOCK_MONOTONIC, &query->time_sent);
1.1 florian 2707: INSIST(query->sock != NULL);
2708: query->waiting_senddone = ISC_TRUE;
2709: result = isc_socket_sendtov2(query->sock, &query->sendlist,
2710: global_task, send_done, query,
2711: &query->sockaddr, NULL,
2712: ISC_SOCKFLAG_NORETRY);
2713: check_result(result, "isc_socket_sendtov");
2714: sendcount++;
2715: }
2716:
2717: /*%
2718: * IO timeout handler, used for both connect and recv timeouts. If
2719: * retries are still allowed, either resend the UDP packet or queue a
2720: * new TCP lookup. Otherwise, cancel the lookup.
2721: */
2722: static void
2723: connect_timeout(isc_task_t *task, isc_event_t *event) {
2724: dig_lookup_t *l = NULL;
2725: dig_query_t *query = NULL, *cq;
2726:
2727: UNUSED(task);
2728: REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);
2729:
2730: debug("connect_timeout()");
2731:
2732: query = event->ev_arg;
2733: l = query->lookup;
2734: isc_event_free(&event);
2735:
2736: INSIST(!free_now);
2737:
2738: if ((query != NULL) && (query->lookup->current_query != NULL) &&
2739: ISC_LINK_LINKED(query->lookup->current_query, link) &&
2740: (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {
2741: debug("trying next server...");
2742: cq = query->lookup->current_query;
2743: if (!l->tcp_mode)
2744: send_udp(ISC_LIST_NEXT(cq, link));
2745: else {
2746: if (query->sock != NULL)
2747: isc_socket_cancel(query->sock, NULL,
2748: ISC_SOCKCANCEL_ALL);
2749: send_tcp_connect(ISC_LIST_NEXT(cq, link));
2750: }
2751: return;
2752: }
2753:
2754: if (l->tcp_mode && query->sock != NULL) {
2755: query->timedout = ISC_TRUE;
2756: isc_socket_cancel(query->sock, NULL, ISC_SOCKCANCEL_ALL);
2757: }
2758:
2759: if (l->retries > 1) {
2760: if (!l->tcp_mode) {
2761: l->retries--;
2762: debug("resending UDP request to first server");
2763: send_udp(ISC_LIST_HEAD(l->q));
2764: } else {
2765: debug("making new TCP request, %d tries left",
2766: l->retries);
2767: l->retries--;
2768: requeue_lookup(l, ISC_TRUE);
2769: cancel_lookup(l);
2770: check_next_lookup(l);
2771: }
2772: } else {
2773: if (!l->ns_search_only) {
2774: fputs(l->cmdline, stdout);
2775: printf(";; connection timed out; no servers could be "
2776: "reached\n");
2777: }
2778: cancel_lookup(l);
2779: check_next_lookup(l);
2780: if (exitcode < 9)
2781: exitcode = 9;
2782: }
2783: }
2784:
2785: /*%
2786: * Event handler for the TCP recv which gets the length header of TCP
2787: * packets. Start the next recv of length bytes.
2788: */
2789: static void
2790: tcp_length_done(isc_task_t *task, isc_event_t *event) {
2791: isc_socketevent_t *sevent;
2792: isc_buffer_t *b = NULL;
2793: isc_result_t result;
2794: dig_query_t *query = NULL;
2795: dig_lookup_t *l, *n;
2796: uint16_t length;
2797:
2798: REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2799: INSIST(!free_now);
2800:
2801: UNUSED(task);
2802:
2803: debug("tcp_length_done()");
2804:
2805: sevent = (isc_socketevent_t *)event;
2806: query = event->ev_arg;
2807:
2808: recvcount--;
2809: INSIST(recvcount >= 0);
2810:
2811: b = ISC_LIST_HEAD(sevent->bufferlist);
2812: INSIST(b == &query->lengthbuf);
2813: ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2814:
2815: if (sevent->result == ISC_R_CANCELED) {
2816: isc_event_free(&event);
2817: l = query->lookup;
2818: clear_query(query);
2819: check_next_lookup(l);
2820: return;
2821: }
2822: if (sevent->result != ISC_R_SUCCESS) {
2823: char sockstr[ISC_SOCKADDR_FORMATSIZE];
2824: isc_sockaddr_format(&query->sockaddr, sockstr,
2825: sizeof(sockstr));
2826: printf(";; communications error to %s: %s\n",
2827: sockstr, isc_result_totext(sevent->result));
2828: if (keep != NULL)
2829: isc_socket_detach(&keep);
2830: l = query->lookup;
2831: isc_socket_detach(&query->sock);
2832: sockcount--;
2833: debug("sockcount=%d", sockcount);
2834: INSIST(sockcount >= 0);
2835: if (sevent->result == ISC_R_EOF && l->eoferr == 0U) {
2836: n = requeue_lookup(l, ISC_TRUE);
2837: n->eoferr++;
2838: }
2839: isc_event_free(&event);
2840: clear_query(query);
2841: cancel_lookup(l);
2842: check_next_lookup(l);
2843: return;
2844: }
2845: length = isc_buffer_getuint16(b);
2846: if (length == 0) {
2847: isc_event_free(&event);
2848: launch_next_query(query, ISC_FALSE);
2849: return;
2850: }
2851:
2852: /*
2853: * Even though the buffer was already init'ed, we need
2854: * to redo it now, to force the length we want.
2855: */
2856: isc_buffer_invalidate(&query->recvbuf);
2857: isc_buffer_init(&query->recvbuf, query->recvspace, length);
2858: ENSURE(ISC_LIST_EMPTY(query->recvlist));
2859: ISC_LINK_INIT(&query->recvbuf, link);
2860: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
2861: debug("recving with lookup=%p, query=%p", query->lookup, query);
2862: result = isc_socket_recvv(query->sock, &query->recvlist, length, task,
2863: recv_done, query);
2864: check_result(result, "isc_socket_recvv");
2865: recvcount++;
2866: debug("resubmitted recv request with length %d, recvcount=%d",
2867: length, recvcount);
2868: isc_event_free(&event);
2869: }
2870:
2871: /*%
2872: * For transfers that involve multiple recvs (XFR's in particular),
2873: * launch the next recv.
2874: */
2875: static void
2876: launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
2877: isc_result_t result;
2878: dig_lookup_t *l;
2879: isc_buffer_t *buffer;
2880:
2881: INSIST(!free_now);
2882:
2883: debug("launch_next_query()");
2884:
2885: if (!query->lookup->pending) {
2886: debug("ignoring launch_next_query because !pending");
2887: isc_socket_detach(&query->sock);
2888: sockcount--;
2889: debug("sockcount=%d", sockcount);
2890: INSIST(sockcount >= 0);
2891: query->waiting_connect = ISC_FALSE;
2892: l = query->lookup;
2893: clear_query(query);
2894: check_next_lookup(l);
2895: return;
2896: }
2897:
2898: isc_buffer_clear(&query->slbuf);
2899: isc_buffer_clear(&query->lengthbuf);
2900: isc_buffer_putuint16(&query->slbuf, (uint16_t) query->sendbuf.used);
2901: ISC_LIST_INIT(query->sendlist);
2902: ISC_LINK_INIT(&query->slbuf, link);
2903: if (!query->first_soa_rcvd) {
2904: buffer = clone_buffer(&query->slbuf);
2905: ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
2906: if (include_question) {
2907: buffer = clone_buffer(&query->sendbuf);
2908: ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
2909: }
2910: }
2911:
2912: ISC_LINK_INIT(&query->lengthbuf, link);
2913: ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
2914:
2915: result = isc_socket_recvv(query->sock, &query->lengthlist, 0,
2916: global_task, tcp_length_done, query);
2917: check_result(result, "isc_socket_recvv");
2918: recvcount++;
2919: debug("recvcount=%d", recvcount);
2920: if (!query->first_soa_rcvd) {
2921: debug("sending a request in launch_next_query");
1.13 florian 2922: clock_gettime(CLOCK_MONOTONIC, &query->time_sent);
1.1 florian 2923: query->waiting_senddone = ISC_TRUE;
2924: result = isc_socket_sendv(query->sock, &query->sendlist,
2925: global_task, send_done, query);
2926: check_result(result, "isc_socket_sendv");
2927: sendcount++;
2928: debug("sendcount=%d", sendcount);
2929: }
2930: query->waiting_connect = ISC_FALSE;
2931: return;
2932: }
2933:
2934: /*%
2935: * Event handler for TCP connect complete. Make sure the connection was
2936: * successful, then pass into launch_next_query to actually send the
2937: * question.
2938: */
2939: static void
2940: connect_done(isc_task_t *task, isc_event_t *event) {
2941: char sockstr[ISC_SOCKADDR_FORMATSIZE];
2942: isc_socketevent_t *sevent = NULL;
2943: dig_query_t *query = NULL, *next;
2944: dig_lookup_t *l;
2945:
2946: UNUSED(task);
2947:
2948: REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
2949: INSIST(!free_now);
2950:
2951: debug("connect_done()");
2952:
2953: sevent = (isc_socketevent_t *)event;
2954: query = sevent->ev_arg;
2955:
2956: INSIST(query->waiting_connect);
2957:
2958: query->waiting_connect = ISC_FALSE;
2959:
2960: if (sevent->result == ISC_R_CANCELED) {
2961: debug("in cancel handler");
2962: isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
2963: if (query->timedout)
2964: printf(";; Connection to %s(%s) for %s failed: %s.\n",
2965: sockstr, query->servname,
2966: query->lookup->textname,
2967: isc_result_totext(ISC_R_TIMEDOUT));
2968: isc_socket_detach(&query->sock);
2969: INSIST(sockcount > 0);
2970: sockcount--;
2971: debug("sockcount=%d", sockcount);
2972: query->waiting_connect = ISC_FALSE;
2973: isc_event_free(&event);
2974: l = query->lookup;
2975: clear_query(query);
2976: check_next_lookup(l);
2977: return;
2978: }
2979: if (sevent->result != ISC_R_SUCCESS) {
2980:
2981: debug("unsuccessful connection: %s",
2982: isc_result_totext(sevent->result));
2983: isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
2984: if (sevent->result != ISC_R_CANCELED)
2985: printf(";; Connection to %s(%s) for %s failed: "
2986: "%s.\n", sockstr,
2987: query->servname, query->lookup->textname,
2988: isc_result_totext(sevent->result));
2989: isc_socket_detach(&query->sock);
2990: INSIST(sockcount > 0);
2991: sockcount--;
2992: /* XXX Clean up exitcodes */
2993: if (exitcode < 9)
2994: exitcode = 9;
2995: debug("sockcount=%d", sockcount);
2996: query->waiting_connect = ISC_FALSE;
2997: isc_event_free(&event);
2998: l = query->lookup;
2999: if ((l->current_query != NULL) &&
3000: (ISC_LINK_LINKED(l->current_query, link)))
3001: next = ISC_LIST_NEXT(l->current_query, link);
3002: else
3003: next = NULL;
3004: clear_query(query);
3005: if (next != NULL) {
3006: bringup_timer(next, TCP_TIMEOUT);
3007: send_tcp_connect(next);
3008: } else
3009: check_next_lookup(l);
3010: return;
3011: }
3012: if (keep_open) {
3013: if (keep != NULL)
3014: isc_socket_detach(&keep);
3015: isc_socket_attach(query->sock, &keep);
3016: keepaddr = query->sockaddr;
3017: }
3018: launch_next_query(query, ISC_TRUE);
3019: isc_event_free(&event);
3020: }
3021:
3022: /*%
3023: * Check if the ongoing XFR needs more data before it's complete, using
3024: * the semantics of IXFR and AXFR protocols. Much of the complexity of
3025: * this routine comes from determining when an IXFR is complete.
3026: * ISC_FALSE means more data is on the way, and the recv has been issued.
3027: */
3028: static isc_boolean_t
3029: check_for_more_data(dig_query_t *query, dns_message_t *msg,
3030: isc_socketevent_t *sevent)
3031: {
3032: dns_rdataset_t *rdataset = NULL;
3033: dns_rdata_t rdata = DNS_RDATA_INIT;
3034: dns_rdata_soa_t soa;
3035: uint32_t ixfr_serial = query->lookup->ixfr_serial, serial;
3036: isc_result_t result;
3037: isc_boolean_t ixfr = query->lookup->rdtype == dns_rdatatype_ixfr;
3038: isc_boolean_t axfr = query->lookup->rdtype == dns_rdatatype_axfr;
3039:
3040: if (ixfr)
3041: axfr = query->ixfr_axfr;
3042:
3043: debug("check_for_more_data()");
3044:
3045: /*
3046: * By the time we're in this routine, we know we're doing
3047: * either an AXFR or IXFR. If there's no second_rr_type,
3048: * then we don't yet know which kind of answer we got back
3049: * from the server. Here, we're going to walk through the
3050: * rr's in the message, acting as necessary whenever we hit
3051: * an SOA rr.
3052: */
3053:
3054: query->msg_count++;
3055: query->byte_count += sevent->n;
3056: result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
3057: if (result != ISC_R_SUCCESS) {
3058: puts("; Transfer failed.");
3059: return (ISC_TRUE);
3060: }
3061: do {
3062: dns_name_t *name;
3063: name = NULL;
3064: dns_message_currentname(msg, DNS_SECTION_ANSWER,
3065: &name);
3066: for (rdataset = ISC_LIST_HEAD(name->list);
3067: rdataset != NULL;
3068: rdataset = ISC_LIST_NEXT(rdataset, link)) {
3069: result = dns_rdataset_first(rdataset);
3070: if (result != ISC_R_SUCCESS)
3071: continue;
3072: do {
3073: query->rr_count++;
3074: dns_rdata_reset(&rdata);
3075: dns_rdataset_current(rdataset, &rdata);
3076: /*
3077: * If this is the first rr, make sure
3078: * it's an SOA
3079: */
3080: if ((!query->first_soa_rcvd) &&
3081: (rdata.type != dns_rdatatype_soa)) {
3082: puts("; Transfer failed. "
3083: "Didn't start with SOA answer.");
3084: return (ISC_TRUE);
3085: }
3086: if ((!query->second_rr_rcvd) &&
3087: (rdata.type != dns_rdatatype_soa)) {
3088: query->second_rr_rcvd = ISC_TRUE;
3089: query->second_rr_serial = 0;
3090: debug("got the second rr as nonsoa");
3091: axfr = query->ixfr_axfr = ISC_TRUE;
3092: goto next_rdata;
3093: }
3094:
3095: /*
3096: * If the record is anything except an SOA
3097: * now, just continue on...
3098: */
3099: if (rdata.type != dns_rdatatype_soa)
3100: goto next_rdata;
3101:
3102: /* Now we have an SOA. Work with it. */
3103: debug("got an SOA");
3104: result = dns_rdata_tostruct(&rdata, &soa);
3105: check_result(result, "dns_rdata_tostruct");
3106: serial = soa.serial;
3107: dns_rdata_freestruct(&soa);
3108: if (!query->first_soa_rcvd) {
3109: query->first_soa_rcvd = ISC_TRUE;
3110: query->first_rr_serial = serial;
3111: debug("this is the first serial %u",
3112: serial);
3113: if (ixfr && isc_serial_ge(ixfr_serial,
3114: serial)) {
3115: debug("got up to date "
3116: "response");
3117: goto doexit;
3118: }
3119: goto next_rdata;
3120: }
3121: if (axfr) {
3122: debug("doing axfr, got second SOA");
3123: goto doexit;
3124: }
3125: if (!query->second_rr_rcvd) {
3126: if (query->first_rr_serial == serial) {
3127: debug("doing ixfr, got "
3128: "empty zone");
3129: goto doexit;
3130: }
3131: debug("this is the second serial %u",
3132: serial);
3133: query->second_rr_rcvd = ISC_TRUE;
3134: query->second_rr_serial = serial;
3135: goto next_rdata;
3136: }
3137: /*
3138: * If we get to this point, we're doing an
3139: * IXFR and have to start really looking
3140: * at serial numbers.
3141: */
3142: if (query->first_rr_serial == serial) {
3143: debug("got a match for ixfr");
3144: if (!query->first_repeat_rcvd) {
3145: query->first_repeat_rcvd =
3146: ISC_TRUE;
3147: goto next_rdata;
3148: }
3149: debug("done with ixfr");
3150: goto doexit;
3151: }
3152: debug("meaningless soa %u", serial);
3153: next_rdata:
3154: result = dns_rdataset_next(rdataset);
3155: } while (result == ISC_R_SUCCESS);
3156: }
3157: result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
3158: } while (result == ISC_R_SUCCESS);
3159: launch_next_query(query, ISC_FALSE);
3160: return (ISC_FALSE);
3161: doexit:
3162: dighost_received(sevent->n, &sevent->address, query);
3163: return (ISC_TRUE);
3164: }
3165:
3166: static void
3167: process_sit(dig_lookup_t *l, dns_message_t *msg,
3168: isc_buffer_t *optbuf, size_t optlen)
3169: {
3170: char bb[256];
3171: isc_buffer_t hexbuf;
3172: size_t len;
3173: const unsigned char *sit;
3174: isc_boolean_t copysit;
3175: isc_result_t result;
3176:
3177: if (l->sitvalue != NULL) {
3178: isc_buffer_init(&hexbuf, bb, sizeof(bb));
3179: result = isc_hex_decodestring(l->sitvalue, &hexbuf);
3180: check_result(result, "isc_hex_decodestring");
3181: sit = isc_buffer_base(&hexbuf);
3182: len = isc_buffer_usedlength(&hexbuf);
3183: copysit = ISC_FALSE;
3184: } else {
3185: sit = cookie;
3186: len = sizeof(cookie);
3187: copysit = ISC_TRUE;
3188: }
3189:
3190: INSIST(msg->sitok == 0 && msg->sitbad == 0);
3191: if (optlen >= len && optlen >= 8U) {
3192: if (isc_safe_memequal(isc_buffer_current(optbuf), sit, 8)) {
3193: msg->sitok = 1;
3194: } else {
3195: printf(";; Warning: SIT client cookie mismatch\n");
3196: msg->sitbad = 1;
3197: copysit = ISC_FALSE;
3198: }
3199: } else {
3200: printf(";; Warning: SIT bad token (too short)\n");
3201: msg->sitbad = 1;
3202: copysit = ISC_FALSE;
3203: }
3204: if (copysit) {
3205: isc_region_t r;
3206:
3207: r.base = isc_buffer_current(optbuf);
3208: r.length = (unsigned int)optlen;
3209: isc_buffer_init(&hexbuf, sitvalue, sizeof(sitvalue));
3210: result = isc_hex_totext(&r, 2, "", &hexbuf);
3211: check_result(result, "isc_hex_totext");
3212: if (isc_buffer_availablelength(&hexbuf) > 0) {
3213: isc_buffer_putuint8(&hexbuf, 0);
3214: l->sitvalue = sitvalue;
3215: }
3216: }
3217: isc_buffer_forward(optbuf, (unsigned int)optlen);
3218: }
3219:
3220: static void
3221: process_opt(dig_lookup_t *l, dns_message_t *msg) {
3222: dns_rdata_t rdata;
3223: isc_result_t result;
3224: isc_buffer_t optbuf;
3225: uint16_t optcode, optlen;
3226: dns_rdataset_t *opt = msg->opt;
3227: isc_boolean_t seen_cookie = ISC_FALSE;
3228:
3229: result = dns_rdataset_first(opt);
3230: if (result == ISC_R_SUCCESS) {
3231: dns_rdata_init(&rdata);
3232: dns_rdataset_current(opt, &rdata);
3233: isc_buffer_init(&optbuf, rdata.data, rdata.length);
3234: isc_buffer_add(&optbuf, rdata.length);
3235: while (isc_buffer_remaininglength(&optbuf) >= 4) {
3236: optcode = isc_buffer_getuint16(&optbuf);
3237: optlen = isc_buffer_getuint16(&optbuf);
3238: switch (optcode) {
3239: case DNS_OPT_COOKIE:
3240: /*
3241: * Only process the first cookie option.
3242: */
3243: if (seen_cookie) {
3244: isc_buffer_forward(&optbuf, optlen);
3245: break;
3246: }
3247: process_sit(l, msg, &optbuf, optlen);
3248: seen_cookie = ISC_TRUE;
3249: break;
3250: default:
3251: isc_buffer_forward(&optbuf, optlen);
3252: break;
3253: }
3254: }
3255: }
3256: }
3257:
3258: static int
3259: ednsvers(dns_rdataset_t *opt) {
3260: return ((opt->ttl >> 16) & 0xff);
3261: }
3262:
3263: /*%
3264: * Event handler for recv complete. Perform whatever actions are necessary,
3265: * based on the specifics of the user's request.
3266: */
3267: static void
3268: recv_done(isc_task_t *task, isc_event_t *event) {
3269: isc_socketevent_t *sevent = NULL;
3270: dig_query_t *query = NULL;
3271: isc_buffer_t *b = NULL;
3272: dns_message_t *msg = NULL;
3273: isc_result_t result;
3274: dig_lookup_t *n, *l;
3275: isc_boolean_t docancel = ISC_FALSE;
3276: isc_boolean_t match = ISC_TRUE;
3277: unsigned int parseflags;
3278: dns_messageid_t id;
3279: unsigned int msgflags;
3280: int newedns;
3281:
3282: UNUSED(task);
3283: INSIST(!free_now);
3284:
3285: debug("recv_done()");
3286:
3287: recvcount--;
3288: debug("recvcount=%d", recvcount);
3289: INSIST(recvcount >= 0);
3290:
3291: query = event->ev_arg;
1.13 florian 3292: clock_gettime(CLOCK_MONOTONIC, &query->time_recv);
1.1 florian 3293: debug("lookup=%p, query=%p", query->lookup, query);
3294:
3295: l = query->lookup;
3296:
3297: REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
3298: sevent = (isc_socketevent_t *)event;
3299:
3300: b = ISC_LIST_HEAD(sevent->bufferlist);
3301: INSIST(b == &query->recvbuf);
3302: ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link);
3303:
3304: if ((l->tcp_mode) && (query->timer != NULL))
3305: isc_timer_touch(query->timer);
3306: if ((!l->pending && !l->ns_search_only) || cancel_now) {
3307: debug("no longer pending. Got %s",
3308: isc_result_totext(sevent->result));
3309: query->waiting_connect = ISC_FALSE;
3310:
3311: isc_event_free(&event);
3312: clear_query(query);
3313: check_next_lookup(l);
3314: return;
3315: }
3316:
3317: if (sevent->result != ISC_R_SUCCESS) {
3318: if (sevent->result == ISC_R_CANCELED) {
3319: debug("in recv cancel handler");
3320: query->waiting_connect = ISC_FALSE;
3321: } else {
3322: printf(";; communications error: %s\n",
3323: isc_result_totext(sevent->result));
3324: if (keep != NULL)
3325: isc_socket_detach(&keep);
3326: isc_socket_detach(&query->sock);
3327: sockcount--;
3328: debug("sockcount=%d", sockcount);
3329: INSIST(sockcount >= 0);
3330: }
3331: if (sevent->result == ISC_R_EOF && l->eoferr == 0U) {
3332: n = requeue_lookup(l, ISC_TRUE);
3333: n->eoferr++;
3334: }
3335: isc_event_free(&event);
3336: clear_query(query);
3337: cancel_lookup(l);
3338: check_next_lookup(l);
3339: return;
3340: }
3341:
3342: if (!l->tcp_mode &&
3343: !isc_sockaddr_compare(&sevent->address, &query->sockaddr,
3344: ISC_SOCKADDR_CMPADDR|
3345: ISC_SOCKADDR_CMPPORT|
3346: ISC_SOCKADDR_CMPSCOPE|
3347: ISC_SOCKADDR_CMPSCOPEZERO)) {
3348: char buf1[ISC_SOCKADDR_FORMATSIZE];
3349: char buf2[ISC_SOCKADDR_FORMATSIZE];
3350: isc_sockaddr_t any;
3351:
3352: if (isc_sockaddr_pf(&query->sockaddr) == AF_INET)
3353: isc_sockaddr_any(&any);
3354: else
3355: isc_sockaddr_any6(&any);
3356:
3357: /*
3358: * We don't expect a match when the packet is
3359: * sent to 0.0.0.0, :: or to a multicast addresses.
3360: * XXXMPA broadcast needs to be handled here as well.
3361: */
3362: if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) &&
3363: !isc_sockaddr_ismulticast(&query->sockaddr)) ||
3364: isc_sockaddr_getport(&query->sockaddr) !=
3365: isc_sockaddr_getport(&sevent->address)) {
3366: isc_sockaddr_format(&sevent->address, buf1,
3367: sizeof(buf1));
3368: isc_sockaddr_format(&query->sockaddr, buf2,
3369: sizeof(buf2));
3370: printf(";; reply from unexpected source: %s,"
3371: " expected %s\n", buf1, buf2);
3372: match = ISC_FALSE;
3373: }
3374: }
3375:
3376: result = dns_message_peekheader(b, &id, &msgflags);
3377: if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
3378: match = ISC_FALSE;
3379: if (l->tcp_mode) {
3380: isc_boolean_t fail = ISC_TRUE;
3381: if (result == ISC_R_SUCCESS) {
3382: if (!query->first_soa_rcvd ||
3383: query->warn_id)
3384: printf(";; %s: ID mismatch: "
3385: "expected ID %u, got %u\n",
3386: query->first_soa_rcvd ?
3387: "WARNING" : "ERROR",
3388: l->sendmsg->id, id);
3389: if (query->first_soa_rcvd)
3390: fail = ISC_FALSE;
3391: query->warn_id = ISC_FALSE;
3392: } else
3393: printf(";; ERROR: short "
3394: "(< header size) message\n");
3395: if (fail) {
3396: isc_event_free(&event);
3397: clear_query(query);
3398: cancel_lookup(l);
3399: check_next_lookup(l);
3400: return;
3401: }
3402: match = ISC_TRUE;
3403: } else if (result == ISC_R_SUCCESS)
3404: printf(";; Warning: ID mismatch: "
3405: "expected ID %u, got %u\n", l->sendmsg->id, id);
3406: else
3407: printf(";; Warning: short "
3408: "(< header size) message received\n");
3409: }
3410:
3411: if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0)
3412: printf(";; Warning: query response not set\n");
3413:
3414: if (!match)
3415: goto udp_mismatch;
3416:
3417: result = dns_message_create(DNS_MESSAGE_INTENTPARSE, &msg);
3418: check_result(result, "dns_message_create");
3419:
3420: if (tsigkey != NULL) {
3421: if (l->querysig == NULL) {
3422: debug("getting initial querysig");
3423: result = dns_message_getquerytsig(l->sendmsg,
3424: &l->querysig);
3425: check_result(result, "dns_message_getquerytsig");
3426: }
3427: result = dns_message_setquerytsig(msg, l->querysig);
3428: check_result(result, "dns_message_setquerytsig");
3429: result = dns_message_settsigkey(msg, tsigkey);
3430: check_result(result, "dns_message_settsigkey");
3431: msg->tsigctx = l->tsigctx;
3432: l->tsigctx = NULL;
3433: if (l->msgcounter != 0)
3434: msg->tcp_continuation = 1;
3435: l->msgcounter++;
3436: }
3437:
3438: debug("before parse starts");
3439: parseflags = DNS_MESSAGEPARSE_PRESERVEORDER;
3440: if (l->besteffort) {
3441: parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
3442: parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
3443: }
3444: result = dns_message_parse(msg, b, parseflags);
3445: if (result == DNS_R_RECOVERABLE) {
3446: printf(";; Warning: Message parser reports malformed "
3447: "message packet.\n");
3448: result = ISC_R_SUCCESS;
3449: }
3450: if (result != ISC_R_SUCCESS) {
3451: printf(";; Got bad packet: %s\n", isc_result_totext(result));
3452: hex_dump(b);
3453: query->waiting_connect = ISC_FALSE;
3454: dns_message_destroy(&msg);
3455: isc_event_free(&event);
3456: clear_query(query);
3457: cancel_lookup(l);
3458: check_next_lookup(l);
3459: return;
3460: }
3461: if (msg->counts[DNS_SECTION_QUESTION] != 0) {
3462: match = ISC_TRUE;
3463: for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
3464: result == ISC_R_SUCCESS && match;
3465: result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) {
3466: dns_name_t *name = NULL;
3467: dns_rdataset_t *rdataset;
3468:
3469: dns_message_currentname(msg, DNS_SECTION_QUESTION,
3470: &name);
3471: for (rdataset = ISC_LIST_HEAD(name->list);
3472: rdataset != NULL;
3473: rdataset = ISC_LIST_NEXT(rdataset, link)) {
3474: if (l->rdtype != rdataset->type ||
3475: l->rdclass != rdataset->rdclass ||
3476: !dns_name_equal(l->name, name)) {
3477: char namestr[DNS_NAME_FORMATSIZE];
3478: char typebuf[DNS_RDATATYPE_FORMATSIZE];
3479: char classbuf[DNS_RDATACLASS_FORMATSIZE];
3480: dns_name_format(name, namestr,
3481: sizeof(namestr));
3482: dns_rdatatype_format(rdataset->type,
3483: typebuf,
3484: sizeof(typebuf));
3485: dns_rdataclass_format(rdataset->rdclass,
3486: classbuf,
3487: sizeof(classbuf));
3488: printf(";; Question section mismatch: "
3489: "got %s/%s/%s\n",
3490: namestr, typebuf, classbuf);
3491: match = ISC_FALSE;
3492: }
3493: }
3494: }
3495: if (!match) {
3496: dns_message_destroy(&msg);
3497: if (l->tcp_mode) {
3498: isc_event_free(&event);
3499: clear_query(query);
3500: cancel_lookup(l);
3501: check_next_lookup(l);
3502: return;
3503: } else
3504: goto udp_mismatch;
3505: }
3506: }
3507: if (msg->rcode == dns_rcode_badvers && msg->opt != NULL &&
3508: (newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg) {
3509: /*
3510: * Add minimum EDNS version required checks here if needed.
3511: */
3512: if (l->comments)
3513: printf(";; BADVERS, retrying with EDNS version %u.\n",
3514: (unsigned int)newedns);
3515: l->edns = newedns;
3516: n = requeue_lookup(l, ISC_TRUE);
3517: if (l->trace && l->trace_root)
3518: n->rdtype = l->qrdtype;
3519: dns_message_destroy(&msg);
3520: isc_event_free(&event);
3521: clear_query(query);
3522: cancel_lookup(l);
3523: check_next_lookup(l);
3524: return;
3525: }
3526: if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 &&
3527: !l->ignore && !l->tcp_mode) {
3528: if (l->sitvalue == NULL && l->sit && msg->opt != NULL)
3529: process_opt(l, msg);
3530: if (l->comments)
3531: printf(";; Truncated, retrying in TCP mode.\n");
3532: n = requeue_lookup(l, ISC_TRUE);
3533: n->tcp_mode = ISC_TRUE;
3534: if (l->trace && l->trace_root)
3535: n->rdtype = l->qrdtype;
3536: dns_message_destroy(&msg);
3537: isc_event_free(&event);
3538: clear_query(query);
3539: cancel_lookup(l);
3540: check_next_lookup(l);
3541: return;
3542: }
3543: if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
3544: (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
3545: {
3546: dig_query_t *next = ISC_LIST_NEXT(query, link);
3547: if (l->current_query == query)
3548: l->current_query = NULL;
3549: if (next != NULL) {
3550: debug("sending query %p\n", next);
3551: if (l->tcp_mode)
3552: send_tcp_connect(next);
3553: else
3554: send_udp(next);
3555: }
3556: /*
3557: * If our query is at the head of the list and there
3558: * is no next, we're the only one left, so fall
3559: * through to print the message.
3560: */
3561: if ((ISC_LIST_HEAD(l->q) != query) ||
3562: (ISC_LIST_NEXT(query, link) != NULL)) {
3563: if (l->comments)
3564: printf(";; Got %s from %s, "
3565: "trying next server\n",
3566: msg->rcode == dns_rcode_servfail ?
3567: "SERVFAIL reply" :
3568: "recursion not available",
3569: query->servname);
3570: clear_query(query);
3571: check_next_lookup(l);
3572: dns_message_destroy(&msg);
3573: isc_event_free(&event);
3574: return;
3575: }
3576: }
3577:
3578: if (tsigkey != NULL) {
3579: result = dns_tsig_verify(&query->recvbuf, msg);
3580: if (result != ISC_R_SUCCESS) {
3581: printf(";; Couldn't verify signature: %s\n",
3582: isc_result_totext(result));
3583: validated = ISC_FALSE;
3584: }
3585: l->tsigctx = msg->tsigctx;
3586: msg->tsigctx = NULL;
3587: if (l->querysig != NULL) {
3588: debug("freeing querysig buffer %p", l->querysig);
3589: isc_buffer_free(&l->querysig);
3590: }
3591: result = dns_message_getquerytsig(msg, &l->querysig);
3592: check_result(result,"dns_message_getquerytsig");
3593: }
3594:
3595: extrabytes = isc_buffer_remaininglength(b);
3596:
3597: debug("after parse");
3598: if (l->doing_xfr && l->xfr_q == NULL) {
3599: l->xfr_q = query;
3600: /*
3601: * Once we are in the XFR message, increase
3602: * the timeout to much longer, so brief network
3603: * outages won't cause the XFR to abort
3604: */
3605: if (timeout != INT_MAX && query->timer != NULL) {
3606: unsigned int local_timeout;
3607:
3608: if (timeout == 0) {
3609: if (l->tcp_mode)
3610: local_timeout = TCP_TIMEOUT * 4;
3611: else
3612: local_timeout = UDP_TIMEOUT * 4;
3613: } else {
3614: if (timeout < (INT_MAX / 4))
3615: local_timeout = timeout * 4;
3616: else
3617: local_timeout = INT_MAX;
3618: }
3619: debug("have local timeout of %d", local_timeout);
1.9 florian 3620: l->interval.tv_sec = local_timeout;
3621: l->interval.tv_nsec = 0;
1.1 florian 3622: result = isc_timer_reset(query->timer,
3623: &l->interval,
3624: ISC_FALSE);
3625: check_result(result, "isc_timer_reset");
3626: }
3627: }
3628:
3629: if (l->sitvalue != NULL) {
3630: if (msg->opt == NULL)
3631: printf(";; expected opt record in response\n");
3632: else
3633: process_opt(l, msg);
3634: } else if (l->sit && msg->opt != NULL)
3635: process_opt(l, msg);
3636:
3637: if (!l->doing_xfr || l->xfr_q == query) {
3638: if (msg->rcode == dns_rcode_nxdomain &&
3639: (l->origin != NULL || l->need_search)) {
3640: if (!next_origin(query->lookup) || showsearch) {
3641: dighost_printmessage(query, msg, ISC_TRUE);
3642: dighost_received(b->used, &sevent->address, query);
3643: }
3644: } else if (!l->trace && !l->ns_search_only) {
3645: dighost_printmessage(query, msg, ISC_TRUE);
3646: } else if (l->trace) {
3647: int nl = 0;
3648: int count = msg->counts[DNS_SECTION_ANSWER];
3649:
3650: debug("in TRACE code");
3651: if (!l->ns_search_only)
3652: dighost_printmessage(query, msg, ISC_TRUE);
3653:
3654: l->rdtype = l->qrdtype;
3655: if (l->trace_root || (l->ns_search_only && count > 0)) {
3656: if (!l->trace_root)
3657: l->rdtype = dns_rdatatype_soa;
3658: nl = followup_lookup(msg, query,
3659: DNS_SECTION_ANSWER);
3660: l->trace_root = ISC_FALSE;
3661: } else if (count == 0)
3662: nl = followup_lookup(msg, query,
3663: DNS_SECTION_AUTHORITY);
3664: if (nl == 0)
3665: docancel = ISC_TRUE;
3666: } else {
3667: debug("in NSSEARCH code");
3668:
3669: if (l->trace_root) {
3670: /*
3671: * This is the initial NS query.
3672: */
3673: int nl;
3674:
3675: l->rdtype = dns_rdatatype_soa;
3676: nl = followup_lookup(msg, query,
3677: DNS_SECTION_ANSWER);
3678: if (nl == 0)
3679: docancel = ISC_TRUE;
3680: l->trace_root = ISC_FALSE;
3681: usesearch = ISC_FALSE;
3682: } else
3683: dighost_printmessage(query, msg, ISC_TRUE);
3684: }
3685: }
3686:
3687: if (l->pending)
3688: debug("still pending.");
3689: if (l->doing_xfr) {
3690: if (query != l->xfr_q) {
3691: dns_message_destroy(&msg);
3692: isc_event_free(&event);
3693: query->waiting_connect = ISC_FALSE;
3694: return;
3695: }
3696: if (!docancel)
3697: docancel = check_for_more_data(query, msg, sevent);
3698: if (docancel) {
3699: dns_message_destroy(&msg);
3700: clear_query(query);
3701: cancel_lookup(l);
3702: check_next_lookup(l);
3703: }
3704: } else {
3705:
3706: if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
3707:
3708: dighost_received(b->used, &sevent->address, query);
3709: }
3710:
3711: if (!query->lookup->ns_search_only)
3712: query->lookup->pending = ISC_FALSE;
3713: if (!query->lookup->ns_search_only ||
3714: query->lookup->trace_root || docancel) {
3715: dns_message_destroy(&msg);
3716:
3717: cancel_lookup(l);
3718: }
3719: clear_query(query);
3720: check_next_lookup(l);
3721: }
3722: if (msg != NULL) {
3723: dns_message_destroy(&msg);
3724: }
3725: isc_event_free(&event);
3726: return;
3727:
3728: udp_mismatch:
3729: isc_buffer_invalidate(&query->recvbuf);
3730: isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
3731: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
3732: result = isc_socket_recvv(query->sock, &query->recvlist, 1,
3733: global_task, recv_done, query);
3734: check_result(result, "isc_socket_recvv");
3735: recvcount++;
3736: isc_event_free(&event);
3737: return;
3738: }
3739:
3740: /*%
3741: * Turn a name into an address, using system-supplied routines. This is
3742: * used in looking up server names, etc... and needs to use system-supplied
3743: * routines, since they may be using a non-DNS system for these lookups.
3744: */
3745: isc_result_t
3746: get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr) {
3747: int count;
3748: isc_result_t result;
3749:
3750: result = get_addresses(host, myport, sockaddr, 1, &count);
3751: if (result != ISC_R_SUCCESS)
3752: return (result);
3753:
3754: INSIST(count == 1);
3755:
3756: return (ISC_R_SUCCESS);
3757: }
3758:
3759: int
3760: getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp) {
3761: isc_result_t result;
3762: isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
3763: isc_netaddr_t netaddr;
3764: int count, i;
3765: dig_server_t *srv;
3766: char tmp[ISC_NETADDR_FORMATSIZE];
3767:
3768: result = get_addresses(host, 0, sockaddrs,
3769: DIG_MAX_ADDRESSES, &count);
3770: if (resultp != NULL)
3771: *resultp = result;
3772: if (result != ISC_R_SUCCESS) {
3773: if (resultp == NULL)
3774: fatal("couldn't get address for '%s': %s",
3775: host, isc_result_totext(result));
3776: return (0);
3777: }
3778:
3779: for (i = 0; i < count; i++) {
3780: isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
3781: isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
3782: srv = make_server(tmp, host);
3783: ISC_LIST_APPEND(lookup->my_server_list, srv, link);
3784: }
3785:
3786: return (count);
3787: }
3788:
3789: /*%
3790: * Initiate either a TCP or UDP lookup
3791: */
3792: void
3793: do_lookup(dig_lookup_t *lookup) {
3794: dig_query_t *query;
3795:
3796: REQUIRE(lookup != NULL);
3797:
3798: debug("do_lookup()");
3799: lookup->pending = ISC_TRUE;
3800: query = ISC_LIST_HEAD(lookup->q);
3801: if (query != NULL) {
3802: if (lookup->tcp_mode)
3803: send_tcp_connect(query);
3804: else
3805: send_udp(query);
3806: }
3807: }
3808:
3809: /*%
3810: * Start everything in action upon task startup.
3811: */
3812: void
3813: onrun_callback(isc_task_t *task, isc_event_t *event) {
3814: UNUSED(task);
3815:
3816: isc_event_free(&event);
3817: start_lookup();
3818: }
3819:
3820: /*%
3821: * Make everything on the lookup queue go away. Mainly used by the
3822: * SIGINT handler.
3823: */
3824: void
3825: cancel_all(void) {
3826: dig_lookup_t *l, *n;
3827: dig_query_t *q, *nq;
3828:
3829: debug("cancel_all()");
3830:
3831: if (free_now) {
3832: return;
3833: }
3834: cancel_now = ISC_TRUE;
3835: if (current_lookup != NULL) {
3836: for (q = ISC_LIST_HEAD(current_lookup->q);
3837: q != NULL;
3838: q = nq)
3839: {
3840: nq = ISC_LIST_NEXT(q, link);
3841: debug("canceling pending query %p, belonging to %p",
3842: q, current_lookup);
3843: if (q->sock != NULL)
3844: isc_socket_cancel(q->sock, NULL,
3845: ISC_SOCKCANCEL_ALL);
3846: else
3847: clear_query(q);
3848: }
3849: for (q = ISC_LIST_HEAD(current_lookup->connecting);
3850: q != NULL;
3851: q = nq)
3852: {
3853: nq = ISC_LIST_NEXT(q, clink);
3854: debug("canceling connecting query %p, belonging to %p",
3855: q, current_lookup);
3856: if (q->sock != NULL)
3857: isc_socket_cancel(q->sock, NULL,
3858: ISC_SOCKCANCEL_ALL);
3859: else
3860: clear_query(q);
3861: }
3862: }
3863: l = ISC_LIST_HEAD(lookup_list);
3864: while (l != NULL) {
3865: n = ISC_LIST_NEXT(l, link);
3866: ISC_LIST_DEQUEUE(lookup_list, l, link);
3867: try_clear_lookup(l);
3868: l = n;
3869: }
3870: }
3871:
3872: /*%
3873: * Destroy all of the libs we are using, and get everything ready for a
3874: * clean shutdown.
3875: */
3876: void
3877: destroy_libs(void) {
3878:
3879: if (keep != NULL)
3880: isc_socket_detach(&keep);
3881: debug("destroy_libs()");
3882: if (global_task != NULL) {
3883: debug("freeing task");
3884: isc_task_detach(&global_task);
3885: }
3886: /*
3887: * The taskmgr_destroy() call blocks until all events are cleared
3888: * from the task.
3889: */
3890: if (taskmgr != NULL) {
3891: debug("freeing taskmgr");
3892: isc_taskmgr_destroy(&taskmgr);
3893: }
3894: REQUIRE(sockcount == 0);
3895: REQUIRE(recvcount == 0);
3896: REQUIRE(sendcount == 0);
3897:
3898: INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
3899: INSIST(current_lookup == NULL);
3900: INSIST(!free_now);
3901:
3902: free_now = ISC_TRUE;
3903:
3904: lwres_conf_clear(lwconf);
3905:
3906: flush_server_list();
3907:
3908: clear_searchlist();
3909:
3910: if (socketmgr != NULL) {
3911: debug("freeing socketmgr");
3912: isc_socketmgr_destroy(&socketmgr);
3913: }
3914: if (timermgr != NULL) {
3915: debug("freeing timermgr");
3916: isc_timermgr_destroy(&timermgr);
3917: }
3918: if (tsigkey != NULL) {
3919: debug("freeing key %p", tsigkey);
3920: dns_tsigkey_detach(&tsigkey);
3921: }
3922: if (namebuf != NULL)
3923: isc_buffer_free(&namebuf);
3924:
3925: if (is_dst_up) {
3926: debug("destroy DST lib");
3927: dst_lib_destroy();
3928: is_dst_up = ISC_FALSE;
3929: }
3930:
3931: debug("Removing log context");
3932: isc_log_destroy(&lctx);
3933:
3934: }
3935: