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