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