1 /* $NetBSD: host.c,v 1.7 2021/04/29 17:26:09 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 /*! \file */ 15 16 #include <inttypes.h> 17 #include <limits.h> 18 #include <stdbool.h> 19 #include <stdlib.h> 20 21 #ifdef HAVE_LOCALE_H 22 #include <locale.h> 23 #endif /* ifdef HAVE_LOCALE_H */ 24 25 #include <isc/app.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 <dig/dig.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 ISC_PLATFORM_NORETURN_PRE static void 107 show_usage(void) ISC_PLATFORM_NORETURN_POST; 108 109 static void 110 show_usage(void) { 111 fputs("Usage: host [-aCdilrTvVw] [-c class] [-N ndots] [-t type] [-W " 112 "time]\n" 113 " [-R number] [-m flag] [-p port] hostname [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 lookup " 122 "is done\n" 123 " -p specifies the port on the server to query\n" 124 " -r disables recursive processing\n" 125 " -R specifies number of retries for UDP packets\n" 126 " -s a SERVFAIL response should stop query\n" 127 " -t specifies the query type\n" 128 " -T enables TCP/IP mode\n" 129 " -U enables UDP mode\n" 130 " -v enables verbose output\n" 131 " -V print version number and exit\n" 132 " -w specifies to wait forever for a reply\n" 133 " -W specifies how long to wait for a reply\n" 134 " -4 use IPv4 query transport only\n" 135 " -6 use IPv6 query transport only\n", 136 stderr); 137 exit(1); 138 } 139 140 static void 141 host_shutdown(void) { 142 (void)isc_app_shutdown(); 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 TIME_NOW_HIRES(&now); 155 } else { 156 TIME_NOW(&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 bufsize *= 2; 189 goto retry; 190 } 191 check_result(result, "dns_rdata_totext"); 192 isc_buffer_usedregion(b, &r); 193 if (query->lookup->identify_previous_line) { 194 printf("Nameserver %s:\n\t", query->servname); 195 } 196 printf("%s %s %.*s", namestr, msg, (int)r.length, (char *)r.base); 197 if (query->lookup->identify) { 198 printf(" on server %s", query->servname); 199 } 200 printf("\n"); 201 isc_buffer_free(&b); 202 } 203 204 static isc_result_t 205 printsection(dns_message_t *msg, dns_section_t sectionid, 206 const char *section_name, bool headers, dig_query_t *query) { 207 dns_name_t *name, *print_name; 208 dns_rdataset_t *rdataset; 209 dns_rdata_t rdata = DNS_RDATA_INIT; 210 isc_buffer_t target; 211 isc_result_t result, loopresult; 212 isc_region_t r; 213 dns_name_t empty_name; 214 char tbuf[4096]; 215 bool first; 216 bool no_rdata; 217 218 if (sectionid == DNS_SECTION_QUESTION) { 219 no_rdata = true; 220 } else { 221 no_rdata = false; 222 } 223 224 if (headers) { 225 printf(";; %s SECTION:\n", section_name); 226 } 227 228 dns_name_init(&empty_name, NULL); 229 230 result = dns_message_firstname(msg, sectionid); 231 if (result == ISC_R_NOMORE) { 232 return (ISC_R_SUCCESS); 233 } else if (result != ISC_R_SUCCESS) { 234 return (result); 235 } 236 237 for (;;) { 238 name = NULL; 239 dns_message_currentname(msg, sectionid, &name); 240 241 isc_buffer_init(&target, tbuf, sizeof(tbuf)); 242 first = true; 243 print_name = name; 244 245 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; 246 rdataset = ISC_LIST_NEXT(rdataset, link)) 247 { 248 if (query->lookup->rdtype == dns_rdatatype_axfr && 249 !((!list_addresses && 250 (list_type == dns_rdatatype_any || 251 rdataset->type == list_type)) || 252 (list_addresses && 253 (rdataset->type == dns_rdatatype_a || 254 rdataset->type == dns_rdatatype_aaaa || 255 rdataset->type == dns_rdatatype_ns || 256 rdataset->type == dns_rdatatype_ptr)))) 257 { 258 continue; 259 } 260 if (list_almost_all && 261 (rdataset->type == dns_rdatatype_rrsig || 262 rdataset->type == dns_rdatatype_nsec || 263 rdataset->type == dns_rdatatype_nsec3)) 264 { 265 continue; 266 } 267 if (!short_form) { 268 result = dns_rdataset_totext(rdataset, 269 print_name, false, 270 no_rdata, &target); 271 if (result != ISC_R_SUCCESS) { 272 return (result); 273 } 274 #ifdef USEINITALWS 275 if (first) { 276 print_name = &empty_name; 277 first = false; 278 } 279 #else /* ifdef USEINITALWS */ 280 UNUSED(first); /* Shut up compiler. */ 281 #endif /* ifdef USEINITALWS */ 282 } else { 283 loopresult = dns_rdataset_first(rdataset); 284 while (loopresult == ISC_R_SUCCESS) { 285 struct rtype *t; 286 const char *rtt; 287 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 288 char typebuf2[DNS_RDATATYPE_FORMATSIZE + 289 20]; 290 dns_rdataset_current(rdataset, &rdata); 291 292 for (t = rtypes; t->text != NULL; t++) { 293 if (t->type == rdata.type) { 294 rtt = t->text; 295 goto found; 296 } 297 } 298 299 dns_rdatatype_format(rdata.type, 300 typebuf, 301 sizeof(typebuf)); 302 snprintf(typebuf2, sizeof(typebuf2), 303 "has %s record", typebuf); 304 rtt = typebuf2; 305 found: 306 say_message(print_name, rtt, &rdata, 307 query); 308 dns_rdata_reset(&rdata); 309 loopresult = 310 dns_rdataset_next(rdataset); 311 } 312 } 313 } 314 if (!short_form) { 315 isc_buffer_usedregion(&target, &r); 316 if (no_rdata) { 317 printf(";%.*s", (int)r.length, (char *)r.base); 318 } else { 319 printf("%.*s", (int)r.length, (char *)r.base); 320 } 321 } 322 323 result = dns_message_nextname(msg, sectionid); 324 if (result == ISC_R_NOMORE) { 325 break; 326 } else if (result != ISC_R_SUCCESS) { 327 return (result); 328 } 329 } 330 331 return (ISC_R_SUCCESS); 332 } 333 334 static isc_result_t 335 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, 336 const dns_name_t *owner, const char *set_name, bool headers) { 337 isc_buffer_t target; 338 isc_result_t result; 339 isc_region_t r; 340 char tbuf[4096]; 341 342 UNUSED(msg); 343 if (headers) { 344 printf(";; %s SECTION:\n", set_name); 345 } 346 347 isc_buffer_init(&target, tbuf, sizeof(tbuf)); 348 349 result = dns_rdataset_totext(rdataset, owner, false, false, &target); 350 if (result != ISC_R_SUCCESS) { 351 return (result); 352 } 353 isc_buffer_usedregion(&target, &r); 354 printf("%.*s", (int)r.length, (char *)r.base); 355 356 return (ISC_R_SUCCESS); 357 } 358 359 static void 360 chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { 361 isc_result_t result; 362 dns_rdataset_t *rdataset; 363 dns_rdata_cname_t cname; 364 dns_rdata_t rdata = DNS_RDATA_INIT; 365 unsigned int i = msg->counts[DNS_SECTION_ANSWER]; 366 367 while (i-- > 0) { 368 rdataset = NULL; 369 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 370 dns_rdatatype_cname, 0, NULL, 371 &rdataset); 372 if (result != ISC_R_SUCCESS) { 373 return; 374 } 375 result = dns_rdataset_first(rdataset); 376 check_result(result, "dns_rdataset_first"); 377 dns_rdata_reset(&rdata); 378 dns_rdataset_current(rdataset, &rdata); 379 result = dns_rdata_tostruct(&rdata, &cname, NULL); 380 check_result(result, "dns_rdata_tostruct"); 381 dns_name_copynf(&cname.cname, qname); 382 dns_rdata_freestruct(&cname); 383 } 384 } 385 386 static isc_result_t 387 printmessage(dig_query_t *query, const isc_buffer_t *msgbuf, dns_message_t *msg, 388 bool headers) { 389 bool did_flag = false; 390 dns_rdataset_t *opt, *tsig = NULL; 391 const dns_name_t *tsigname; 392 isc_result_t result = ISC_R_SUCCESS; 393 int force_error; 394 395 UNUSED(msgbuf); 396 UNUSED(headers); 397 398 /* 399 * We get called multiple times. 400 * Preserve any existing error status. 401 */ 402 force_error = (seen_error == 1) ? 1 : 0; 403 seen_error = 1; 404 if (listed_server && !printed_server) { 405 char sockstr[ISC_SOCKADDR_FORMATSIZE]; 406 407 printf("Using domain server:\n"); 408 printf("Name: %s\n", query->userarg); 409 isc_sockaddr_format(&query->sockaddr, sockstr, sizeof(sockstr)); 410 printf("Address: %s\n", sockstr); 411 printf("Aliases: \n\n"); 412 printed_server = true; 413 } 414 415 if (msg->rcode != 0) { 416 char namestr[DNS_NAME_FORMATSIZE]; 417 dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 418 419 if (query->lookup->identify_previous_line) { 420 printf("Nameserver %s:\n\t%s not found: %d(%s)\n", 421 query->servname, 422 (msg->rcode != dns_rcode_nxdomain) 423 ? namestr 424 : query->lookup->textname, 425 msg->rcode, rcode_totext(msg->rcode)); 426 } else { 427 printf("Host %s not found: %d(%s)\n", 428 (msg->rcode != dns_rcode_nxdomain) 429 ? namestr 430 : query->lookup->textname, 431 msg->rcode, rcode_totext(msg->rcode)); 432 } 433 return (ISC_R_SUCCESS); 434 } 435 436 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { 437 char namestr[DNS_NAME_FORMATSIZE]; 438 dig_lookup_t *lookup; 439 dns_fixedname_t fixed; 440 dns_name_t *name; 441 442 /* Add AAAA and MX lookups. */ 443 name = dns_fixedname_initname(&fixed); 444 dns_name_copynf(query->lookup->name, name); 445 chase_cnamechain(msg, name); 446 dns_name_format(name, namestr, sizeof(namestr)); 447 lookup = clone_lookup(query->lookup, false); 448 if (lookup != NULL) { 449 strlcpy(lookup->textname, namestr, 450 sizeof(lookup->textname)); 451 lookup->rdtype = dns_rdatatype_aaaa; 452 lookup->rdtypeset = true; 453 lookup->origin = NULL; 454 lookup->retries = tries; 455 ISC_LIST_APPEND(lookup_list, lookup, link); 456 } 457 lookup = clone_lookup(query->lookup, false); 458 if (lookup != NULL) { 459 strlcpy(lookup->textname, namestr, 460 sizeof(lookup->textname)); 461 lookup->rdtype = dns_rdatatype_mx; 462 lookup->rdtypeset = true; 463 lookup->origin = NULL; 464 lookup->retries = tries; 465 ISC_LIST_APPEND(lookup_list, lookup, link); 466 } 467 } 468 469 if (!short_form) { 470 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", 471 opcodetext[msg->opcode], rcode_totext(msg->rcode), 472 msg->id); 473 printf(";; flags: "); 474 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 475 printf("qr"); 476 did_flag = true; 477 } 478 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 479 printf("%saa", did_flag ? " " : ""); 480 did_flag = true; 481 } 482 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 483 printf("%stc", did_flag ? " " : ""); 484 did_flag = true; 485 } 486 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 487 printf("%srd", did_flag ? " " : ""); 488 did_flag = true; 489 } 490 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 491 printf("%sra", did_flag ? " " : ""); 492 did_flag = true; 493 } 494 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 495 printf("%sad", did_flag ? " " : ""); 496 did_flag = true; 497 } 498 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 499 printf("%scd", did_flag ? " " : ""); 500 did_flag = true; 501 POST(did_flag); 502 } 503 printf("; QUERY: %u, ANSWER: %u, " 504 "AUTHORITY: %u, ADDITIONAL: %u\n", 505 msg->counts[DNS_SECTION_QUESTION], 506 msg->counts[DNS_SECTION_ANSWER], 507 msg->counts[DNS_SECTION_AUTHORITY], 508 msg->counts[DNS_SECTION_ADDITIONAL]); 509 opt = dns_message_getopt(msg); 510 if (opt != NULL) { 511 printf(";; EDNS: version: %u, udp=%u\n", 512 (unsigned int)((opt->ttl & 0x00ff0000) >> 16), 513 (unsigned int)opt->rdclass); 514 } 515 tsigname = NULL; 516 tsig = dns_message_gettsig(msg, &tsigname); 517 if (tsig != NULL) { 518 printf(";; PSEUDOSECTIONS: TSIG\n"); 519 } 520 } 521 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) && !short_form) 522 { 523 printf("\n"); 524 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION", 525 true, query); 526 if (result != ISC_R_SUCCESS) { 527 return (result); 528 } 529 } 530 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { 531 if (!short_form) { 532 printf("\n"); 533 } 534 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER", 535 !short_form, query); 536 if (result != ISC_R_SUCCESS) { 537 return (result); 538 } 539 } 540 541 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && 542 !short_form) { 543 printf("\n"); 544 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY", 545 true, query); 546 if (result != ISC_R_SUCCESS) { 547 return (result); 548 } 549 } 550 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) && 551 !short_form) { 552 printf("\n"); 553 result = printsection(msg, DNS_SECTION_ADDITIONAL, "ADDITIONAL", 554 true, query); 555 if (result != ISC_R_SUCCESS) { 556 return (result); 557 } 558 } 559 if ((tsig != NULL) && !short_form) { 560 printf("\n"); 561 result = printrdata(msg, tsig, tsigname, "PSEUDOSECTION TSIG", 562 true); 563 if (result != ISC_R_SUCCESS) { 564 return (result); 565 } 566 } 567 if (!short_form) { 568 printf("\n"); 569 } 570 571 if (short_form && !default_lookups && 572 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) 573 { 574 char namestr[DNS_NAME_FORMATSIZE]; 575 char typestr[DNS_RDATATYPE_FORMATSIZE]; 576 dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 577 dns_rdatatype_format(query->lookup->rdtype, typestr, 578 sizeof(typestr)); 579 printf("%s has no %s record\n", namestr, typestr); 580 } 581 seen_error = force_error; 582 return (result); 583 } 584 585 static const char *optstring = "46aAc:dilnm:p:rst:vVwCDN:R:TUW:"; 586 587 /*% version */ 588 static void 589 version(void) { 590 fputs("host " VERSION "\n", stderr); 591 } 592 593 static void 594 pre_parse_args(int argc, char **argv) { 595 int c; 596 597 while ((c = isc_commandline_parse(argc, argv, optstring)) != -1) { 598 switch (c) { 599 case 'm': 600 memdebugging = true; 601 if (strcasecmp("trace", isc_commandline_argument) == 0) 602 { 603 isc_mem_debugging |= ISC_MEM_DEBUGTRACE; 604 } else if (strcasecmp("record", 605 isc_commandline_argument) == 0) { 606 isc_mem_debugging |= ISC_MEM_DEBUGRECORD; 607 } else if (strcasecmp("usage", 608 isc_commandline_argument) == 0) { 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 rdtype = dns_rdatatype_ixfr; 721 /* XXXMPA add error checking */ 722 serial = strtoul(isc_commandline_argument + 5, 723 NULL, 10); 724 result = ISC_R_SUCCESS; 725 } else { 726 tr.base = isc_commandline_argument; 727 tr.length = strlen(isc_commandline_argument); 728 result = dns_rdatatype_fromtext( 729 &rdtype, (isc_textregion_t *)&tr); 730 } 731 732 if (result != ISC_R_SUCCESS) { 733 fatalexit = 2; 734 fatal("invalid type: %s\n", 735 isc_commandline_argument); 736 } 737 if (!lookup->rdtypeset || 738 lookup->rdtype != dns_rdatatype_axfr) { 739 lookup->rdtype = rdtype; 740 } 741 lookup->rdtypeset = true; 742 if (rdtype == dns_rdatatype_axfr) { 743 /* -l -t any -v */ 744 list_type = dns_rdatatype_any; 745 short_form = false; 746 lookup->tcp_mode = true; 747 } else if (rdtype == dns_rdatatype_ixfr) { 748 lookup->ixfr_serial = serial; 749 lookup->tcp_mode = true; 750 list_type = rdtype; 751 } else if (rdtype == dns_rdatatype_any) { 752 if (!lookup->tcp_mode_set) { 753 lookup->tcp_mode = true; 754 } 755 } else { 756 list_type = rdtype; 757 } 758 list_addresses = false; 759 default_lookups = false; 760 break; 761 case 'c': 762 tr.base = isc_commandline_argument; 763 tr.length = strlen(isc_commandline_argument); 764 result = dns_rdataclass_fromtext( 765 &rdclass, (isc_textregion_t *)&tr); 766 767 if (result != ISC_R_SUCCESS) { 768 fatalexit = 2; 769 fatal("invalid class: %s\n", 770 isc_commandline_argument); 771 } else { 772 lookup->rdclass = rdclass; 773 lookup->rdclassset = true; 774 } 775 default_lookups = false; 776 break; 777 case 'A': 778 list_almost_all = true; 779 /* FALL THROUGH */ 780 case 'a': 781 if (!lookup->rdtypeset || 782 lookup->rdtype != dns_rdatatype_axfr) { 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