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