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