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