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