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