1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /*! \file */ 18 #include <sys/cdefs.h> 19 20 #include <err.h> 21 #include <limits.h> 22 #include <locale.h> 23 #include <stdlib.h> 24 #include <string.h> 25 #include <unistd.h> 26 #include <time.h> 27 #include <stdint.h> 28 29 #include <isc/app.h> 30 #include <isc/util.h> 31 #include <isc/time.h> 32 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/rdatatype.h> 40 41 #include "dig.h" 42 43 static isc_boolean_t short_form = ISC_TRUE, listed_server = ISC_FALSE; 44 static isc_boolean_t default_lookups = ISC_TRUE; 45 static int seen_error = -1; 46 static isc_boolean_t list_addresses = ISC_TRUE; 47 static dns_rdatatype_t list_type = dns_rdatatype_a; 48 static isc_boolean_t printed_server = ISC_FALSE; 49 static isc_boolean_t ipv4only = ISC_FALSE, ipv6only = ISC_FALSE; 50 51 static const char *opcodetext[] = { 52 "QUERY", 53 "IQUERY", 54 "STATUS", 55 "RESERVED3", 56 "NOTIFY", 57 "UPDATE", 58 "RESERVED6", 59 "RESERVED7", 60 "RESERVED8", 61 "RESERVED9", 62 "RESERVED10", 63 "RESERVED11", 64 "RESERVED12", 65 "RESERVED13", 66 "RESERVED14", 67 "RESERVED15" 68 }; 69 70 static const char *rcodetext[] = { 71 "NOERROR", 72 "FORMERR", 73 "SERVFAIL", 74 "NXDOMAIN", 75 "NOTIMP", 76 "REFUSED", 77 "YXDOMAIN", 78 "YXRRSET", 79 "NXRRSET", 80 "NOTAUTH", 81 "NOTZONE", 82 "RESERVED11", 83 "RESERVED12", 84 "RESERVED13", 85 "RESERVED14", 86 "RESERVED15", 87 "BADVERS" 88 }; 89 90 struct rtype { 91 unsigned int type; 92 const char *text; 93 }; 94 95 static struct rtype rtypes[] = { 96 { 1, "has address" }, 97 { 2, "name server" }, 98 { 5, "is an alias for" }, 99 { 11, "has well known services" }, 100 { 12, "domain name pointer" }, 101 { 13, "host information" }, 102 { 15, "mail is handled by" }, 103 { 16, "descriptive text" }, 104 { 19, "x25 address" }, 105 { 20, "ISDN address" }, 106 { 24, "has signature" }, 107 { 25, "has key" }, 108 { 28, "has IPv6 address" }, 109 { 29, "location" }, 110 { 0, NULL } 111 }; 112 113 static char * 114 rcode_totext(dns_rcode_t rcode) 115 { 116 static char buf[sizeof("?65535")]; 117 union { 118 const char *consttext; 119 char *deconsttext; 120 } totext; 121 122 if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 123 snprintf(buf, sizeof(buf), "?%u", rcode); 124 totext.deconsttext = buf; 125 } else 126 totext.consttext = rcodetext[rcode]; 127 return totext.deconsttext; 128 } 129 130 static __dead void 131 show_usage(void); 132 133 static void 134 show_usage(void) { 135 fputs( 136 "usage: host [-46aCdilrsTVvw] [-c class] [-m flag] [-N ndots] [-R number]\n" 137 " [-t type] [-W wait] name [server]\n", stderr); 138 exit(1); 139 } 140 141 static void 142 host_shutdown(void) { 143 (void) isc_app_shutdown(); 144 } 145 146 static void 147 received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { 148 struct timespec now; 149 int diff; 150 151 if (!short_form) { 152 char fromtext[ISC_SOCKADDR_FORMATSIZE]; 153 isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 154 clock_gettime(CLOCK_MONOTONIC, &now); 155 diff = (int) isc_time_microdiff(&now, &query->time_sent); 156 printf("Received %u bytes from %s in %d ms\n", 157 bytes, fromtext, diff/1000); 158 } 159 } 160 161 static void 162 trying(char *frm, dig_lookup_t *lookup) { 163 UNUSED(lookup); 164 165 if (!short_form) 166 printf("Trying \"%s\"\n", frm); 167 } 168 169 static void 170 say_message(dns_name_t *name, const char *msg, dns_rdata_t *rdata, 171 dig_query_t *query) 172 { 173 isc_buffer_t *b = NULL; 174 char namestr[DNS_NAME_FORMATSIZE]; 175 isc_region_t r; 176 isc_result_t result; 177 unsigned int bufsize = BUFSIZ; 178 179 dns_name_format(name, namestr, sizeof(namestr)); 180 retry: 181 result = isc_buffer_allocate(&b, bufsize); 182 check_result(result, "isc_buffer_allocate"); 183 result = dns_rdata_totext(rdata, NULL, b); 184 if (result == ISC_R_NOSPACE) { 185 isc_buffer_free(&b); 186 bufsize *= 2; 187 goto retry; 188 } 189 check_result(result, "dns_rdata_totext"); 190 isc_buffer_usedregion(b, &r); 191 if (query->lookup->identify_previous_line) { 192 printf("Nameserver %s:\n\t", 193 query->servname); 194 } 195 printf("%s %s %.*s", namestr, 196 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 static isc_result_t 204 printsection(dns_message_t *msg, dns_section_t sectionid, 205 const char *section_name, isc_boolean_t headers, 206 dig_query_t *query) 207 { 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]; 216 isc_boolean_t first; 217 isc_boolean_t no_rdata; 218 219 if (sectionid == DNS_SECTION_QUESTION) 220 no_rdata = ISC_TRUE; 221 else 222 no_rdata = ISC_FALSE; 223 224 if (headers) 225 printf(";; %s SECTION:\n", section_name); 226 227 dns_name_init(&empty_name, NULL); 228 229 result = dns_message_firstname(msg, sectionid); 230 if (result == ISC_R_NOMORE) 231 return (ISC_R_SUCCESS); 232 else if (result != ISC_R_SUCCESS) 233 return (result); 234 235 for (;;) { 236 name = NULL; 237 dns_message_currentname(msg, sectionid, &name); 238 239 isc_buffer_init(&target, tbuf, sizeof(tbuf)); 240 first = ISC_TRUE; 241 print_name = name; 242 243 for (rdataset = ISC_LIST_HEAD(name->list); 244 rdataset != NULL; 245 rdataset = ISC_LIST_NEXT(rdataset, link)) { 246 if (query->lookup->rdtype == dns_rdatatype_axfr && 247 !((!list_addresses && 248 (list_type == dns_rdatatype_any || 249 rdataset->type == list_type)) || 250 (list_addresses && 251 (rdataset->type == dns_rdatatype_a || 252 rdataset->type == dns_rdatatype_aaaa || 253 rdataset->type == dns_rdatatype_ns || 254 rdataset->type == dns_rdatatype_ptr)))) 255 continue; 256 if (!short_form) { 257 result = dns_rdataset_totext(rdataset, 258 print_name, 259 ISC_FALSE, 260 no_rdata, 261 &target); 262 if (result != ISC_R_SUCCESS) 263 return (result); 264 UNUSED(first); /* Shut up compiler. */ 265 } else { 266 loopresult = dns_rdataset_first(rdataset); 267 while (loopresult == ISC_R_SUCCESS) { 268 struct rtype *t; 269 const char *rtt; 270 char typebuf[DNS_RDATATYPE_FORMATSIZE]; 271 char typebuf2[DNS_RDATATYPE_FORMATSIZE 272 + 20]; 273 dns_rdataset_current(rdataset, &rdata); 274 275 for (t = rtypes; t->text != NULL; t++) { 276 if (t->type == rdata.type) { 277 rtt = t->text; 278 goto found; 279 } 280 } 281 282 dns_rdatatype_format(rdata.type, 283 typebuf, 284 sizeof(typebuf)); 285 snprintf(typebuf2, sizeof(typebuf2), 286 "has %s record", typebuf); 287 rtt = typebuf2; 288 found: 289 say_message(print_name, rtt, 290 &rdata, query); 291 dns_rdata_reset(&rdata); 292 loopresult = 293 dns_rdataset_next(rdataset); 294 } 295 } 296 } 297 if (!short_form) { 298 isc_buffer_usedregion(&target, &r); 299 if (no_rdata) 300 printf(";%.*s", (int)r.length, 301 (char *)r.base); 302 else 303 printf("%.*s", (int)r.length, (char *)r.base); 304 } 305 306 result = dns_message_nextname(msg, sectionid); 307 if (result == ISC_R_NOMORE) 308 break; 309 else if (result != ISC_R_SUCCESS) 310 return (result); 311 } 312 313 return (ISC_R_SUCCESS); 314 } 315 316 static isc_result_t 317 printrdata(dns_message_t *msg, dns_rdataset_t *rdataset, dns_name_t *owner, 318 const char *set_name, isc_boolean_t headers) 319 { 320 isc_buffer_t target; 321 isc_result_t result; 322 isc_region_t r; 323 char tbuf[4096]; 324 325 UNUSED(msg); 326 if (headers) 327 printf(";; %s SECTION:\n", set_name); 328 329 isc_buffer_init(&target, tbuf, sizeof(tbuf)); 330 331 result = dns_rdataset_totext(rdataset, owner, ISC_FALSE, ISC_FALSE, 332 &target); 333 if (result != ISC_R_SUCCESS) 334 return (result); 335 isc_buffer_usedregion(&target, &r); 336 printf("%.*s", (int)r.length, (char *)r.base); 337 338 return (ISC_R_SUCCESS); 339 } 340 341 static void 342 chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { 343 isc_result_t result; 344 dns_rdataset_t *rdataset; 345 dns_rdata_cname_t cname; 346 dns_rdata_t rdata = DNS_RDATA_INIT; 347 unsigned int i = msg->counts[DNS_SECTION_ANSWER]; 348 349 while (i-- > 0) { 350 rdataset = NULL; 351 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 352 dns_rdatatype_cname, 0, NULL, 353 &rdataset); 354 if (result != ISC_R_SUCCESS) 355 return; 356 result = dns_rdataset_first(rdataset); 357 check_result(result, "dns_rdataset_first"); 358 dns_rdata_reset(&rdata); 359 dns_rdataset_current(rdataset, &rdata); 360 result = dns_rdata_tostruct_cname(&rdata, &cname); 361 check_result(result, "dns_rdata_tostruct_cname"); 362 dns_name_copy(&cname.cname, qname, NULL); 363 dns_rdata_freestruct_cname(&cname); 364 } 365 } 366 367 static isc_result_t 368 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 369 isc_boolean_t did_flag = ISC_FALSE; 370 dns_rdataset_t *opt, *tsig = NULL; 371 dns_name_t *tsigname; 372 isc_result_t result = ISC_R_SUCCESS; 373 int force_error; 374 375 UNUSED(headers); 376 377 /* 378 * We get called multiple times. 379 * Preserve any existing error status. 380 */ 381 force_error = (seen_error == 1) ? 1 : 0; 382 seen_error = 1; 383 if (listed_server && !printed_server) { 384 char sockstr[ISC_SOCKADDR_FORMATSIZE]; 385 386 printf("Using domain server:\n"); 387 printf("Name: %s\n", query->userarg); 388 isc_sockaddr_format(&query->sockaddr, sockstr, 389 sizeof(sockstr)); 390 printf("Address: %s\n", sockstr); 391 printf("Aliases: \n\n"); 392 printed_server = ISC_TRUE; 393 } 394 395 if (msg->rcode != 0) { 396 char namestr[DNS_NAME_FORMATSIZE]; 397 dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 398 399 if (query->lookup->identify_previous_line) 400 printf("Nameserver %s:\n\t%s not found: %d(%s)\n", 401 query->servname, 402 (msg->rcode != dns_rcode_nxdomain) ? namestr : 403 query->lookup->textname, msg->rcode, 404 rcode_totext(msg->rcode)); 405 else 406 printf("Host %s not found: %d(%s)\n", 407 (msg->rcode != dns_rcode_nxdomain) ? namestr : 408 query->lookup->textname, msg->rcode, 409 rcode_totext(msg->rcode)); 410 return (ISC_R_SUCCESS); 411 } 412 413 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) { 414 char namestr[DNS_NAME_FORMATSIZE]; 415 dig_lookup_t *lookup; 416 dns_fixedname_t fixed; 417 dns_name_t *name; 418 419 /* Add AAAA and MX lookups. */ 420 dns_fixedname_init(&fixed); 421 name = dns_fixedname_name(&fixed); 422 dns_name_copy(query->lookup->name, name, NULL); 423 chase_cnamechain(msg, name); 424 dns_name_format(name, namestr, sizeof(namestr)); 425 lookup = clone_lookup(query->lookup, ISC_FALSE); 426 if (lookup != NULL) { 427 strlcpy(lookup->textname, namestr, 428 sizeof(lookup->textname)); 429 lookup->rdtype = dns_rdatatype_aaaa; 430 lookup->rdtypeset = ISC_TRUE; 431 lookup->origin = NULL; 432 lookup->retries = tries; 433 ISC_LIST_APPEND(lookup_list, lookup, link); 434 } 435 lookup = clone_lookup(query->lookup, ISC_FALSE); 436 if (lookup != NULL) { 437 strlcpy(lookup->textname, namestr, 438 sizeof(lookup->textname)); 439 lookup->rdtype = dns_rdatatype_mx; 440 lookup->rdtypeset = ISC_TRUE; 441 lookup->origin = NULL; 442 lookup->retries = tries; 443 ISC_LIST_APPEND(lookup_list, lookup, link); 444 } 445 } 446 447 if (!short_form) { 448 printf(";; ->>HEADER<<- opcode: %s, status: %s, id: %u\n", 449 opcodetext[msg->opcode], rcode_totext(msg->rcode), 450 msg->id); 451 printf(";; flags: "); 452 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 453 printf("qr"); 454 did_flag = ISC_TRUE; 455 } 456 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 457 printf("%saa", did_flag ? " " : ""); 458 did_flag = ISC_TRUE; 459 } 460 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 461 printf("%stc", did_flag ? " " : ""); 462 did_flag = ISC_TRUE; 463 } 464 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 465 printf("%srd", did_flag ? " " : ""); 466 did_flag = ISC_TRUE; 467 } 468 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 469 printf("%sra", did_flag ? " " : ""); 470 did_flag = ISC_TRUE; 471 } 472 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 473 printf("%sad", did_flag ? " " : ""); 474 did_flag = ISC_TRUE; 475 } 476 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 477 printf("%scd", did_flag ? " " : ""); 478 did_flag = ISC_TRUE; 479 POST(did_flag); 480 } 481 printf("; QUERY: %u, ANSWER: %u, " 482 "AUTHORITY: %u, ADDITIONAL: %u\n", 483 msg->counts[DNS_SECTION_QUESTION], 484 msg->counts[DNS_SECTION_ANSWER], 485 msg->counts[DNS_SECTION_AUTHORITY], 486 msg->counts[DNS_SECTION_ADDITIONAL]); 487 opt = dns_message_getopt(msg); 488 if (opt != NULL) 489 printf(";; EDNS: version: %u, udp=%u\n", 490 (unsigned int)((opt->ttl & 0x00ff0000) >> 16), 491 (unsigned int)opt->rdclass); 492 tsigname = NULL; 493 tsig = dns_message_gettsig(msg, &tsigname); 494 if (tsig != NULL) 495 printf(";; PSEUDOSECTIONS: TSIG\n"); 496 } 497 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_QUESTION]) && 498 !short_form) { 499 printf("\n"); 500 result = printsection(msg, DNS_SECTION_QUESTION, "QUESTION", 501 ISC_TRUE, query); 502 if (result != ISC_R_SUCCESS) 503 return (result); 504 } 505 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { 506 if (!short_form) 507 printf("\n"); 508 result = printsection(msg, DNS_SECTION_ANSWER, "ANSWER", 509 ISC_TF(!short_form), query); 510 if (result != ISC_R_SUCCESS) 511 return (result); 512 } 513 514 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_AUTHORITY]) && 515 !short_form) { 516 printf("\n"); 517 result = printsection(msg, DNS_SECTION_AUTHORITY, "AUTHORITY", 518 ISC_TRUE, query); 519 if (result != ISC_R_SUCCESS) 520 return (result); 521 } 522 if (! ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ADDITIONAL]) && 523 !short_form) { 524 printf("\n"); 525 result = printsection(msg, DNS_SECTION_ADDITIONAL, 526 "ADDITIONAL", ISC_TRUE, query); 527 if (result != ISC_R_SUCCESS) 528 return (result); 529 } 530 if ((tsig != NULL) && !short_form) { 531 printf("\n"); 532 result = printrdata(msg, tsig, tsigname, 533 "PSEUDOSECTION TSIG", ISC_TRUE); 534 if (result != ISC_R_SUCCESS) 535 return (result); 536 } 537 if (!short_form) 538 printf("\n"); 539 540 if (short_form && !default_lookups && 541 ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) { 542 char namestr[DNS_NAME_FORMATSIZE]; 543 char typestr[DNS_RDATATYPE_FORMATSIZE]; 544 dns_name_format(query->lookup->name, namestr, sizeof(namestr)); 545 dns_rdatatype_format(query->lookup->rdtype, typestr, 546 sizeof(typestr)); 547 printf("%s has no %s record\n", namestr, typestr); 548 } 549 seen_error = force_error; 550 return (result); 551 } 552 553 static const char * optstring = "46ac:dilnrst:vVwCDN:R:TW:"; 554 555 /*% version */ 556 static void 557 version(void) { 558 fputs("host " VERSION "\n", stderr); 559 } 560 561 static void 562 pre_parse_args(int argc, char **argv) { 563 int c; 564 565 while ((c = getopt(argc, argv, optstring)) != -1) { 566 switch (c) { 567 case '4': 568 if (ipv6only) 569 fatal("only one of -4 and -6 allowed"); 570 ipv4only = ISC_TRUE; 571 break; 572 case '6': 573 if (ipv4only) 574 fatal("only one of -4 and -6 allowed"); 575 ipv6only = ISC_TRUE; 576 break; 577 case 'a': break; 578 case 'c': break; 579 case 'd': break; 580 case 'i': break; 581 case 'l': break; 582 case 'n': break; 583 case 'r': break; 584 case 's': break; 585 case 't': break; 586 case 'v': break; 587 case 'V': 588 version(); 589 exit(0); 590 break; 591 case 'w': break; 592 case 'C': break; 593 case 'D': 594 if (debugging) 595 debugtiming = ISC_TRUE; 596 debugging = ISC_TRUE; 597 break; 598 case 'N': break; 599 case 'R': break; 600 case 'T': break; 601 case 'W': break; 602 default: 603 show_usage(); 604 } 605 } 606 optind = 1; 607 optreset = 1; 608 } 609 610 static void 611 parse_args(int argc, char **argv) { 612 char hostname[MXNAME]; 613 dig_lookup_t *lookup; 614 int c; 615 char store[MXNAME]; 616 isc_textregion_t tr; 617 isc_result_t result = ISC_R_SUCCESS; 618 dns_rdatatype_t rdtype; 619 dns_rdataclass_t rdclass; 620 uint32_t serial = 0; 621 const char *errstr; 622 623 lookup = make_empty_lookup(); 624 625 lookup->servfail_stops = ISC_FALSE; 626 lookup->comments = ISC_FALSE; 627 628 while ((c = getopt(argc, argv, optstring)) != -1) { 629 switch (c) { 630 case 'l': 631 lookup->tcp_mode = ISC_TRUE; 632 lookup->rdtype = dns_rdatatype_axfr; 633 lookup->rdtypeset = ISC_TRUE; 634 fatalexit = 3; 635 break; 636 case 'v': 637 case 'd': 638 short_form = ISC_FALSE; 639 break; 640 case 'r': 641 lookup->recurse = ISC_FALSE; 642 break; 643 case 't': 644 if (strncasecmp(optarg, "ixfr=", 5) == 0) { 645 rdtype = dns_rdatatype_ixfr; 646 /* XXXMPA add error checking */ 647 serial = strtoul(optarg + 5, 648 NULL, 10); 649 result = ISC_R_SUCCESS; 650 } else { 651 tr.base = optarg; 652 tr.length = strlen(optarg); 653 result = dns_rdatatype_fromtext(&rdtype, 654 (isc_textregion_t *)&tr); 655 } 656 657 if (result != ISC_R_SUCCESS) { 658 fatalexit = 2; 659 fatal("invalid type: %s\n", optarg); 660 } 661 if (!lookup->rdtypeset || 662 lookup->rdtype != dns_rdatatype_axfr) 663 lookup->rdtype = rdtype; 664 lookup->rdtypeset = ISC_TRUE; 665 if (rdtype == dns_rdatatype_axfr) { 666 /* -l -t any -v */ 667 list_type = dns_rdatatype_any; 668 short_form = ISC_FALSE; 669 lookup->tcp_mode = ISC_TRUE; 670 } else if (rdtype == dns_rdatatype_ixfr) { 671 lookup->ixfr_serial = serial; 672 lookup->tcp_mode = ISC_TRUE; 673 list_type = rdtype; 674 } else 675 list_type = rdtype; 676 list_addresses = ISC_FALSE; 677 default_lookups = ISC_FALSE; 678 break; 679 case 'c': 680 tr.base = optarg; 681 tr.length = strlen(optarg); 682 result = dns_rdataclass_fromtext(&rdclass, 683 (isc_textregion_t *)&tr); 684 685 if (result != ISC_R_SUCCESS) { 686 fatalexit = 2; 687 fatal("invalid class: %s\n", optarg); 688 } else { 689 lookup->rdclass = rdclass; 690 lookup->rdclassset = ISC_TRUE; 691 } 692 default_lookups = ISC_FALSE; 693 break; 694 case 'a': 695 if (!lookup->rdtypeset || 696 lookup->rdtype != dns_rdatatype_axfr) 697 lookup->rdtype = dns_rdatatype_any; 698 list_type = dns_rdatatype_any; 699 list_addresses = ISC_FALSE; 700 lookup->rdtypeset = ISC_TRUE; 701 short_form = ISC_FALSE; 702 default_lookups = ISC_FALSE; 703 break; 704 case 'i': 705 lookup->ip6_int = ISC_TRUE; 706 break; 707 case 'n': 708 /* deprecated */ 709 break; 710 case 'm': 711 /* Handled by pre_parse_args(). */ 712 break; 713 case 'w': 714 /* 715 * The timer routines are coded such that 716 * timeout==MAXINT doesn't enable the timer 717 */ 718 timeout = INT_MAX; 719 break; 720 case 'W': 721 timeout = strtonum(optarg, 0, INT_MAX, &errstr); 722 if (errstr != NULL) 723 errx(1, "timeout is %s: %s", errstr, optarg); 724 if (timeout < 1) 725 timeout = 1; 726 break; 727 case 'R': 728 tries = strtonum(optarg, INT_MIN, INT_MAX - 1, &errstr); 729 if (errstr != NULL) 730 errx(1, "retries is %s: %s", errstr, optarg); 731 tries++; 732 if (tries < 2) 733 tries = 2; 734 break; 735 case 'T': 736 lookup->tcp_mode = ISC_TRUE; 737 break; 738 case 'C': 739 debug("showing all SOAs"); 740 lookup->rdtype = dns_rdatatype_ns; 741 lookup->rdtypeset = ISC_TRUE; 742 lookup->rdclass = dns_rdataclass_in; 743 lookup->rdclassset = ISC_TRUE; 744 lookup->ns_search_only = ISC_TRUE; 745 lookup->trace_root = ISC_TRUE; 746 lookup->identify_previous_line = ISC_TRUE; 747 default_lookups = ISC_FALSE; 748 break; 749 case 'N': 750 debug("setting NDOTS to %s", optarg); 751 ndots = strtonum(optarg, 0, INT_MAX, &errstr); 752 if (errstr != NULL) 753 errx(1, "ndots is %s: %s", errstr, optarg); 754 break; 755 case 'D': 756 /* Handled by pre_parse_args(). */ 757 break; 758 case '4': 759 /* Handled by pre_parse_args(). */ 760 break; 761 case '6': 762 /* Handled by pre_parse_args(). */ 763 break; 764 case 's': 765 lookup->servfail_stops = ISC_TRUE; 766 break; 767 default: 768 show_usage(); 769 } 770 } 771 772 lookup->retries = tries; 773 774 argc -= optind; 775 argv += optind; 776 777 if (argc == 0) 778 show_usage(); 779 780 strlcpy(hostname, argv[0], sizeof(hostname)); 781 782 if (argc >= 2) { 783 isc_result_t res; 784 785 if ((res = set_nameserver(argv[1]))) 786 fatal("couldn't get address for '%s': %s", 787 argv[1], isc_result_totext(res)); 788 debug("server is %s", *argv + 1); 789 listed_server = ISC_TRUE; 790 } else 791 check_ra = ISC_TRUE; 792 793 lookup->pending = ISC_FALSE; 794 if (get_reverse(store, sizeof(store), hostname, 795 lookup->ip6_int, ISC_TRUE) == ISC_R_SUCCESS) { 796 strlcpy(lookup->textname, store, sizeof(lookup->textname)); 797 lookup->rdtype = dns_rdatatype_ptr; 798 lookup->rdtypeset = ISC_TRUE; 799 default_lookups = ISC_FALSE; 800 } else { 801 strlcpy(lookup->textname, hostname, sizeof(lookup->textname)); 802 usesearch = ISC_TRUE; 803 } 804 lookup->new_search = ISC_TRUE; 805 ISC_LIST_APPEND(lookup_list, lookup, link); 806 } 807 808 int 809 host_main(int argc, char **argv) { 810 isc_result_t result; 811 812 tries = 2; 813 814 ISC_LIST_INIT(lookup_list); 815 ISC_LIST_INIT(server_list); 816 ISC_LIST_INIT(root_hints_server_list); 817 ISC_LIST_INIT(search_list); 818 819 fatalexit = 1; 820 821 /* setup dighost callbacks */ 822 dighost_printmessage = printmessage; 823 dighost_received = received; 824 dighost_trying = trying; 825 dighost_shutdown = host_shutdown; 826 827 debug("main()"); 828 progname = argv[0]; 829 pre_parse_args(argc, argv); 830 result = isc_app_start(); 831 check_result(result, "isc_app_start"); 832 833 if (pledge("stdio rpath inet dns", NULL) == -1) { 834 perror("pledge"); 835 exit(1); 836 } 837 838 setup_libs(); 839 840 if (pledge("stdio inet dns", NULL) == -1) { 841 perror("pledge"); 842 exit(1); 843 } 844 845 parse_args(argc, argv); 846 setup_system(ipv4only, ipv6only); 847 result = isc_app_onrun(global_task, onrun_callback, NULL); 848 check_result(result, "isc_app_onrun"); 849 isc_app_run(); 850 cancel_all(); 851 destroy_libs(); 852 return ((seen_error == 0) ? 0 : 1); 853 } 854