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