Annotation of src/usr.bin/dig/dighost.c, Revision 1.9
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.9 ! florian 17: /* $Id: dighost.c,v 1.8 2020/02/16 18:05:08 florian Exp $ */
1.1 florian 18:
19: /*! \file
20: * \note
21: * Notice to programmers: Do not use this code as an example of how to
22: * use the ISC library to perform DNS lookups. Dig and Host both operate
23: * on the request level, since they allow fine-tuning of output and are
24: * intended as debugging tools. As a result, they perform many of the
25: * functions which could be better handled using the dns_resolver
26: * functions in most applications.
27: */
28:
29: #include <sys/socket.h>
30: #include <limits.h>
31: #include <locale.h>
32: #include <netdb.h>
1.6 florian 33: #include <resolv.h>
1.1 florian 34: #include <stdlib.h>
35: #include <string.h>
36:
37: #include <dns/byaddr.h>
38: #include <dns/fixedname.h>
39: #include <dns/log.h>
40: #include <dns/message.h>
41: #include <dns/name.h>
42: #include <dns/rdata.h>
43: #include <dns/rdataclass.h>
44: #include <dns/rdatalist.h>
45: #include <dns/rdataset.h>
46: #include "rdatastruct.h"
47: #include <dns/rdatatype.h>
48: #include <dns/result.h>
49: #include <dns/tsig.h>
50:
51: #include <dst/dst.h>
52: #include <dst/result.h>
53:
54: #include <isc/app.h>
55: #include <isc/base64.h>
56: #include <isc/hex.h>
57: #include <isc/log.h>
58: #include <isc/netaddr.h>
59: #include <isc/parseint.h>
60: #include <isc/result.h>
61: #include <isc/safe.h>
62: #include <isc/serial.h>
63: #include <isc/sockaddr.h>
64: #include <isc/task.h>
65: #include <isc/timer.h>
66: #include <isc/types.h>
67: #include <isc/util.h>
68:
69: #include <isccfg/namedconf.h>
70: #include <lwres/lwres.h>
71:
72: #include "dig.h"
73:
74: static lwres_conf_t lwconfdata;
75: static lwres_conf_t *lwconf = &lwconfdata;
76:
77: dig_lookuplist_t lookup_list;
78: dig_serverlist_t server_list;
1.5 florian 79: dig_serverlist_t root_hints_server_list;
1.1 florian 80: dig_searchlistlist_t search_list;
81:
82: isc_boolean_t
83: check_ra = ISC_FALSE,
84: have_ipv4 = ISC_TRUE,
85: have_ipv6 = ISC_TRUE,
86: specified_source = ISC_FALSE,
87: free_now = ISC_FALSE,
88: cancel_now = ISC_FALSE,
89: usesearch = ISC_FALSE,
90: showsearch = ISC_FALSE,
91: qr = ISC_FALSE,
92: is_dst_up = ISC_FALSE,
93: keep_open = ISC_FALSE;
94: in_port_t port = 53;
95: unsigned int timeout = 0;
96: unsigned int extrabytes;
97: isc_log_t *lctx = NULL;
98: isc_taskmgr_t *taskmgr = NULL;
99: isc_task_t *global_task = NULL;
100: isc_timermgr_t *timermgr = NULL;
101: isc_socketmgr_t *socketmgr = NULL;
102: isc_sockaddr_t bind_address;
103: isc_sockaddr_t bind_any;
104: int sendcount = 0;
105: int recvcount = 0;
106: int sockcount = 0;
107: int ndots = -1;
108: int tries = 3;
109: int lookup_counter = 0;
110:
111: static char sitvalue[256];
112:
113: isc_socket_t *keep = NULL;
114: isc_sockaddr_t keepaddr;
115:
1.5 florian 116: static const struct {
117: const char *ns;
118: const int af;
119: } root_hints[] = {
120: { "198.41.0.4", AF_INET }, /* a.root-servers.net */
121: { "2001:503:ba3e::2:30", AF_INET6 }, /* a.root-servers.net */
122: { "199.9.14.201", AF_INET }, /* b.root-servers.net */
123: { "2001:500:200::b", AF_INET6 }, /* b.root-servers.net */
124: { "192.33.4.12", AF_INET }, /* c.root-servers.net */
125: { "2001:500:2::c", AF_INET6 }, /* c.root-servers.net */
126: { "199.7.91.13", AF_INET }, /* d.root-servers.net */
127: { "2001:500:2d::d", AF_INET6 }, /* d.root-servers.net */
128: { "192.203.230.10", AF_INET }, /* e.root-servers.net */
129: { "2001:500:a8::e", AF_INET6 }, /* e.root-servers.net */
130: { "192.5.5.241", AF_INET }, /* f.root-servers.net */
131: { "2001:500:2f::f", AF_INET6 }, /* f.root-servers.net */
132: { "192.112.36.4", AF_INET }, /* g.root-servers.net */
133: { "2001:500:12::d0d", AF_INET6 }, /* g.root-servers.net */
134: { "198.97.190.53", AF_INET }, /* h.root-servers.net */
135: { "2001:500:1::53", AF_INET6 }, /* h.root-servers.net */
136: { "192.36.148.17", AF_INET }, /* i.root-servers.net */
137: { "2001:7fe::53", AF_INET6 }, /* i.root-servers.net */
138: { "192.58.128.30", AF_INET }, /* j.root-servers.net */
139: { "2001:503:c27::2:30", AF_INET6 }, /* j.root-servers.net */
140: { "193.0.14.129", AF_INET }, /* k.root-servers.net */
141: { "2001:7fd::1", AF_INET6 }, /* k.root-servers.net */
142: { "199.7.83.42", AF_INET }, /* l.root-servers.net */
143: { "2001:500:9f::42", AF_INET6 }, /* l.root-servers.net */
144: { "202.12.27.33", AF_INET }, /* m.root-servers.net */
145: { "2001:dc3::35", AF_INET6 } /* m.root-servers.net */
146: };
147:
1.1 florian 148: /*%
149: * Exit Codes:
150: *
151: *\li 0 Everything went well, including things like NXDOMAIN
152: *\li 1 Usage error
153: *\li 7 Got too many RR's or Names
154: *\li 8 Couldn't open batch file
155: *\li 9 No reply from server
156: *\li 10 Internal error
157: */
158: int exitcode = 0;
159: int fatalexit = 0;
160: char keynametext[MXNAME];
161: char keyfile[MXNAME] = "";
162: char keysecret[MXNAME] = "";
163: unsigned char cookie_secret[33];
164: unsigned char cookie[8];
165: dns_name_t *hmacname = NULL;
166: unsigned int digestbits = 0;
167: isc_buffer_t *namebuf = NULL;
168: dns_tsigkey_t *tsigkey = NULL;
169: isc_boolean_t validated = ISC_TRUE;
170: isc_boolean_t debugging = ISC_FALSE;
171: isc_boolean_t debugtiming = ISC_FALSE;
172: 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) {
383: TIME_NOW(&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: dst_key_t *dstkey = NULL;
1136:
1137: debug("setup_file_key()");
1138:
1139: /* Try reading the key from a K* pair */
1140: result = dst_key_fromnamedfile(keyfile, NULL,
1141: DST_TYPE_PRIVATE | DST_TYPE_KEY,
1142: &dstkey);
1143:
1144: /* If that didn't work, try reading it as a session.key keyfile */
1145: if (result != ISC_R_SUCCESS) {
1146: result = read_confkey();
1147: if (result == ISC_R_SUCCESS)
1148: return;
1149: }
1150:
1151: if (result != ISC_R_SUCCESS) {
1152: fprintf(stderr, "Couldn't read key from %s: %s\n",
1153: keyfile, isc_result_totext(result));
1154: goto failure;
1155: }
1156:
1157: switch (dst_key_alg(dstkey)) {
1158: case DST_ALG_HMACSHA1:
1159: hmacname = DNS_TSIG_HMACSHA1_NAME;
1160: break;
1161: case DST_ALG_HMACSHA224:
1162: hmacname = DNS_TSIG_HMACSHA224_NAME;
1163: break;
1164: case DST_ALG_HMACSHA256:
1165: hmacname = DNS_TSIG_HMACSHA256_NAME;
1166: break;
1167: case DST_ALG_HMACSHA384:
1168: hmacname = DNS_TSIG_HMACSHA384_NAME;
1169: break;
1170: case DST_ALG_HMACSHA512:
1171: hmacname = DNS_TSIG_HMACSHA512_NAME;
1172: break;
1173: default:
1174: printf(";; Couldn't create key %s: bad algorithm\n",
1175: keynametext);
1176: goto failure;
1177: }
1178: result = dns_tsigkey_createfromkey(dst_key_name(dstkey), hmacname,
1179: dstkey, ISC_FALSE, NULL, 0, 0,
1180: &tsigkey);
1181: if (result != ISC_R_SUCCESS) {
1182: printf(";; Couldn't create key %s: %s\n",
1183: keynametext, isc_result_totext(result));
1184: goto failure;
1185: }
1186: failure:
1187: if (dstkey != NULL)
1188: dst_key_free(&dstkey);
1189: }
1190:
1191: static dig_searchlist_t *
1192: make_searchlist_entry(char *domain) {
1193: dig_searchlist_t *search;
1194: search = malloc(sizeof(*search));
1195: if (search == NULL)
1196: fatal("memory allocation failure in %s:%d",
1197: __FILE__, __LINE__);
1198: strlcpy(search->origin, domain, MXNAME);
1199: search->origin[MXNAME-1] = 0;
1200: ISC_LINK_INIT(search, link);
1201: return (search);
1202: }
1203:
1204: static void
1205: clear_searchlist(void) {
1206: dig_searchlist_t *search;
1207: while ((search = ISC_LIST_HEAD(search_list)) != NULL) {
1208: ISC_LIST_UNLINK(search_list, search, link);
1209: free(search);
1210: }
1211: }
1212:
1213: static void
1214: create_search_list(lwres_conf_t *confdata) {
1215: int i;
1216: dig_searchlist_t *search;
1217:
1218: debug("create_search_list()");
1219: clear_searchlist();
1220:
1221: for (i = 0; i < confdata->searchnxt; i++) {
1222: search = make_searchlist_entry(confdata->search[i]);
1223: ISC_LIST_APPEND(search_list, search, link);
1224: }
1225: }
1226:
1227: /*%
1228: * Setup the system as a whole, reading key information and resolv.conf
1229: * settings.
1230: */
1231: void
1232: setup_system(isc_boolean_t ipv4only, isc_boolean_t ipv6only) {
1233: dig_searchlist_t *domain = NULL;
1234: lwres_result_t lwresult;
1235: int lwresflags = 0;
1236:
1237: debug("setup_system()");
1238:
1239: if (ipv4only) {
1240: if (have_ipv4) {
1241: isc_net_disableipv6();
1242: have_ipv6 = ISC_FALSE;
1243: } else {
1244: fatal("can't find IPv4 networking");
1245: }
1246: }
1247:
1248: if (ipv6only) {
1249: if (have_ipv6) {
1250: isc_net_disableipv4();
1251: have_ipv4 = ISC_FALSE;
1252: } else {
1253: fatal("can't find IPv6 networking");
1254: }
1255: }
1256:
1257: if (have_ipv4)
1258: lwresflags |= LWRES_USEIPV4;
1259: if (have_ipv6)
1260: lwresflags |= LWRES_USEIPV6;
1261: lwres_conf_init(lwconf, lwresflags);
1262:
1.6 florian 1263: lwresult = lwres_conf_parse(lwconf, _PATH_RESCONF);
1.1 florian 1264: if (lwresult != LWRES_R_SUCCESS && lwresult != LWRES_R_NOTFOUND)
1.6 florian 1265: fatal("parse of %s failed", _PATH_RESCONF);
1.1 florian 1266:
1267: /* Make the search list */
1268: if (lwconf->searchnxt > 0)
1269: create_search_list(lwconf);
1270: else { /* No search list. Use the domain name if any */
1271: if (lwconf->domainname != NULL) {
1272: domain = make_searchlist_entry(lwconf->domainname);
1273: ISC_LIST_APPEND(search_list, domain, link);
1274: domain = NULL;
1275: }
1276: }
1277:
1278: if (ndots == -1) {
1279: ndots = lwconf->ndots;
1280: debug("ndots is %d.", ndots);
1281: }
1282:
1283: /* If user doesn't specify server use nameservers from resolv.conf. */
1284: if (ISC_LIST_EMPTY(server_list))
1285: copy_server_list(lwconf, &server_list);
1286:
1287: /* If we don't find a nameserver fall back to localhost */
1288: if (ISC_LIST_EMPTY(server_list)) {
1289: if (have_ipv4) {
1290: lwresult = add_nameserver(lwconf, "127.0.0.1", AF_INET);
1291: if (lwresult != ISC_R_SUCCESS)
1292: fatal("add_nameserver failed");
1293: }
1294: if (have_ipv6) {
1295: lwresult = add_nameserver(lwconf, "::1", AF_INET6);
1296: if (lwresult != ISC_R_SUCCESS)
1297: fatal("add_nameserver failed");
1298: }
1299:
1300: copy_server_list(lwconf, &server_list);
1301: }
1302:
1303: if (keyfile[0] != 0)
1304: setup_file_key();
1305: else if (keysecret[0] != 0)
1306: setup_text_key();
1307: arc4random_buf(cookie_secret, sizeof(cookie_secret));
1308: }
1309:
1310: /*%
1311: * Override the search list derived from resolv.conf by 'domain'.
1312: */
1313: void
1314: set_search_domain(char *domain) {
1315: dig_searchlist_t *search;
1316:
1317: clear_searchlist();
1318: search = make_searchlist_entry(domain);
1319: ISC_LIST_APPEND(search_list, search, link);
1320: }
1321:
1322: /*%
1323: * Setup the ISC and DNS libraries for use by the system.
1324: */
1325: void
1326: setup_libs(void) {
1327: isc_result_t result;
1328: isc_logconfig_t *logconfig = NULL;
1329:
1330: debug("setup_libs()");
1331:
1332: dns_result_register();
1333:
1334: result = isc_log_create(&lctx, &logconfig);
1335: check_result(result, "isc_log_create");
1336:
1337: isc_log_setcontext(lctx);
1338: dns_log_init(lctx);
1339: dns_log_setcontext(lctx);
1340:
1341: result = isc_log_usechannel(logconfig, "default_debug", NULL, NULL);
1342: check_result(result, "isc_log_usechannel");
1343:
1344: isc_log_setdebuglevel(lctx, 0);
1345:
1346: result = isc_taskmgr_create(1, 0, &taskmgr);
1347: check_result(result, "isc_taskmgr_create");
1348:
1349: result = isc_task_create(taskmgr, 0, &global_task);
1350: check_result(result, "isc_task_create");
1351: isc_task_setname(global_task, "dig", NULL);
1352:
1353: result = isc_timermgr_create(&timermgr);
1354: check_result(result, "isc_timermgr_create");
1355:
1356: result = isc_socketmgr_create(&socketmgr);
1357: check_result(result, "isc_socketmgr_create");
1358:
1359: check_result(result, "isc_entropy_create");
1360:
1361: result = dst_lib_init();
1362: check_result(result, "dst_lib_init");
1363: is_dst_up = ISC_TRUE;
1364: }
1365:
1366: typedef struct dig_ednsoptname {
1367: uint32_t code;
1368: const char *name;
1369: } dig_ednsoptname_t;
1370:
1371: dig_ednsoptname_t optnames[] = {
1372: { 3, "NSID" }, /* RFC 5001 */
1373: { 5, "DAU" }, /* RFC 6975 */
1374: { 6, "DHU" }, /* RFC 6975 */
1375: { 7, "N3U" }, /* RFC 6975 */
1376: { 8, "ECS" }, /* RFC 7871 */
1377: { 9, "EXPIRE" }, /* RFC 7314 */
1378: { 10, "COOKIE" }, /* RFC 7873 */
1379: { 11, "KEEPALIVE" }, /* RFC 7828 */
1380: { 12, "PADDING" }, /* RFC 7830 */
1381: { 12, "PAD" }, /* shorthand */
1382: { 13, "CHAIN" }, /* RFC 7901 */
1383: { 14, "KEY-TAG" }, /* RFC 8145 */
1384: { 26946, "DEVICEID" }, /* Brian Hartvigsen */
1385: };
1386:
1387: #define N_EDNS_OPTNAMES (sizeof(optnames) / sizeof(optnames[0]))
1388:
1389: void
1390: save_opt(dig_lookup_t *lookup, char *code, char *value) {
1391: isc_result_t result;
1392: uint32_t num = 0;
1393: isc_buffer_t b;
1394: isc_boolean_t found = ISC_FALSE;
1395: unsigned int i;
1396:
1397: if (lookup->ednsoptscnt >= EDNSOPT_OPTIONS)
1398: fatal("too many ednsopts");
1399:
1400: for (i = 0; i < N_EDNS_OPTNAMES; i++) {
1401: if (strcasecmp(code, optnames[i].name) == 0) {
1402: num = optnames[i].code;
1403: found = ISC_TRUE;
1404: break;
1405: }
1406: }
1407:
1408: if (!found) {
1409: result = parse_uint(&num, code, 65535, "ednsopt");
1410: if (result != ISC_R_SUCCESS)
1411: fatal("bad edns code point: %s", code);
1412: }
1413:
1414: if (lookup->ednsopts == NULL) {
1415: cloneopts(lookup, NULL);
1416: }
1417:
1418: if (lookup->ednsopts[lookup->ednsoptscnt].value != NULL)
1419: free(lookup->ednsopts[lookup->ednsoptscnt].value);
1420:
1421: lookup->ednsopts[lookup->ednsoptscnt].code = num;
1422: lookup->ednsopts[lookup->ednsoptscnt].length = 0;
1423: lookup->ednsopts[lookup->ednsoptscnt].value = NULL;
1424:
1425: if (value != NULL) {
1426: char *buf;
1427: buf = malloc(strlen(value)/2 + 1);
1428: if (buf == NULL)
1429: fatal("out of memory");
1430: isc_buffer_init(&b, buf, (unsigned int) strlen(value)/2 + 1);
1431: result = isc_hex_decodestring(value, &b);
1432: check_result(result, "isc_hex_decodestring");
1433: lookup->ednsopts[lookup->ednsoptscnt].value =
1434: isc_buffer_base(&b);
1435: lookup->ednsopts[lookup->ednsoptscnt].length =
1436: isc_buffer_usedlength(&b);
1437: }
1438:
1439: lookup->ednsoptscnt++;
1440: }
1441:
1442: /*%
1443: * Add EDNS0 option record to a message. Currently, the only supported
1444: * options are UDP buffer size, the DO bit, and EDNS options
1445: * (e.g., NSID, SIT, client-subnet)
1446: */
1447: static void
1448: add_opt(dns_message_t *msg, uint16_t udpsize, uint16_t edns,
1449: unsigned int flags, dns_ednsopt_t *opts, size_t count)
1450: {
1451: dns_rdataset_t *rdataset = NULL;
1452: isc_result_t result;
1453:
1454: debug("add_opt()");
1455: result = dns_message_buildopt(msg, &rdataset, edns, udpsize, flags,
1456: opts, count);
1457: check_result(result, "dns_message_buildopt");
1458: result = dns_message_setopt(msg, rdataset);
1459: check_result(result, "dns_message_setopt");
1460: }
1461:
1462: /*%
1463: * Add a question section to a message, asking for the specified name,
1464: * type, and class.
1465: */
1466: static void
1467: add_question(dns_message_t *message, dns_name_t *name,
1468: dns_rdataclass_t rdclass, dns_rdatatype_t rdtype)
1469: {
1470: dns_rdataset_t *rdataset;
1471: isc_result_t result;
1472:
1473: debug("add_question()");
1474: rdataset = NULL;
1475: result = dns_message_gettemprdataset(message, &rdataset);
1476: check_result(result, "dns_message_gettemprdataset()");
1477: dns_rdataset_makequestion(rdataset, rdclass, rdtype);
1478: ISC_LIST_APPEND(name->list, rdataset, link);
1479: }
1480:
1481: /*%
1482: * Check if we're done with all the queued lookups, which is true iff
1483: * all sockets, sends, and recvs are accounted for (counters == 0),
1484: * and the lookup list is empty.
1485: * If we are done, pass control back out to dighost_shutdown() (which is
1486: * part of dig.c, host.c, or nslookup.c) to either shutdown the system as
1487: * a whole or reseed the lookup list.
1488: */
1489: static void
1490: check_if_done(void) {
1491: debug("check_if_done()");
1492: debug("list %s", ISC_LIST_EMPTY(lookup_list) ? "empty" : "full");
1493: if (ISC_LIST_EMPTY(lookup_list) && current_lookup == NULL &&
1494: sendcount == 0) {
1495: INSIST(sockcount == 0);
1496: INSIST(recvcount == 0);
1497: debug("shutting down");
1498: dighost_shutdown();
1499: }
1500: }
1501:
1502: /*%
1503: * Clear out a query when we're done with it. WARNING: This routine
1504: * WILL invalidate the query pointer.
1505: */
1506: static void
1507: clear_query(dig_query_t *query) {
1508: dig_lookup_t *lookup;
1509:
1510: REQUIRE(query != NULL);
1511:
1512: debug("clear_query(%p)", query);
1513:
1514: if (query->timer != NULL)
1515: isc_timer_detach(&query->timer);
1516: lookup = query->lookup;
1517:
1518: if (lookup->current_query == query)
1519: lookup->current_query = NULL;
1520:
1521: if (ISC_LINK_LINKED(query, link))
1522: ISC_LIST_UNLINK(lookup->q, query, link);
1523: if (ISC_LINK_LINKED(query, clink))
1524: ISC_LIST_UNLINK(lookup->connecting, query, clink);
1525: if (ISC_LINK_LINKED(&query->recvbuf, link))
1526: ISC_LIST_DEQUEUE(query->recvlist, &query->recvbuf,
1527: link);
1528: if (ISC_LINK_LINKED(&query->lengthbuf, link))
1529: ISC_LIST_DEQUEUE(query->lengthlist, &query->lengthbuf,
1530: link);
1531: INSIST(query->recvspace != NULL);
1532:
1533: if (query->sock != NULL) {
1534: isc_socket_detach(&query->sock);
1535: sockcount--;
1536: debug("sockcount=%d", sockcount);
1537: }
1538: free(query->recvspace);
1539: isc_buffer_invalidate(&query->recvbuf);
1540: isc_buffer_invalidate(&query->lengthbuf);
1541: if (query->waiting_senddone)
1542: query->pending_free = ISC_TRUE;
1543: else
1544: free(query);
1545: }
1546:
1547: /*%
1548: * Try and clear out a lookup if we're done with it. Return ISC_TRUE if
1549: * the lookup was successfully cleared. If ISC_TRUE is returned, the
1550: * lookup pointer has been invalidated.
1551: */
1552: static isc_boolean_t
1553: try_clear_lookup(dig_lookup_t *lookup) {
1554: dig_query_t *q;
1555:
1556: REQUIRE(lookup != NULL);
1557:
1558: debug("try_clear_lookup(%p)", lookup);
1559:
1560: if (ISC_LIST_HEAD(lookup->q) != NULL ||
1561: ISC_LIST_HEAD(lookup->connecting) != NULL)
1562: {
1563: if (debugging) {
1564: q = ISC_LIST_HEAD(lookup->q);
1565: while (q != NULL) {
1566: debug("query to %s still pending", q->servname);
1567: q = ISC_LIST_NEXT(q, link);
1568: }
1569:
1570: q = ISC_LIST_HEAD(lookup->connecting);
1571: while (q != NULL) {
1572: debug("query to %s still connecting",
1573: q->servname);
1574: q = ISC_LIST_NEXT(q, clink);
1575: }
1576: }
1577: return (ISC_FALSE);
1578: }
1579:
1580: /*
1581: * At this point, we know there are no queries on the lookup,
1582: * so can make it go away also.
1583: */
1584: destroy_lookup(lookup);
1585: return (ISC_TRUE);
1586: }
1587:
1588: void
1589: destroy_lookup(dig_lookup_t *lookup) {
1590: dig_server_t *s;
1591: void *ptr;
1592:
1593: debug("destroy");
1594: s = ISC_LIST_HEAD(lookup->my_server_list);
1595: while (s != NULL) {
1596: debug("freeing server %p belonging to %p", s, lookup);
1597: ptr = s;
1598: s = ISC_LIST_NEXT(s, link);
1599: ISC_LIST_DEQUEUE(lookup->my_server_list,
1600: (dig_server_t *)ptr, link);
1601: free(ptr);
1602: }
1603: if (lookup->sendmsg != NULL)
1604: dns_message_destroy(&lookup->sendmsg);
1605: if (lookup->querysig != NULL) {
1606: debug("freeing buffer %p", lookup->querysig);
1607: isc_buffer_free(&lookup->querysig);
1608: }
1609: if (lookup->sendspace != NULL)
1610: free(lookup->sendspace);
1611:
1612: if (lookup->tsigctx != NULL)
1613: dst_context_destroy(&lookup->tsigctx);
1614:
1615: if (lookup->ecs_addr != NULL)
1616: free(lookup->ecs_addr);
1617:
1618: if (lookup->ednsopts != NULL) {
1619: size_t i;
1620: for (i = 0; i < EDNSOPT_OPTIONS; i++) {
1621: if (lookup->ednsopts[i].value != NULL)
1622: free(lookup->ednsopts[i].value);
1623: }
1624: free(lookup->ednsopts);
1625: }
1626:
1627: free(lookup);
1628: }
1629:
1630: /*%
1631: * If we can, start the next lookup in the queue running.
1632: * This assumes that the lookup on the head of the queue hasn't been
1633: * started yet. It also removes the lookup from the head of the queue,
1634: * setting the current_lookup pointer pointing to it.
1635: */
1636: void
1637: start_lookup(void) {
1638: debug("start_lookup()");
1639: if (cancel_now)
1640: return;
1641:
1642: /*
1643: * If there's a current lookup running, we really shouldn't get
1644: * here.
1645: */
1646: INSIST(current_lookup == NULL);
1647:
1648: current_lookup = ISC_LIST_HEAD(lookup_list);
1649: /*
1650: * Put the current lookup somewhere so cancel_all can find it
1651: */
1652: if (current_lookup != NULL) {
1653: ISC_LIST_DEQUEUE(lookup_list, current_lookup, link);
1654: if (setup_lookup(current_lookup))
1655: do_lookup(current_lookup);
1656: else if (next_origin(current_lookup))
1657: check_next_lookup(current_lookup);
1658: } else {
1659: check_if_done();
1660: }
1661: }
1662:
1663: /*%
1664: * If we can, clear the current lookup and start the next one running.
1665: * This calls try_clear_lookup, so may invalidate the lookup pointer.
1666: */
1667: static void
1668: check_next_lookup(dig_lookup_t *lookup) {
1669:
1670: INSIST(!free_now);
1671:
1672: debug("check_next_lookup(%p)", lookup);
1673:
1674: if (ISC_LIST_HEAD(lookup->q) != NULL) {
1675: debug("still have a worker");
1676: return;
1677: }
1678: if (try_clear_lookup(lookup)) {
1679: current_lookup = NULL;
1680: start_lookup();
1681: }
1682: }
1683:
1684: /*%
1685: * Create and queue a new lookup as a followup to the current lookup,
1686: * based on the supplied message and section. This is used in trace and
1687: * name server search modes to start a new lookup using servers from
1688: * NS records in a reply. Returns the number of followup lookups made.
1689: */
1690: static int
1691: followup_lookup(dns_message_t *msg, dig_query_t *query, dns_section_t section)
1692: {
1693: dig_lookup_t *lookup = NULL;
1694: dig_server_t *srv = NULL;
1695: dns_rdataset_t *rdataset = NULL;
1696: dns_rdata_t rdata = DNS_RDATA_INIT;
1697: dns_name_t *name = NULL;
1698: isc_result_t result;
1699: isc_boolean_t success = ISC_FALSE;
1700: int numLookups = 0;
1701: int num;
1702: isc_result_t lresult, addresses_result;
1703: char bad_namestr[DNS_NAME_FORMATSIZE];
1704: dns_name_t *domain;
1705: isc_boolean_t horizontal = ISC_FALSE, bad = ISC_FALSE;
1706:
1707: INSIST(!free_now);
1708:
1709: debug("following up %s", query->lookup->textname);
1710:
1711: addresses_result = ISC_R_SUCCESS;
1712: bad_namestr[0] = '\0';
1713: for (result = dns_message_firstname(msg, section);
1714: result == ISC_R_SUCCESS;
1715: result = dns_message_nextname(msg, section)) {
1716: name = NULL;
1717: dns_message_currentname(msg, section, &name);
1718:
1719: if (section == DNS_SECTION_AUTHORITY) {
1720: rdataset = NULL;
1721: result = dns_message_findtype(name, dns_rdatatype_soa,
1722: 0, &rdataset);
1723: if (result == ISC_R_SUCCESS)
1724: return (0);
1725: }
1726: rdataset = NULL;
1727: result = dns_message_findtype(name, dns_rdatatype_ns, 0,
1728: &rdataset);
1729: if (result != ISC_R_SUCCESS)
1730: continue;
1731:
1732: debug("found NS set");
1733:
1734: if (query->lookup->trace && !query->lookup->trace_root) {
1735: dns_namereln_t namereln;
1736: unsigned int nlabels;
1737: int order;
1738:
1739: domain = dns_fixedname_name(&query->lookup->fdomain);
1740: namereln = dns_name_fullcompare(name, domain,
1741: &order, &nlabels);
1742: if (namereln == dns_namereln_equal) {
1743: if (!horizontal)
1744: printf(";; BAD (HORIZONTAL) REFERRAL\n");
1745: horizontal = ISC_TRUE;
1746: } else if (namereln != dns_namereln_subdomain) {
1747: if (!bad)
1748: printf(";; BAD REFERRAL\n");
1749: bad = ISC_TRUE;
1750: continue;
1751: }
1752: }
1753:
1754: for (result = dns_rdataset_first(rdataset);
1755: result == ISC_R_SUCCESS;
1756: result = dns_rdataset_next(rdataset)) {
1757: char namestr[DNS_NAME_FORMATSIZE];
1758: dns_rdata_ns_t ns;
1759:
1760: if (query->lookup->trace_root &&
1761: query->lookup->nsfound >= MXSERV)
1762: break;
1763:
1764: dns_rdataset_current(rdataset, &rdata);
1765:
1766: query->lookup->nsfound++;
1767: result = dns_rdata_tostruct(&rdata, &ns);
1768: check_result(result, "dns_rdata_tostruct");
1769: dns_name_format(&ns.name, namestr, sizeof(namestr));
1770: dns_rdata_freestruct(&ns);
1771:
1772: /* Initialize lookup if we've not yet */
1773: debug("found NS %s", namestr);
1774: if (!success) {
1775: success = ISC_TRUE;
1776: lookup_counter++;
1777: lookup = requeue_lookup(query->lookup,
1778: ISC_FALSE);
1779: cancel_lookup(query->lookup);
1780: lookup->doing_xfr = ISC_FALSE;
1781: if (!lookup->trace_root &&
1782: section == DNS_SECTION_ANSWER)
1783: lookup->trace = ISC_FALSE;
1784: else
1785: lookup->trace = query->lookup->trace;
1786: lookup->ns_search_only =
1787: query->lookup->ns_search_only;
1788: lookup->trace_root = ISC_FALSE;
1789: if (lookup->ns_search_only)
1790: lookup->recurse = ISC_FALSE;
1791: domain = dns_fixedname_name(&lookup->fdomain);
1792: dns_name_copy(name, domain, NULL);
1793: }
1794: debug("adding server %s", namestr);
1795: num = getaddresses(lookup, namestr, &lresult);
1796: if (lresult != ISC_R_SUCCESS) {
1797: printf("couldn't get address for '%s': %s\n",
1798: namestr, isc_result_totext(lresult));
1799: if (addresses_result == ISC_R_SUCCESS) {
1800: addresses_result = lresult;
1801: strlcpy(bad_namestr, namestr,
1802: sizeof(bad_namestr));
1803: }
1804: }
1805: numLookups += num;
1806: dns_rdata_reset(&rdata);
1807: }
1808: }
1809: if (numLookups == 0 && addresses_result != ISC_R_SUCCESS) {
1810: fatal("couldn't get address for '%s': %s",
1811: bad_namestr, isc_result_totext(result));
1812: }
1813:
1814: if (lookup == NULL &&
1815: section == DNS_SECTION_ANSWER &&
1816: (query->lookup->trace || query->lookup->ns_search_only))
1817: return (followup_lookup(msg, query, DNS_SECTION_AUTHORITY));
1818:
1819: /*
1820: * Randomize the order the nameserver will be tried.
1821: */
1822: if (numLookups > 1) {
1823: uint32_t i, j;
1824: dig_serverlist_t my_server_list;
1825: dig_server_t *next;
1826:
1827: ISC_LIST_INIT(my_server_list);
1828:
1829: i = numLookups;
1830: for (srv = ISC_LIST_HEAD(lookup->my_server_list);
1831: srv != NULL;
1832: srv = ISC_LIST_HEAD(lookup->my_server_list)) {
1833: INSIST(i > 0);
1834: j = arc4random_uniform(i);
1835: next = ISC_LIST_NEXT(srv, link);
1836: while (j-- > 0 && next != NULL) {
1837: srv = next;
1838: next = ISC_LIST_NEXT(srv, link);
1839: }
1840: ISC_LIST_DEQUEUE(lookup->my_server_list, srv, link);
1841: ISC_LIST_APPEND(my_server_list, srv, link);
1842: i--;
1843: }
1844: ISC_LIST_APPENDLIST(lookup->my_server_list,
1845: my_server_list, link);
1846: }
1847:
1848: return (numLookups);
1849: }
1850:
1851: /*%
1852: * Create and queue a new lookup using the next origin from the search
1853: * list, read in setup_system().
1854: *
1855: * Return ISC_TRUE iff there was another searchlist entry.
1856: */
1857: static isc_boolean_t
1858: next_origin(dig_lookup_t *oldlookup) {
1859: dig_lookup_t *newlookup;
1860: dig_searchlist_t *search;
1861: dns_fixedname_t fixed;
1862: dns_name_t *name;
1863: isc_result_t result;
1864:
1865: INSIST(!free_now);
1866:
1867: debug("next_origin()");
1868: debug("following up %s", oldlookup->textname);
1869:
1870: if (!usesearch)
1871: /*
1872: * We're not using a search list, so don't even think
1873: * about finding the next entry.
1874: */
1875: return (ISC_FALSE);
1876:
1877: /*
1878: * Check for a absolute name or ndots being met.
1879: */
1880: dns_fixedname_init(&fixed);
1881: name = dns_fixedname_name(&fixed);
1882: result = dns_name_fromstring2(name, oldlookup->textname, NULL, 0);
1883: if (result == ISC_R_SUCCESS &&
1884: (dns_name_isabsolute(name) ||
1885: (int)dns_name_countlabels(name) > ndots))
1886: return (ISC_FALSE);
1887:
1888: if (oldlookup->origin == NULL && !oldlookup->need_search)
1889: /*
1890: * Then we just did rootorg; there's nothing left.
1891: */
1892: return (ISC_FALSE);
1893: if (oldlookup->origin == NULL && oldlookup->need_search) {
1894: newlookup = requeue_lookup(oldlookup, ISC_TRUE);
1895: newlookup->origin = ISC_LIST_HEAD(search_list);
1896: newlookup->need_search = ISC_FALSE;
1897: } else {
1898: search = ISC_LIST_NEXT(oldlookup->origin, link);
1899: if (search == NULL && oldlookup->done_as_is)
1900: return (ISC_FALSE);
1901: newlookup = requeue_lookup(oldlookup, ISC_TRUE);
1902: newlookup->origin = search;
1903: }
1904: cancel_lookup(oldlookup);
1905: return (ISC_TRUE);
1906: }
1907:
1908: /*%
1909: * Insert an SOA record into the sendmessage in a lookup. Used for
1910: * creating IXFR queries.
1911: */
1912: static void
1913: insert_soa(dig_lookup_t *lookup) {
1914: isc_result_t result;
1915: dns_rdata_soa_t soa;
1916: dns_rdata_t *rdata = NULL;
1917: dns_rdatalist_t *rdatalist = NULL;
1918: dns_rdataset_t *rdataset = NULL;
1919: dns_name_t *soaname = NULL;
1920:
1921: debug("insert_soa()");
1922: soa.serial = lookup->ixfr_serial;
1923: soa.refresh = 0;
1924: soa.retry = 0;
1925: soa.expire = 0;
1926: soa.minimum = 0;
1927: soa.common.rdclass = lookup->rdclass;
1928: soa.common.rdtype = dns_rdatatype_soa;
1929:
1930: dns_name_init(&soa.origin, NULL);
1931: dns_name_init(&soa.contact, NULL);
1932:
1933: dns_name_clone(dns_rootname, &soa.origin);
1934: dns_name_clone(dns_rootname, &soa.contact);
1935:
1936: isc_buffer_init(&lookup->rdatabuf, lookup->rdatastore,
1937: sizeof(lookup->rdatastore));
1938:
1939: result = dns_message_gettemprdata(lookup->sendmsg, &rdata);
1940: check_result(result, "dns_message_gettemprdata");
1941:
1942: result = dns_rdata_fromstruct(rdata, lookup->rdclass,
1943: dns_rdatatype_soa, &soa,
1944: &lookup->rdatabuf);
1945: check_result(result, "isc_rdata_fromstruct");
1946:
1947: result = dns_message_gettemprdatalist(lookup->sendmsg, &rdatalist);
1948: check_result(result, "dns_message_gettemprdatalist");
1949:
1950: result = dns_message_gettemprdataset(lookup->sendmsg, &rdataset);
1951: check_result(result, "dns_message_gettemprdataset");
1952:
1953: dns_rdatalist_init(rdatalist);
1954: rdatalist->type = dns_rdatatype_soa;
1955: rdatalist->rdclass = lookup->rdclass;
1956: ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
1957:
1958: dns_rdatalist_tordataset(rdatalist, rdataset);
1959:
1960: result = dns_message_gettempname(lookup->sendmsg, &soaname);
1961: check_result(result, "dns_message_gettempname");
1962: dns_name_init(soaname, NULL);
1963: dns_name_clone(lookup->name, soaname);
1964: ISC_LIST_INIT(soaname->list);
1965: ISC_LIST_APPEND(soaname->list, rdataset, link);
1966: dns_message_addname(lookup->sendmsg, soaname, DNS_SECTION_AUTHORITY);
1967: }
1968:
1969: static void
1970: compute_cookie(unsigned char *clientcookie, size_t len) {
1971: /* XXXMPA need to fix, should be per server. */
1972: INSIST(len >= 8U);
1973: memmove(clientcookie, cookie_secret, 8);
1974: }
1975:
1.5 florian 1976: #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
1977: static void
1978: populate_root_hints()
1979: {
1980: dig_server_t *newsrv;
1981: size_t i;
1982:
1983: if (!ISC_LIST_EMPTY(root_hints_server_list))
1984: return;
1985:
1986: for (i = 0; i < nitems(root_hints); i++) {
1987: if (!have_ipv4 && root_hints[i].af == AF_INET)
1988: continue;
1989: if (!have_ipv6 && root_hints[i].af == AF_INET6)
1990: continue;
1991: newsrv = make_server(root_hints[i].ns, root_hints[i].ns);
1992: ISC_LINK_INIT(newsrv, link);
1993: ISC_LIST_ENQUEUE(root_hints_server_list, newsrv, link);
1994: }
1995: }
1996: #undef nitems
1997:
1.1 florian 1998: /*%
1999: * Setup the supplied lookup structure, making it ready to start sending
2000: * queries to servers. Create and initialize the message to be sent as
2001: * well as the query structures and buffer space for the replies. If the
2002: * server list is empty, clone it from the system default list.
2003: */
2004: isc_boolean_t
2005: setup_lookup(dig_lookup_t *lookup) {
2006: isc_result_t result;
2007: uint32_t id;
2008: unsigned int len;
2009: dig_server_t *serv;
2010: dig_query_t *query;
2011: isc_buffer_t b;
2012: dns_compress_t cctx;
2013: char store[MXNAME];
2014: char ecsbuf[20];
2015: char sitbuf[256];
2016:
2017: REQUIRE(lookup != NULL);
2018: INSIST(!free_now);
2019:
2020: debug("setup_lookup(%p)", lookup);
2021:
2022: result = dns_message_create(DNS_MESSAGE_INTENTRENDER,
2023: &lookup->sendmsg);
2024: check_result(result, "dns_message_create");
2025:
2026: if (lookup->new_search) {
2027: debug("resetting lookup counter.");
2028: lookup_counter = 0;
2029: }
2030:
2031: if (ISC_LIST_EMPTY(lookup->my_server_list)) {
1.5 florian 2032: if (lookup->trace && lookup->trace_root) {
2033: populate_root_hints();
2034: clone_server_list(root_hints_server_list,
2035: &lookup->my_server_list);
2036: } else {
2037: debug("cloning server list");
2038: clone_server_list(server_list,
2039: &lookup->my_server_list);
2040: }
1.1 florian 2041: }
2042: result = dns_message_gettempname(lookup->sendmsg, &lookup->name);
2043: check_result(result, "dns_message_gettempname");
2044: dns_name_init(lookup->name, NULL);
2045:
2046: isc_buffer_init(&lookup->namebuf, lookup->name_space,
2047: sizeof(lookup->name_space));
2048: isc_buffer_init(&lookup->onamebuf, lookup->oname_space,
2049: sizeof(lookup->oname_space));
2050:
2051: /*
2052: * If the name has too many dots, force the origin to be NULL
2053: * (which produces an absolute lookup). Otherwise, take the origin
2054: * we have if there's one in the struct already. If it's NULL,
2055: * take the first entry in the searchlist iff either usesearch
2056: * is TRUE or we got a domain line in the resolv.conf file.
2057: */
2058: if (lookup->new_search) {
2059: if ((count_dots(lookup->textname) >= ndots) || !usesearch) {
2060: lookup->origin = NULL; /* Force abs lookup */
2061: lookup->done_as_is = ISC_TRUE;
2062: lookup->need_search = usesearch;
2063: } else if (lookup->origin == NULL && usesearch) {
2064: lookup->origin = ISC_LIST_HEAD(search_list);
2065: lookup->need_search = ISC_FALSE;
2066: }
2067: }
2068:
2069: if (lookup->origin != NULL) {
2070: debug("trying origin %s", lookup->origin->origin);
2071: result = dns_message_gettempname(lookup->sendmsg,
2072: &lookup->oname);
2073: check_result(result, "dns_message_gettempname");
2074: dns_name_init(lookup->oname, NULL);
2075: /* XXX Helper funct to conv char* to name? */
2076: len = (unsigned int) strlen(lookup->origin->origin);
2077: isc_buffer_init(&b, lookup->origin->origin, len);
2078: isc_buffer_add(&b, len);
2079: result = dns_name_fromtext(lookup->oname, &b, dns_rootname,
2080: 0, &lookup->onamebuf);
2081: if (result != ISC_R_SUCCESS) {
2082: dns_message_puttempname(lookup->sendmsg,
2083: &lookup->name);
2084: dns_message_puttempname(lookup->sendmsg,
2085: &lookup->oname);
2086: fatal("'%s' is not in legal name syntax (%s)",
2087: lookup->origin->origin,
2088: isc_result_totext(result));
2089: }
2090: if (lookup->trace && lookup->trace_root) {
2091: dns_name_clone(dns_rootname, lookup->name);
2092: } else {
2093: dns_fixedname_t fixed;
2094: dns_name_t *name;
2095:
2096: dns_fixedname_init(&fixed);
2097: name = dns_fixedname_name(&fixed);
2098: len = (unsigned int) strlen(lookup->textname);
2099: isc_buffer_init(&b, lookup->textname, len);
2100: isc_buffer_add(&b, len);
2101: result = dns_name_fromtext(name, &b, NULL, 0, NULL);
2102: if (result == ISC_R_SUCCESS &&
2103: !dns_name_isabsolute(name))
2104: result = dns_name_concatenate(name,
2105: lookup->oname,
2106: lookup->name,
2107: &lookup->namebuf);
2108: else if (result == ISC_R_SUCCESS)
2109: result = dns_name_copy(name, lookup->name,
2110: &lookup->namebuf);
2111: if (result != ISC_R_SUCCESS) {
2112: dns_message_puttempname(lookup->sendmsg,
2113: &lookup->name);
2114: dns_message_puttempname(lookup->sendmsg,
2115: &lookup->oname);
2116: if (result == DNS_R_NAMETOOLONG)
2117: return (ISC_FALSE);
2118: fatal("'%s' is not in legal name syntax (%s)",
2119: lookup->textname,
2120: isc_result_totext(result));
2121: }
2122: }
2123: dns_message_puttempname(lookup->sendmsg, &lookup->oname);
2124: } else
2125: {
2126: debug("using root origin");
2127: if (lookup->trace && lookup->trace_root)
2128: dns_name_clone(dns_rootname, lookup->name);
2129: else {
2130: len = (unsigned int) strlen(lookup->textname);
2131: isc_buffer_init(&b, lookup->textname, len);
2132: isc_buffer_add(&b, len);
2133: result = dns_name_fromtext(lookup->name, &b,
2134: dns_rootname, 0,
2135: &lookup->namebuf);
2136: }
2137: if (result != ISC_R_SUCCESS) {
2138: dns_message_puttempname(lookup->sendmsg,
2139: &lookup->name);
2140: fatal("'%s' is not a legal name "
2141: "(%s)", lookup->textname,
2142: isc_result_totext(result));
2143: }
2144: }
2145: dns_name_format(lookup->name, store, sizeof(store));
2146: dighost_trying(store, lookup);
2147: INSIST(dns_name_isabsolute(lookup->name));
2148:
2149: id = arc4random();
2150: lookup->sendmsg->id = (unsigned short)id & 0xFFFF;
2151: lookup->sendmsg->opcode = lookup->opcode;
2152: lookup->msgcounter = 0;
2153: /*
2154: * If this is a trace request, completely disallow recursion, since
2155: * it's meaningless for traces.
2156: */
2157: if (lookup->trace || (lookup->ns_search_only && !lookup->trace_root))
2158: lookup->recurse = ISC_FALSE;
2159:
2160: if (lookup->recurse &&
2161: lookup->rdtype != dns_rdatatype_axfr &&
2162: lookup->rdtype != dns_rdatatype_ixfr) {
2163: debug("recursive query");
2164: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_RD;
2165: }
2166:
2167: /* XXX aaflag */
2168: if (lookup->aaonly) {
2169: debug("AA query");
2170: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AA;
2171: }
2172:
2173: if (lookup->adflag) {
2174: debug("AD query");
2175: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_AD;
2176: }
2177:
2178: if (lookup->cdflag) {
2179: debug("CD query");
2180: lookup->sendmsg->flags |= DNS_MESSAGEFLAG_CD;
2181: }
2182:
2183: dns_message_addname(lookup->sendmsg, lookup->name,
2184: DNS_SECTION_QUESTION);
2185:
2186: if (lookup->trace && lookup->trace_root) {
2187: lookup->qrdtype = lookup->rdtype;
2188: lookup->rdtype = dns_rdatatype_ns;
2189: }
2190:
2191: if ((lookup->rdtype == dns_rdatatype_axfr) ||
2192: (lookup->rdtype == dns_rdatatype_ixfr)) {
2193: /*
2194: * Force TCP mode if we're doing an axfr.
2195: */
2196: if (lookup->rdtype == dns_rdatatype_axfr) {
2197: lookup->doing_xfr = ISC_TRUE;
2198: lookup->tcp_mode = ISC_TRUE;
2199: } else if (lookup->tcp_mode) {
2200: lookup->doing_xfr = ISC_TRUE;
2201: }
2202: }
2203:
2204: add_question(lookup->sendmsg, lookup->name, lookup->rdclass,
2205: lookup->rdtype);
2206:
2207: /* add_soa */
2208: if (lookup->rdtype == dns_rdatatype_ixfr)
2209: insert_soa(lookup);
2210:
2211: /* XXX Insist this? */
2212: lookup->tsigctx = NULL;
2213: lookup->querysig = NULL;
2214: if (tsigkey != NULL) {
2215: debug("initializing keys");
2216: result = dns_message_settsigkey(lookup->sendmsg, tsigkey);
2217: check_result(result, "dns_message_settsigkey");
2218: }
2219:
2220: lookup->sendspace = malloc(COMMSIZE);
2221: if (lookup->sendspace == NULL)
2222: fatal("memory allocation failure");
2223:
2224: result = dns_compress_init(&cctx, -1);
2225: check_result(result, "dns_compress_init");
2226:
2227: debug("starting to render the message");
2228: isc_buffer_init(&lookup->renderbuf, lookup->sendspace, COMMSIZE);
2229: result = dns_message_renderbegin(lookup->sendmsg, &cctx,
2230: &lookup->renderbuf);
2231: check_result(result, "dns_message_renderbegin");
2232: if (lookup->udpsize > 0 || lookup->dnssec ||
2233: lookup->edns > -1 || lookup->ecs_addr != NULL)
2234: {
2235: #define MAXOPTS (EDNSOPT_OPTIONS + DNS_EDNSOPTIONS)
2236: dns_ednsopt_t opts[MAXOPTS];
2237: unsigned int flags;
2238: unsigned int i = 0;
2239:
2240: if (lookup->udpsize == 0)
2241: lookup->udpsize = 4096;
2242: if (lookup->edns < 0)
2243: lookup->edns = 0;
2244:
2245: if (lookup->nsid) {
2246: INSIST(i < MAXOPTS);
2247: opts[i].code = DNS_OPT_NSID;
2248: opts[i].length = 0;
2249: opts[i].value = NULL;
2250: i++;
2251: }
2252:
2253: if (lookup->ecs_addr != NULL) {
2254: uint8_t addr[16];
2255: uint16_t family;
2256: uint32_t plen;
2257: struct sockaddr *sa;
2258: struct sockaddr_in *sin;
2259: struct sockaddr_in6 *sin6;
2260: size_t addrl;
2261:
2262: sa = &lookup->ecs_addr->type.sa;
2263: plen = lookup->ecs_addr->length;
2264:
2265: /* Round up prefix len to a multiple of 8 */
2266: addrl = (plen + 7) / 8;
2267:
2268: INSIST(i < MAXOPTS);
2269: opts[i].code = DNS_OPT_CLIENT_SUBNET;
2270: opts[i].length = (uint16_t) addrl + 4;
2271: check_result(result, "isc_buffer_allocate");
2272:
2273: /*
2274: * XXXMUKS: According to RFC7871, "If there is
2275: * no ADDRESS set, i.e., SOURCE PREFIX-LENGTH is
2276: * set to 0, then FAMILY SHOULD be set to the
2277: * transport over which the query is sent."
2278: *
2279: * However, at this point we don't know what
2280: * transport(s) we'll be using, so we can't
2281: * set the value now. For now, we're using
2282: * IPv4 as the default the +subnet option
2283: * used an IPv4 prefix, or for +subnet=0,
2284: * and IPv6 if the +subnet option used an
2285: * IPv6 prefix.
2286: *
2287: * (For future work: preserve the offset into
2288: * the buffer where the family field is;
2289: * that way we can update it in send_udp()
2290: * or send_tcp_connect() once we know
2291: * what it outght to be.)
2292: */
2293: switch (sa->sa_family) {
2294: case AF_UNSPEC:
2295: INSIST(plen == 0);
2296: family = 1;
2297: break;
2298: case AF_INET:
2299: INSIST(plen <= 32);
2300: family = 1;
2301: sin = (struct sockaddr_in *) sa;
2302: memmove(addr, &sin->sin_addr, addrl);
2303: break;
2304: case AF_INET6:
2305: INSIST(plen <= 128);
2306: family = 2;
2307: sin6 = (struct sockaddr_in6 *) sa;
2308: memmove(addr, &sin6->sin6_addr, addrl);
2309: break;
2310: default:
2311: INSIST(0);
2312: }
2313:
2314: isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
2315: /* family */
2316: isc_buffer_putuint16(&b, family);
2317: /* source prefix-length */
2318: isc_buffer_putuint8(&b, plen);
2319: /* scope prefix-length */
2320: isc_buffer_putuint8(&b, 0);
2321:
2322: /* address */
2323: if (addrl > 0) {
2324: /* Mask off last address byte */
2325: if ((plen % 8) != 0)
2326: addr[addrl - 1] &=
2327: ~0U << (8 - (plen % 8));
2328: isc_buffer_putmem(&b, addr,
2329: (unsigned)addrl);
2330: }
2331:
2332: opts[i].value = (uint8_t *) ecsbuf;
2333: i++;
2334: }
2335:
2336: if (lookup->sit) {
2337: INSIST(i < MAXOPTS);
2338: opts[i].code = DNS_OPT_COOKIE;
2339: if (lookup->sitvalue != NULL) {
2340: isc_buffer_init(&b, sitbuf, sizeof(sitbuf));
2341: result = isc_hex_decodestring(lookup->sitvalue,
2342: &b);
2343: check_result(result, "isc_hex_decodestring");
2344: opts[i].value = isc_buffer_base(&b);
2345: opts[i].length = isc_buffer_usedlength(&b);
2346: } else {
2347: compute_cookie(cookie, sizeof(cookie));
2348: opts[i].length = 8;
2349: opts[i].value = cookie;
2350: }
2351: i++;
2352: }
2353:
2354: if (lookup->expire) {
2355: INSIST(i < MAXOPTS);
2356: opts[i].code = DNS_OPT_EXPIRE;
2357: opts[i].length = 0;
2358: opts[i].value = NULL;
2359: i++;
2360: }
2361:
2362: if (lookup->ednsoptscnt != 0) {
2363: INSIST(i + lookup->ednsoptscnt <= MAXOPTS);
2364: memmove(&opts[i], lookup->ednsopts,
2365: sizeof(dns_ednsopt_t) * lookup->ednsoptscnt);
2366: i += lookup->ednsoptscnt;
2367: }
2368:
2369: flags = lookup->ednsflags;
2370: flags &= ~DNS_MESSAGEEXTFLAG_DO;
2371: if (lookup->dnssec)
2372: flags |= DNS_MESSAGEEXTFLAG_DO;
2373: add_opt(lookup->sendmsg, lookup->udpsize,
2374: lookup->edns, flags, opts, i);
2375: }
2376:
2377: result = dns_message_rendersection(lookup->sendmsg,
2378: DNS_SECTION_QUESTION, 0);
2379: check_result(result, "dns_message_rendersection");
2380: result = dns_message_rendersection(lookup->sendmsg,
2381: DNS_SECTION_AUTHORITY, 0);
2382: check_result(result, "dns_message_rendersection");
2383: result = dns_message_renderend(lookup->sendmsg);
2384: check_result(result, "dns_message_renderend");
2385: debug("done rendering");
2386:
2387: dns_compress_invalidate(&cctx);
2388:
2389: /*
2390: * Force TCP mode if the request is larger than 512 bytes.
2391: */
2392: if (isc_buffer_usedlength(&lookup->renderbuf) > 512)
2393: lookup->tcp_mode = ISC_TRUE;
2394:
2395: lookup->pending = ISC_FALSE;
2396:
2397: for (serv = ISC_LIST_HEAD(lookup->my_server_list);
2398: serv != NULL;
2399: serv = ISC_LIST_NEXT(serv, link)) {
2400: query = malloc(sizeof(dig_query_t));
2401: if (query == NULL)
2402: fatal("memory allocation failure in %s:%d",
2403: __FILE__, __LINE__);
2404: debug("create query %p linked to lookup %p",
2405: query, lookup);
2406: query->lookup = lookup;
2407: query->timer = NULL;
2408: query->waiting_connect = ISC_FALSE;
2409: query->waiting_senddone = ISC_FALSE;
2410: query->pending_free = ISC_FALSE;
2411: query->recv_made = ISC_FALSE;
2412: query->first_pass = ISC_TRUE;
2413: query->first_soa_rcvd = ISC_FALSE;
2414: query->second_rr_rcvd = ISC_FALSE;
2415: query->first_repeat_rcvd = ISC_FALSE;
2416: query->warn_id = ISC_TRUE;
2417: query->timedout = ISC_FALSE;
2418: query->first_rr_serial = 0;
2419: query->second_rr_serial = 0;
2420: query->servname = serv->servername;
2421: query->userarg = serv->userarg;
2422: query->rr_count = 0;
2423: query->msg_count = 0;
2424: query->byte_count = 0;
2425: query->ixfr_axfr = ISC_FALSE;
2426: ISC_LIST_INIT(query->recvlist);
2427: ISC_LIST_INIT(query->lengthlist);
2428: query->sock = NULL;
2429: query->recvspace = malloc(COMMSIZE);
2430: if (query->recvspace == NULL)
2431: fatal("memory allocation failure");
2432:
2433: isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
2434: isc_buffer_init(&query->lengthbuf, query->lengthspace, 2);
2435: isc_buffer_init(&query->slbuf, query->slspace, 2);
2436: query->sendbuf = lookup->renderbuf;
2437:
2438: ISC_LINK_INIT(query, clink);
2439: ISC_LINK_INIT(query, link);
2440: ISC_LIST_ENQUEUE(lookup->q, query, link);
2441: }
2442:
2443: /* XXX qrflag, print_query, etc... */
2444: if (!ISC_LIST_EMPTY(lookup->q) && qr) {
2445: extrabytes = 0;
2446: dighost_printmessage(ISC_LIST_HEAD(lookup->q), lookup->sendmsg,
2447: ISC_TRUE);
2448: }
2449: return (ISC_TRUE);
2450: }
2451:
2452: /*%
2453: * Event handler for send completion. Track send counter, and clear out
2454: * the query if the send was canceled.
2455: */
2456: static void
2457: send_done(isc_task_t *_task, isc_event_t *event) {
2458: isc_socketevent_t *sevent = (isc_socketevent_t *)event;
2459: isc_buffer_t *b = NULL;
2460: dig_query_t *query, *next;
2461: dig_lookup_t *l;
2462:
2463: REQUIRE(event->ev_type == ISC_SOCKEVENT_SENDDONE);
2464:
2465: UNUSED(_task);
2466:
2467: debug("send_done()");
2468: sendcount--;
2469: debug("sendcount=%d", sendcount);
2470: INSIST(sendcount >= 0);
2471:
2472: for (b = ISC_LIST_HEAD(sevent->bufferlist);
2473: b != NULL;
2474: b = ISC_LIST_HEAD(sevent->bufferlist)) {
2475: ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2476: free(b);
2477: }
2478:
2479: query = event->ev_arg;
2480: query->waiting_senddone = ISC_FALSE;
2481: l = query->lookup;
2482:
2483: if (l->ns_search_only && !l->trace_root && !l->tcp_mode) {
2484: debug("sending next, since searching");
2485: next = ISC_LIST_NEXT(query, link);
2486: if (next != NULL)
2487: send_udp(next);
2488: }
2489:
2490: isc_event_free(&event);
2491:
2492: if (query->pending_free)
2493: free(query);
2494:
2495: check_if_done();
2496: }
2497:
2498: /*%
2499: * Cancel a lookup, sending isc_socket_cancel() requests to all outstanding
2500: * IO sockets. The cancel handlers should take care of cleaning up the
2501: * query and lookup structures
2502: */
2503: static void
2504: cancel_lookup(dig_lookup_t *lookup) {
2505: dig_query_t *query, *next;
2506:
2507: debug("cancel_lookup()");
2508: query = ISC_LIST_HEAD(lookup->q);
2509: while (query != NULL) {
2510: next = ISC_LIST_NEXT(query, link);
2511: if (query->sock != NULL) {
2512: isc_socket_cancel(query->sock, global_task,
2513: ISC_SOCKCANCEL_ALL);
2514: check_if_done();
2515: } else {
2516: clear_query(query);
2517: }
2518: query = next;
2519: }
2520: lookup->pending = ISC_FALSE;
2521: lookup->retries = 0;
2522: }
2523:
2524: static void
2525: bringup_timer(dig_query_t *query, unsigned int default_timeout) {
2526: dig_lookup_t *l;
2527: unsigned int local_timeout;
2528: isc_result_t result;
2529:
2530: debug("bringup_timer()");
2531: /*
2532: * If the timer already exists, that means we're calling this
2533: * a second time (for a retry). Don't need to recreate it,
2534: * just reset it.
2535: */
2536: l = query->lookup;
2537: if (ISC_LINK_LINKED(query, link) && ISC_LIST_NEXT(query, link) != NULL)
2538: local_timeout = SERVER_TIMEOUT;
2539: else {
2540: if (timeout == 0)
2541: local_timeout = default_timeout;
2542: else
2543: local_timeout = timeout;
2544: }
2545: debug("have local timeout of %d", local_timeout);
1.9 ! florian 2546: l->interval.tv_sec = local_timeout;
! 2547: l->interval.tv_nsec = 0;
1.1 florian 2548: if (query->timer != NULL)
2549: isc_timer_detach(&query->timer);
1.7 florian 2550: result = isc_timer_create(timermgr,
1.1 florian 2551: &l->interval, global_task, connect_timeout,
2552: query, &query->timer);
2553: check_result(result, "isc_timer_create");
2554: }
2555:
2556: static void
2557: force_timeout(dig_query_t *query) {
2558: isc_event_t *event;
2559:
2560: debug("force_timeout ()");
2561: event = isc_event_allocate(query, ISC_TIMEREVENT_IDLE,
2562: connect_timeout, query,
2563: sizeof(isc_event_t));
2564: if (event == NULL) {
2565: fatal("isc_event_allocate: %s",
2566: isc_result_totext(ISC_R_NOMEMORY));
2567: }
2568: isc_task_send(global_task, &event);
2569:
2570: /*
2571: * The timer may have expired if, for example, get_address() takes
2572: * long time and the timer was running on a different thread.
2573: * We need to cancel the possible timeout event not to confuse
2574: * ourselves due to the duplicate events.
2575: */
2576: if (query->timer != NULL)
2577: isc_timer_detach(&query->timer);
2578: }
2579:
2580:
2581: static void
2582: connect_done(isc_task_t *task, isc_event_t *event);
2583:
2584: /*%
2585: * Unlike send_udp, this can't be called multiple times with the same
2586: * query. When we retry TCP, we requeue the whole lookup, which should
2587: * start anew.
2588: */
2589: static void
2590: send_tcp_connect(dig_query_t *query) {
2591: isc_result_t result;
2592: dig_query_t *next;
2593: dig_lookup_t *l;
2594:
2595: debug("send_tcp_connect(%p)", query);
2596:
2597: l = query->lookup;
2598: query->waiting_connect = ISC_TRUE;
2599: query->lookup->current_query = query;
2600: result = get_address(query->servname, port, &query->sockaddr);
2601: if (result != ISC_R_SUCCESS) {
2602: /*
2603: * This servname doesn't have an address. Try the next server
2604: * by triggering an immediate 'timeout' (we lie, but the effect
2605: * is the same).
2606: */
2607: force_timeout(query);
2608: return;
2609: }
2610:
2611: if (specified_source &&
2612: (isc_sockaddr_pf(&query->sockaddr) !=
2613: isc_sockaddr_pf(&bind_address))) {
2614: printf(";; Skipping server %s, incompatible "
2615: "address family\n", query->servname);
2616: query->waiting_connect = ISC_FALSE;
2617: if (ISC_LINK_LINKED(query, link))
2618: next = ISC_LIST_NEXT(query, link);
2619: else
2620: next = NULL;
2621: l = query->lookup;
2622: clear_query(query);
2623: if (next == NULL) {
2624: printf(";; No acceptable nameservers\n");
2625: check_next_lookup(l);
2626: return;
2627: }
2628: send_tcp_connect(next);
2629: return;
2630: }
2631:
2632: INSIST(query->sock == NULL);
2633:
2634: if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) {
2635: sockcount++;
2636: isc_socket_attach(keep, &query->sock);
2637: query->waiting_connect = ISC_FALSE;
2638: launch_next_query(query, ISC_TRUE);
2639: goto search;
2640: }
2641:
2642: result = isc_socket_create(socketmgr,
2643: isc_sockaddr_pf(&query->sockaddr),
2644: isc_sockettype_tcp, &query->sock);
2645: check_result(result, "isc_socket_create");
2646: sockcount++;
2647: debug("sockcount=%d", sockcount);
2648: if (specified_source)
2649: result = isc_socket_bind(query->sock, &bind_address,
2650: ISC_SOCKET_REUSEADDRESS);
2651: else {
2652: if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
2653: have_ipv4)
2654: isc_sockaddr_any(&bind_any);
2655: else
2656: isc_sockaddr_any6(&bind_any);
2657: result = isc_socket_bind(query->sock, &bind_any, 0);
2658: }
2659: check_result(result, "isc_socket_bind");
2660: bringup_timer(query, TCP_TIMEOUT);
2661: result = isc_socket_connect(query->sock, &query->sockaddr,
2662: global_task, connect_done, query);
2663: check_result(result, "isc_socket_connect");
2664: search:
2665: /*
2666: * If we're at the endgame of a nameserver search, we need to
2667: * immediately bring up all the queries. Do it here.
2668: */
2669: if (l->ns_search_only && !l->trace_root) {
2670: debug("sending next, since searching");
2671: if (ISC_LINK_LINKED(query, link)) {
2672: next = ISC_LIST_NEXT(query, link);
2673: ISC_LIST_DEQUEUE(l->q, query, link);
2674: } else
2675: next = NULL;
2676: ISC_LIST_ENQUEUE(l->connecting, query, clink);
2677: if (next != NULL)
2678: send_tcp_connect(next);
2679: }
2680: }
2681:
2682: static isc_buffer_t *
2683: clone_buffer(isc_buffer_t *source) {
2684: isc_buffer_t *buffer;
2685: buffer = malloc(sizeof(*buffer));
2686: if (buffer == NULL)
2687: fatal("memory allocation failure in %s:%d",
2688: __FILE__, __LINE__);
2689: *buffer = *source;
2690: return (buffer);
2691: }
2692:
2693: /*%
2694: * Send a UDP packet to the remote nameserver, possible starting the
2695: * recv action as well. Also make sure that the timer is running and
2696: * is properly reset.
2697: */
2698: static void
2699: send_udp(dig_query_t *query) {
2700: dig_lookup_t *l = NULL;
2701: isc_result_t result;
2702: isc_buffer_t *sendbuf;
2703:
2704: debug("send_udp(%p)", query);
2705:
2706: l = query->lookup;
2707: bringup_timer(query, UDP_TIMEOUT);
2708: l->current_query = query;
2709: debug("working on lookup %p, query %p", query->lookup, query);
2710: if (!query->recv_made) {
2711: /* XXX Check the sense of this, need assertion? */
2712: query->waiting_connect = ISC_FALSE;
2713: result = get_address(query->servname, port, &query->sockaddr);
2714: if (result != ISC_R_SUCCESS) {
2715: /* This servname doesn't have an address. */
2716: force_timeout(query);
2717: return;
2718: }
2719:
2720: result = isc_socket_create(socketmgr,
2721: isc_sockaddr_pf(&query->sockaddr),
2722: isc_sockettype_udp, &query->sock);
2723: check_result(result, "isc_socket_create");
2724: sockcount++;
2725: debug("sockcount=%d", sockcount);
2726: if (specified_source) {
2727: result = isc_socket_bind(query->sock, &bind_address,
2728: ISC_SOCKET_REUSEADDRESS);
2729: } else {
2730: isc_sockaddr_anyofpf(&bind_any,
2731: isc_sockaddr_pf(&query->sockaddr));
2732: result = isc_socket_bind(query->sock, &bind_any, 0);
2733: }
2734: check_result(result, "isc_socket_bind");
2735:
2736: query->recv_made = ISC_TRUE;
2737: ISC_LINK_INIT(&query->recvbuf, link);
2738: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,
2739: link);
2740: debug("recving with lookup=%p, query=%p, sock=%p",
2741: query->lookup, query, query->sock);
2742: result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2743: global_task, recv_done, query);
2744: check_result(result, "isc_socket_recvv");
2745: recvcount++;
2746: debug("recvcount=%d", recvcount);
2747: }
2748: ISC_LIST_INIT(query->sendlist);
2749: sendbuf = clone_buffer(&query->sendbuf);
2750: ISC_LIST_ENQUEUE(query->sendlist, sendbuf, link);
2751: debug("sending a request");
2752: TIME_NOW(&query->time_sent);
2753: INSIST(query->sock != NULL);
2754: query->waiting_senddone = ISC_TRUE;
2755: result = isc_socket_sendtov2(query->sock, &query->sendlist,
2756: global_task, send_done, query,
2757: &query->sockaddr, NULL,
2758: ISC_SOCKFLAG_NORETRY);
2759: check_result(result, "isc_socket_sendtov");
2760: sendcount++;
2761: }
2762:
2763: /*%
2764: * IO timeout handler, used for both connect and recv timeouts. If
2765: * retries are still allowed, either resend the UDP packet or queue a
2766: * new TCP lookup. Otherwise, cancel the lookup.
2767: */
2768: static void
2769: connect_timeout(isc_task_t *task, isc_event_t *event) {
2770: dig_lookup_t *l = NULL;
2771: dig_query_t *query = NULL, *cq;
2772:
2773: UNUSED(task);
2774: REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);
2775:
2776: debug("connect_timeout()");
2777:
2778: query = event->ev_arg;
2779: l = query->lookup;
2780: isc_event_free(&event);
2781:
2782: INSIST(!free_now);
2783:
2784: if ((query != NULL) && (query->lookup->current_query != NULL) &&
2785: ISC_LINK_LINKED(query->lookup->current_query, link) &&
2786: (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {
2787: debug("trying next server...");
2788: cq = query->lookup->current_query;
2789: if (!l->tcp_mode)
2790: send_udp(ISC_LIST_NEXT(cq, link));
2791: else {
2792: if (query->sock != NULL)
2793: isc_socket_cancel(query->sock, NULL,
2794: ISC_SOCKCANCEL_ALL);
2795: send_tcp_connect(ISC_LIST_NEXT(cq, link));
2796: }
2797: return;
2798: }
2799:
2800: if (l->tcp_mode && query->sock != NULL) {
2801: query->timedout = ISC_TRUE;
2802: isc_socket_cancel(query->sock, NULL, ISC_SOCKCANCEL_ALL);
2803: }
2804:
2805: if (l->retries > 1) {
2806: if (!l->tcp_mode) {
2807: l->retries--;
2808: debug("resending UDP request to first server");
2809: send_udp(ISC_LIST_HEAD(l->q));
2810: } else {
2811: debug("making new TCP request, %d tries left",
2812: l->retries);
2813: l->retries--;
2814: requeue_lookup(l, ISC_TRUE);
2815: cancel_lookup(l);
2816: check_next_lookup(l);
2817: }
2818: } else {
2819: if (!l->ns_search_only) {
2820: fputs(l->cmdline, stdout);
2821: printf(";; connection timed out; no servers could be "
2822: "reached\n");
2823: }
2824: cancel_lookup(l);
2825: check_next_lookup(l);
2826: if (exitcode < 9)
2827: exitcode = 9;
2828: }
2829: }
2830:
2831: /*%
2832: * Event handler for the TCP recv which gets the length header of TCP
2833: * packets. Start the next recv of length bytes.
2834: */
2835: static void
2836: tcp_length_done(isc_task_t *task, isc_event_t *event) {
2837: isc_socketevent_t *sevent;
2838: isc_buffer_t *b = NULL;
2839: isc_result_t result;
2840: dig_query_t *query = NULL;
2841: dig_lookup_t *l, *n;
2842: uint16_t length;
2843:
2844: REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2845: INSIST(!free_now);
2846:
2847: UNUSED(task);
2848:
2849: debug("tcp_length_done()");
2850:
2851: sevent = (isc_socketevent_t *)event;
2852: query = event->ev_arg;
2853:
2854: recvcount--;
2855: INSIST(recvcount >= 0);
2856:
2857: b = ISC_LIST_HEAD(sevent->bufferlist);
2858: INSIST(b == &query->lengthbuf);
2859: ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2860:
2861: if (sevent->result == ISC_R_CANCELED) {
2862: isc_event_free(&event);
2863: l = query->lookup;
2864: clear_query(query);
2865: check_next_lookup(l);
2866: return;
2867: }
2868: if (sevent->result != ISC_R_SUCCESS) {
2869: char sockstr[ISC_SOCKADDR_FORMATSIZE];
2870: isc_sockaddr_format(&query->sockaddr, sockstr,
2871: sizeof(sockstr));
2872: printf(";; communications error to %s: %s\n",
2873: sockstr, isc_result_totext(sevent->result));
2874: if (keep != NULL)
2875: isc_socket_detach(&keep);
2876: l = query->lookup;
2877: isc_socket_detach(&query->sock);
2878: sockcount--;
2879: debug("sockcount=%d", sockcount);
2880: INSIST(sockcount >= 0);
2881: if (sevent->result == ISC_R_EOF && l->eoferr == 0U) {
2882: n = requeue_lookup(l, ISC_TRUE);
2883: n->eoferr++;
2884: }
2885: isc_event_free(&event);
2886: clear_query(query);
2887: cancel_lookup(l);
2888: check_next_lookup(l);
2889: return;
2890: }
2891: length = isc_buffer_getuint16(b);
2892: if (length == 0) {
2893: isc_event_free(&event);
2894: launch_next_query(query, ISC_FALSE);
2895: return;
2896: }
2897:
2898: /*
2899: * Even though the buffer was already init'ed, we need
2900: * to redo it now, to force the length we want.
2901: */
2902: isc_buffer_invalidate(&query->recvbuf);
2903: isc_buffer_init(&query->recvbuf, query->recvspace, length);
2904: ENSURE(ISC_LIST_EMPTY(query->recvlist));
2905: ISC_LINK_INIT(&query->recvbuf, link);
2906: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
2907: debug("recving with lookup=%p, query=%p", query->lookup, query);
2908: result = isc_socket_recvv(query->sock, &query->recvlist, length, task,
2909: recv_done, query);
2910: check_result(result, "isc_socket_recvv");
2911: recvcount++;
2912: debug("resubmitted recv request with length %d, recvcount=%d",
2913: length, recvcount);
2914: isc_event_free(&event);
2915: }
2916:
2917: /*%
2918: * For transfers that involve multiple recvs (XFR's in particular),
2919: * launch the next recv.
2920: */
2921: static void
2922: launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
2923: isc_result_t result;
2924: dig_lookup_t *l;
2925: isc_buffer_t *buffer;
2926:
2927: INSIST(!free_now);
2928:
2929: debug("launch_next_query()");
2930:
2931: if (!query->lookup->pending) {
2932: debug("ignoring launch_next_query because !pending");
2933: isc_socket_detach(&query->sock);
2934: sockcount--;
2935: debug("sockcount=%d", sockcount);
2936: INSIST(sockcount >= 0);
2937: query->waiting_connect = ISC_FALSE;
2938: l = query->lookup;
2939: clear_query(query);
2940: check_next_lookup(l);
2941: return;
2942: }
2943:
2944: isc_buffer_clear(&query->slbuf);
2945: isc_buffer_clear(&query->lengthbuf);
2946: isc_buffer_putuint16(&query->slbuf, (uint16_t) query->sendbuf.used);
2947: ISC_LIST_INIT(query->sendlist);
2948: ISC_LINK_INIT(&query->slbuf, link);
2949: if (!query->first_soa_rcvd) {
2950: buffer = clone_buffer(&query->slbuf);
2951: ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
2952: if (include_question) {
2953: buffer = clone_buffer(&query->sendbuf);
2954: ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
2955: }
2956: }
2957:
2958: ISC_LINK_INIT(&query->lengthbuf, link);
2959: ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
2960:
2961: result = isc_socket_recvv(query->sock, &query->lengthlist, 0,
2962: global_task, tcp_length_done, query);
2963: check_result(result, "isc_socket_recvv");
2964: recvcount++;
2965: debug("recvcount=%d", recvcount);
2966: if (!query->first_soa_rcvd) {
2967: debug("sending a request in launch_next_query");
2968: TIME_NOW(&query->time_sent);
2969: query->waiting_senddone = ISC_TRUE;
2970: result = isc_socket_sendv(query->sock, &query->sendlist,
2971: global_task, send_done, query);
2972: check_result(result, "isc_socket_sendv");
2973: sendcount++;
2974: debug("sendcount=%d", sendcount);
2975: }
2976: query->waiting_connect = ISC_FALSE;
2977: return;
2978: }
2979:
2980: /*%
2981: * Event handler for TCP connect complete. Make sure the connection was
2982: * successful, then pass into launch_next_query to actually send the
2983: * question.
2984: */
2985: static void
2986: connect_done(isc_task_t *task, isc_event_t *event) {
2987: char sockstr[ISC_SOCKADDR_FORMATSIZE];
2988: isc_socketevent_t *sevent = NULL;
2989: dig_query_t *query = NULL, *next;
2990: dig_lookup_t *l;
2991:
2992: UNUSED(task);
2993:
2994: REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
2995: INSIST(!free_now);
2996:
2997: debug("connect_done()");
2998:
2999: sevent = (isc_socketevent_t *)event;
3000: query = sevent->ev_arg;
3001:
3002: INSIST(query->waiting_connect);
3003:
3004: query->waiting_connect = ISC_FALSE;
3005:
3006: if (sevent->result == ISC_R_CANCELED) {
3007: debug("in cancel handler");
3008: isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
3009: if (query->timedout)
3010: printf(";; Connection to %s(%s) for %s failed: %s.\n",
3011: sockstr, query->servname,
3012: query->lookup->textname,
3013: isc_result_totext(ISC_R_TIMEDOUT));
3014: isc_socket_detach(&query->sock);
3015: INSIST(sockcount > 0);
3016: sockcount--;
3017: debug("sockcount=%d", sockcount);
3018: query->waiting_connect = ISC_FALSE;
3019: isc_event_free(&event);
3020: l = query->lookup;
3021: clear_query(query);
3022: check_next_lookup(l);
3023: return;
3024: }
3025: if (sevent->result != ISC_R_SUCCESS) {
3026:
3027: debug("unsuccessful connection: %s",
3028: isc_result_totext(sevent->result));
3029: isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
3030: if (sevent->result != ISC_R_CANCELED)
3031: printf(";; Connection to %s(%s) for %s failed: "
3032: "%s.\n", sockstr,
3033: query->servname, query->lookup->textname,
3034: isc_result_totext(sevent->result));
3035: isc_socket_detach(&query->sock);
3036: INSIST(sockcount > 0);
3037: sockcount--;
3038: /* XXX Clean up exitcodes */
3039: if (exitcode < 9)
3040: exitcode = 9;
3041: debug("sockcount=%d", sockcount);
3042: query->waiting_connect = ISC_FALSE;
3043: isc_event_free(&event);
3044: l = query->lookup;
3045: if ((l->current_query != NULL) &&
3046: (ISC_LINK_LINKED(l->current_query, link)))
3047: next = ISC_LIST_NEXT(l->current_query, link);
3048: else
3049: next = NULL;
3050: clear_query(query);
3051: if (next != NULL) {
3052: bringup_timer(next, TCP_TIMEOUT);
3053: send_tcp_connect(next);
3054: } else
3055: check_next_lookup(l);
3056: return;
3057: }
3058: if (keep_open) {
3059: if (keep != NULL)
3060: isc_socket_detach(&keep);
3061: isc_socket_attach(query->sock, &keep);
3062: keepaddr = query->sockaddr;
3063: }
3064: launch_next_query(query, ISC_TRUE);
3065: isc_event_free(&event);
3066: }
3067:
3068: /*%
3069: * Check if the ongoing XFR needs more data before it's complete, using
3070: * the semantics of IXFR and AXFR protocols. Much of the complexity of
3071: * this routine comes from determining when an IXFR is complete.
3072: * ISC_FALSE means more data is on the way, and the recv has been issued.
3073: */
3074: static isc_boolean_t
3075: check_for_more_data(dig_query_t *query, dns_message_t *msg,
3076: isc_socketevent_t *sevent)
3077: {
3078: dns_rdataset_t *rdataset = NULL;
3079: dns_rdata_t rdata = DNS_RDATA_INIT;
3080: dns_rdata_soa_t soa;
3081: uint32_t ixfr_serial = query->lookup->ixfr_serial, serial;
3082: isc_result_t result;
3083: isc_boolean_t ixfr = query->lookup->rdtype == dns_rdatatype_ixfr;
3084: isc_boolean_t axfr = query->lookup->rdtype == dns_rdatatype_axfr;
3085:
3086: if (ixfr)
3087: axfr = query->ixfr_axfr;
3088:
3089: debug("check_for_more_data()");
3090:
3091: /*
3092: * By the time we're in this routine, we know we're doing
3093: * either an AXFR or IXFR. If there's no second_rr_type,
3094: * then we don't yet know which kind of answer we got back
3095: * from the server. Here, we're going to walk through the
3096: * rr's in the message, acting as necessary whenever we hit
3097: * an SOA rr.
3098: */
3099:
3100: query->msg_count++;
3101: query->byte_count += sevent->n;
3102: result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
3103: if (result != ISC_R_SUCCESS) {
3104: puts("; Transfer failed.");
3105: return (ISC_TRUE);
3106: }
3107: do {
3108: dns_name_t *name;
3109: name = NULL;
3110: dns_message_currentname(msg, DNS_SECTION_ANSWER,
3111: &name);
3112: for (rdataset = ISC_LIST_HEAD(name->list);
3113: rdataset != NULL;
3114: rdataset = ISC_LIST_NEXT(rdataset, link)) {
3115: result = dns_rdataset_first(rdataset);
3116: if (result != ISC_R_SUCCESS)
3117: continue;
3118: do {
3119: query->rr_count++;
3120: dns_rdata_reset(&rdata);
3121: dns_rdataset_current(rdataset, &rdata);
3122: /*
3123: * If this is the first rr, make sure
3124: * it's an SOA
3125: */
3126: if ((!query->first_soa_rcvd) &&
3127: (rdata.type != dns_rdatatype_soa)) {
3128: puts("; Transfer failed. "
3129: "Didn't start with SOA answer.");
3130: return (ISC_TRUE);
3131: }
3132: if ((!query->second_rr_rcvd) &&
3133: (rdata.type != dns_rdatatype_soa)) {
3134: query->second_rr_rcvd = ISC_TRUE;
3135: query->second_rr_serial = 0;
3136: debug("got the second rr as nonsoa");
3137: axfr = query->ixfr_axfr = ISC_TRUE;
3138: goto next_rdata;
3139: }
3140:
3141: /*
3142: * If the record is anything except an SOA
3143: * now, just continue on...
3144: */
3145: if (rdata.type != dns_rdatatype_soa)
3146: goto next_rdata;
3147:
3148: /* Now we have an SOA. Work with it. */
3149: debug("got an SOA");
3150: result = dns_rdata_tostruct(&rdata, &soa);
3151: check_result(result, "dns_rdata_tostruct");
3152: serial = soa.serial;
3153: dns_rdata_freestruct(&soa);
3154: if (!query->first_soa_rcvd) {
3155: query->first_soa_rcvd = ISC_TRUE;
3156: query->first_rr_serial = serial;
3157: debug("this is the first serial %u",
3158: serial);
3159: if (ixfr && isc_serial_ge(ixfr_serial,
3160: serial)) {
3161: debug("got up to date "
3162: "response");
3163: goto doexit;
3164: }
3165: goto next_rdata;
3166: }
3167: if (axfr) {
3168: debug("doing axfr, got second SOA");
3169: goto doexit;
3170: }
3171: if (!query->second_rr_rcvd) {
3172: if (query->first_rr_serial == serial) {
3173: debug("doing ixfr, got "
3174: "empty zone");
3175: goto doexit;
3176: }
3177: debug("this is the second serial %u",
3178: serial);
3179: query->second_rr_rcvd = ISC_TRUE;
3180: query->second_rr_serial = serial;
3181: goto next_rdata;
3182: }
3183: /*
3184: * If we get to this point, we're doing an
3185: * IXFR and have to start really looking
3186: * at serial numbers.
3187: */
3188: if (query->first_rr_serial == serial) {
3189: debug("got a match for ixfr");
3190: if (!query->first_repeat_rcvd) {
3191: query->first_repeat_rcvd =
3192: ISC_TRUE;
3193: goto next_rdata;
3194: }
3195: debug("done with ixfr");
3196: goto doexit;
3197: }
3198: debug("meaningless soa %u", serial);
3199: next_rdata:
3200: result = dns_rdataset_next(rdataset);
3201: } while (result == ISC_R_SUCCESS);
3202: }
3203: result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
3204: } while (result == ISC_R_SUCCESS);
3205: launch_next_query(query, ISC_FALSE);
3206: return (ISC_FALSE);
3207: doexit:
3208: dighost_received(sevent->n, &sevent->address, query);
3209: return (ISC_TRUE);
3210: }
3211:
3212: static void
3213: process_sit(dig_lookup_t *l, dns_message_t *msg,
3214: isc_buffer_t *optbuf, size_t optlen)
3215: {
3216: char bb[256];
3217: isc_buffer_t hexbuf;
3218: size_t len;
3219: const unsigned char *sit;
3220: isc_boolean_t copysit;
3221: isc_result_t result;
3222:
3223: if (l->sitvalue != NULL) {
3224: isc_buffer_init(&hexbuf, bb, sizeof(bb));
3225: result = isc_hex_decodestring(l->sitvalue, &hexbuf);
3226: check_result(result, "isc_hex_decodestring");
3227: sit = isc_buffer_base(&hexbuf);
3228: len = isc_buffer_usedlength(&hexbuf);
3229: copysit = ISC_FALSE;
3230: } else {
3231: sit = cookie;
3232: len = sizeof(cookie);
3233: copysit = ISC_TRUE;
3234: }
3235:
3236: INSIST(msg->sitok == 0 && msg->sitbad == 0);
3237: if (optlen >= len && optlen >= 8U) {
3238: if (isc_safe_memequal(isc_buffer_current(optbuf), sit, 8)) {
3239: msg->sitok = 1;
3240: } else {
3241: printf(";; Warning: SIT client cookie mismatch\n");
3242: msg->sitbad = 1;
3243: copysit = ISC_FALSE;
3244: }
3245: } else {
3246: printf(";; Warning: SIT bad token (too short)\n");
3247: msg->sitbad = 1;
3248: copysit = ISC_FALSE;
3249: }
3250: if (copysit) {
3251: isc_region_t r;
3252:
3253: r.base = isc_buffer_current(optbuf);
3254: r.length = (unsigned int)optlen;
3255: isc_buffer_init(&hexbuf, sitvalue, sizeof(sitvalue));
3256: result = isc_hex_totext(&r, 2, "", &hexbuf);
3257: check_result(result, "isc_hex_totext");
3258: if (isc_buffer_availablelength(&hexbuf) > 0) {
3259: isc_buffer_putuint8(&hexbuf, 0);
3260: l->sitvalue = sitvalue;
3261: }
3262: }
3263: isc_buffer_forward(optbuf, (unsigned int)optlen);
3264: }
3265:
3266: static void
3267: process_opt(dig_lookup_t *l, dns_message_t *msg) {
3268: dns_rdata_t rdata;
3269: isc_result_t result;
3270: isc_buffer_t optbuf;
3271: uint16_t optcode, optlen;
3272: dns_rdataset_t *opt = msg->opt;
3273: isc_boolean_t seen_cookie = ISC_FALSE;
3274:
3275: result = dns_rdataset_first(opt);
3276: if (result == ISC_R_SUCCESS) {
3277: dns_rdata_init(&rdata);
3278: dns_rdataset_current(opt, &rdata);
3279: isc_buffer_init(&optbuf, rdata.data, rdata.length);
3280: isc_buffer_add(&optbuf, rdata.length);
3281: while (isc_buffer_remaininglength(&optbuf) >= 4) {
3282: optcode = isc_buffer_getuint16(&optbuf);
3283: optlen = isc_buffer_getuint16(&optbuf);
3284: switch (optcode) {
3285: case DNS_OPT_COOKIE:
3286: /*
3287: * Only process the first cookie option.
3288: */
3289: if (seen_cookie) {
3290: isc_buffer_forward(&optbuf, optlen);
3291: break;
3292: }
3293: process_sit(l, msg, &optbuf, optlen);
3294: seen_cookie = ISC_TRUE;
3295: break;
3296: default:
3297: isc_buffer_forward(&optbuf, optlen);
3298: break;
3299: }
3300: }
3301: }
3302: }
3303:
3304: static int
3305: ednsvers(dns_rdataset_t *opt) {
3306: return ((opt->ttl >> 16) & 0xff);
3307: }
3308:
3309: /*%
3310: * Event handler for recv complete. Perform whatever actions are necessary,
3311: * based on the specifics of the user's request.
3312: */
3313: static void
3314: recv_done(isc_task_t *task, isc_event_t *event) {
3315: isc_socketevent_t *sevent = NULL;
3316: dig_query_t *query = NULL;
3317: isc_buffer_t *b = NULL;
3318: dns_message_t *msg = NULL;
3319: isc_result_t result;
3320: dig_lookup_t *n, *l;
3321: isc_boolean_t docancel = ISC_FALSE;
3322: isc_boolean_t match = ISC_TRUE;
3323: unsigned int parseflags;
3324: dns_messageid_t id;
3325: unsigned int msgflags;
3326: int newedns;
3327:
3328: UNUSED(task);
3329: INSIST(!free_now);
3330:
3331: debug("recv_done()");
3332:
3333: recvcount--;
3334: debug("recvcount=%d", recvcount);
3335: INSIST(recvcount >= 0);
3336:
3337: query = event->ev_arg;
3338: TIME_NOW(&query->time_recv);
3339: debug("lookup=%p, query=%p", query->lookup, query);
3340:
3341: l = query->lookup;
3342:
3343: REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
3344: sevent = (isc_socketevent_t *)event;
3345:
3346: b = ISC_LIST_HEAD(sevent->bufferlist);
3347: INSIST(b == &query->recvbuf);
3348: ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link);
3349:
3350: if ((l->tcp_mode) && (query->timer != NULL))
3351: isc_timer_touch(query->timer);
3352: if ((!l->pending && !l->ns_search_only) || cancel_now) {
3353: debug("no longer pending. Got %s",
3354: isc_result_totext(sevent->result));
3355: query->waiting_connect = ISC_FALSE;
3356:
3357: isc_event_free(&event);
3358: clear_query(query);
3359: check_next_lookup(l);
3360: return;
3361: }
3362:
3363: if (sevent->result != ISC_R_SUCCESS) {
3364: if (sevent->result == ISC_R_CANCELED) {
3365: debug("in recv cancel handler");
3366: query->waiting_connect = ISC_FALSE;
3367: } else {
3368: printf(";; communications error: %s\n",
3369: isc_result_totext(sevent->result));
3370: if (keep != NULL)
3371: isc_socket_detach(&keep);
3372: isc_socket_detach(&query->sock);
3373: sockcount--;
3374: debug("sockcount=%d", sockcount);
3375: INSIST(sockcount >= 0);
3376: }
3377: if (sevent->result == ISC_R_EOF && l->eoferr == 0U) {
3378: n = requeue_lookup(l, ISC_TRUE);
3379: n->eoferr++;
3380: }
3381: isc_event_free(&event);
3382: clear_query(query);
3383: cancel_lookup(l);
3384: check_next_lookup(l);
3385: return;
3386: }
3387:
3388: if (!l->tcp_mode &&
3389: !isc_sockaddr_compare(&sevent->address, &query->sockaddr,
3390: ISC_SOCKADDR_CMPADDR|
3391: ISC_SOCKADDR_CMPPORT|
3392: ISC_SOCKADDR_CMPSCOPE|
3393: ISC_SOCKADDR_CMPSCOPEZERO)) {
3394: char buf1[ISC_SOCKADDR_FORMATSIZE];
3395: char buf2[ISC_SOCKADDR_FORMATSIZE];
3396: isc_sockaddr_t any;
3397:
3398: if (isc_sockaddr_pf(&query->sockaddr) == AF_INET)
3399: isc_sockaddr_any(&any);
3400: else
3401: isc_sockaddr_any6(&any);
3402:
3403: /*
3404: * We don't expect a match when the packet is
3405: * sent to 0.0.0.0, :: or to a multicast addresses.
3406: * XXXMPA broadcast needs to be handled here as well.
3407: */
3408: if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) &&
3409: !isc_sockaddr_ismulticast(&query->sockaddr)) ||
3410: isc_sockaddr_getport(&query->sockaddr) !=
3411: isc_sockaddr_getport(&sevent->address)) {
3412: isc_sockaddr_format(&sevent->address, buf1,
3413: sizeof(buf1));
3414: isc_sockaddr_format(&query->sockaddr, buf2,
3415: sizeof(buf2));
3416: printf(";; reply from unexpected source: %s,"
3417: " expected %s\n", buf1, buf2);
3418: match = ISC_FALSE;
3419: }
3420: }
3421:
3422: result = dns_message_peekheader(b, &id, &msgflags);
3423: if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
3424: match = ISC_FALSE;
3425: if (l->tcp_mode) {
3426: isc_boolean_t fail = ISC_TRUE;
3427: if (result == ISC_R_SUCCESS) {
3428: if (!query->first_soa_rcvd ||
3429: query->warn_id)
3430: printf(";; %s: ID mismatch: "
3431: "expected ID %u, got %u\n",
3432: query->first_soa_rcvd ?
3433: "WARNING" : "ERROR",
3434: l->sendmsg->id, id);
3435: if (query->first_soa_rcvd)
3436: fail = ISC_FALSE;
3437: query->warn_id = ISC_FALSE;
3438: } else
3439: printf(";; ERROR: short "
3440: "(< header size) message\n");
3441: if (fail) {
3442: isc_event_free(&event);
3443: clear_query(query);
3444: cancel_lookup(l);
3445: check_next_lookup(l);
3446: return;
3447: }
3448: match = ISC_TRUE;
3449: } else if (result == ISC_R_SUCCESS)
3450: printf(";; Warning: ID mismatch: "
3451: "expected ID %u, got %u\n", l->sendmsg->id, id);
3452: else
3453: printf(";; Warning: short "
3454: "(< header size) message received\n");
3455: }
3456:
3457: if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0)
3458: printf(";; Warning: query response not set\n");
3459:
3460: if (!match)
3461: goto udp_mismatch;
3462:
3463: result = dns_message_create(DNS_MESSAGE_INTENTPARSE, &msg);
3464: check_result(result, "dns_message_create");
3465:
3466: if (tsigkey != NULL) {
3467: if (l->querysig == NULL) {
3468: debug("getting initial querysig");
3469: result = dns_message_getquerytsig(l->sendmsg,
3470: &l->querysig);
3471: check_result(result, "dns_message_getquerytsig");
3472: }
3473: result = dns_message_setquerytsig(msg, l->querysig);
3474: check_result(result, "dns_message_setquerytsig");
3475: result = dns_message_settsigkey(msg, tsigkey);
3476: check_result(result, "dns_message_settsigkey");
3477: msg->tsigctx = l->tsigctx;
3478: l->tsigctx = NULL;
3479: if (l->msgcounter != 0)
3480: msg->tcp_continuation = 1;
3481: l->msgcounter++;
3482: }
3483:
3484: debug("before parse starts");
3485: parseflags = DNS_MESSAGEPARSE_PRESERVEORDER;
3486: if (l->besteffort) {
3487: parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
3488: parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
3489: }
3490: result = dns_message_parse(msg, b, parseflags);
3491: if (result == DNS_R_RECOVERABLE) {
3492: printf(";; Warning: Message parser reports malformed "
3493: "message packet.\n");
3494: result = ISC_R_SUCCESS;
3495: }
3496: if (result != ISC_R_SUCCESS) {
3497: printf(";; Got bad packet: %s\n", isc_result_totext(result));
3498: hex_dump(b);
3499: query->waiting_connect = ISC_FALSE;
3500: dns_message_destroy(&msg);
3501: isc_event_free(&event);
3502: clear_query(query);
3503: cancel_lookup(l);
3504: check_next_lookup(l);
3505: return;
3506: }
3507: if (msg->counts[DNS_SECTION_QUESTION] != 0) {
3508: match = ISC_TRUE;
3509: for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
3510: result == ISC_R_SUCCESS && match;
3511: result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) {
3512: dns_name_t *name = NULL;
3513: dns_rdataset_t *rdataset;
3514:
3515: dns_message_currentname(msg, DNS_SECTION_QUESTION,
3516: &name);
3517: for (rdataset = ISC_LIST_HEAD(name->list);
3518: rdataset != NULL;
3519: rdataset = ISC_LIST_NEXT(rdataset, link)) {
3520: if (l->rdtype != rdataset->type ||
3521: l->rdclass != rdataset->rdclass ||
3522: !dns_name_equal(l->name, name)) {
3523: char namestr[DNS_NAME_FORMATSIZE];
3524: char typebuf[DNS_RDATATYPE_FORMATSIZE];
3525: char classbuf[DNS_RDATACLASS_FORMATSIZE];
3526: dns_name_format(name, namestr,
3527: sizeof(namestr));
3528: dns_rdatatype_format(rdataset->type,
3529: typebuf,
3530: sizeof(typebuf));
3531: dns_rdataclass_format(rdataset->rdclass,
3532: classbuf,
3533: sizeof(classbuf));
3534: printf(";; Question section mismatch: "
3535: "got %s/%s/%s\n",
3536: namestr, typebuf, classbuf);
3537: match = ISC_FALSE;
3538: }
3539: }
3540: }
3541: if (!match) {
3542: dns_message_destroy(&msg);
3543: if (l->tcp_mode) {
3544: isc_event_free(&event);
3545: clear_query(query);
3546: cancel_lookup(l);
3547: check_next_lookup(l);
3548: return;
3549: } else
3550: goto udp_mismatch;
3551: }
3552: }
3553: if (msg->rcode == dns_rcode_badvers && msg->opt != NULL &&
3554: (newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg) {
3555: /*
3556: * Add minimum EDNS version required checks here if needed.
3557: */
3558: if (l->comments)
3559: printf(";; BADVERS, retrying with EDNS version %u.\n",
3560: (unsigned int)newedns);
3561: l->edns = newedns;
3562: n = requeue_lookup(l, ISC_TRUE);
3563: if (l->trace && l->trace_root)
3564: n->rdtype = l->qrdtype;
3565: dns_message_destroy(&msg);
3566: isc_event_free(&event);
3567: clear_query(query);
3568: cancel_lookup(l);
3569: check_next_lookup(l);
3570: return;
3571: }
3572: if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 &&
3573: !l->ignore && !l->tcp_mode) {
3574: if (l->sitvalue == NULL && l->sit && msg->opt != NULL)
3575: process_opt(l, msg);
3576: if (l->comments)
3577: printf(";; Truncated, retrying in TCP mode.\n");
3578: n = requeue_lookup(l, ISC_TRUE);
3579: n->tcp_mode = ISC_TRUE;
3580: if (l->trace && l->trace_root)
3581: n->rdtype = l->qrdtype;
3582: dns_message_destroy(&msg);
3583: isc_event_free(&event);
3584: clear_query(query);
3585: cancel_lookup(l);
3586: check_next_lookup(l);
3587: return;
3588: }
3589: if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
3590: (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
3591: {
3592: dig_query_t *next = ISC_LIST_NEXT(query, link);
3593: if (l->current_query == query)
3594: l->current_query = NULL;
3595: if (next != NULL) {
3596: debug("sending query %p\n", next);
3597: if (l->tcp_mode)
3598: send_tcp_connect(next);
3599: else
3600: send_udp(next);
3601: }
3602: /*
3603: * If our query is at the head of the list and there
3604: * is no next, we're the only one left, so fall
3605: * through to print the message.
3606: */
3607: if ((ISC_LIST_HEAD(l->q) != query) ||
3608: (ISC_LIST_NEXT(query, link) != NULL)) {
3609: if (l->comments)
3610: printf(";; Got %s from %s, "
3611: "trying next server\n",
3612: msg->rcode == dns_rcode_servfail ?
3613: "SERVFAIL reply" :
3614: "recursion not available",
3615: query->servname);
3616: clear_query(query);
3617: check_next_lookup(l);
3618: dns_message_destroy(&msg);
3619: isc_event_free(&event);
3620: return;
3621: }
3622: }
3623:
3624: if (tsigkey != NULL) {
3625: result = dns_tsig_verify(&query->recvbuf, msg);
3626: if (result != ISC_R_SUCCESS) {
3627: printf(";; Couldn't verify signature: %s\n",
3628: isc_result_totext(result));
3629: validated = ISC_FALSE;
3630: }
3631: l->tsigctx = msg->tsigctx;
3632: msg->tsigctx = NULL;
3633: if (l->querysig != NULL) {
3634: debug("freeing querysig buffer %p", l->querysig);
3635: isc_buffer_free(&l->querysig);
3636: }
3637: result = dns_message_getquerytsig(msg, &l->querysig);
3638: check_result(result,"dns_message_getquerytsig");
3639: }
3640:
3641: extrabytes = isc_buffer_remaininglength(b);
3642:
3643: debug("after parse");
3644: if (l->doing_xfr && l->xfr_q == NULL) {
3645: l->xfr_q = query;
3646: /*
3647: * Once we are in the XFR message, increase
3648: * the timeout to much longer, so brief network
3649: * outages won't cause the XFR to abort
3650: */
3651: if (timeout != INT_MAX && query->timer != NULL) {
3652: unsigned int local_timeout;
3653:
3654: if (timeout == 0) {
3655: if (l->tcp_mode)
3656: local_timeout = TCP_TIMEOUT * 4;
3657: else
3658: local_timeout = UDP_TIMEOUT * 4;
3659: } else {
3660: if (timeout < (INT_MAX / 4))
3661: local_timeout = timeout * 4;
3662: else
3663: local_timeout = INT_MAX;
3664: }
3665: debug("have local timeout of %d", local_timeout);
1.9 ! florian 3666: l->interval.tv_sec = local_timeout;
! 3667: l->interval.tv_nsec = 0;
1.1 florian 3668: result = isc_timer_reset(query->timer,
3669: &l->interval,
3670: ISC_FALSE);
3671: check_result(result, "isc_timer_reset");
3672: }
3673: }
3674:
3675: if (l->sitvalue != NULL) {
3676: if (msg->opt == NULL)
3677: printf(";; expected opt record in response\n");
3678: else
3679: process_opt(l, msg);
3680: } else if (l->sit && msg->opt != NULL)
3681: process_opt(l, msg);
3682:
3683: if (!l->doing_xfr || l->xfr_q == query) {
3684: if (msg->rcode == dns_rcode_nxdomain &&
3685: (l->origin != NULL || l->need_search)) {
3686: if (!next_origin(query->lookup) || showsearch) {
3687: dighost_printmessage(query, msg, ISC_TRUE);
3688: dighost_received(b->used, &sevent->address, query);
3689: }
3690: } else if (!l->trace && !l->ns_search_only) {
3691: dighost_printmessage(query, msg, ISC_TRUE);
3692: } else if (l->trace) {
3693: int nl = 0;
3694: int count = msg->counts[DNS_SECTION_ANSWER];
3695:
3696: debug("in TRACE code");
3697: if (!l->ns_search_only)
3698: dighost_printmessage(query, msg, ISC_TRUE);
3699:
3700: l->rdtype = l->qrdtype;
3701: if (l->trace_root || (l->ns_search_only && count > 0)) {
3702: if (!l->trace_root)
3703: l->rdtype = dns_rdatatype_soa;
3704: nl = followup_lookup(msg, query,
3705: DNS_SECTION_ANSWER);
3706: l->trace_root = ISC_FALSE;
3707: } else if (count == 0)
3708: nl = followup_lookup(msg, query,
3709: DNS_SECTION_AUTHORITY);
3710: if (nl == 0)
3711: docancel = ISC_TRUE;
3712: } else {
3713: debug("in NSSEARCH code");
3714:
3715: if (l->trace_root) {
3716: /*
3717: * This is the initial NS query.
3718: */
3719: int nl;
3720:
3721: l->rdtype = dns_rdatatype_soa;
3722: nl = followup_lookup(msg, query,
3723: DNS_SECTION_ANSWER);
3724: if (nl == 0)
3725: docancel = ISC_TRUE;
3726: l->trace_root = ISC_FALSE;
3727: usesearch = ISC_FALSE;
3728: } else
3729: dighost_printmessage(query, msg, ISC_TRUE);
3730: }
3731: }
3732:
3733: if (l->pending)
3734: debug("still pending.");
3735: if (l->doing_xfr) {
3736: if (query != l->xfr_q) {
3737: dns_message_destroy(&msg);
3738: isc_event_free(&event);
3739: query->waiting_connect = ISC_FALSE;
3740: return;
3741: }
3742: if (!docancel)
3743: docancel = check_for_more_data(query, msg, sevent);
3744: if (docancel) {
3745: dns_message_destroy(&msg);
3746: clear_query(query);
3747: cancel_lookup(l);
3748: check_next_lookup(l);
3749: }
3750: } else {
3751:
3752: if (msg->rcode == dns_rcode_noerror || l->origin == NULL) {
3753:
3754: dighost_received(b->used, &sevent->address, query);
3755: }
3756:
3757: if (!query->lookup->ns_search_only)
3758: query->lookup->pending = ISC_FALSE;
3759: if (!query->lookup->ns_search_only ||
3760: query->lookup->trace_root || docancel) {
3761: dns_message_destroy(&msg);
3762:
3763: cancel_lookup(l);
3764: }
3765: clear_query(query);
3766: check_next_lookup(l);
3767: }
3768: if (msg != NULL) {
3769: dns_message_destroy(&msg);
3770: }
3771: isc_event_free(&event);
3772: return;
3773:
3774: udp_mismatch:
3775: isc_buffer_invalidate(&query->recvbuf);
3776: isc_buffer_init(&query->recvbuf, query->recvspace, COMMSIZE);
3777: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
3778: result = isc_socket_recvv(query->sock, &query->recvlist, 1,
3779: global_task, recv_done, query);
3780: check_result(result, "isc_socket_recvv");
3781: recvcount++;
3782: isc_event_free(&event);
3783: return;
3784: }
3785:
3786: /*%
3787: * Turn a name into an address, using system-supplied routines. This is
3788: * used in looking up server names, etc... and needs to use system-supplied
3789: * routines, since they may be using a non-DNS system for these lookups.
3790: */
3791: isc_result_t
3792: get_address(char *host, in_port_t myport, isc_sockaddr_t *sockaddr) {
3793: int count;
3794: isc_result_t result;
3795: isc_boolean_t is_running;
3796:
3797: is_running = isc_app_isrunning();
3798: if (is_running)
3799: isc_app_block();
3800: result = get_addresses(host, myport, sockaddr, 1, &count);
3801: if (is_running)
3802: isc_app_unblock();
3803: if (result != ISC_R_SUCCESS)
3804: return (result);
3805:
3806: INSIST(count == 1);
3807:
3808: return (ISC_R_SUCCESS);
3809: }
3810:
3811: int
3812: getaddresses(dig_lookup_t *lookup, const char *host, isc_result_t *resultp) {
3813: isc_result_t result;
3814: isc_sockaddr_t sockaddrs[DIG_MAX_ADDRESSES];
3815: isc_netaddr_t netaddr;
3816: int count, i;
3817: dig_server_t *srv;
3818: char tmp[ISC_NETADDR_FORMATSIZE];
3819:
3820: result = get_addresses(host, 0, sockaddrs,
3821: DIG_MAX_ADDRESSES, &count);
3822: if (resultp != NULL)
3823: *resultp = result;
3824: if (result != ISC_R_SUCCESS) {
3825: if (resultp == NULL)
3826: fatal("couldn't get address for '%s': %s",
3827: host, isc_result_totext(result));
3828: return (0);
3829: }
3830:
3831: for (i = 0; i < count; i++) {
3832: isc_netaddr_fromsockaddr(&netaddr, &sockaddrs[i]);
3833: isc_netaddr_format(&netaddr, tmp, sizeof(tmp));
3834: srv = make_server(tmp, host);
3835: ISC_LIST_APPEND(lookup->my_server_list, srv, link);
3836: }
3837:
3838: return (count);
3839: }
3840:
3841: /*%
3842: * Initiate either a TCP or UDP lookup
3843: */
3844: void
3845: do_lookup(dig_lookup_t *lookup) {
3846: dig_query_t *query;
3847:
3848: REQUIRE(lookup != NULL);
3849:
3850: debug("do_lookup()");
3851: lookup->pending = ISC_TRUE;
3852: query = ISC_LIST_HEAD(lookup->q);
3853: if (query != NULL) {
3854: if (lookup->tcp_mode)
3855: send_tcp_connect(query);
3856: else
3857: send_udp(query);
3858: }
3859: }
3860:
3861: /*%
3862: * Start everything in action upon task startup.
3863: */
3864: void
3865: onrun_callback(isc_task_t *task, isc_event_t *event) {
3866: UNUSED(task);
3867:
3868: isc_event_free(&event);
3869: start_lookup();
3870: }
3871:
3872: /*%
3873: * Make everything on the lookup queue go away. Mainly used by the
3874: * SIGINT handler.
3875: */
3876: void
3877: cancel_all(void) {
3878: dig_lookup_t *l, *n;
3879: dig_query_t *q, *nq;
3880:
3881: debug("cancel_all()");
3882:
3883: if (free_now) {
3884: return;
3885: }
3886: cancel_now = ISC_TRUE;
3887: if (current_lookup != NULL) {
3888: for (q = ISC_LIST_HEAD(current_lookup->q);
3889: q != NULL;
3890: q = nq)
3891: {
3892: nq = ISC_LIST_NEXT(q, link);
3893: debug("canceling pending query %p, belonging to %p",
3894: q, current_lookup);
3895: if (q->sock != NULL)
3896: isc_socket_cancel(q->sock, NULL,
3897: ISC_SOCKCANCEL_ALL);
3898: else
3899: clear_query(q);
3900: }
3901: for (q = ISC_LIST_HEAD(current_lookup->connecting);
3902: q != NULL;
3903: q = nq)
3904: {
3905: nq = ISC_LIST_NEXT(q, clink);
3906: debug("canceling connecting query %p, belonging to %p",
3907: q, current_lookup);
3908: if (q->sock != NULL)
3909: isc_socket_cancel(q->sock, NULL,
3910: ISC_SOCKCANCEL_ALL);
3911: else
3912: clear_query(q);
3913: }
3914: }
3915: l = ISC_LIST_HEAD(lookup_list);
3916: while (l != NULL) {
3917: n = ISC_LIST_NEXT(l, link);
3918: ISC_LIST_DEQUEUE(lookup_list, l, link);
3919: try_clear_lookup(l);
3920: l = n;
3921: }
3922: }
3923:
3924: /*%
3925: * Destroy all of the libs we are using, and get everything ready for a
3926: * clean shutdown.
3927: */
3928: void
3929: destroy_libs(void) {
3930:
3931: if (keep != NULL)
3932: isc_socket_detach(&keep);
3933: debug("destroy_libs()");
3934: if (global_task != NULL) {
3935: debug("freeing task");
3936: isc_task_detach(&global_task);
3937: }
3938: /*
3939: * The taskmgr_destroy() call blocks until all events are cleared
3940: * from the task.
3941: */
3942: if (taskmgr != NULL) {
3943: debug("freeing taskmgr");
3944: isc_taskmgr_destroy(&taskmgr);
3945: }
3946: REQUIRE(sockcount == 0);
3947: REQUIRE(recvcount == 0);
3948: REQUIRE(sendcount == 0);
3949:
3950: INSIST(ISC_LIST_HEAD(lookup_list) == NULL);
3951: INSIST(current_lookup == NULL);
3952: INSIST(!free_now);
3953:
3954: free_now = ISC_TRUE;
3955:
3956: lwres_conf_clear(lwconf);
3957:
3958: flush_server_list();
3959:
3960: clear_searchlist();
3961:
3962: dns_name_destroy();
3963:
3964: if (socketmgr != NULL) {
3965: debug("freeing socketmgr");
3966: isc_socketmgr_destroy(&socketmgr);
3967: }
3968: if (timermgr != NULL) {
3969: debug("freeing timermgr");
3970: isc_timermgr_destroy(&timermgr);
3971: }
3972: if (tsigkey != NULL) {
3973: debug("freeing key %p", tsigkey);
3974: dns_tsigkey_detach(&tsigkey);
3975: }
3976: if (namebuf != NULL)
3977: isc_buffer_free(&namebuf);
3978:
3979: if (is_dst_up) {
3980: debug("destroy DST lib");
3981: dst_lib_destroy();
3982: is_dst_up = ISC_FALSE;
3983: }
3984:
3985: debug("Removing log context");
3986: isc_log_destroy(&lctx);
3987:
3988: }
3989: