1 /* $NetBSD: host.c,v 1.13 2025/01/26 16:24:32 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 /*! \file */ 17 18 #include <inttypes.h> 19 #include <limits.h> 20 #include <locale.h> 21 #include <stdbool.h> 22 #include <stdlib.h> 23 24 #include <isc/attributes.h> 25 #include <isc/commandline.h> 26 #include <isc/loop.h> 27 #include <isc/netaddr.h> 28 #include <isc/string.h> 29 #include <isc/util.h> 30 31 #include <dns/byaddr.h> 32 #include <dns/fixedname.h> 33 #include <dns/message.h> 34 #include <dns/name.h> 35 #include <dns/rdata.h> 36 #include <dns/rdataclass.h> 37 #include <dns/rdataset.h> 38 #include <dns/rdatastruct.h> 39 #include <dns/rdatatype.h> 40 41 #include "dighost.h" 42 43 static bool short_form = true, listed_server = false; 44 static bool default_lookups = true; 45 static int seen_error = -1; 46 static bool list_addresses = true; 47 static bool list_almost_all = false; 48 static dns_rdatatype_t list_type = dns_rdatatype_a; 49 static bool printed_server = false; 50 static bool ipv4only = false, ipv6only = false; 51 52 static const char *opcodetext[] = { "QUERY", "IQUERY", "STATUS", 53 "RESERVED3", "NOTIFY", "UPDATE", 54 "RESERVED6", "RESERVED7", "RESERVED8", 55 "RESERVED9", "RESERVED10", "RESERVED11", 56 "RESERVED12", "RESERVED13", "RESERVED14", 57 "RESERVED15" }; 58 59 static const char *rcodetext[] = { "NOERROR", "FORMERR", "SERVFAIL", 60 "NXDOMAIN", "NOTIMP", "REFUSED", 61 "YXDOMAIN", "YXRRSET", "NXRRSET", 62 "NOTAUTH", "NOTZONE", "RESERVED11", 63 "RESERVED12", "RESERVED13", "RESERVED14", 64 "RESERVED15", "BADVERS" }; 65 66 struct rtype { 67 unsigned int type; 68 const char *text; 69 }; 70 71 struct rtype rtypes[] = { { 1, "has address" }, 72 { 2, "name server" }, 73 { 5, "is an alias for" }, 74 { 11, "has well known services" }, 75 { 12, "domain name pointer" }, 76 { 13, "host information" }, 77 { 15, "mail is handled by" }, 78 { 16, "descriptive text" }, 79 { 19, "x25 address" }, 80 { 20, "ISDN address" }, 81 { 24, "has signature" }, 82 { 25, "has key" }, 83 { 28, "has IPv6 address" }, 84 { 29, "location" }, 85 { 0, NULL } }; 86 87 static char * 88 rcode_totext(dns_rcode_t rcode) { 89 static char buf[sizeof("?65535")]; 90 union { 91 const char *consttext; 92 char *deconsttext; 93 } totext; 94 95 if (rcode >= (sizeof(rcodetext) / sizeof(rcodetext[0]))) { 96 snprintf(buf, sizeof(buf), "?%u", rcode); 97 totext.deconsttext = buf; 98 } else { 99 totext.consttext = rcodetext[rcode]; 100 } 101 return totext.deconsttext; 102 } 103 104 noreturn static void 105 show_usage(void); 106 107 static void 108 show_usage(void) { 109 fprintf(stderr, 110 "Usage: host [-aCdilrTvVw] [-c class] [-N ndots] [-t type] [-W " 111 "time]\n" 112 " [-R number] [-m flag] [-p port] hostname " 113 "[server]\n" 114 " -a is equivalent to -v -t ANY\n" 115 " -A is like -a but omits RRSIG, NSEC, NSEC3\n" 116 " -c specifies query class for non-IN data\n" 117 " -C compares SOA records on authoritative nameservers\n" 118 " -d is equivalent to -v\n" 119 " -l lists all hosts in a domain, using AXFR\n" 120 " -m set memory debugging flag (trace|record|usage)\n" 121 " -N changes the number of dots allowed before root " 122 "lookup " 123 "is done\n" 124 " -p specifies the port on the server to query\n" 125 " -r disables recursive processing\n" 126 " -R specifies number of retries for UDP packets\n" 127 " -s a SERVFAIL response should stop query\n" 128 " -t specifies the query type\n" 129 " -T enables TCP/IP mode\n" 130 " -U enables UDP mode\n" 131 " -v enables verbose output\n" 132 " -V print version number and exit\n" 133 " -w specifies to wait forever for a reply\n" 134 " -W specifies how long to wait for a reply\n" 135 " -4 use IPv4 query transport only\n" 136 " -6 use IPv6 query transport only\n"); 137 exit(EXIT_FAILURE); 138 } 139 140 static void 141 host_shutdown(void) { 142 isc_loopmgr_shutdown(loopmgr); 143 } 144 145 static void 146 received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { 147 isc_time_t now; 148 int diff; 149 150 if (!short_form) { 151 char fromtext[ISC_SOCKADDR_FORMATSIZE]; 152 isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 153 if (query->lookup->use_usec) { 154 now = isc_time_now_hires(); 155 } else { 156 now = isc_time_now(); 157 } 158 diff = (int)isc_time_microdiff(&now, &query->time_sent); 159 printf("Received %u bytes from %s in %d ms\n", bytes, fromtext, 160 diff / 1000); 161 } 162 } 163 164 static void 165 trying(char *frm, dig_lookup_t *lookup) { 166 UNUSED(lookup); 167 168 if (!short_form) { 169 printf("Trying \"%s\"\n", frm); 170 } 171 } 172 173 static void 174 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata, 175 dig_query_t *query) { 176 isc_buffer_t *b = NULL; 177 char namestr[DNS_NAME_FORMATSIZE]; 178 isc_region_t r; 179 isc_result_t result; 180 unsigned int bufsize = BUFSIZ; 181 182 dns_name_format(name, namestr, sizeof(namestr)); 183 retry: 184 isc_buffer_allocate(mctx, &b, bufsize); 185 result = dns_rdata_totext(rdata, NULL, b); 186 if (result == ISC_R_NOSPACE) { 187 isc_buffer_free(&b); 188 INSIST(bufsize <= (UINT_MAX / 2)); 189 bufsize *= 2; 190 goto retry; 191 } 192 check_result(result, "dns_rdata_totext"); 193 isc_buffer_usedregion(b, &r); 194 if (query->lookup->identify_previous_line) { 195 printf("Nameserver %s:\n\t", query->servname); 196 } 197 printf("%s %s %.*s", namestr, msg, (int)r.length, (char *)r.base); 198 if (query->lookup->identify) { 199 printf(" on server %s", query->servname); 200 } 201 printf("\n"); 202 isc_buffer_free(&b); 203 } 204 205 static isc_result_t 206 printsection(dns_message_t *msg, dns_section_t sectionid, 207 const char *section_name, bool headers, dig_query_t *query) { 208 dns_name_t *name, *print_name; 209 dns_rdataset_t *rdataset; 210 dns_rdata_t rdata = DNS_RDATA_INIT; 211 isc_buffer_t target; 212 isc_result_t result, loopresult; 213 isc_region_t r; 214 dns_name_t empty_name; 215 char tbuf[4096] = { 0 }; 216 bool first; 217 bool no_rdata = (sectionid == DNS_SECTION_QUESTION); 218 219 if (headers) { 220 printf(";; %s SECTION:\n", section_name); 221 } 222 223 dns_name_init(&empty_name, NULL); 224 225 result = dns_message_firstname(msg, sectionid); 226 if (result == ISC_R_NOMORE) { 227 return ISC_R_SUCCESS; 228 } else if (result != ISC_R_SUCCESS) { 229 return result; 230 } 231 232 for (;;) { 233 name = NULL; 234 dns_message_currentname(msg, sectionid, &name); 235 236 isc_buffer_init(&target, tbuf, sizeof(tbuf)); 237 first = true; 238 print_name = name; 239 240 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 241 rdataset = ISC_LIST_NEXT(rdataset, link)) 242 { 243 if (query->lookup->rdtype == dns_rdatatype_axfr && 244 !((!list_addresses && 245 (list_type == dns_rdatatype_any || 246 rdataset->type == list_type)) || 247 (list_addresses && 248 (rdataset->type == dns_rdatatype_a || 249 rdataset->type == dns_rdatatype_aaaa || 250 rdataset->type == dns_rdatatype_ns || 251 rdataset->type == dns_rdatatype_ptr)))) 252 { 253 continue; 254 } 255 if (list_almost_all && 256 (rdataset->type == dns_rdatatype_rrsig || 257 rdataset->type == dns_rdatatype_nsec || 258 rdataset->type == dns_rdatatype_nsec3)) 259 { 260 continue; 261 } 262 if (!short_form) { 263 result = dns_rdataset_totext(rdataset, 264 print_name, false, 265 no_rdata, &target); 266 if (result != ISC_R_SUCCESS) { 267 return result; 268 } 269 #ifdef USEINITALWS 270 if (first) { 271 print_name = &empty_name; 272 first = false; 273 } 274 #else /* ifdef USEINITALWS */ 275 UNUSED(first); /* Shut up compiler. */ 276 #endif /* ifdef USEINITALWS */ 277 } else { 278 loopresult = dns_rdataset_first(rdataset); 279 while (loopresult == ISC_R_SUCCESS) { 280 struct rtype *t; 281 const char *rtt; 282 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 283 char typebuf2[DNS_RDATATYPE_FORMATSIZE + 284 20]; 285 dns_rdataset_current(rdataset, &rdata); 286 287 for (t = rtypes; t->text != NULL; t++) { 288 if (t->type == rdata.type) { 289 rtt = t->text; 290 goto found; 291 } 292 } 293 294 dns_rdatatype_format(rdata.type, 295 typebuf, 296 sizeof(typebuf)); 297 snprintf(typebuf2, sizeof(typebuf2), 298 "has %s record", typebuf); 299 rtt = typebuf2; 300 found: 301 say_message(print_name, rtt, &rdata, 302 query); 303 dns_rdata_reset(&rdata); 304 loopresult = 305 dns_rdataset_next(rdataset); 306 } 307 } 308 } 309 if (!short_form) { 310 isc_buffer_usedregion(&target, &r); 311 if (no_rdata) { 312 printf(";%.*s", (int)r.length, (char *)r.base); 313 } else { 314 printf("%.*s", (int)r.length, (char *)r.base); 315 } 316 } 317 318 result = dns_message_nextname(msg, sectionid); 319 if (result == ISC_R_NOMORE) { 320 break; 321 } else if (result != ISC_R_SUCCESS) { 322 return result; 323 } 324 } 325 326 return ISC_R_SUCCESS; 327 } 328 329 static isc_result_t 330 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, 331 const dns_name_t *owner, const char *set_name, bool headers) { 332 isc_buffer_t target; 333 isc_result_t result; 334 isc_region_t r; 335 char tbuf[4096]; 336 337 UNUSED(msg); 338 if (headers) { 339 printf(";; %s SECTION:\n", set_name); 340 } 341 342 isc_buffer_init(&target, tbuf, sizeof(tbuf)); 343 344 result = dns_rdataset_totext(rdataset, owner, false, false, &target); 345 if (result != ISC_R_SUCCESS) { 346 return result; 347 } 348 isc_buffer_usedregion(&target, &r); 349 printf("%.*s", (int)r.length, (char *)r.base); 350 351 return ISC_R_SUCCESS; 352 } 353 354 static void 355 chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { 356 isc_result_t result; 357 dns_rdataset_t *rdataset; 358 dns_rdata_cname_t cname; 359 dns_rdata_t rdata = DNS_RDATA_INIT; 360 unsigned int i = msg->counts[DNS_SECTION_ANSWER]; 361 362 while (i-- > 0) { 363 rdataset = NULL; 364 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 365 dns_rdatatype_cname, 0, NULL, 366 &rdataset); 367 if (result != ISC_R_SUCCESS) { 368 return; 369 } 370 result = dns_rdataset_first(rdataset); 371 check_result(result, "dns_rdataset_first"); 372 dns_rdata_reset(&rdata); 373 dns_rdataset_current(rdataset, &rdata); 374 result = dns_rdata_tostruct(&rdata, &cname, NULL); 375 check_result(result, "dns_rdata_tostruct"); 376 dns_name_copy(&cname.cname, qname); 377 dns_rdata_freestruct(&cname); 378 } 379 } 380 381 static isc_result_t 382 printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg, 383 bool headers) { 384 bool did_flag = false; 385 dns_rdataset_t *opt, *tsig = NULL; 386 const dns_name_t *tsigname; 387 isc_result_t result = ISC_R_SUCCESS; 388 int force_error; 389 390 UNUSED(msgbuf); 391 UNUSED(headers); 392 393 /* 394 * We get called multiple times. 395 * Preserve any existing error status. 396 */ 397 force_error = (seen_error == 1) ? 1 : 0; 398 seen_error = 1; 399 if (listed_server && !printed_server) { 400 char sockstr[ISC_SOCKADDR_FORMATSIZE]; 401 402 printf("Using domain server:\n"); 403 printf("Name: %s\n", query->userarg); 404 isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); 405 printf("Address: %s\n", sockstr); 406 printf("Aliases: \n\n"); 407 printed_server = true; 408 } 409 410 if (msg->rcode != 0) { 411 char namestr[DNS_NAME_FORMATSIZE]; 412 dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 413 414 if (query->lookup->identify_previous_line) { 415 printf("Nameserver %s:\n\t%s not found: %d(%s)\n", 416 query->servname, 417 (msg->rcode != dns_rcode_nxdomain) 418 ? namestr 419 : query->lookup->textname, 420 msg->rcode, rcode_totext(msg->rcode)); 421 } else { 422 printf("Host %s not found: %d(%s)\n", 423 (msg->rcode != dns_rcode_nxdomain) 424 ? namestr 425 : query->lookup->textname, 426 msg->rcode, rcode_totext(msg->rcode)); 427 } 428 return ISC_R_SUCCESS; 429 } 430 431 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { 432 char namestr[DNS_NAME_FORMATSIZE]; 433 dig_lookup_t *lookup; 434 dns_fixedname_t fixed; 435 dns_name_t *name; 436 437 /* Add AAAA and MX lookups. */ 438 name = dns_fixedname_initname(&fixed); 439 dns_name_copy(query->lookup->name, name); 440 chase_cnamechain(msg, name); 441 dns_name_format(name, namestr, sizeof(namestr)); 442 lookup = clone_lookup(query->lookup, false); 443 if (lookup != NULL) { 444 strlcpy(lookup->textname, namestr, 445 sizeof(lookup->textname)); 446 lookup->rdtype = dns_rdatatype_aaaa; 447 lookup->rdtypeset = true; 448 lookup->origin = NULL; 449 lookup->retries = tries; 450 ISC_LIST_APPEND(lookup_list, lookup, link); 451 } 452 lookup = clone_lookup(query->lookup, false); 453 if (lookup != NULL) { 454 strlcpy(lookup->textname, namestr, 455 sizeof(lookup->textname)); 456 lookup->rdtype = dns_rdatatype_mx; 457 lookup->rdtypeset = true; 458 lookup->origin = NULL; 459 lookup->retries = tries; 460 ISC_LIST_APPEND(lookup_list, lookup, link); 461 } 462 } 463 464 if (!short_form) { 465 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", 466 opcodetext[msg->opcode], rcode_totext(msg->rcode), 467 msg->id); 468 printf(";; flags: "); 469 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 470 printf("qr"); 471 did_flag = true; 472 } 473 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 474 printf("%saa", did_flag ? " " : ""); 475 did_flag = true; 476 } 477 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 478 printf("%stc", did_flag ? " " : ""); 479 did_flag = true; 480 } 481 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 482 printf("%srd", did_flag ? " " : ""); 483 did_flag = true; 484 } 485 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 486 printf("%sra", did_flag ? " " : ""); 487 did_flag = true; 488 } 489 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 490 printf("%sad", did_flag ? " " : ""); 491 did_flag = true; 492 } 493 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 494 printf("%scd", did_flag ? " " : ""); 495 did_flag = true; 496 POST(did_flag); 497 } 498 printf("; QUERY: %u, ANSWER: %u, " 499 "AUTHORITY: %u, ADDITIONAL: %u\n", 500 msg->counts[DNS_SECTION_QUESTION], 501 msg->counts[DNS_SECTION_ANSWER], 502 msg->counts[DNS_SECTION_AUTHORITY], 503 msg->counts[DNS_SECTION_ADDITIONAL]); 504 opt = dns_message_getopt(msg); 505 if (opt != NULL) { 506 printf(";; EDNS: version: %u, udp=%u\n", 507 (unsigned int)((opt->ttl & 0x00ff0000) >> 16), 508 (unsigned int)opt->rdclass); 509 } 510 tsigname = NULL; 511 tsig = dns_message_gettsig(msg, &tsigname); 512 if (tsig != NULL) { 513 printf(";; PSEUDOSECTIONS: TSIG\n"); 514 } 515 } 516 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) && !short_form) 517 { 518 printf("\n"); 519 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION", 520 true, query); 521 if (result != ISC_R_SUCCESS) { 522 return result; 523 } 524 } 525 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { 526 if (!short_form) { 527 printf("\n"); 528 } 529 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER", 530 !short_form, query); 531 if (result != ISC_R_SUCCESS) { 532 return result; 533 } 534 } 535 536 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && 537 !short_form) 538 { 539 printf("\n"); 540 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY", 541 true, query); 542 if (result != ISC_R_SUCCESS) { 543 return result; 544 } 545 } 546 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) && 547 !short_form) 548 { 549 printf("\n"); 550 result = printsection(msg, DNS_SECTION_ADDITIONAL, "ADDITIONAL", 551 true, query); 552 if (result != ISC_R_SUCCESS) { 553 return result; 554 } 555 } 556 if ((tsig != NULL) && !short_form) { 557 printf("\n"); 558 result = printrdata(msg, tsig, tsigname, "PSEUDOSECTION TSIG", 559 true); 560 if (result != ISC_R_SUCCESS) { 561 return result; 562 } 563 } 564 if (!short_form) { 565 printf("\n"); 566 } 567 568 if (short_form && !default_lookups && 569 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) 570 { 571 char namestr[DNS_NAME_FORMATSIZE]; 572 char typestr[DNS_RDATATYPE_FORMATSIZE]; 573 dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 574 dns_rdatatype_format(query->lookup->rdtype, typestr, 575 sizeof(typestr)); 576 printf("%s has no %s record\n", namestr, typestr); 577 } 578 seen_error = force_error; 579 return result; 580 } 581 582 static const char *optstring = "46aAc:dilnm:p:rst:vVwCDN:R:TUW:"; 583 584 static void 585 pre_parse_args(int argc, char **argv) { 586 int c; 587 588 while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { 589 switch (c) { 590 case 'm': 591 memdebugging = true; 592 if (strcasecmp("trace", isc_commandline_argument) == 0) 593 { 594 isc_mem_debugging |= ISC_MEM_DEBUGTRACE; 595 } else if (strcasecmp("record", 596 isc_commandline_argument) == 0) 597 { 598 isc_mem_debugging |= ISC_MEM_DEBUGRECORD; 599 } else if (strcasecmp("usage", 600 isc_commandline_argument) == 0) 601 { 602 isc_mem_debugging |= ISC_MEM_DEBUGUSAGE; 603 } 604 break; 605 606 case '4': 607 if (ipv6only) { 608 fatal("only one of -4 and -6 allowed"); 609 } 610 ipv4only = true; 611 break; 612 case '6': 613 if (ipv4only) { 614 fatal("only one of -4 and -6 allowed"); 615 } 616 ipv6only = true; 617 break; 618 case 'a': 619 break; 620 case 'A': 621 break; 622 case 'c': 623 break; 624 case 'C': 625 break; 626 case 'd': 627 break; 628 case 'D': 629 if (debugging) { 630 debugtiming = true; 631 } 632 debugging = true; 633 break; 634 case 'i': 635 break; 636 case 'l': 637 break; 638 case 'n': 639 break; 640 case 'N': 641 break; 642 case 'p': 643 break; 644 case 'r': 645 break; 646 case 'R': 647 break; 648 case 's': 649 break; 650 case 't': 651 break; 652 case 'T': 653 break; 654 case 'U': 655 break; 656 case 'v': 657 break; 658 case 'V': 659 printf("host %s\n", PACKAGE_VERSION); 660 exit(EXIT_SUCCESS); 661 break; 662 case 'w': 663 break; 664 case 'W': 665 break; 666 default: 667 show_usage(); 668 } 669 } 670 isc_commandline_reset = true; 671 isc_commandline_index = 1; 672 } 673 674 static void 675 parse_args(bool is_batchfile, int argc, char **argv) { 676 char hostname[MXNAME]; 677 dig_lookup_t *lookup; 678 int c; 679 char store[MXNAME]; 680 isc_textregion_t tr; 681 isc_result_t result = ISC_R_SUCCESS; 682 dns_rdatatype_t rdtype; 683 dns_rdataclass_t rdclass; 684 uint32_t serial = 0; 685 686 UNUSED(is_batchfile); 687 688 lookup = make_empty_lookup(); 689 690 lookup->servfail_stops = false; 691 lookup->besteffort = false; 692 lookup->comments = false; 693 short_form = !verbose; 694 695 while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { 696 switch (c) { 697 case 'l': 698 lookup->tcp_mode = true; 699 lookup->rdtype = dns_rdatatype_axfr; 700 lookup->rdtypeset = true; 701 fatalexit = 3; 702 break; 703 case 'v': 704 case 'd': 705 short_form = false; 706 break; 707 case 'r': 708 lookup->recurse = false; 709 break; 710 case 't': 711 if (strncasecmp(isc_commandline_argument, "ixfr=", 5) == 712 0) 713 { 714 rdtype = dns_rdatatype_ixfr; 715 /* XXXMPA add error checking */ 716 serial = strtoul(isc_commandline_argument + 5, 717 NULL, 10); 718 result = ISC_R_SUCCESS; 719 } else { 720 tr.base = isc_commandline_argument; 721 tr.length = strlen(isc_commandline_argument); 722 result = dns_rdatatype_fromtext( 723 &rdtype, (isc_textregion_t *)&tr); 724 } 725 726 if (result != ISC_R_SUCCESS) { 727 fatalexit = 2; 728 fatal("invalid type: %s\n", 729 isc_commandline_argument); 730 } 731 if (!lookup->rdtypeset || 732 lookup->rdtype != dns_rdatatype_axfr) 733 { 734 lookup->rdtype = rdtype; 735 } 736 lookup->rdtypeset = true; 737 if (rdtype == dns_rdatatype_axfr) { 738 /* -l -t any -v */ 739 list_type = dns_rdatatype_any; 740 short_form = false; 741 lookup->tcp_mode = true; 742 } else if (rdtype == dns_rdatatype_ixfr) { 743 lookup->ixfr_serial = serial; 744 lookup->tcp_mode = true; 745 list_type = rdtype; 746 } else if (rdtype == dns_rdatatype_any) { 747 if (!lookup->tcp_mode_set) { 748 lookup->tcp_mode = true; 749 } 750 } else { 751 list_type = rdtype; 752 } 753 list_addresses = false; 754 default_lookups = false; 755 break; 756 case 'c': 757 tr.base = isc_commandline_argument; 758 tr.length = strlen(isc_commandline_argument); 759 result = dns_rdataclass_fromtext( 760 &rdclass, (isc_textregion_t *)&tr); 761 762 if (result != ISC_R_SUCCESS) { 763 fatalexit = 2; 764 fatal("invalid class: %s\n", 765 isc_commandline_argument); 766 } else { 767 lookup->rdclass = rdclass; 768 lookup->rdclassset = true; 769 } 770 default_lookups = false; 771 break; 772 case 'A': 773 list_almost_all = true; 774 FALLTHROUGH; 775 case 'a': 776 if (!lookup->rdtypeset || 777 lookup->rdtype != dns_rdatatype_axfr) 778 { 779 lookup->rdtype = dns_rdatatype_any; 780 } 781 list_type = dns_rdatatype_any; 782 list_addresses = false; 783 lookup->rdtypeset = true; 784 short_form = false; 785 default_lookups = false; 786 break; 787 case 'i': 788 /* deprecated */ 789 break; 790 case 'n': 791 /* deprecated */ 792 break; 793 case 'm': 794 /* Handled by pre_parse_args(). */ 795 break; 796 case 'w': 797 /* 798 * The timer routines are coded such that 799 * timeout==MAXINT doesn't enable the timer 800 */ 801 timeout = INT_MAX; 802 break; 803 case 'W': 804 timeout = atoi(isc_commandline_argument); 805 if (timeout < 1) { 806 timeout = 1; 807 } 808 break; 809 case 'R': 810 tries = atoi(isc_commandline_argument) + 1; 811 if (tries < 2) { 812 tries = 2; 813 } 814 break; 815 case 'T': 816 lookup->tcp_mode = true; 817 lookup->tcp_mode_set = true; 818 break; 819 case 'U': 820 lookup->tcp_mode = false; 821 lookup->tcp_mode_set = true; 822 break; 823 case 'C': 824 debug("showing all SOAs"); 825 lookup->rdtype = dns_rdatatype_ns; 826 lookup->rdtypeset = true; 827 lookup->rdclass = dns_rdataclass_in; 828 lookup->rdclassset = true; 829 lookup->ns_search_only = true; 830 lookup->trace_root = true; 831 lookup->identify_previous_line = true; 832 default_lookups = false; 833 break; 834 case 'N': 835 debug("setting NDOTS to %s", isc_commandline_argument); 836 ndots = atoi(isc_commandline_argument); 837 break; 838 case 'D': 839 /* Handled by pre_parse_args(). */ 840 break; 841 case '4': 842 /* Handled by pre_parse_args(). */ 843 break; 844 case '6': 845 /* Handled by pre_parse_args(). */ 846 break; 847 case 's': 848 lookup->servfail_stops = true; 849 break; 850 case 'p': 851 port = atoi(isc_commandline_argument); 852 port_set = true; 853 break; 854 } 855 } 856 857 lookup->retries = tries; 858 859 if (isc_commandline_index >= argc) { 860 show_usage(); 861 } 862 863 strlcpy(hostname, argv[isc_commandline_index], sizeof(hostname)); 864 865 if (argc > isc_commandline_index + 1) { 866 set_nameserver(argv[isc_commandline_index + 1]); 867 debug("server is %s", argv[isc_commandline_index + 1]); 868 listed_server = true; 869 } else { 870 check_ra = true; 871 } 872 873 lookup->pending = false; 874 if (get_reverse(store, sizeof(store), hostname, true) == ISC_R_SUCCESS) 875 { 876 strlcpy(lookup->textname, store, sizeof(lookup->textname)); 877 lookup->rdtype = dns_rdatatype_ptr; 878 lookup->rdtypeset = true; 879 default_lookups = false; 880 } else { 881 strlcpy(lookup->textname, hostname, sizeof(lookup->textname)); 882 usesearch = true; 883 } 884 lookup->new_search = true; 885 ISC_LIST_APPEND(lookup_list, lookup, link); 886 } 887 888 int 889 main(int argc, char **argv) { 890 tries = 2; 891 892 ISC_LIST_INIT(lookup_list); 893 ISC_LIST_INIT(server_list); 894 ISC_LIST_INIT(search_list); 895 896 fatalexit = 1; 897 898 /* setup dighost callbacks */ 899 dighost_printmessage = printmessage; 900 dighost_received = received; 901 dighost_trying = trying; 902 dighost_shutdown = host_shutdown; 903 904 debug("main()"); 905 progname = argv[0]; 906 pre_parse_args(argc, argv); 907 setup_libs(); 908 setup_system(ipv4only, ipv6only); 909 parse_args(false, argc, argv); 910 if (keyfile[0] != 0) { 911 setup_file_key(); 912 } else if (keysecret[0] != 0) { 913 setup_text_key(); 914 } 915 916 isc_loopmgr_setup(loopmgr, run_loop, NULL); 917 isc_loopmgr_run(loopmgr); 918 919 cancel_all(); 920 destroy_libs(); 921 922 return (seen_error == 0) ? 0 : 1; 923 } 924