Annotation of src/usr.bin/dig/dighost.c, Revision 1.6
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.6 ! florian 17: /* $Id: dighost.c,v 1.5 2020/02/13 19:29:47 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;
378: isc_time_t t;
379:
380: if (debugging) {
381: fflush(stdout);
382: if (debugtiming) {
383: TIME_NOW(&t);
384: fprintf(stderr, "%u.%06u: ", isc_time_seconds(&t),
385: isc_time_nanoseconds(&t) / 1000);
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);
2546: interval_set(&l->interval, local_timeout, 0);
2547: if (query->timer != NULL)
2548: isc_timer_detach(&query->timer);
2549: result = isc_timer_create(timermgr, isc_timertype_once, NULL,
2550: &l->interval, global_task, connect_timeout,
2551: query, &query->timer);
2552: check_result(result, "isc_timer_create");
2553: }
2554:
2555: static void
2556: force_timeout(dig_query_t *query) {
2557: isc_event_t *event;
2558:
2559: debug("force_timeout ()");
2560: event = isc_event_allocate(query, ISC_TIMEREVENT_IDLE,
2561: connect_timeout, query,
2562: sizeof(isc_event_t));
2563: if (event == NULL) {
2564: fatal("isc_event_allocate: %s",
2565: isc_result_totext(ISC_R_NOMEMORY));
2566: }
2567: isc_task_send(global_task, &event);
2568:
2569: /*
2570: * The timer may have expired if, for example, get_address() takes
2571: * long time and the timer was running on a different thread.
2572: * We need to cancel the possible timeout event not to confuse
2573: * ourselves due to the duplicate events.
2574: */
2575: if (query->timer != NULL)
2576: isc_timer_detach(&query->timer);
2577: }
2578:
2579:
2580: static void
2581: connect_done(isc_task_t *task, isc_event_t *event);
2582:
2583: /*%
2584: * Unlike send_udp, this can't be called multiple times with the same
2585: * query. When we retry TCP, we requeue the whole lookup, which should
2586: * start anew.
2587: */
2588: static void
2589: send_tcp_connect(dig_query_t *query) {
2590: isc_result_t result;
2591: dig_query_t *next;
2592: dig_lookup_t *l;
2593:
2594: debug("send_tcp_connect(%p)", query);
2595:
2596: l = query->lookup;
2597: query->waiting_connect = ISC_TRUE;
2598: query->lookup->current_query = query;
2599: result = get_address(query->servname, port, &query->sockaddr);
2600: if (result != ISC_R_SUCCESS) {
2601: /*
2602: * This servname doesn't have an address. Try the next server
2603: * by triggering an immediate 'timeout' (we lie, but the effect
2604: * is the same).
2605: */
2606: force_timeout(query);
2607: return;
2608: }
2609:
2610: if (specified_source &&
2611: (isc_sockaddr_pf(&query->sockaddr) !=
2612: isc_sockaddr_pf(&bind_address))) {
2613: printf(";; Skipping server %s, incompatible "
2614: "address family\n", query->servname);
2615: query->waiting_connect = ISC_FALSE;
2616: if (ISC_LINK_LINKED(query, link))
2617: next = ISC_LIST_NEXT(query, link);
2618: else
2619: next = NULL;
2620: l = query->lookup;
2621: clear_query(query);
2622: if (next == NULL) {
2623: printf(";; No acceptable nameservers\n");
2624: check_next_lookup(l);
2625: return;
2626: }
2627: send_tcp_connect(next);
2628: return;
2629: }
2630:
2631: INSIST(query->sock == NULL);
2632:
2633: if (keep != NULL && isc_sockaddr_equal(&keepaddr, &query->sockaddr)) {
2634: sockcount++;
2635: isc_socket_attach(keep, &query->sock);
2636: query->waiting_connect = ISC_FALSE;
2637: launch_next_query(query, ISC_TRUE);
2638: goto search;
2639: }
2640:
2641: result = isc_socket_create(socketmgr,
2642: isc_sockaddr_pf(&query->sockaddr),
2643: isc_sockettype_tcp, &query->sock);
2644: check_result(result, "isc_socket_create");
2645: sockcount++;
2646: debug("sockcount=%d", sockcount);
2647: if (specified_source)
2648: result = isc_socket_bind(query->sock, &bind_address,
2649: ISC_SOCKET_REUSEADDRESS);
2650: else {
2651: if ((isc_sockaddr_pf(&query->sockaddr) == AF_INET) &&
2652: have_ipv4)
2653: isc_sockaddr_any(&bind_any);
2654: else
2655: isc_sockaddr_any6(&bind_any);
2656: result = isc_socket_bind(query->sock, &bind_any, 0);
2657: }
2658: check_result(result, "isc_socket_bind");
2659: bringup_timer(query, TCP_TIMEOUT);
2660: result = isc_socket_connect(query->sock, &query->sockaddr,
2661: global_task, connect_done, query);
2662: check_result(result, "isc_socket_connect");
2663: search:
2664: /*
2665: * If we're at the endgame of a nameserver search, we need to
2666: * immediately bring up all the queries. Do it here.
2667: */
2668: if (l->ns_search_only && !l->trace_root) {
2669: debug("sending next, since searching");
2670: if (ISC_LINK_LINKED(query, link)) {
2671: next = ISC_LIST_NEXT(query, link);
2672: ISC_LIST_DEQUEUE(l->q, query, link);
2673: } else
2674: next = NULL;
2675: ISC_LIST_ENQUEUE(l->connecting, query, clink);
2676: if (next != NULL)
2677: send_tcp_connect(next);
2678: }
2679: }
2680:
2681: static isc_buffer_t *
2682: clone_buffer(isc_buffer_t *source) {
2683: isc_buffer_t *buffer;
2684: buffer = malloc(sizeof(*buffer));
2685: if (buffer == NULL)
2686: fatal("memory allocation failure in %s:%d",
2687: __FILE__, __LINE__);
2688: *buffer = *source;
2689: return (buffer);
2690: }
2691:
2692: /*%
2693: * Send a UDP packet to the remote nameserver, possible starting the
2694: * recv action as well. Also make sure that the timer is running and
2695: * is properly reset.
2696: */
2697: static void
2698: send_udp(dig_query_t *query) {
2699: dig_lookup_t *l = NULL;
2700: isc_result_t result;
2701: isc_buffer_t *sendbuf;
2702:
2703: debug("send_udp(%p)", query);
2704:
2705: l = query->lookup;
2706: bringup_timer(query, UDP_TIMEOUT);
2707: l->current_query = query;
2708: debug("working on lookup %p, query %p", query->lookup, query);
2709: if (!query->recv_made) {
2710: /* XXX Check the sense of this, need assertion? */
2711: query->waiting_connect = ISC_FALSE;
2712: result = get_address(query->servname, port, &query->sockaddr);
2713: if (result != ISC_R_SUCCESS) {
2714: /* This servname doesn't have an address. */
2715: force_timeout(query);
2716: return;
2717: }
2718:
2719: result = isc_socket_create(socketmgr,
2720: isc_sockaddr_pf(&query->sockaddr),
2721: isc_sockettype_udp, &query->sock);
2722: check_result(result, "isc_socket_create");
2723: sockcount++;
2724: debug("sockcount=%d", sockcount);
2725: if (specified_source) {
2726: result = isc_socket_bind(query->sock, &bind_address,
2727: ISC_SOCKET_REUSEADDRESS);
2728: } else {
2729: isc_sockaddr_anyofpf(&bind_any,
2730: isc_sockaddr_pf(&query->sockaddr));
2731: result = isc_socket_bind(query->sock, &bind_any, 0);
2732: }
2733: check_result(result, "isc_socket_bind");
2734:
2735: query->recv_made = ISC_TRUE;
2736: ISC_LINK_INIT(&query->recvbuf, link);
2737: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf,
2738: link);
2739: debug("recving with lookup=%p, query=%p, sock=%p",
2740: query->lookup, query, query->sock);
2741: result = isc_socket_recvv(query->sock, &query->recvlist, 1,
2742: global_task, recv_done, query);
2743: check_result(result, "isc_socket_recvv");
2744: recvcount++;
2745: debug("recvcount=%d", recvcount);
2746: }
2747: ISC_LIST_INIT(query->sendlist);
2748: sendbuf = clone_buffer(&query->sendbuf);
2749: ISC_LIST_ENQUEUE(query->sendlist, sendbuf, link);
2750: debug("sending a request");
2751: TIME_NOW(&query->time_sent);
2752: INSIST(query->sock != NULL);
2753: query->waiting_senddone = ISC_TRUE;
2754: result = isc_socket_sendtov2(query->sock, &query->sendlist,
2755: global_task, send_done, query,
2756: &query->sockaddr, NULL,
2757: ISC_SOCKFLAG_NORETRY);
2758: check_result(result, "isc_socket_sendtov");
2759: sendcount++;
2760: }
2761:
2762: /*%
2763: * IO timeout handler, used for both connect and recv timeouts. If
2764: * retries are still allowed, either resend the UDP packet or queue a
2765: * new TCP lookup. Otherwise, cancel the lookup.
2766: */
2767: static void
2768: connect_timeout(isc_task_t *task, isc_event_t *event) {
2769: dig_lookup_t *l = NULL;
2770: dig_query_t *query = NULL, *cq;
2771:
2772: UNUSED(task);
2773: REQUIRE(event->ev_type == ISC_TIMEREVENT_IDLE);
2774:
2775: debug("connect_timeout()");
2776:
2777: query = event->ev_arg;
2778: l = query->lookup;
2779: isc_event_free(&event);
2780:
2781: INSIST(!free_now);
2782:
2783: if ((query != NULL) && (query->lookup->current_query != NULL) &&
2784: ISC_LINK_LINKED(query->lookup->current_query, link) &&
2785: (ISC_LIST_NEXT(query->lookup->current_query, link) != NULL)) {
2786: debug("trying next server...");
2787: cq = query->lookup->current_query;
2788: if (!l->tcp_mode)
2789: send_udp(ISC_LIST_NEXT(cq, link));
2790: else {
2791: if (query->sock != NULL)
2792: isc_socket_cancel(query->sock, NULL,
2793: ISC_SOCKCANCEL_ALL);
2794: send_tcp_connect(ISC_LIST_NEXT(cq, link));
2795: }
2796: return;
2797: }
2798:
2799: if (l->tcp_mode && query->sock != NULL) {
2800: query->timedout = ISC_TRUE;
2801: isc_socket_cancel(query->sock, NULL, ISC_SOCKCANCEL_ALL);
2802: }
2803:
2804: if (l->retries > 1) {
2805: if (!l->tcp_mode) {
2806: l->retries--;
2807: debug("resending UDP request to first server");
2808: send_udp(ISC_LIST_HEAD(l->q));
2809: } else {
2810: debug("making new TCP request, %d tries left",
2811: l->retries);
2812: l->retries--;
2813: requeue_lookup(l, ISC_TRUE);
2814: cancel_lookup(l);
2815: check_next_lookup(l);
2816: }
2817: } else {
2818: if (!l->ns_search_only) {
2819: fputs(l->cmdline, stdout);
2820: printf(";; connection timed out; no servers could be "
2821: "reached\n");
2822: }
2823: cancel_lookup(l);
2824: check_next_lookup(l);
2825: if (exitcode < 9)
2826: exitcode = 9;
2827: }
2828: }
2829:
2830: /*%
2831: * Event handler for the TCP recv which gets the length header of TCP
2832: * packets. Start the next recv of length bytes.
2833: */
2834: static void
2835: tcp_length_done(isc_task_t *task, isc_event_t *event) {
2836: isc_socketevent_t *sevent;
2837: isc_buffer_t *b = NULL;
2838: isc_result_t result;
2839: dig_query_t *query = NULL;
2840: dig_lookup_t *l, *n;
2841: uint16_t length;
2842:
2843: REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
2844: INSIST(!free_now);
2845:
2846: UNUSED(task);
2847:
2848: debug("tcp_length_done()");
2849:
2850: sevent = (isc_socketevent_t *)event;
2851: query = event->ev_arg;
2852:
2853: recvcount--;
2854: INSIST(recvcount >= 0);
2855:
2856: b = ISC_LIST_HEAD(sevent->bufferlist);
2857: INSIST(b == &query->lengthbuf);
2858: ISC_LIST_DEQUEUE(sevent->bufferlist, b, link);
2859:
2860: if (sevent->result == ISC_R_CANCELED) {
2861: isc_event_free(&event);
2862: l = query->lookup;
2863: clear_query(query);
2864: check_next_lookup(l);
2865: return;
2866: }
2867: if (sevent->result != ISC_R_SUCCESS) {
2868: char sockstr[ISC_SOCKADDR_FORMATSIZE];
2869: isc_sockaddr_format(&query->sockaddr, sockstr,
2870: sizeof(sockstr));
2871: printf(";; communications error to %s: %s\n",
2872: sockstr, isc_result_totext(sevent->result));
2873: if (keep != NULL)
2874: isc_socket_detach(&keep);
2875: l = query->lookup;
2876: isc_socket_detach(&query->sock);
2877: sockcount--;
2878: debug("sockcount=%d", sockcount);
2879: INSIST(sockcount >= 0);
2880: if (sevent->result == ISC_R_EOF && l->eoferr == 0U) {
2881: n = requeue_lookup(l, ISC_TRUE);
2882: n->eoferr++;
2883: }
2884: isc_event_free(&event);
2885: clear_query(query);
2886: cancel_lookup(l);
2887: check_next_lookup(l);
2888: return;
2889: }
2890: length = isc_buffer_getuint16(b);
2891: if (length == 0) {
2892: isc_event_free(&event);
2893: launch_next_query(query, ISC_FALSE);
2894: return;
2895: }
2896:
2897: /*
2898: * Even though the buffer was already init'ed, we need
2899: * to redo it now, to force the length we want.
2900: */
2901: isc_buffer_invalidate(&query->recvbuf);
2902: isc_buffer_init(&query->recvbuf, query->recvspace, length);
2903: ENSURE(ISC_LIST_EMPTY(query->recvlist));
2904: ISC_LINK_INIT(&query->recvbuf, link);
2905: ISC_LIST_ENQUEUE(query->recvlist, &query->recvbuf, link);
2906: debug("recving with lookup=%p, query=%p", query->lookup, query);
2907: result = isc_socket_recvv(query->sock, &query->recvlist, length, task,
2908: recv_done, query);
2909: check_result(result, "isc_socket_recvv");
2910: recvcount++;
2911: debug("resubmitted recv request with length %d, recvcount=%d",
2912: length, recvcount);
2913: isc_event_free(&event);
2914: }
2915:
2916: /*%
2917: * For transfers that involve multiple recvs (XFR's in particular),
2918: * launch the next recv.
2919: */
2920: static void
2921: launch_next_query(dig_query_t *query, isc_boolean_t include_question) {
2922: isc_result_t result;
2923: dig_lookup_t *l;
2924: isc_buffer_t *buffer;
2925:
2926: INSIST(!free_now);
2927:
2928: debug("launch_next_query()");
2929:
2930: if (!query->lookup->pending) {
2931: debug("ignoring launch_next_query because !pending");
2932: isc_socket_detach(&query->sock);
2933: sockcount--;
2934: debug("sockcount=%d", sockcount);
2935: INSIST(sockcount >= 0);
2936: query->waiting_connect = ISC_FALSE;
2937: l = query->lookup;
2938: clear_query(query);
2939: check_next_lookup(l);
2940: return;
2941: }
2942:
2943: isc_buffer_clear(&query->slbuf);
2944: isc_buffer_clear(&query->lengthbuf);
2945: isc_buffer_putuint16(&query->slbuf, (uint16_t) query->sendbuf.used);
2946: ISC_LIST_INIT(query->sendlist);
2947: ISC_LINK_INIT(&query->slbuf, link);
2948: if (!query->first_soa_rcvd) {
2949: buffer = clone_buffer(&query->slbuf);
2950: ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
2951: if (include_question) {
2952: buffer = clone_buffer(&query->sendbuf);
2953: ISC_LIST_ENQUEUE(query->sendlist, buffer, link);
2954: }
2955: }
2956:
2957: ISC_LINK_INIT(&query->lengthbuf, link);
2958: ISC_LIST_ENQUEUE(query->lengthlist, &query->lengthbuf, link);
2959:
2960: result = isc_socket_recvv(query->sock, &query->lengthlist, 0,
2961: global_task, tcp_length_done, query);
2962: check_result(result, "isc_socket_recvv");
2963: recvcount++;
2964: debug("recvcount=%d", recvcount);
2965: if (!query->first_soa_rcvd) {
2966: debug("sending a request in launch_next_query");
2967: TIME_NOW(&query->time_sent);
2968: query->waiting_senddone = ISC_TRUE;
2969: result = isc_socket_sendv(query->sock, &query->sendlist,
2970: global_task, send_done, query);
2971: check_result(result, "isc_socket_sendv");
2972: sendcount++;
2973: debug("sendcount=%d", sendcount);
2974: }
2975: query->waiting_connect = ISC_FALSE;
2976: return;
2977: }
2978:
2979: /*%
2980: * Event handler for TCP connect complete. Make sure the connection was
2981: * successful, then pass into launch_next_query to actually send the
2982: * question.
2983: */
2984: static void
2985: connect_done(isc_task_t *task, isc_event_t *event) {
2986: char sockstr[ISC_SOCKADDR_FORMATSIZE];
2987: isc_socketevent_t *sevent = NULL;
2988: dig_query_t *query = NULL, *next;
2989: dig_lookup_t *l;
2990:
2991: UNUSED(task);
2992:
2993: REQUIRE(event->ev_type == ISC_SOCKEVENT_CONNECT);
2994: INSIST(!free_now);
2995:
2996: debug("connect_done()");
2997:
2998: sevent = (isc_socketevent_t *)event;
2999: query = sevent->ev_arg;
3000:
3001: INSIST(query->waiting_connect);
3002:
3003: query->waiting_connect = ISC_FALSE;
3004:
3005: if (sevent->result == ISC_R_CANCELED) {
3006: debug("in cancel handler");
3007: isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
3008: if (query->timedout)
3009: printf(";; Connection to %s(%s) for %s failed: %s.\n",
3010: sockstr, query->servname,
3011: query->lookup->textname,
3012: isc_result_totext(ISC_R_TIMEDOUT));
3013: isc_socket_detach(&query->sock);
3014: INSIST(sockcount > 0);
3015: sockcount--;
3016: debug("sockcount=%d", sockcount);
3017: query->waiting_connect = ISC_FALSE;
3018: isc_event_free(&event);
3019: l = query->lookup;
3020: clear_query(query);
3021: check_next_lookup(l);
3022: return;
3023: }
3024: if (sevent->result != ISC_R_SUCCESS) {
3025:
3026: debug("unsuccessful connection: %s",
3027: isc_result_totext(sevent->result));
3028: isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr));
3029: if (sevent->result != ISC_R_CANCELED)
3030: printf(";; Connection to %s(%s) for %s failed: "
3031: "%s.\n", sockstr,
3032: query->servname, query->lookup->textname,
3033: isc_result_totext(sevent->result));
3034: isc_socket_detach(&query->sock);
3035: INSIST(sockcount > 0);
3036: sockcount--;
3037: /* XXX Clean up exitcodes */
3038: if (exitcode < 9)
3039: exitcode = 9;
3040: debug("sockcount=%d", sockcount);
3041: query->waiting_connect = ISC_FALSE;
3042: isc_event_free(&event);
3043: l = query->lookup;
3044: if ((l->current_query != NULL) &&
3045: (ISC_LINK_LINKED(l->current_query, link)))
3046: next = ISC_LIST_NEXT(l->current_query, link);
3047: else
3048: next = NULL;
3049: clear_query(query);
3050: if (next != NULL) {
3051: bringup_timer(next, TCP_TIMEOUT);
3052: send_tcp_connect(next);
3053: } else
3054: check_next_lookup(l);
3055: return;
3056: }
3057: if (keep_open) {
3058: if (keep != NULL)
3059: isc_socket_detach(&keep);
3060: isc_socket_attach(query->sock, &keep);
3061: keepaddr = query->sockaddr;
3062: }
3063: launch_next_query(query, ISC_TRUE);
3064: isc_event_free(&event);
3065: }
3066:
3067: /*%
3068: * Check if the ongoing XFR needs more data before it's complete, using
3069: * the semantics of IXFR and AXFR protocols. Much of the complexity of
3070: * this routine comes from determining when an IXFR is complete.
3071: * ISC_FALSE means more data is on the way, and the recv has been issued.
3072: */
3073: static isc_boolean_t
3074: check_for_more_data(dig_query_t *query, dns_message_t *msg,
3075: isc_socketevent_t *sevent)
3076: {
3077: dns_rdataset_t *rdataset = NULL;
3078: dns_rdata_t rdata = DNS_RDATA_INIT;
3079: dns_rdata_soa_t soa;
3080: uint32_t ixfr_serial = query->lookup->ixfr_serial, serial;
3081: isc_result_t result;
3082: isc_boolean_t ixfr = query->lookup->rdtype == dns_rdatatype_ixfr;
3083: isc_boolean_t axfr = query->lookup->rdtype == dns_rdatatype_axfr;
3084:
3085: if (ixfr)
3086: axfr = query->ixfr_axfr;
3087:
3088: debug("check_for_more_data()");
3089:
3090: /*
3091: * By the time we're in this routine, we know we're doing
3092: * either an AXFR or IXFR. If there's no second_rr_type,
3093: * then we don't yet know which kind of answer we got back
3094: * from the server. Here, we're going to walk through the
3095: * rr's in the message, acting as necessary whenever we hit
3096: * an SOA rr.
3097: */
3098:
3099: query->msg_count++;
3100: query->byte_count += sevent->n;
3101: result = dns_message_firstname(msg, DNS_SECTION_ANSWER);
3102: if (result != ISC_R_SUCCESS) {
3103: puts("; Transfer failed.");
3104: return (ISC_TRUE);
3105: }
3106: do {
3107: dns_name_t *name;
3108: name = NULL;
3109: dns_message_currentname(msg, DNS_SECTION_ANSWER,
3110: &name);
3111: for (rdataset = ISC_LIST_HEAD(name->list);
3112: rdataset != NULL;
3113: rdataset = ISC_LIST_NEXT(rdataset, link)) {
3114: result = dns_rdataset_first(rdataset);
3115: if (result != ISC_R_SUCCESS)
3116: continue;
3117: do {
3118: query->rr_count++;
3119: dns_rdata_reset(&rdata);
3120: dns_rdataset_current(rdataset, &rdata);
3121: /*
3122: * If this is the first rr, make sure
3123: * it's an SOA
3124: */
3125: if ((!query->first_soa_rcvd) &&
3126: (rdata.type != dns_rdatatype_soa)) {
3127: puts("; Transfer failed. "
3128: "Didn't start with SOA answer.");
3129: return (ISC_TRUE);
3130: }
3131: if ((!query->second_rr_rcvd) &&
3132: (rdata.type != dns_rdatatype_soa)) {
3133: query->second_rr_rcvd = ISC_TRUE;
3134: query->second_rr_serial = 0;
3135: debug("got the second rr as nonsoa");
3136: axfr = query->ixfr_axfr = ISC_TRUE;
3137: goto next_rdata;
3138: }
3139:
3140: /*
3141: * If the record is anything except an SOA
3142: * now, just continue on...
3143: */
3144: if (rdata.type != dns_rdatatype_soa)
3145: goto next_rdata;
3146:
3147: /* Now we have an SOA. Work with it. */
3148: debug("got an SOA");
3149: result = dns_rdata_tostruct(&rdata, &soa);
3150: check_result(result, "dns_rdata_tostruct");
3151: serial = soa.serial;
3152: dns_rdata_freestruct(&soa);
3153: if (!query->first_soa_rcvd) {
3154: query->first_soa_rcvd = ISC_TRUE;
3155: query->first_rr_serial = serial;
3156: debug("this is the first serial %u",
3157: serial);
3158: if (ixfr && isc_serial_ge(ixfr_serial,
3159: serial)) {
3160: debug("got up to date "
3161: "response");
3162: goto doexit;
3163: }
3164: goto next_rdata;
3165: }
3166: if (axfr) {
3167: debug("doing axfr, got second SOA");
3168: goto doexit;
3169: }
3170: if (!query->second_rr_rcvd) {
3171: if (query->first_rr_serial == serial) {
3172: debug("doing ixfr, got "
3173: "empty zone");
3174: goto doexit;
3175: }
3176: debug("this is the second serial %u",
3177: serial);
3178: query->second_rr_rcvd = ISC_TRUE;
3179: query->second_rr_serial = serial;
3180: goto next_rdata;
3181: }
3182: /*
3183: * If we get to this point, we're doing an
3184: * IXFR and have to start really looking
3185: * at serial numbers.
3186: */
3187: if (query->first_rr_serial == serial) {
3188: debug("got a match for ixfr");
3189: if (!query->first_repeat_rcvd) {
3190: query->first_repeat_rcvd =
3191: ISC_TRUE;
3192: goto next_rdata;
3193: }
3194: debug("done with ixfr");
3195: goto doexit;
3196: }
3197: debug("meaningless soa %u", serial);
3198: next_rdata:
3199: result = dns_rdataset_next(rdataset);
3200: } while (result == ISC_R_SUCCESS);
3201: }
3202: result = dns_message_nextname(msg, DNS_SECTION_ANSWER);
3203: } while (result == ISC_R_SUCCESS);
3204: launch_next_query(query, ISC_FALSE);
3205: return (ISC_FALSE);
3206: doexit:
3207: dighost_received(sevent->n, &sevent->address, query);
3208: return (ISC_TRUE);
3209: }
3210:
3211: static void
3212: process_sit(dig_lookup_t *l, dns_message_t *msg,
3213: isc_buffer_t *optbuf, size_t optlen)
3214: {
3215: char bb[256];
3216: isc_buffer_t hexbuf;
3217: size_t len;
3218: const unsigned char *sit;
3219: isc_boolean_t copysit;
3220: isc_result_t result;
3221:
3222: if (l->sitvalue != NULL) {
3223: isc_buffer_init(&hexbuf, bb, sizeof(bb));
3224: result = isc_hex_decodestring(l->sitvalue, &hexbuf);
3225: check_result(result, "isc_hex_decodestring");
3226: sit = isc_buffer_base(&hexbuf);
3227: len = isc_buffer_usedlength(&hexbuf);
3228: copysit = ISC_FALSE;
3229: } else {
3230: sit = cookie;
3231: len = sizeof(cookie);
3232: copysit = ISC_TRUE;
3233: }
3234:
3235: INSIST(msg->sitok == 0 && msg->sitbad == 0);
3236: if (optlen >= len && optlen >= 8U) {
3237: if (isc_safe_memequal(isc_buffer_current(optbuf), sit, 8)) {
3238: msg->sitok = 1;
3239: } else {
3240: printf(";; Warning: SIT client cookie mismatch\n");
3241: msg->sitbad = 1;
3242: copysit = ISC_FALSE;
3243: }
3244: } else {
3245: printf(";; Warning: SIT bad token (too short)\n");
3246: msg->sitbad = 1;
3247: copysit = ISC_FALSE;
3248: }
3249: if (copysit) {
3250: isc_region_t r;
3251:
3252: r.base = isc_buffer_current(optbuf);
3253: r.length = (unsigned int)optlen;
3254: isc_buffer_init(&hexbuf, sitvalue, sizeof(sitvalue));
3255: result = isc_hex_totext(&r, 2, "", &hexbuf);
3256: check_result(result, "isc_hex_totext");
3257: if (isc_buffer_availablelength(&hexbuf) > 0) {
3258: isc_buffer_putuint8(&hexbuf, 0);
3259: l->sitvalue = sitvalue;
3260: }
3261: }
3262: isc_buffer_forward(optbuf, (unsigned int)optlen);
3263: }
3264:
3265: static void
3266: process_opt(dig_lookup_t *l, dns_message_t *msg) {
3267: dns_rdata_t rdata;
3268: isc_result_t result;
3269: isc_buffer_t optbuf;
3270: uint16_t optcode, optlen;
3271: dns_rdataset_t *opt = msg->opt;
3272: isc_boolean_t seen_cookie = ISC_FALSE;
3273:
3274: result = dns_rdataset_first(opt);
3275: if (result == ISC_R_SUCCESS) {
3276: dns_rdata_init(&rdata);
3277: dns_rdataset_current(opt, &rdata);
3278: isc_buffer_init(&optbuf, rdata.data, rdata.length);
3279: isc_buffer_add(&optbuf, rdata.length);
3280: while (isc_buffer_remaininglength(&optbuf) >= 4) {
3281: optcode = isc_buffer_getuint16(&optbuf);
3282: optlen = isc_buffer_getuint16(&optbuf);
3283: switch (optcode) {
3284: case DNS_OPT_COOKIE:
3285: /*
3286: * Only process the first cookie option.
3287: */
3288: if (seen_cookie) {
3289: isc_buffer_forward(&optbuf, optlen);
3290: break;
3291: }
3292: process_sit(l, msg, &optbuf, optlen);
3293: seen_cookie = ISC_TRUE;
3294: break;
3295: default:
3296: isc_buffer_forward(&optbuf, optlen);
3297: break;
3298: }
3299: }
3300: }
3301: }
3302:
3303: static int
3304: ednsvers(dns_rdataset_t *opt) {
3305: return ((opt->ttl >> 16) & 0xff);
3306: }
3307:
3308: /*%
3309: * Event handler for recv complete. Perform whatever actions are necessary,
3310: * based on the specifics of the user's request.
3311: */
3312: static void
3313: recv_done(isc_task_t *task, isc_event_t *event) {
3314: isc_socketevent_t *sevent = NULL;
3315: dig_query_t *query = NULL;
3316: isc_buffer_t *b = NULL;
3317: dns_message_t *msg = NULL;
3318: isc_result_t result;
3319: dig_lookup_t *n, *l;
3320: isc_boolean_t docancel = ISC_FALSE;
3321: isc_boolean_t match = ISC_TRUE;
3322: unsigned int parseflags;
3323: dns_messageid_t id;
3324: unsigned int msgflags;
3325: int newedns;
3326:
3327: UNUSED(task);
3328: INSIST(!free_now);
3329:
3330: debug("recv_done()");
3331:
3332: recvcount--;
3333: debug("recvcount=%d", recvcount);
3334: INSIST(recvcount >= 0);
3335:
3336: query = event->ev_arg;
3337: TIME_NOW(&query->time_recv);
3338: debug("lookup=%p, query=%p", query->lookup, query);
3339:
3340: l = query->lookup;
3341:
3342: REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
3343: sevent = (isc_socketevent_t *)event;
3344:
3345: b = ISC_LIST_HEAD(sevent->bufferlist);
3346: INSIST(b == &query->recvbuf);
3347: ISC_LIST_DEQUEUE(sevent->bufferlist, &query->recvbuf, link);
3348:
3349: if ((l->tcp_mode) && (query->timer != NULL))
3350: isc_timer_touch(query->timer);
3351: if ((!l->pending && !l->ns_search_only) || cancel_now) {
3352: debug("no longer pending. Got %s",
3353: isc_result_totext(sevent->result));
3354: query->waiting_connect = ISC_FALSE;
3355:
3356: isc_event_free(&event);
3357: clear_query(query);
3358: check_next_lookup(l);
3359: return;
3360: }
3361:
3362: if (sevent->result != ISC_R_SUCCESS) {
3363: if (sevent->result == ISC_R_CANCELED) {
3364: debug("in recv cancel handler");
3365: query->waiting_connect = ISC_FALSE;
3366: } else {
3367: printf(";; communications error: %s\n",
3368: isc_result_totext(sevent->result));
3369: if (keep != NULL)
3370: isc_socket_detach(&keep);
3371: isc_socket_detach(&query->sock);
3372: sockcount--;
3373: debug("sockcount=%d", sockcount);
3374: INSIST(sockcount >= 0);
3375: }
3376: if (sevent->result == ISC_R_EOF && l->eoferr == 0U) {
3377: n = requeue_lookup(l, ISC_TRUE);
3378: n->eoferr++;
3379: }
3380: isc_event_free(&event);
3381: clear_query(query);
3382: cancel_lookup(l);
3383: check_next_lookup(l);
3384: return;
3385: }
3386:
3387: if (!l->tcp_mode &&
3388: !isc_sockaddr_compare(&sevent->address, &query->sockaddr,
3389: ISC_SOCKADDR_CMPADDR|
3390: ISC_SOCKADDR_CMPPORT|
3391: ISC_SOCKADDR_CMPSCOPE|
3392: ISC_SOCKADDR_CMPSCOPEZERO)) {
3393: char buf1[ISC_SOCKADDR_FORMATSIZE];
3394: char buf2[ISC_SOCKADDR_FORMATSIZE];
3395: isc_sockaddr_t any;
3396:
3397: if (isc_sockaddr_pf(&query->sockaddr) == AF_INET)
3398: isc_sockaddr_any(&any);
3399: else
3400: isc_sockaddr_any6(&any);
3401:
3402: /*
3403: * We don't expect a match when the packet is
3404: * sent to 0.0.0.0, :: or to a multicast addresses.
3405: * XXXMPA broadcast needs to be handled here as well.
3406: */
3407: if ((!isc_sockaddr_eqaddr(&query->sockaddr, &any) &&
3408: !isc_sockaddr_ismulticast(&query->sockaddr)) ||
3409: isc_sockaddr_getport(&query->sockaddr) !=
3410: isc_sockaddr_getport(&sevent->address)) {
3411: isc_sockaddr_format(&sevent->address, buf1,
3412: sizeof(buf1));
3413: isc_sockaddr_format(&query->sockaddr, buf2,
3414: sizeof(buf2));
3415: printf(";; reply from unexpected source: %s,"
3416: " expected %s\n", buf1, buf2);
3417: match = ISC_FALSE;
3418: }
3419: }
3420:
3421: result = dns_message_peekheader(b, &id, &msgflags);
3422: if (result != ISC_R_SUCCESS || l->sendmsg->id != id) {
3423: match = ISC_FALSE;
3424: if (l->tcp_mode) {
3425: isc_boolean_t fail = ISC_TRUE;
3426: if (result == ISC_R_SUCCESS) {
3427: if (!query->first_soa_rcvd ||
3428: query->warn_id)
3429: printf(";; %s: ID mismatch: "
3430: "expected ID %u, got %u\n",
3431: query->first_soa_rcvd ?
3432: "WARNING" : "ERROR",
3433: l->sendmsg->id, id);
3434: if (query->first_soa_rcvd)
3435: fail = ISC_FALSE;
3436: query->warn_id = ISC_FALSE;
3437: } else
3438: printf(";; ERROR: short "
3439: "(< header size) message\n");
3440: if (fail) {
3441: isc_event_free(&event);
3442: clear_query(query);
3443: cancel_lookup(l);
3444: check_next_lookup(l);
3445: return;
3446: }
3447: match = ISC_TRUE;
3448: } else if (result == ISC_R_SUCCESS)
3449: printf(";; Warning: ID mismatch: "
3450: "expected ID %u, got %u\n", l->sendmsg->id, id);
3451: else
3452: printf(";; Warning: short "
3453: "(< header size) message received\n");
3454: }
3455:
3456: if (result == ISC_R_SUCCESS && (msgflags & DNS_MESSAGEFLAG_QR) == 0)
3457: printf(";; Warning: query response not set\n");
3458:
3459: if (!match)
3460: goto udp_mismatch;
3461:
3462: result = dns_message_create(DNS_MESSAGE_INTENTPARSE, &msg);
3463: check_result(result, "dns_message_create");
3464:
3465: if (tsigkey != NULL) {
3466: if (l->querysig == NULL) {
3467: debug("getting initial querysig");
3468: result = dns_message_getquerytsig(l->sendmsg,
3469: &l->querysig);
3470: check_result(result, "dns_message_getquerytsig");
3471: }
3472: result = dns_message_setquerytsig(msg, l->querysig);
3473: check_result(result, "dns_message_setquerytsig");
3474: result = dns_message_settsigkey(msg, tsigkey);
3475: check_result(result, "dns_message_settsigkey");
3476: msg->tsigctx = l->tsigctx;
3477: l->tsigctx = NULL;
3478: if (l->msgcounter != 0)
3479: msg->tcp_continuation = 1;
3480: l->msgcounter++;
3481: }
3482:
3483: debug("before parse starts");
3484: parseflags = DNS_MESSAGEPARSE_PRESERVEORDER;
3485: if (l->besteffort) {
3486: parseflags |= DNS_MESSAGEPARSE_BESTEFFORT;
3487: parseflags |= DNS_MESSAGEPARSE_IGNORETRUNCATION;
3488: }
3489: result = dns_message_parse(msg, b, parseflags);
3490: if (result == DNS_R_RECOVERABLE) {
3491: printf(";; Warning: Message parser reports malformed "
3492: "message packet.\n");
3493: result = ISC_R_SUCCESS;
3494: }
3495: if (result != ISC_R_SUCCESS) {
3496: printf(";; Got bad packet: %s\n", isc_result_totext(result));
3497: hex_dump(b);
3498: query->waiting_connect = ISC_FALSE;
3499: dns_message_destroy(&msg);
3500: isc_event_free(&event);
3501: clear_query(query);
3502: cancel_lookup(l);
3503: check_next_lookup(l);
3504: return;
3505: }
3506: if (msg->counts[DNS_SECTION_QUESTION] != 0) {
3507: match = ISC_TRUE;
3508: for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION);
3509: result == ISC_R_SUCCESS && match;
3510: result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) {
3511: dns_name_t *name = NULL;
3512: dns_rdataset_t *rdataset;
3513:
3514: dns_message_currentname(msg, DNS_SECTION_QUESTION,
3515: &name);
3516: for (rdataset = ISC_LIST_HEAD(name->list);
3517: rdataset != NULL;
3518: rdataset = ISC_LIST_NEXT(rdataset, link)) {
3519: if (l->rdtype != rdataset->type ||
3520: l->rdclass != rdataset->rdclass ||
3521: !dns_name_equal(l->name, name)) {
3522: char namestr[DNS_NAME_FORMATSIZE];
3523: char typebuf[DNS_RDATATYPE_FORMATSIZE];
3524: char classbuf[DNS_RDATACLASS_FORMATSIZE];
3525: dns_name_format(name, namestr,
3526: sizeof(namestr));
3527: dns_rdatatype_format(rdataset->type,
3528: typebuf,
3529: sizeof(typebuf));
3530: dns_rdataclass_format(rdataset->rdclass,
3531: classbuf,
3532: sizeof(classbuf));
3533: printf(";; Question section mismatch: "
3534: "got %s/%s/%s\n",
3535: namestr, typebuf, classbuf);
3536: match = ISC_FALSE;
3537: }
3538: }
3539: }
3540: if (!match) {
3541: dns_message_destroy(&msg);
3542: if (l->tcp_mode) {
3543: isc_event_free(&event);
3544: clear_query(query);
3545: cancel_lookup(l);
3546: check_next_lookup(l);
3547: return;
3548: } else
3549: goto udp_mismatch;
3550: }
3551: }
3552: if (msg->rcode == dns_rcode_badvers && msg->opt != NULL &&
3553: (newedns = ednsvers(msg->opt)) < l->edns && l->ednsneg) {
3554: /*
3555: * Add minimum EDNS version required checks here if needed.
3556: */
3557: if (l->comments)
3558: printf(";; BADVERS, retrying with EDNS version %u.\n",
3559: (unsigned int)newedns);
3560: l->edns = newedns;
3561: n = requeue_lookup(l, ISC_TRUE);
3562: if (l->trace && l->trace_root)
3563: n->rdtype = l->qrdtype;
3564: dns_message_destroy(&msg);
3565: isc_event_free(&event);
3566: clear_query(query);
3567: cancel_lookup(l);
3568: check_next_lookup(l);
3569: return;
3570: }
3571: if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0 &&
3572: !l->ignore && !l->tcp_mode) {
3573: if (l->sitvalue == NULL && l->sit && msg->opt != NULL)
3574: process_opt(l, msg);
3575: if (l->comments)
3576: printf(";; Truncated, retrying in TCP mode.\n");
3577: n = requeue_lookup(l, ISC_TRUE);
3578: n->tcp_mode = ISC_TRUE;
3579: if (l->trace && l->trace_root)
3580: n->rdtype = l->qrdtype;
3581: dns_message_destroy(&msg);
3582: isc_event_free(&event);
3583: clear_query(query);
3584: cancel_lookup(l);
3585: check_next_lookup(l);
3586: return;
3587: }
3588: if ((msg->rcode == dns_rcode_servfail && !l->servfail_stops) ||
3589: (check_ra && (msg->flags & DNS_MESSAGEFLAG_RA) == 0 && l->recurse))
3590: {
3591: dig_query_t *next = ISC_LIST_NEXT(query, link);
3592: if (l->current_query == query)
3593: l->current_query = NULL;
3594: if (next != NULL) {
3595: debug("sending query %p\n", next);
3596: if (l->tcp_mode)
3597: send_tcp_connect(next);
3598: else
3599: send_udp(next);
3600: }
3601: /*
3602: * If our query is at the head of the list and there
3603: * is no next, we're the only one left, so fall
3604: * through to print the message.
3605: */
3606: if ((ISC_LIST_HEAD(l->q) != query) ||
3607: (ISC_LIST_NEXT(query, link) != NULL)) {
3608: if (l->comments)
3609: printf(";; Got %s from %s, "
3610: "trying next server\n",
3611: msg->rcode == dns_rcode_servfail ?
3612: "SERVFAIL reply" :
3613: "recursion not available",
3614: query->servname);
3615: clear_query(query);
3616: check_next_lookup(l);
3617: dns_message_destroy(&msg);
3618: isc_event_free(&event);
3619: return;
3620: }
3621: }
3622:
3623: if (tsigkey != NULL) {
3624: result = dns_tsig_verify(&query->recvbuf, msg);
3625: if (result != ISC_R_SUCCESS) {
3626: printf(";; Couldn't verify signature: %s\n",
3627: isc_result_totext(result));
3628: validated = ISC_FALSE;
3629: }
3630: l->tsigctx = msg->tsigctx;
3631: msg->tsigctx = NULL;
3632: if (l->querysig != NULL) {
3633: debug("freeing querysig buffer %p", l->querysig);
3634: isc_buffer_free(&l->querysig);
3635: }
3636: result = dns_message_getquerytsig(msg, &l->querysig);
3637: check_result(result,"dns_message_getquerytsig");
3638: }
3639:
3640: extrabytes = isc_buffer_remaininglength(b);
3641:
3642: debug("after parse");
3643: if (l->doing_xfr && l->xfr_q == NULL) {
3644: l->xfr_q = query;
3645: /*
3646: * Once we are in the XFR message, increase
3647: * the timeout to much longer, so brief network
3648: * outages won't cause the XFR to abort
3649: */
3650: if (timeout != INT_MAX && query->timer != NULL) {
3651: unsigned int local_timeout;
3652:
3653: if (timeout == 0) {
3654: if (l->tcp_mode)
3655: local_timeout = TCP_TIMEOUT * 4;
3656: else
3657: local_timeout = UDP_TIMEOUT * 4;
3658: } else {
3659: if (timeout < (INT_MAX / 4))
3660: local_timeout = timeout * 4;
3661: else
3662: local_timeout = INT_MAX;
3663: }
3664: debug("have local timeout of %d", local_timeout);
3665: interval_set(&l->interval, local_timeout, 0);
3666: result = isc_timer_reset(query->timer,
3667: isc_timertype_once,
3668: NULL,
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: