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