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