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