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