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