nslookup.c revision 1.5
1/* $NetBSD: nslookup.c,v 1.5 2019/11/27 05:48:39 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 http://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#include <config.h> 15 16#include <inttypes.h> 17#include <stdbool.h> 18#include <stdlib.h> 19#include <unistd.h> 20 21#include <isc/app.h> 22#include <isc/buffer.h> 23#include <isc/commandline.h> 24#include <isc/event.h> 25#include <isc/parseint.h> 26#include <isc/print.h> 27#include <isc/string.h> 28#include <isc/util.h> 29#include <isc/task.h> 30#include <isc/netaddr.h> 31 32#include <dns/message.h> 33#include <dns/name.h> 34#include <dns/fixedname.h> 35#include <dns/rdata.h> 36#include <dns/rdataclass.h> 37#include <dns/rdataset.h> 38#include <dns/rdatastruct.h> 39#include <dns/rdatatype.h> 40#include <dns/byaddr.h> 41 42#include <dig/dig.h> 43 44#if defined(HAVE_READLINE) 45#if defined(HAVE_EDIT_READLINE_READLINE_H) 46#include <edit/readline/readline.h> 47#if defined(HAVE_EDIT_READLINE_HISTORY_H) 48#include <edit/readline/history.h> 49#endif 50#elif defined(HAVE_EDITLINE_READLINE_H) 51#include <editline/readline.h> 52#elif defined(HAVE_READLINE_READLINE_H) 53#include <readline/readline.h> 54#if defined (HAVE_READLINE_HISTORY_H) 55#include <readline/history.h> 56#endif 57#endif 58#endif 59 60static bool short_form = true, 61 tcpmode = false, tcpmode_set = false, 62 identify = false, stats = true, 63 comments = true, section_question = true, 64 section_answer = true, section_authority = true, 65 section_additional = true, recurse = true, 66 aaonly = false, nofail = true, 67 default_lookups = true, a_noanswer = false; 68 69static bool interactive; 70 71static bool in_use = false; 72static char defclass[MXRD] = "IN"; 73static char deftype[MXRD] = "A"; 74static isc_event_t *global_event = NULL; 75static int query_error = 1, print_error = 0; 76 77static char domainopt[DNS_NAME_MAXTEXT]; 78 79static const char *rcodetext[] = { 80 "NOERROR", 81 "FORMERR", 82 "SERVFAIL", 83 "NXDOMAIN", 84 "NOTIMP", 85 "REFUSED", 86 "YXDOMAIN", 87 "YXRRSET", 88 "NXRRSET", 89 "NOTAUTH", 90 "NOTZONE", 91 "RESERVED11", 92 "RESERVED12", 93 "RESERVED13", 94 "RESERVED14", 95 "RESERVED15", 96 "BADVERS" 97}; 98 99static const char *rtypetext[] = { 100 "rtype_0 = ", /* 0 */ 101 "internet address = ", /* 1 */ 102 "nameserver = ", /* 2 */ 103 "md = ", /* 3 */ 104 "mf = ", /* 4 */ 105 "canonical name = ", /* 5 */ 106 "soa = ", /* 6 */ 107 "mb = ", /* 7 */ 108 "mg = ", /* 8 */ 109 "mr = ", /* 9 */ 110 "rtype_10 = ", /* 10 */ 111 "protocol = ", /* 11 */ 112 "name = ", /* 12 */ 113 "hinfo = ", /* 13 */ 114 "minfo = ", /* 14 */ 115 "mail exchanger = ", /* 15 */ 116 "text = ", /* 16 */ 117 "rp = ", /* 17 */ 118 "afsdb = ", /* 18 */ 119 "x25 address = ", /* 19 */ 120 "isdn address = ", /* 20 */ 121 "rt = ", /* 21 */ 122 "nsap = ", /* 22 */ 123 "nsap_ptr = ", /* 23 */ 124 "signature = ", /* 24 */ 125 "key = ", /* 25 */ 126 "px = ", /* 26 */ 127 "gpos = ", /* 27 */ 128 "has AAAA address ", /* 28 */ 129 "loc = ", /* 29 */ 130 "next = ", /* 30 */ 131 "rtype_31 = ", /* 31 */ 132 "rtype_32 = ", /* 32 */ 133 "service = ", /* 33 */ 134 "rtype_34 = ", /* 34 */ 135 "naptr = ", /* 35 */ 136 "kx = ", /* 36 */ 137 "cert = ", /* 37 */ 138 "v6 address = ", /* 38 */ 139 "dname = ", /* 39 */ 140 "rtype_40 = ", /* 40 */ 141 "optional = " /* 41 */ 142}; 143 144#define N_KNOWN_RRTYPES (sizeof(rtypetext) / sizeof(rtypetext[0])) 145 146static void flush_lookup_list(void); 147static void getinput(isc_task_t *task, isc_event_t *event); 148 149static char * 150rcode_totext(dns_rcode_t rcode) 151{ 152 static char buf[sizeof("?65535")]; 153 union { 154 const char *consttext; 155 char *deconsttext; 156 } totext; 157 158 if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 159 snprintf(buf, sizeof(buf), "?%u", rcode); 160 totext.deconsttext = buf; 161 } else 162 totext.consttext = rcodetext[rcode]; 163 return totext.deconsttext; 164} 165 166static void 167query_finished(void) { 168 isc_event_t *event = global_event; 169 170 flush_lookup_list(); 171 debug("dighost_shutdown()"); 172 173 if (!in_use) { 174 isc_app_shutdown(); 175 return; 176 } 177 178 isc_task_send(global_task, &event); 179} 180 181static void 182printsoa(dns_rdata_t *rdata) { 183 dns_rdata_soa_t soa; 184 isc_result_t result; 185 char namebuf[DNS_NAME_FORMATSIZE]; 186 187 result = dns_rdata_tostruct(rdata, &soa, NULL); 188 check_result(result, "dns_rdata_tostruct"); 189 190 dns_name_format(&soa.origin, namebuf, sizeof(namebuf)); 191 printf("\torigin = %s\n", namebuf); 192 dns_name_format(&soa.contact, namebuf, sizeof(namebuf)); 193 printf("\tmail addr = %s\n", namebuf); 194 printf("\tserial = %u\n", soa.serial); 195 printf("\trefresh = %u\n", soa.refresh); 196 printf("\tretry = %u\n", soa.retry); 197 printf("\texpire = %u\n", soa.expire); 198 printf("\tminimum = %u\n", soa.minimum); 199 dns_rdata_freestruct(&soa); 200} 201 202static void 203printaddr(dns_rdata_t *rdata) { 204 isc_result_t result; 205 char text[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; 206 isc_buffer_t b; 207 208 isc_buffer_init(&b, text, sizeof(text)); 209 result = dns_rdata_totext(rdata, NULL, &b); 210 check_result(result, "dns_rdata_totext"); 211 printf("Address: %.*s\n", (int)isc_buffer_usedlength(&b), 212 (char *)isc_buffer_base(&b)); 213} 214 215static void 216printrdata(dns_rdata_t *rdata) { 217 isc_result_t result; 218 isc_buffer_t *b = NULL; 219 unsigned int size = 1024; 220 bool done = false; 221 222 if (rdata->type < N_KNOWN_RRTYPES) 223 printf("%s", rtypetext[rdata->type]); 224 else 225 printf("rdata_%d = ", rdata->type); 226 227 while (!done) { 228 result = isc_buffer_allocate(mctx, &b, size); 229 if (result != ISC_R_SUCCESS) 230 check_result(result, "isc_buffer_allocate"); 231 result = dns_rdata_totext(rdata, NULL, b); 232 if (result == ISC_R_SUCCESS) { 233 printf("%.*s\n", (int)isc_buffer_usedlength(b), 234 (char *)isc_buffer_base(b)); 235 done = true; 236 } else if (result != ISC_R_NOSPACE) 237 check_result(result, "dns_rdata_totext"); 238 isc_buffer_free(&b); 239 size *= 2; 240 } 241} 242 243static isc_result_t 244printsection(dig_query_t *query, dns_message_t *msg, bool headers, 245 dns_section_t section) { 246 isc_result_t result, loopresult; 247 dns_name_t *name; 248 dns_rdataset_t *rdataset = NULL; 249 dns_rdata_t rdata = DNS_RDATA_INIT; 250 char namebuf[DNS_NAME_FORMATSIZE]; 251 252 UNUSED(query); 253 UNUSED(headers); 254 255 debug("printsection()"); 256 257 result = dns_message_firstname(msg, section); 258 if (result == ISC_R_NOMORE) 259 return (ISC_R_SUCCESS); 260 else if (result != ISC_R_SUCCESS) 261 return (result); 262 for (;;) { 263 name = NULL; 264 dns_message_currentname(msg, section, 265 &name); 266 for (rdataset = ISC_LIST_HEAD(name->list); 267 rdataset != NULL; 268 rdataset = ISC_LIST_NEXT(rdataset, link)) { 269 loopresult = dns_rdataset_first(rdataset); 270 while (loopresult == ISC_R_SUCCESS) { 271 dns_rdataset_current(rdataset, &rdata); 272 switch (rdata.type) { 273 case dns_rdatatype_a: 274 case dns_rdatatype_aaaa: 275 if (section != DNS_SECTION_ANSWER) 276 goto def_short_section; 277 dns_name_format(name, namebuf, 278 sizeof(namebuf)); 279 printf("Name:\t%s\n", namebuf); 280 printaddr(&rdata); 281 break; 282 case dns_rdatatype_soa: 283 dns_name_format(name, namebuf, 284 sizeof(namebuf)); 285 printf("%s\n", namebuf); 286 printsoa(&rdata); 287 break; 288 default: 289 def_short_section: 290 dns_name_format(name, namebuf, 291 sizeof(namebuf)); 292 printf("%s\t", namebuf); 293 printrdata(&rdata); 294 break; 295 } 296 dns_rdata_reset(&rdata); 297 loopresult = dns_rdataset_next(rdataset); 298 } 299 } 300 result = dns_message_nextname(msg, section); 301 if (result == ISC_R_NOMORE) 302 break; 303 else if (result != ISC_R_SUCCESS) { 304 return (result); 305 } 306 } 307 return (ISC_R_SUCCESS); 308} 309 310static isc_result_t 311detailsection(dig_query_t *query, dns_message_t *msg, bool headers, 312 dns_section_t section) { 313 isc_result_t result, loopresult; 314 dns_name_t *name; 315 dns_rdataset_t *rdataset = NULL; 316 dns_rdata_t rdata = DNS_RDATA_INIT; 317 char namebuf[DNS_NAME_FORMATSIZE]; 318 319 UNUSED(query); 320 321 debug("detailsection()"); 322 323 if (headers) { 324 switch (section) { 325 case DNS_SECTION_QUESTION: 326 puts(" QUESTIONS:"); 327 break; 328 case DNS_SECTION_ANSWER: 329 puts(" ANSWERS:"); 330 break; 331 case DNS_SECTION_AUTHORITY: 332 puts(" AUTHORITY RECORDS:"); 333 break; 334 case DNS_SECTION_ADDITIONAL: 335 puts(" ADDITIONAL RECORDS:"); 336 break; 337 } 338 } 339 340 result = dns_message_firstname(msg, section); 341 if (result == ISC_R_NOMORE) 342 return (ISC_R_SUCCESS); 343 else if (result != ISC_R_SUCCESS) 344 return (result); 345 for (;;) { 346 name = NULL; 347 dns_message_currentname(msg, section, 348 &name); 349 for (rdataset = ISC_LIST_HEAD(name->list); 350 rdataset != NULL; 351 rdataset = ISC_LIST_NEXT(rdataset, link)) { 352 if (section == DNS_SECTION_QUESTION) { 353 dns_name_format(name, namebuf, 354 sizeof(namebuf)); 355 printf("\t%s, ", namebuf); 356 dns_rdatatype_format(rdataset->type, 357 namebuf, 358 sizeof(namebuf)); 359 printf("type = %s, ", namebuf); 360 dns_rdataclass_format(rdataset->rdclass, 361 namebuf, 362 sizeof(namebuf)); 363 printf("class = %s\n", namebuf); 364 } 365 loopresult = dns_rdataset_first(rdataset); 366 while (loopresult == ISC_R_SUCCESS) { 367 dns_rdataset_current(rdataset, &rdata); 368 369 dns_name_format(name, namebuf, 370 sizeof(namebuf)); 371 printf(" -> %s\n", namebuf); 372 373 switch (rdata.type) { 374 case dns_rdatatype_soa: 375 printsoa(&rdata); 376 break; 377 default: 378 printf("\t"); 379 printrdata(&rdata); 380 } 381 dns_rdata_reset(&rdata); 382 printf("\tttl = %u\n", rdataset->ttl); 383 loopresult = dns_rdataset_next(rdataset); 384 } 385 } 386 result = dns_message_nextname(msg, section); 387 if (result == ISC_R_NOMORE) 388 break; 389 else if (result != ISC_R_SUCCESS) { 390 return (result); 391 } 392 } 393 return (ISC_R_SUCCESS); 394} 395 396static void 397received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) 398{ 399 UNUSED(bytes); 400 UNUSED(from); 401 UNUSED(query); 402} 403 404static void 405trying(char *frm, dig_lookup_t *lookup) { 406 UNUSED(frm); 407 UNUSED(lookup); 408} 409 410static void 411chase_cnamechain(dns_message_t *msg, dns_name_t *qname) { 412 isc_result_t result; 413 dns_rdataset_t *rdataset; 414 dns_rdata_cname_t cname; 415 dns_rdata_t rdata = DNS_RDATA_INIT; 416 unsigned int i = msg->counts[DNS_SECTION_ANSWER]; 417 418 while (i-- > 0) { 419 rdataset = NULL; 420 result = dns_message_findname(msg, DNS_SECTION_ANSWER, qname, 421 dns_rdatatype_cname, 0, NULL, &rdataset); 422 if (result != ISC_R_SUCCESS) 423 return; 424 result = dns_rdataset_first(rdataset); 425 check_result(result, "dns_rdataset_first"); 426 dns_rdata_reset(&rdata); 427 dns_rdataset_current(rdataset, &rdata); 428 result = dns_rdata_tostruct(&rdata, &cname, NULL); 429 check_result(result, "dns_rdata_tostruct"); 430 dns_name_copynf(&cname.cname, qname); 431 dns_rdata_freestruct(&cname); 432 } 433} 434 435static isc_result_t 436printmessage(dig_query_t *query, dns_message_t *msg, bool headers) { 437 char servtext[ISC_SOCKADDR_FORMATSIZE]; 438 439 /* I've we've gotten this far, we've reached a server. */ 440 query_error = 0; 441 442 debug("printmessage()"); 443 444 if(!default_lookups || query->lookup->rdtype == dns_rdatatype_a) { 445 isc_sockaddr_format(&query->sockaddr, servtext, sizeof(servtext)); 446 printf("Server:\t\t%s\n", query->userarg); 447 printf("Address:\t%s\n", servtext); 448 449 puts(""); 450 } 451 452 if (!short_form) { 453 puts("------------"); 454 /* detailheader(query, msg);*/ 455 detailsection(query, msg, true, DNS_SECTION_QUESTION); 456 detailsection(query, msg, true, DNS_SECTION_ANSWER); 457 detailsection(query, msg, true, DNS_SECTION_AUTHORITY); 458 detailsection(query, msg, true, DNS_SECTION_ADDITIONAL); 459 puts("------------"); 460 } 461 462 if (msg->rcode != 0) { 463 char nametext[DNS_NAME_FORMATSIZE]; 464 dns_name_format(query->lookup->name, 465 nametext, sizeof(nametext)); 466 printf("** server can't find %s: %s\n", 467 nametext, rcode_totext(msg->rcode)); 468 debug("returning with rcode == 0"); 469 470 /* the lookup failed */ 471 print_error |= 1; 472 return (ISC_R_SUCCESS); 473 } 474 475 if ( default_lookups && query->lookup->rdtype == dns_rdatatype_a) { 476 char namestr[DNS_NAME_FORMATSIZE]; 477 dig_lookup_t *lookup; 478 dns_fixedname_t fixed; 479 dns_name_t *name; 480 481 /* Add AAAA lookup. */ 482 name = dns_fixedname_initname(&fixed); 483 dns_name_copynf(query->lookup->name, name); 484 chase_cnamechain(msg, name); 485 dns_name_format(name, namestr, sizeof(namestr)); 486 lookup = clone_lookup(query->lookup, false); 487 if (lookup != NULL) { 488 strlcpy(lookup->textname, namestr, 489 sizeof(lookup->textname)); 490 lookup->rdtype = dns_rdatatype_aaaa; 491 lookup->rdtypeset = true; 492 lookup->origin = NULL; 493 lookup->retries = tries; 494 ISC_LIST_APPEND(lookup_list, lookup, link); 495 } 496 } 497 498 if ((msg->flags & DNS_MESSAGEFLAG_AA) == 0 && 499 ( !default_lookups || query->lookup->rdtype == dns_rdatatype_a) ) 500 puts("Non-authoritative answer:"); 501 if (!ISC_LIST_EMPTY(msg->sections[DNS_SECTION_ANSWER])) 502 printsection(query, msg, headers, DNS_SECTION_ANSWER); 503 else { 504 if (default_lookups && query->lookup->rdtype == dns_rdatatype_a) 505 a_noanswer = true; 506 507 else if (!default_lookups || 508 (query->lookup->rdtype == dns_rdatatype_aaaa && 509 a_noanswer ) ) 510 printf("*** Can't find %s: No answer\n", 511 query->lookup->textname); 512 } 513 514 if (((msg->flags & DNS_MESSAGEFLAG_AA) == 0) && 515 (query->lookup->rdtype != dns_rdatatype_a) && 516 (query->lookup->rdtype != dns_rdatatype_aaaa) ) { 517 puts("\nAuthoritative answers can be found from:"); 518 printsection(query, msg, headers, 519 DNS_SECTION_AUTHORITY); 520 printsection(query, msg, headers, 521 DNS_SECTION_ADDITIONAL); 522 } 523 return (ISC_R_SUCCESS); 524} 525 526static void 527show_settings(bool full, bool serv_only) { 528 dig_server_t *srv; 529 isc_sockaddr_t sockaddr; 530 dig_searchlist_t *listent; 531 isc_result_t result; 532 533 srv = ISC_LIST_HEAD(server_list); 534 535 while (srv != NULL) { 536 char sockstr[ISC_SOCKADDR_FORMATSIZE]; 537 538 result = get_address(srv->servername, port, &sockaddr); 539 check_result(result, "get_address"); 540 541 isc_sockaddr_format(&sockaddr, sockstr, sizeof(sockstr)); 542 printf("Default server: %s\nAddress: %s\n", 543 srv->userarg, sockstr); 544 if (!full) 545 return; 546 srv = ISC_LIST_NEXT(srv, link); 547 } 548 if (serv_only) 549 return; 550 printf("\nSet options:\n"); 551 printf(" %s\t\t\t%s\t\t%s\n", 552 tcpmode ? "vc" : "novc", 553 short_form ? "nodebug" : "debug", 554 debugging ? "d2" : "nod2"); 555 printf(" %s\t\t%s\n", 556 usesearch ? "search" : "nosearch", 557 recurse ? "recurse" : "norecurse"); 558 printf(" timeout = %u\t\tretry = %d\tport = %u\tndots = %d\n", 559 timeout, tries, port, ndots); 560 printf(" querytype = %-8s\tclass = %s\n", deftype, defclass); 561 printf(" srchlist = "); 562 for (listent = ISC_LIST_HEAD(search_list); 563 listent != NULL; 564 listent = ISC_LIST_NEXT(listent, link)) { 565 printf("%s", listent->origin); 566 if (ISC_LIST_NEXT(listent, link) != NULL) 567 printf("/"); 568 } 569 printf("\n"); 570} 571 572static bool 573testtype(char *typetext) { 574 isc_result_t result; 575 isc_textregion_t tr; 576 dns_rdatatype_t rdtype; 577 578 tr.base = typetext; 579 tr.length = strlen(typetext); 580 result = dns_rdatatype_fromtext(&rdtype, &tr); 581 if (result == ISC_R_SUCCESS) 582 return (true); 583 else { 584 printf("unknown query type: %s\n", typetext); 585 return (false); 586 } 587} 588 589static bool 590testclass(char *typetext) { 591 isc_result_t result; 592 isc_textregion_t tr; 593 dns_rdataclass_t rdclass; 594 595 tr.base = typetext; 596 tr.length = strlen(typetext); 597 result = dns_rdataclass_fromtext(&rdclass, &tr); 598 if (result == ISC_R_SUCCESS) 599 return (true); 600 else { 601 printf("unknown query class: %s\n", typetext); 602 return (false); 603 } 604} 605 606static void 607set_port(const char *value) { 608 uint32_t n; 609 isc_result_t result = parse_uint(&n, value, 65535, "port"); 610 if (result == ISC_R_SUCCESS) 611 port = (uint16_t) n; 612} 613 614static void 615set_timeout(const char *value) { 616 uint32_t n; 617 isc_result_t result = parse_uint(&n, value, UINT_MAX, "timeout"); 618 if (result == ISC_R_SUCCESS) 619 timeout = n; 620} 621 622static void 623set_tries(const char *value) { 624 uint32_t n; 625 isc_result_t result = parse_uint(&n, value, INT_MAX, "tries"); 626 if (result == ISC_R_SUCCESS) 627 tries = n; 628} 629 630static void 631set_ndots(const char *value) { 632 uint32_t n; 633 isc_result_t result = parse_uint(&n, value, 128, "ndots"); 634 if (result == ISC_R_SUCCESS) 635 ndots = n; 636} 637 638static void 639version(void) { 640 fputs("nslookup " VERSION "\n", stderr); 641} 642 643static void 644setoption(char *opt) { 645 size_t l = strlen(opt); 646 647#define CHECKOPT(A, N) \ 648 ((l >= N) && (l < sizeof(A)) && (strncasecmp(opt, A, l) == 0)) 649 650 if (CHECKOPT("all", 3)) { 651 show_settings(true, false); 652 } else if (strncasecmp(opt, "class=", 6) == 0) { 653 if (testclass(&opt[6])) 654 strlcpy(defclass, &opt[6], sizeof(defclass)); 655 } else if (strncasecmp(opt, "cl=", 3) == 0) { 656 if (testclass(&opt[3])) 657 strlcpy(defclass, &opt[3], sizeof(defclass)); 658 } else if (strncasecmp(opt, "type=", 5) == 0) { 659 if (testtype(&opt[5])) { 660 strlcpy(deftype, &opt[5], sizeof(deftype)); 661 default_lookups = false; 662 } 663 } else if (strncasecmp(opt, "ty=", 3) == 0) { 664 if (testtype(&opt[3])) { 665 strlcpy(deftype, &opt[3], sizeof(deftype)); 666 default_lookups = false; 667 } 668 } else if (strncasecmp(opt, "querytype=", 10) == 0) { 669 if (testtype(&opt[10])) { 670 strlcpy(deftype, &opt[10], sizeof(deftype)); 671 default_lookups = false; 672 } 673 } else if (strncasecmp(opt, "query=", 6) == 0) { 674 if (testtype(&opt[6])) { 675 strlcpy(deftype, &opt[6], sizeof(deftype)); 676 default_lookups = false; 677 } 678 } else if (strncasecmp(opt, "qu=", 3) == 0) { 679 if (testtype(&opt[3])) { 680 strlcpy(deftype, &opt[3], sizeof(deftype)); 681 default_lookups = false; 682 } 683 } else if (strncasecmp(opt, "q=", 2) == 0) { 684 if (testtype(&opt[2])) { 685 strlcpy(deftype, &opt[2], sizeof(deftype)); 686 default_lookups = false; 687 } 688 } else if (strncasecmp(opt, "domain=", 7) == 0) { 689 strlcpy(domainopt, &opt[7], sizeof(domainopt)); 690 set_search_domain(domainopt); 691 usesearch = true; 692 } else if (strncasecmp(opt, "do=", 3) == 0) { 693 strlcpy(domainopt, &opt[3], sizeof(domainopt)); 694 set_search_domain(domainopt); 695 usesearch = true; 696 } else if (strncasecmp(opt, "port=", 5) == 0) { 697 set_port(&opt[5]); 698 } else if (strncasecmp(opt, "po=", 3) == 0) { 699 set_port(&opt[3]); 700 } else if (strncasecmp(opt, "timeout=", 8) == 0) { 701 set_timeout(&opt[8]); 702 } else if (strncasecmp(opt, "t=", 2) == 0) { 703 set_timeout(&opt[2]); 704 } else if (CHECKOPT("recurse", 3)) { 705 recurse = true; 706 } else if (CHECKOPT("norecurse", 5)) { 707 recurse = false; 708 } else if (strncasecmp(opt, "retry=", 6) == 0) { 709 set_tries(&opt[6]); 710 } else if (strncasecmp(opt, "ret=", 4) == 0) { 711 set_tries(&opt[4]); 712 } else if (CHECKOPT("defname", 3)) { 713 usesearch = true; 714 } else if (CHECKOPT("nodefname", 5)) { 715 usesearch = false; 716 } else if (CHECKOPT("vc", 2)) { 717 tcpmode = true; 718 tcpmode_set = true; 719 } else if (CHECKOPT("novc", 4)) { 720 tcpmode = false; 721 tcpmode_set = true; 722 } else if (CHECKOPT("debug", 3)) { 723 short_form = false; 724 showsearch = true; 725 } else if (CHECKOPT("nodebug", 5)) { 726 short_form = true; 727 showsearch = false; 728 } else if (CHECKOPT("d2", 2)) { 729 debugging = true; 730 } else if (CHECKOPT("nod2", 4)) { 731 debugging = false; 732 } else if (CHECKOPT("search", 3)) { 733 usesearch = true; 734 } else if (CHECKOPT("nosearch", 5)) { 735 usesearch = false; 736 } else if (CHECKOPT("sil", 3)) { 737 /* deprecation_msg = false; */ 738 } else if (CHECKOPT("fail", 3)) { 739 nofail=false; 740 } else if (CHECKOPT("nofail", 5)) { 741 nofail=true; 742 } else if (strncasecmp(opt, "ndots=", 6) == 0) { 743 set_ndots(&opt[6]); 744 } else { 745 printf("*** Invalid option: %s\n", opt); 746 } 747} 748 749static void 750addlookup(char *opt) { 751 dig_lookup_t *lookup; 752 isc_result_t result; 753 isc_textregion_t tr; 754 dns_rdatatype_t rdtype; 755 dns_rdataclass_t rdclass; 756 char store[MXNAME]; 757 758 debug("addlookup()"); 759 760 a_noanswer = false; 761 762 tr.base = deftype; 763 tr.length = strlen(deftype); 764 result = dns_rdatatype_fromtext(&rdtype, &tr); 765 if (result != ISC_R_SUCCESS) { 766 printf("unknown query type: %s\n", deftype); 767 rdclass = dns_rdatatype_a; 768 } 769 tr.base = defclass; 770 tr.length = strlen(defclass); 771 result = dns_rdataclass_fromtext(&rdclass, &tr); 772 if (result != ISC_R_SUCCESS) { 773 printf("unknown query class: %s\n", defclass); 774 rdclass = dns_rdataclass_in; 775 } 776 lookup = make_empty_lookup(); 777 if (get_reverse(store, sizeof(store), opt, true) 778 == ISC_R_SUCCESS) { 779 strlcpy(lookup->textname, store, sizeof(lookup->textname)); 780 lookup->rdtype = dns_rdatatype_ptr; 781 lookup->rdtypeset = true; 782 } else { 783 strlcpy(lookup->textname, opt, sizeof(lookup->textname)); 784 lookup->rdtype = rdtype; 785 lookup->rdtypeset = true; 786 } 787 lookup->rdclass = rdclass; 788 lookup->rdclassset = true; 789 lookup->trace = false; 790 lookup->trace_root = lookup->trace; 791 lookup->ns_search_only = false; 792 lookup->identify = identify; 793 lookup->recurse = recurse; 794 lookup->aaonly = aaonly; 795 lookup->retries = tries; 796 lookup->udpsize = 0; 797 lookup->comments = comments; 798 if (lookup->rdtype == dns_rdatatype_any && !tcpmode_set) 799 lookup->tcp_mode = true; 800 else 801 lookup->tcp_mode = tcpmode; 802 lookup->stats = stats; 803 lookup->section_question = section_question; 804 lookup->section_answer = section_answer; 805 lookup->section_authority = section_authority; 806 lookup->section_additional = section_additional; 807 lookup->new_search = true; 808 if (nofail) 809 lookup->servfail_stops = false; 810 ISC_LIST_INIT(lookup->q); 811 ISC_LINK_INIT(lookup, link); 812 ISC_LIST_APPEND(lookup_list, lookup, link); 813 lookup->origin = NULL; 814 ISC_LIST_INIT(lookup->my_server_list); 815 debug("looking up %s", lookup->textname); 816} 817 818static void 819do_next_command(char *input) { 820 char *ptr, *arg, *last; 821 822 if ((ptr = strtok_r(input, " \t\r\n", &last)) == NULL) { 823 return; 824 } 825 arg = strtok_r(NULL, " \t\r\n", &last); 826 if ((strcasecmp(ptr, "set") == 0) && 827 (arg != NULL)) 828 setoption(arg); 829 else if ((strcasecmp(ptr, "server") == 0) || 830 (strcasecmp(ptr, "lserver") == 0)) { 831 isc_app_block(); 832 set_nameserver(arg); 833 check_ra = false; 834 isc_app_unblock(); 835 show_settings(true, true); 836 } else if (strcasecmp(ptr, "exit") == 0) { 837 in_use = false; 838 } else if (strcasecmp(ptr, "help") == 0 || 839 strcasecmp(ptr, "?") == 0) { 840 printf("The '%s' command is not yet implemented.\n", ptr); 841 } else if (strcasecmp(ptr, "finger") == 0 || 842 strcasecmp(ptr, "root") == 0 || 843 strcasecmp(ptr, "ls") == 0 || 844 strcasecmp(ptr, "view") == 0) { 845 printf("The '%s' command is not implemented.\n", ptr); 846 } else 847 addlookup(ptr); 848} 849 850static void 851get_next_command(void) { 852 char *buf; 853 char *ptr; 854 855 fflush(stdout); 856 buf = isc_mem_allocate(mctx, COMMSIZE); 857 if (buf == NULL) 858 fatal("memory allocation failure"); 859 isc_app_block(); 860 if (interactive) { 861#ifdef HAVE_READLINE 862 ptr = readline("> "); 863 if (ptr != NULL) 864 add_history(ptr); 865#else 866 fputs("> ", stderr); 867 fflush(stderr); 868 ptr = fgets(buf, COMMSIZE, stdin); 869#endif 870 } else 871 ptr = fgets(buf, COMMSIZE, stdin); 872 isc_app_unblock(); 873 if (ptr == NULL) { 874 in_use = false; 875 } else 876 do_next_command(ptr); 877#ifdef HAVE_READLINE 878 if (interactive) 879 free(ptr); 880#endif 881 isc_mem_free(mctx, buf); 882} 883 884ISC_PLATFORM_NORETURN_PRE static void 885usage(void) ISC_PLATFORM_NORETURN_POST; 886 887static void 888usage(void) { 889 fprintf(stderr, "Usage:\n"); 890 fprintf(stderr, 891" nslookup [-opt ...] # interactive mode using default server\n"); 892 fprintf(stderr, 893" nslookup [-opt ...] - server # interactive mode using 'server'\n"); 894 fprintf(stderr, 895" nslookup [-opt ...] host # just look up 'host' using default server\n"); 896 fprintf(stderr, 897" nslookup [-opt ...] host server # just look up 'host' using 'server'\n"); 898 exit(1); 899} 900 901static void 902parse_args(int argc, char **argv) { 903 bool have_lookup = false; 904 905 usesearch = true; 906 for (argc--, argv++; argc > 0 && argv[0] != NULL; argc--, argv++) { 907 debug("main parsing %s", argv[0]); 908 if (argv[0][0] == '-') { 909 if (strncasecmp(argv[0], "-ver", 4) == 0) { 910 version(); 911 exit(0); 912 } else if (argv[0][1] != 0) { 913 setoption(&argv[0][1]); 914 } else 915 have_lookup = true; 916 } else { 917 if (!have_lookup) { 918 have_lookup = true; 919 in_use = true; 920 addlookup(argv[0]); 921 } else { 922 if (argv[1] != NULL) { 923 usage(); 924 } 925 set_nameserver(argv[0]); 926 check_ra = false; 927 } 928 } 929 } 930} 931 932static void 933flush_lookup_list(void) { 934 dig_lookup_t *l, *lp; 935 dig_query_t *q, *qp; 936 dig_server_t *s, *sp; 937 938 lookup_counter = 0; 939 l = ISC_LIST_HEAD(lookup_list); 940 while (l != NULL) { 941 q = ISC_LIST_HEAD(l->q); 942 while (q != NULL) { 943 if (q->sock != NULL) { 944 isc_socket_cancel(q->sock, NULL, 945 ISC_SOCKCANCEL_ALL); 946 isc_socket_detach(&q->sock); 947 } 948 isc_buffer_invalidate(&q->recvbuf); 949 isc_buffer_invalidate(&q->lengthbuf); 950 qp = q; 951 q = ISC_LIST_NEXT(q, link); 952 ISC_LIST_DEQUEUE(l->q, qp, link); 953 isc_mem_free(mctx, qp); 954 } 955 s = ISC_LIST_HEAD(l->my_server_list); 956 while (s != NULL) { 957 sp = s; 958 s = ISC_LIST_NEXT(s, link); 959 ISC_LIST_DEQUEUE(l->my_server_list, sp, link); 960 isc_mem_free(mctx, sp); 961 962 } 963 if (l->sendmsg != NULL) 964 dns_message_destroy(&l->sendmsg); 965 lp = l; 966 l = ISC_LIST_NEXT(l, link); 967 ISC_LIST_DEQUEUE(lookup_list, lp, link); 968 isc_mem_free(mctx, lp); 969 } 970} 971 972static void 973getinput(isc_task_t *task, isc_event_t *event) { 974 UNUSED(task); 975 if (global_event == NULL) 976 global_event = event; 977 while (in_use) { 978 get_next_command(); 979 if (ISC_LIST_HEAD(lookup_list) != NULL) { 980 start_lookup(); 981 return; 982 } 983 } 984 isc_app_shutdown(); 985} 986 987int 988main(int argc, char **argv) { 989 isc_result_t result; 990 991 interactive = isatty(0); 992 993 ISC_LIST_INIT(lookup_list); 994 ISC_LIST_INIT(server_list); 995 ISC_LIST_INIT(search_list); 996 997 check_ra = true; 998 999 /* setup dighost callbacks */ 1000 dighost_printmessage = printmessage; 1001 dighost_received = received; 1002 dighost_trying = trying; 1003 dighost_shutdown = query_finished; 1004 1005 result = isc_app_start(); 1006 check_result(result, "isc_app_start"); 1007 1008 setup_libs(); 1009 progname = argv[0]; 1010 1011 setup_system(false, false); 1012 parse_args(argc, argv); 1013 if (keyfile[0] != 0) 1014 setup_file_key(); 1015 else if (keysecret[0] != 0) 1016 setup_text_key(); 1017 if (domainopt[0] != '\0') 1018 set_search_domain(domainopt); 1019 if (in_use) 1020 result = isc_app_onrun(mctx, global_task, onrun_callback, 1021 NULL); 1022 else 1023 result = isc_app_onrun(mctx, global_task, getinput, NULL); 1024 check_result(result, "isc_app_onrun"); 1025 in_use = !in_use; 1026 1027 (void)isc_app_run(); 1028 1029 puts(""); 1030 debug("done, and starting to shut down"); 1031 if (global_event != NULL) 1032 isc_event_free(&global_event); 1033 cancel_all(); 1034 destroy_libs(); 1035 isc_app_finish(); 1036 1037 return (query_error | print_error); 1038} 1039