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