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