1/* 2 * Copyright (C) 2004-2011 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: dig.c,v 1.237.124.4 2011/12/07 17:23:55 each Exp $ */ 19 20/*! \file */ 21 22#include <config.h> 23#include <stdlib.h> 24#include <time.h> 25#include <ctype.h> 26 27#include <isc/app.h> 28#include <isc/netaddr.h> 29#include <isc/parseint.h> 30#include <isc/print.h> 31#include <isc/string.h> 32#include <isc/util.h> 33#include <isc/task.h> 34 35#include <dns/byaddr.h> 36#include <dns/fixedname.h> 37#include <dns/masterdump.h> 38#include <dns/message.h> 39#include <dns/name.h> 40#include <dns/rdata.h> 41#include <dns/rdataset.h> 42#include <dns/rdatatype.h> 43#include <dns/rdataclass.h> 44#include <dns/result.h> 45#include <dns/tsig.h> 46 47#include <dig/dig.h> 48 49#define ADD_STRING(b, s) { \ 50 if (strlen(s) >= isc_buffer_availablelength(b)) \ 51 return (ISC_R_NOSPACE); \ 52 else \ 53 isc_buffer_putstr(b, s); \ 54} 55 56#define DIG_MAX_ADDRESSES 20 57 58dig_lookup_t *default_lookup = NULL; 59 60static char *batchname = NULL; 61static FILE *batchfp = NULL; 62static char *argv0; 63static int addresscount = 0; 64 65static char domainopt[DNS_NAME_MAXTEXT]; 66 67static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE, 68 ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE, 69 multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE, 70 onesoa = ISC_FALSE; 71 72/*% opcode text */ 73static const char * const opcodetext[] = { 74 "QUERY", 75 "IQUERY", 76 "STATUS", 77 "RESERVED3", 78 "NOTIFY", 79 "UPDATE", 80 "RESERVED6", 81 "RESERVED7", 82 "RESERVED8", 83 "RESERVED9", 84 "RESERVED10", 85 "RESERVED11", 86 "RESERVED12", 87 "RESERVED13", 88 "RESERVED14", 89 "RESERVED15" 90}; 91 92/*% return code text */ 93static const char * const rcodetext[] = { 94 "NOERROR", 95 "FORMERR", 96 "SERVFAIL", 97 "NXDOMAIN", 98 "NOTIMP", 99 "REFUSED", 100 "YXDOMAIN", 101 "YXRRSET", 102 "NXRRSET", 103 "NOTAUTH", 104 "NOTZONE", 105 "RESERVED11", 106 "RESERVED12", 107 "RESERVED13", 108 "RESERVED14", 109 "RESERVED15", 110 "BADVERS" 111}; 112 113/*% safe rcodetext[] */ 114static char * 115rcode_totext(dns_rcode_t rcode) 116{ 117 static char buf[sizeof("?65535")]; 118 union { 119 const char *consttext; 120 char *deconsttext; 121 } totext; 122 123 if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 124 snprintf(buf, sizeof(buf), "?%u", rcode); 125 totext.deconsttext = buf; 126 } else 127 totext.consttext = rcodetext[rcode]; 128 return totext.deconsttext; 129} 130 131/*% print usage */ 132static void 133print_usage(FILE *fp) { 134 fputs( 135"Usage: dig [@global-server] [domain] [q-type] [q-class] {q-opt}\n" 136" {global-d-opt} host [@local-server] {local-d-opt}\n" 137" [ host [@local-server] {local-d-opt} [...]]\n", fp); 138} 139 140ISC_PLATFORM_NORETURN_PRE static void 141usage(void) ISC_PLATFORM_NORETURN_POST; 142 143static void 144usage(void) { 145 print_usage(stderr); 146 fputs("\nUse \"dig -h\" (or \"dig -h | more\") " 147 "for complete list of options\n", stderr); 148 exit(1); 149} 150 151/*% version */ 152static void 153version(void) { 154 fputs("DiG " VERSION "\n", stderr); 155} 156 157/*% help */ 158static void 159help(void) { 160 print_usage(stdout); 161 fputs( 162"Where: domain is in the Domain Name System\n" 163" q-class is one of (in,hs,ch,...) [default: in]\n" 164" q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n" 165" (Use ixfr=version for type ixfr)\n" 166" q-opt is one of:\n" 167" -x dot-notation (shortcut for reverse lookups)\n" 168" -i (use IP6.INT for IPv6 reverse lookups)\n" 169" -f filename (batch mode)\n" 170" -b address[#port] (bind to source address/port)\n" 171" -p port (specify port number)\n" 172" -q name (specify query name)\n" 173" -t type (specify query type)\n" 174" -c class (specify query class)\n" 175" -k keyfile (specify tsig key file)\n" 176" -y [hmac:]name:key (specify named base64 tsig key)\n" 177" -4 (use IPv4 query transport only)\n" 178" -6 (use IPv6 query transport only)\n" 179" -m (enable memory usage debugging)\n" 180" d-opt is of the form +keyword[=value], where keyword is:\n" 181" +[no]vc (TCP mode)\n" 182" +[no]tcp (TCP mode, alternate syntax)\n" 183" +time=### (Set query timeout) [5]\n" 184" +tries=### (Set number of UDP attempts) [3]\n" 185" +retry=### (Set number of UDP retries) [2]\n" 186" +domain=### (Set default domainname)\n" 187" +bufsize=### (Set EDNS0 Max UDP packet size)\n" 188" +ndots=### (Set NDOTS value)\n" 189" +edns=### (Set EDNS version)\n" 190" +[no]search (Set whether to use searchlist)\n" 191" +[no]showsearch (Search with intermediate results)\n" 192" +[no]defname (Ditto)\n" 193" +[no]recurse (Recursive mode)\n" 194" +[no]ignore (Don't revert to TCP for TC responses.)" 195"\n" 196" +[no]fail (Don't try next server on SERVFAIL)\n" 197" +[no]besteffort (Try to parse even illegal messages)\n" 198" +[no]aaonly (Set AA flag in query (+[no]aaflag))\n" 199" +[no]adflag (Set AD flag in query)\n" 200" +[no]cdflag (Set CD flag in query)\n" 201" +[no]cl (Control display of class in records)\n" 202" +[no]cmd (Control display of command line)\n" 203" +[no]comments (Control display of comment lines)\n" 204" +[no]question (Control display of question)\n" 205" +[no]answer (Control display of answer)\n" 206" +[no]authority (Control display of authority)\n" 207" +[no]additional (Control display of additional)\n" 208" +[no]stats (Control display of statistics)\n" 209" +[no]short (Disable everything except short\n" 210" form of answer)\n" 211" +[no]ttlid (Control display of ttls in records)\n" 212" +[no]all (Set or clear all display flags)\n" 213" +[no]qr (Print question before sending)\n" 214" +[no]nssearch (Search all authoritative nameservers)\n" 215" +[no]identify (ID responders in short answers)\n" 216" +[no]trace (Trace delegation down from root)\n" 217" +[no]dnssec (Request DNSSEC records)\n" 218" +[no]nsid (Request Name Server ID)\n" 219#ifdef DIG_SIGCHASE 220" +[no]sigchase (Chase DNSSEC signatures)\n" 221" +trusted-key=#### (Trusted Key when chasing DNSSEC sigs)\n" 222#if DIG_SIGCHASE_TD 223" +[no]topdown (Do DNSSEC validation top down mode)\n" 224#endif 225#endif 226" +[no]multiline (Print records in an expanded format)\n" 227" +[no]onesoa (AXFR prints only one soa record)\n" 228" global d-opts and servers (before host name) affect all queries.\n" 229" local d-opts and servers (after host name) affect only that lookup.\n" 230" -h (print help and exit)\n" 231" -v (print version and exit)\n", 232 stdout); 233} 234 235/*% 236 * Callback from dighost.c to print the received message. 237 */ 238void 239received(int bytes, isc_sockaddr_t *from, dig_query_t *query) { 240 isc_uint64_t diff; 241 isc_time_t now; 242 time_t tnow; 243 char fromtext[ISC_SOCKADDR_FORMATSIZE]; 244 245 isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 246 247 TIME_NOW(&now); 248 249 if (query->lookup->stats && !short_form) { 250 diff = isc_time_microdiff(&now, &query->time_sent); 251 printf(";; Query time: %ld msec\n", (long int)diff/1000); 252 printf(";; SERVER: %s(%s)\n", fromtext, query->servname); 253 time(&tnow); 254 printf(";; WHEN: %s", ctime(&tnow)); 255 if (query->lookup->doing_xfr) { 256 printf(";; XFR size: %u records (messages %u, " 257 "bytes %" ISC_PRINT_QUADFORMAT "u)\n", 258 query->rr_count, query->msg_count, 259 query->byte_count); 260 } else { 261 printf(";; MSG SIZE rcvd: %u\n", bytes); 262 263 } 264 if (key != NULL) { 265 if (!validated) 266 puts(";; WARNING -- Some TSIG could not " 267 "be validated"); 268 } 269 if ((key == NULL) && (keysecret[0] != 0)) { 270 puts(";; WARNING -- TSIG key was not used."); 271 } 272 puts(""); 273 } else if (query->lookup->identify && !short_form) { 274 diff = isc_time_microdiff(&now, &query->time_sent); 275 printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes " 276 "from %s(%s) in %d ms\n\n", 277 query->lookup->doing_xfr ? 278 query->byte_count : (isc_uint64_t)bytes, 279 fromtext, query->servname, 280 (int)diff/1000); 281 } 282} 283 284/* 285 * Callback from dighost.c to print that it is trying a server. 286 * Not used in dig. 287 * XXX print_trying 288 */ 289void 290trying(char *frm, dig_lookup_t *lookup) { 291 UNUSED(frm); 292 UNUSED(lookup); 293} 294 295/*% 296 * Internal print routine used to print short form replies. 297 */ 298static isc_result_t 299say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { 300 isc_result_t result; 301 isc_uint64_t diff; 302 isc_time_t now; 303 char store[sizeof("12345678901234567890")]; 304 305 if (query->lookup->trace || query->lookup->ns_search_only) { 306 result = dns_rdatatype_totext(rdata->type, buf); 307 if (result != ISC_R_SUCCESS) 308 return (result); 309 ADD_STRING(buf, " "); 310 } 311 result = dns_rdata_totext(rdata, NULL, buf); 312 if (result == ISC_R_NOSPACE) 313 return (result); 314 check_result(result, "dns_rdata_totext"); 315 if (query->lookup->identify) { 316 TIME_NOW(&now); 317 diff = isc_time_microdiff(&now, &query->time_sent); 318 ADD_STRING(buf, " from server "); 319 ADD_STRING(buf, query->servname); 320 snprintf(store, 19, " in %d ms.", (int)diff/1000); 321 ADD_STRING(buf, store); 322 } 323 ADD_STRING(buf, "\n"); 324 return (ISC_R_SUCCESS); 325} 326 327/*% 328 * short_form message print handler. Calls above say_message() 329 */ 330static isc_result_t 331short_answer(dns_message_t *msg, dns_messagetextflag_t flags, 332 isc_buffer_t *buf, dig_query_t *query) 333{ 334 dns_name_t *name; 335 dns_rdataset_t *rdataset; 336 isc_result_t result, loopresult; 337 dns_name_t empty_name; 338 dns_rdata_t rdata = DNS_RDATA_INIT; 339 340 UNUSED(flags); 341 342 dns_name_init(&empty_name, NULL); 343 result = dns_message_firstname(msg, DNS_SECTION_ANSWER); 344 if (result == ISC_R_NOMORE) 345 return (ISC_R_SUCCESS); 346 else if (result != ISC_R_SUCCESS) 347 return (result); 348 349 for (;;) { 350 name = NULL; 351 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); 352 353 for (rdataset = ISC_LIST_HEAD(name->list); 354 rdataset != NULL; 355 rdataset = ISC_LIST_NEXT(rdataset, link)) { 356 loopresult = dns_rdataset_first(rdataset); 357 while (loopresult == ISC_R_SUCCESS) { 358 dns_rdataset_current(rdataset, &rdata); 359 result = say_message(&rdata, query, 360 buf); 361 if (result == ISC_R_NOSPACE) 362 return (result); 363 check_result(result, "say_message"); 364 loopresult = dns_rdataset_next(rdataset); 365 dns_rdata_reset(&rdata); 366 } 367 } 368 result = dns_message_nextname(msg, DNS_SECTION_ANSWER); 369 if (result == ISC_R_NOMORE) 370 break; 371 else if (result != ISC_R_SUCCESS) 372 return (result); 373 } 374 375 return (ISC_R_SUCCESS); 376} 377#ifdef DIG_SIGCHASE 378isc_result_t 379printrdataset(dns_name_t *owner_name, dns_rdataset_t *rdataset, 380 isc_buffer_t *target) 381{ 382 isc_result_t result; 383 dns_master_style_t *style = NULL; 384 unsigned int styleflags = 0; 385 386 if (rdataset == NULL || owner_name == NULL || target == NULL) 387 return(ISC_FALSE); 388 389 styleflags |= DNS_STYLEFLAG_REL_OWNER; 390 if (nottl) 391 styleflags |= DNS_STYLEFLAG_NO_TTL; 392 if (noclass) 393 styleflags |= DNS_STYLEFLAG_NO_CLASS; 394 if (multiline) { 395 styleflags |= DNS_STYLEFLAG_OMIT_OWNER; 396 styleflags |= DNS_STYLEFLAG_OMIT_CLASS; 397 styleflags |= DNS_STYLEFLAG_REL_DATA; 398 styleflags |= DNS_STYLEFLAG_OMIT_TTL; 399 styleflags |= DNS_STYLEFLAG_TTL; 400 styleflags |= DNS_STYLEFLAG_MULTILINE; 401 styleflags |= DNS_STYLEFLAG_COMMENT; 402 } 403 if (multiline || (nottl && noclass)) 404 result = dns_master_stylecreate(&style, styleflags, 405 24, 24, 24, 32, 80, 8, mctx); 406 else if (nottl || noclass) 407 result = dns_master_stylecreate(&style, styleflags, 408 24, 24, 32, 40, 80, 8, mctx); 409 else 410 result = dns_master_stylecreate(&style, styleflags, 411 24, 32, 40, 48, 80, 8, mctx); 412 check_result(result, "dns_master_stylecreate"); 413 414 result = dns_master_rdatasettotext(owner_name, rdataset, style, target); 415 416 if (style != NULL) 417 dns_master_styledestroy(&style, mctx); 418 419 return(result); 420} 421#endif 422 423/* 424 * Callback from dighost.c to print the reply from a server 425 */ 426isc_result_t 427printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 428 isc_result_t result; 429 dns_messagetextflag_t flags; 430 isc_buffer_t *buf = NULL; 431 unsigned int len = OUTPUTBUF; 432 dns_master_style_t *style = NULL; 433 unsigned int styleflags = 0; 434 435 styleflags |= DNS_STYLEFLAG_REL_OWNER; 436 if (nottl) 437 styleflags |= DNS_STYLEFLAG_NO_TTL; 438 if (noclass) 439 styleflags |= DNS_STYLEFLAG_NO_CLASS; 440 if (multiline) { 441 styleflags |= DNS_STYLEFLAG_OMIT_OWNER; 442 styleflags |= DNS_STYLEFLAG_OMIT_CLASS; 443 styleflags |= DNS_STYLEFLAG_REL_DATA; 444 styleflags |= DNS_STYLEFLAG_OMIT_TTL; 445 styleflags |= DNS_STYLEFLAG_TTL; 446 styleflags |= DNS_STYLEFLAG_MULTILINE; 447 styleflags |= DNS_STYLEFLAG_COMMENT; 448 } 449 if (multiline || (nottl && noclass)) 450 result = dns_master_stylecreate(&style, styleflags, 451 24, 24, 24, 32, 80, 8, mctx); 452 else if (nottl || noclass) 453 result = dns_master_stylecreate(&style, styleflags, 454 24, 24, 32, 40, 80, 8, mctx); 455 else 456 result = dns_master_stylecreate(&style, styleflags, 457 24, 32, 40, 48, 80, 8, mctx); 458 check_result(result, "dns_master_stylecreate"); 459 460 if (query->lookup->cmdline[0] != 0) { 461 if (!short_form) 462 fputs(query->lookup->cmdline, stdout); 463 query->lookup->cmdline[0]=0; 464 } 465 debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", 466 query->lookup->comments ? "comments" : "nocomments", 467 short_form ? "short_form" : "long_form"); 468 469 flags = 0; 470 if (!headers) { 471 flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; 472 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 473 } 474 if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr) 475 flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA : 476 DNS_MESSAGETEXTFLAG_OMITSOA; 477 if (!query->lookup->comments) 478 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 479 480 result = isc_buffer_allocate(mctx, &buf, len); 481 check_result(result, "isc_buffer_allocate"); 482 483 if (query->lookup->comments && !short_form) { 484 if (query->lookup->cmdline[0] != 0) 485 printf("; %s\n", query->lookup->cmdline); 486 if (msg == query->lookup->sendmsg) 487 printf(";; Sending:\n"); 488 else 489 printf(";; Got answer:\n"); 490 491 if (headers) { 492 printf(";; ->>HEADER<<- opcode: %s, status: %s, " 493 "id: %u\n", 494 opcodetext[msg->opcode], 495 rcode_totext(msg->rcode), 496 msg->id); 497 printf(";; flags:"); 498 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 499 printf(" qr"); 500 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) 501 printf(" aa"); 502 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) 503 printf(" tc"); 504 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) 505 printf(" rd"); 506 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) 507 printf(" ra"); 508 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) 509 printf(" ad"); 510 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) 511 printf(" cd"); 512 if ((msg->flags & 0x0040U) != 0) 513 printf("; MBZ: 0x4"); 514 515 printf("; QUERY: %u, ANSWER: %u, " 516 "AUTHORITY: %u, ADDITIONAL: %u\n", 517 msg->counts[DNS_SECTION_QUESTION], 518 msg->counts[DNS_SECTION_ANSWER], 519 msg->counts[DNS_SECTION_AUTHORITY], 520 msg->counts[DNS_SECTION_ADDITIONAL]); 521 522 if (msg != query->lookup->sendmsg && 523 (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && 524 (msg->flags & DNS_MESSAGEFLAG_RA) == 0) 525 printf(";; WARNING: recursion requested " 526 "but not available\n"); 527 } 528 if (msg != query->lookup->sendmsg && extrabytes != 0U) 529 printf(";; WARNING: Messages has %u extra byte%s at " 530 "end\n", extrabytes, extrabytes != 0 ? "s" : ""); 531 } 532 533repopulate_buffer: 534 535 if (query->lookup->comments && headers && !short_form) { 536 result = dns_message_pseudosectiontotext(msg, 537 DNS_PSEUDOSECTION_OPT, 538 style, flags, buf); 539 if (result == ISC_R_NOSPACE) { 540buftoosmall: 541 len += OUTPUTBUF; 542 isc_buffer_free(&buf); 543 result = isc_buffer_allocate(mctx, &buf, len); 544 if (result == ISC_R_SUCCESS) 545 goto repopulate_buffer; 546 else 547 goto cleanup; 548 } 549 check_result(result, 550 "dns_message_pseudosectiontotext"); 551 } 552 553 if (query->lookup->section_question && headers) { 554 if (!short_form) { 555 result = dns_message_sectiontotext(msg, 556 DNS_SECTION_QUESTION, 557 style, flags, buf); 558 if (result == ISC_R_NOSPACE) 559 goto buftoosmall; 560 check_result(result, "dns_message_sectiontotext"); 561 } 562 } 563 if (query->lookup->section_answer) { 564 if (!short_form) { 565 result = dns_message_sectiontotext(msg, 566 DNS_SECTION_ANSWER, 567 style, flags, buf); 568 if (result == ISC_R_NOSPACE) 569 goto buftoosmall; 570 check_result(result, "dns_message_sectiontotext"); 571 } else { 572 result = short_answer(msg, flags, buf, query); 573 if (result == ISC_R_NOSPACE) 574 goto buftoosmall; 575 check_result(result, "short_answer"); 576 } 577 } 578 if (query->lookup->section_authority) { 579 if (!short_form) { 580 result = dns_message_sectiontotext(msg, 581 DNS_SECTION_AUTHORITY, 582 style, flags, buf); 583 if (result == ISC_R_NOSPACE) 584 goto buftoosmall; 585 check_result(result, "dns_message_sectiontotext"); 586 } 587 } 588 if (query->lookup->section_additional) { 589 if (!short_form) { 590 result = dns_message_sectiontotext(msg, 591 DNS_SECTION_ADDITIONAL, 592 style, flags, buf); 593 if (result == ISC_R_NOSPACE) 594 goto buftoosmall; 595 check_result(result, "dns_message_sectiontotext"); 596 /* 597 * Only print the signature on the first record. 598 */ 599 if (headers) { 600 result = dns_message_pseudosectiontotext( 601 msg, 602 DNS_PSEUDOSECTION_TSIG, 603 style, flags, buf); 604 if (result == ISC_R_NOSPACE) 605 goto buftoosmall; 606 check_result(result, 607 "dns_message_pseudosectiontotext"); 608 result = dns_message_pseudosectiontotext( 609 msg, 610 DNS_PSEUDOSECTION_SIG0, 611 style, flags, buf); 612 if (result == ISC_R_NOSPACE) 613 goto buftoosmall; 614 check_result(result, 615 "dns_message_pseudosectiontotext"); 616 } 617 } 618 } 619 620 if (headers && query->lookup->comments && !short_form) 621 printf("\n"); 622 623 printf("%.*s", (int)isc_buffer_usedlength(buf), 624 (char *)isc_buffer_base(buf)); 625 isc_buffer_free(&buf); 626 627cleanup: 628 if (style != NULL) 629 dns_master_styledestroy(&style, mctx); 630 return (result); 631} 632 633/*% 634 * print the greeting message when the program first starts up. 635 */ 636static void 637printgreeting(int argc, char **argv, dig_lookup_t *lookup) { 638 int i; 639 int remaining; 640 static isc_boolean_t first = ISC_TRUE; 641 char append[MXNAME]; 642 643 if (printcmd) { 644 lookup->cmdline[sizeof(lookup->cmdline) - 1] = 0; 645 snprintf(lookup->cmdline, sizeof(lookup->cmdline), 646 "%s; <<>> DiG " VERSION " <<>>", 647 first?"\n":""); 648 i = 1; 649 while (i < argc) { 650 snprintf(append, sizeof(append), " %s", argv[i++]); 651 remaining = sizeof(lookup->cmdline) - 652 strlen(lookup->cmdline) - 1; 653 strncat(lookup->cmdline, append, remaining); 654 } 655 remaining = sizeof(lookup->cmdline) - 656 strlen(lookup->cmdline) - 1; 657 strncat(lookup->cmdline, "\n", remaining); 658 if (first && addresscount != 0) { 659 snprintf(append, sizeof(append), 660 "; (%d server%s found)\n", 661 addresscount, 662 addresscount > 1 ? "s" : ""); 663 remaining = sizeof(lookup->cmdline) - 664 strlen(lookup->cmdline) - 1; 665 strncat(lookup->cmdline, append, remaining); 666 } 667 if (first) { 668 snprintf(append, sizeof(append), 669 ";; global options:%s%s\n", 670 short_form ? " +short" : "", 671 printcmd ? " +cmd" : ""); 672 first = ISC_FALSE; 673 remaining = sizeof(lookup->cmdline) - 674 strlen(lookup->cmdline) - 1; 675 strncat(lookup->cmdline, append, remaining); 676 } 677 } 678} 679 680/*% 681 * We're not using isc_commandline_parse() here since the command line 682 * syntax of dig is quite a bit different from that which can be described 683 * by that routine. 684 * XXX doc options 685 */ 686 687static void 688plus_option(char *option, isc_boolean_t is_batchfile, 689 dig_lookup_t *lookup) 690{ 691 isc_result_t result; 692 char option_store[256]; 693 char *cmd, *value, *ptr; 694 isc_uint32_t num; 695 isc_boolean_t state = ISC_TRUE; 696#ifdef DIG_SIGCHASE 697 size_t n; 698#endif 699 700 strncpy(option_store, option, sizeof(option_store)); 701 option_store[sizeof(option_store)-1]=0; 702 ptr = option_store; 703 cmd = next_token(&ptr,"="); 704 if (cmd == NULL) { 705 printf(";; Invalid option %s\n", option_store); 706 return; 707 } 708 value = ptr; 709 if (strncasecmp(cmd, "no", 2)==0) { 710 cmd += 2; 711 state = ISC_FALSE; 712 } 713 714#define FULLCHECK(A) \ 715 do { \ 716 size_t _l = strlen(cmd); \ 717 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 718 goto invalid_option; \ 719 } while (0) 720#define FULLCHECK2(A, B) \ 721 do { \ 722 size_t _l = strlen(cmd); \ 723 if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ 724 (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ 725 goto invalid_option; \ 726 } while (0) 727 728 switch (cmd[0]) { 729 case 'a': 730 switch (cmd[1]) { 731 case 'a': /* aaonly / aaflag */ 732 FULLCHECK2("aaonly", "aaflag"); 733 lookup->aaonly = state; 734 break; 735 case 'd': 736 switch (cmd[2]) { 737 case 'd': /* additional */ 738 FULLCHECK("additional"); 739 lookup->section_additional = state; 740 break; 741 case 'f': /* adflag */ 742 case '\0': /* +ad is a synonym for +adflag */ 743 FULLCHECK("adflag"); 744 lookup->adflag = state; 745 break; 746 default: 747 goto invalid_option; 748 } 749 break; 750 case 'l': /* all */ 751 FULLCHECK("all"); 752 lookup->section_question = state; 753 lookup->section_authority = state; 754 lookup->section_answer = state; 755 lookup->section_additional = state; 756 lookup->comments = state; 757 lookup->stats = state; 758 printcmd = state; 759 break; 760 case 'n': /* answer */ 761 FULLCHECK("answer"); 762 lookup->section_answer = state; 763 break; 764 case 'u': /* authority */ 765 FULLCHECK("authority"); 766 lookup->section_authority = state; 767 break; 768 default: 769 goto invalid_option; 770 } 771 break; 772 case 'b': 773 switch (cmd[1]) { 774 case 'e':/* besteffort */ 775 FULLCHECK("besteffort"); 776 lookup->besteffort = state; 777 break; 778 case 'u':/* bufsize */ 779 FULLCHECK("bufsize"); 780 if (value == NULL) 781 goto need_value; 782 if (!state) 783 goto invalid_option; 784 result = parse_uint(&num, value, COMMSIZE, 785 "buffer size"); 786 if (result != ISC_R_SUCCESS) 787 fatal("Couldn't parse buffer size"); 788 lookup->udpsize = num; 789 break; 790 default: 791 goto invalid_option; 792 } 793 break; 794 case 'c': 795 switch (cmd[1]) { 796 case 'd':/* cdflag */ 797 switch (cmd[2]) { 798 case 'f': /* cdflag */ 799 case '\0': /* +cd is a synonym for +cdflag */ 800 FULLCHECK("cdflag"); 801 lookup->cdflag = state; 802 break; 803 default: 804 goto invalid_option; 805 } 806 break; 807 case 'l': /* cl */ 808 FULLCHECK("cl"); 809 noclass = ISC_TF(!state); 810 break; 811 case 'm': /* cmd */ 812 FULLCHECK("cmd"); 813 printcmd = state; 814 break; 815 case 'o': /* comments */ 816 FULLCHECK("comments"); 817 lookup->comments = state; 818 if (lookup == default_lookup) 819 pluscomm = state; 820 break; 821 default: 822 goto invalid_option; 823 } 824 break; 825 case 'd': 826 switch (cmd[1]) { 827 case 'e': /* defname */ 828 FULLCHECK("defname"); 829 if (!lookup->trace) { 830 usesearch = state; 831 } 832 break; 833 case 'n': /* dnssec */ 834 FULLCHECK("dnssec"); 835 if (state && lookup->edns == -1) 836 lookup->edns = 0; 837 lookup->dnssec = state; 838 break; 839 case 'o': /* domain */ 840 FULLCHECK("domain"); 841 if (value == NULL) 842 goto need_value; 843 if (!state) 844 goto invalid_option; 845 strncpy(domainopt, value, sizeof(domainopt)); 846 domainopt[sizeof(domainopt)-1] = '\0'; 847 break; 848 default: 849 goto invalid_option; 850 } 851 break; 852 case 'e': 853 FULLCHECK("edns"); 854 if (!state) { 855 lookup->edns = -1; 856 break; 857 } 858 if (value == NULL) 859 goto need_value; 860 result = parse_uint(&num, value, 255, "edns"); 861 if (result != ISC_R_SUCCESS) 862 fatal("Couldn't parse edns"); 863 lookup->edns = num; 864 break; 865 case 'f': /* fail */ 866 FULLCHECK("fail"); 867 lookup->servfail_stops = state; 868 break; 869 case 'i': 870 switch (cmd[1]) { 871 case 'd': /* identify */ 872 FULLCHECK("identify"); 873 lookup->identify = state; 874 break; 875 case 'g': /* ignore */ 876 default: /* Inherits default for compatibility */ 877 FULLCHECK("ignore"); 878 lookup->ignore = ISC_TRUE; 879 } 880 break; 881 case 'm': /* multiline */ 882 FULLCHECK("multiline"); 883 multiline = state; 884 break; 885 case 'n': 886 switch (cmd[1]) { 887 case 'd': /* ndots */ 888 FULLCHECK("ndots"); 889 if (value == NULL) 890 goto need_value; 891 if (!state) 892 goto invalid_option; 893 result = parse_uint(&num, value, MAXNDOTS, "ndots"); 894 if (result != ISC_R_SUCCESS) 895 fatal("Couldn't parse ndots"); 896 ndots = num; 897 break; 898 case 's': 899 switch (cmd[2]) { 900 case 'i': /* nsid */ 901 FULLCHECK("nsid"); 902 if (state && lookup->edns == -1) 903 lookup->edns = 0; 904 lookup->nsid = state; 905 break; 906 case 's': /* nssearch */ 907 FULLCHECK("nssearch"); 908 lookup->ns_search_only = state; 909 if (state) { 910 lookup->trace_root = ISC_TRUE; 911 lookup->recurse = ISC_TRUE; 912 lookup->identify = ISC_TRUE; 913 lookup->stats = ISC_FALSE; 914 lookup->comments = ISC_FALSE; 915 lookup->section_additional = ISC_FALSE; 916 lookup->section_authority = ISC_FALSE; 917 lookup->section_question = ISC_FALSE; 918 lookup->rdtype = dns_rdatatype_ns; 919 lookup->rdtypeset = ISC_TRUE; 920 short_form = ISC_TRUE; 921 } 922 break; 923 default: 924 goto invalid_option; 925 } 926 break; 927 default: 928 goto invalid_option; 929 } 930 break; 931 case 'o': 932 FULLCHECK("onesoa"); 933 onesoa = state; 934 break; 935 case 'q': 936 switch (cmd[1]) { 937 case 'r': /* qr */ 938 FULLCHECK("qr"); 939 qr = state; 940 break; 941 case 'u': /* question */ 942 FULLCHECK("question"); 943 lookup->section_question = state; 944 if (lookup == default_lookup) 945 plusquest = state; 946 break; 947 default: 948 goto invalid_option; 949 } 950 break; 951 case 'r': 952 switch (cmd[1]) { 953 case 'e': 954 switch (cmd[2]) { 955 case 'c': /* recurse */ 956 FULLCHECK("recurse"); 957 lookup->recurse = state; 958 break; 959 case 't': /* retry / retries */ 960 FULLCHECK2("retry", "retries"); 961 if (value == NULL) 962 goto need_value; 963 if (!state) 964 goto invalid_option; 965 result = parse_uint(&lookup->retries, value, 966 MAXTRIES - 1, "retries"); 967 if (result != ISC_R_SUCCESS) 968 fatal("Couldn't parse retries"); 969 lookup->retries++; 970 break; 971 default: 972 goto invalid_option; 973 } 974 break; 975 default: 976 goto invalid_option; 977 } 978 break; 979 case 's': 980 switch (cmd[1]) { 981 case 'e': /* search */ 982 FULLCHECK("search"); 983 if (!lookup->trace) { 984 usesearch = state; 985 } 986 break; 987 case 'h': 988 if (cmd[2] != 'o') 989 goto invalid_option; 990 switch (cmd[3]) { 991 case 'r': /* short */ 992 FULLCHECK("short"); 993 short_form = state; 994 if (state) { 995 printcmd = ISC_FALSE; 996 lookup->section_additional = ISC_FALSE; 997 lookup->section_answer = ISC_TRUE; 998 lookup->section_authority = ISC_FALSE; 999 lookup->section_question = ISC_FALSE; 1000 lookup->comments = ISC_FALSE; 1001 lookup->stats = ISC_FALSE; 1002 } 1003 break; 1004 case 'w': /* showsearch */ 1005 FULLCHECK("showsearch"); 1006 if (!lookup->trace) { 1007 showsearch = state; 1008 usesearch = state; 1009 } 1010 break; 1011 default: 1012 goto invalid_option; 1013 } 1014 break; 1015#ifdef DIG_SIGCHASE 1016 case 'i': /* sigchase */ 1017 FULLCHECK("sigchase"); 1018 lookup->sigchase = state; 1019 if (lookup->sigchase) 1020 lookup->dnssec = ISC_TRUE; 1021 break; 1022#endif 1023 case 't': /* stats */ 1024 FULLCHECK("stats"); 1025 lookup->stats = state; 1026 break; 1027 default: 1028 goto invalid_option; 1029 } 1030 break; 1031 case 't': 1032 switch (cmd[1]) { 1033 case 'c': /* tcp */ 1034 FULLCHECK("tcp"); 1035 if (!is_batchfile) 1036 lookup->tcp_mode = state; 1037 break; 1038 case 'i': /* timeout */ 1039 FULLCHECK("timeout"); 1040 if (value == NULL) 1041 goto need_value; 1042 if (!state) 1043 goto invalid_option; 1044 result = parse_uint(&timeout, value, MAXTIMEOUT, 1045 "timeout"); 1046 if (result != ISC_R_SUCCESS) 1047 fatal("Couldn't parse timeout"); 1048 if (timeout == 0) 1049 timeout = 1; 1050 break; 1051#if DIG_SIGCHASE_TD 1052 case 'o': /* topdown */ 1053 FULLCHECK("topdown"); 1054 lookup->do_topdown = state; 1055 break; 1056#endif 1057 case 'r': 1058 switch (cmd[2]) { 1059 case 'a': /* trace */ 1060 FULLCHECK("trace"); 1061 lookup->trace = state; 1062 lookup->trace_root = state; 1063 if (state) { 1064 lookup->recurse = ISC_FALSE; 1065 lookup->identify = ISC_TRUE; 1066 lookup->comments = ISC_FALSE; 1067 lookup->stats = ISC_FALSE; 1068 lookup->section_additional = ISC_FALSE; 1069 lookup->section_authority = ISC_TRUE; 1070 lookup->section_question = ISC_FALSE; 1071 usesearch = ISC_FALSE; 1072 } 1073 break; 1074 case 'i': /* tries */ 1075 FULLCHECK("tries"); 1076 if (value == NULL) 1077 goto need_value; 1078 if (!state) 1079 goto invalid_option; 1080 result = parse_uint(&lookup->retries, value, 1081 MAXTRIES, "tries"); 1082 if (result != ISC_R_SUCCESS) 1083 fatal("Couldn't parse tries"); 1084 if (lookup->retries == 0) 1085 lookup->retries = 1; 1086 break; 1087#ifdef DIG_SIGCHASE 1088 case 'u': /* trusted-key */ 1089 FULLCHECK("trusted-key"); 1090 if (value == NULL) 1091 goto need_value; 1092 if (!state) 1093 goto invalid_option; 1094 n = strlcpy(trustedkey, ptr, 1095 sizeof(trustedkey)); 1096 if (n >= sizeof(trustedkey)) 1097 fatal("trusted key too large"); 1098 break; 1099#endif 1100 default: 1101 goto invalid_option; 1102 } 1103 break; 1104 case 't': /* ttlid */ 1105 FULLCHECK("ttlid"); 1106 nottl = ISC_TF(!state); 1107 break; 1108 default: 1109 goto invalid_option; 1110 } 1111 break; 1112 case 'v': 1113 FULLCHECK("vc"); 1114 if (!is_batchfile) 1115 lookup->tcp_mode = state; 1116 break; 1117 default: 1118 invalid_option: 1119 need_value: 1120 fprintf(stderr, "Invalid option: +%s\n", 1121 option); 1122 usage(); 1123 } 1124 return; 1125} 1126 1127/*% 1128 * #ISC_TRUE returned if value was used 1129 */ 1130static const char *single_dash_opts = "46dhimnv"; 1131static const char *dash_opts = "46bcdfhikmnptvyx"; 1132static isc_boolean_t 1133dash_option(char *option, char *next, dig_lookup_t **lookup, 1134 isc_boolean_t *open_type_class, isc_boolean_t *need_clone, 1135 isc_boolean_t config_only, int argc, char **argv, 1136 isc_boolean_t *firstarg) 1137{ 1138 char opt, *value, *ptr, *ptr2, *ptr3; 1139 isc_result_t result; 1140 isc_boolean_t value_from_next; 1141 isc_textregion_t tr; 1142 dns_rdatatype_t rdtype; 1143 dns_rdataclass_t rdclass; 1144 char textname[MXNAME]; 1145 struct in_addr in4; 1146 struct in6_addr in6; 1147 in_port_t srcport; 1148 char *hash, *cmd; 1149 isc_uint32_t num; 1150 1151 while (strpbrk(option, single_dash_opts) == &option[0]) { 1152 /* 1153 * Since the -[46dhimnv] options do not take an argument, 1154 * account for them (in any number and/or combination) 1155 * if they appear as the first character(s) of a q-opt. 1156 */ 1157 opt = option[0]; 1158 switch (opt) { 1159 case '4': 1160 if (have_ipv4) { 1161 isc_net_disableipv6(); 1162 have_ipv6 = ISC_FALSE; 1163 } else { 1164 fatal("can't find IPv4 networking"); 1165 /* NOTREACHED */ 1166 return (ISC_FALSE); 1167 } 1168 break; 1169 case '6': 1170 if (have_ipv6) { 1171 isc_net_disableipv4(); 1172 have_ipv4 = ISC_FALSE; 1173 } else { 1174 fatal("can't find IPv6 networking"); 1175 /* NOTREACHED */ 1176 return (ISC_FALSE); 1177 } 1178 break; 1179 case 'd': 1180 ptr = strpbrk(&option[1], dash_opts); 1181 if (ptr != &option[1]) { 1182 cmd = option; 1183 FULLCHECK("debug"); 1184 debugging = ISC_TRUE; 1185 return (ISC_FALSE); 1186 } else 1187 debugging = ISC_TRUE; 1188 break; 1189 case 'h': 1190 help(); 1191 exit(0); 1192 break; 1193 case 'i': 1194 ip6_int = ISC_TRUE; 1195 break; 1196 case 'm': /* memdebug */ 1197 /* memdebug is handled in preparse_args() */ 1198 break; 1199 case 'n': 1200 /* deprecated */ 1201 break; 1202 case 'v': 1203 version(); 1204 exit(0); 1205 break; 1206 } 1207 if (strlen(option) > 1U) 1208 option = &option[1]; 1209 else 1210 return (ISC_FALSE); 1211 } 1212 opt = option[0]; 1213 if (strlen(option) > 1U) { 1214 value_from_next = ISC_FALSE; 1215 value = &option[1]; 1216 } else { 1217 value_from_next = ISC_TRUE; 1218 value = next; 1219 } 1220 if (value == NULL) 1221 goto invalid_option; 1222 switch (opt) { 1223 case 'b': 1224 hash = strchr(value, '#'); 1225 if (hash != NULL) { 1226 result = parse_uint(&num, hash + 1, MAXPORT, 1227 "port number"); 1228 if (result != ISC_R_SUCCESS) 1229 fatal("Couldn't parse port number"); 1230 srcport = num; 1231 *hash = '\0'; 1232 } else 1233 srcport = 0; 1234 if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { 1235 isc_sockaddr_fromin6(&bind_address, &in6, srcport); 1236 isc_net_disableipv4(); 1237 } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { 1238 isc_sockaddr_fromin(&bind_address, &in4, srcport); 1239 isc_net_disableipv6(); 1240 } else { 1241 if (hash != NULL) 1242 *hash = '#'; 1243 fatal("invalid address %s", value); 1244 } 1245 if (hash != NULL) 1246 *hash = '#'; 1247 specified_source = ISC_TRUE; 1248 return (value_from_next); 1249 case 'c': 1250 if ((*lookup)->rdclassset) { 1251 fprintf(stderr, ";; Warning, extra class option\n"); 1252 } 1253 *open_type_class = ISC_FALSE; 1254 tr.base = value; 1255 tr.length = strlen(value); 1256 result = dns_rdataclass_fromtext(&rdclass, 1257 (isc_textregion_t *)&tr); 1258 if (result == ISC_R_SUCCESS) { 1259 (*lookup)->rdclass = rdclass; 1260 (*lookup)->rdclassset = ISC_TRUE; 1261 } else 1262 fprintf(stderr, ";; Warning, ignoring " 1263 "invalid class %s\n", 1264 value); 1265 return (value_from_next); 1266 case 'f': 1267 batchname = value; 1268 return (value_from_next); 1269 case 'k': 1270 strncpy(keyfile, value, sizeof(keyfile)); 1271 keyfile[sizeof(keyfile)-1]=0; 1272 return (value_from_next); 1273 case 'p': 1274 result = parse_uint(&num, value, MAXPORT, "port number"); 1275 if (result != ISC_R_SUCCESS) 1276 fatal("Couldn't parse port number"); 1277 port = num; 1278 return (value_from_next); 1279 case 'q': 1280 if (!config_only) { 1281 if (*need_clone) 1282 (*lookup) = clone_lookup(default_lookup, 1283 ISC_TRUE); 1284 *need_clone = ISC_TRUE; 1285 strncpy((*lookup)->textname, value, 1286 sizeof((*lookup)->textname)); 1287 (*lookup)->textname[sizeof((*lookup)->textname)-1]=0; 1288 (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1289 (*lookup)->ns_search_only); 1290 (*lookup)->new_search = ISC_TRUE; 1291 if (*firstarg) { 1292 printgreeting(argc, argv, *lookup); 1293 *firstarg = ISC_FALSE; 1294 } 1295 ISC_LIST_APPEND(lookup_list, (*lookup), link); 1296 debug("looking up %s", (*lookup)->textname); 1297 } 1298 return (value_from_next); 1299 case 't': 1300 *open_type_class = ISC_FALSE; 1301 if (strncasecmp(value, "ixfr=", 5) == 0) { 1302 rdtype = dns_rdatatype_ixfr; 1303 result = ISC_R_SUCCESS; 1304 } else { 1305 tr.base = value; 1306 tr.length = strlen(value); 1307 result = dns_rdatatype_fromtext(&rdtype, 1308 (isc_textregion_t *)&tr); 1309 if (result == ISC_R_SUCCESS && 1310 rdtype == dns_rdatatype_ixfr) { 1311 result = DNS_R_UNKNOWN; 1312 } 1313 } 1314 if (result == ISC_R_SUCCESS) { 1315 if ((*lookup)->rdtypeset) { 1316 fprintf(stderr, ";; Warning, " 1317 "extra type option\n"); 1318 } 1319 if (rdtype == dns_rdatatype_ixfr) { 1320 isc_uint32_t serial; 1321 (*lookup)->rdtype = dns_rdatatype_ixfr; 1322 (*lookup)->rdtypeset = ISC_TRUE; 1323 result = parse_uint(&serial, &value[5], 1324 MAXSERIAL, "serial number"); 1325 if (result != ISC_R_SUCCESS) 1326 fatal("Couldn't parse serial number"); 1327 (*lookup)->ixfr_serial = serial; 1328 (*lookup)->section_question = plusquest; 1329 (*lookup)->comments = pluscomm; 1330 (*lookup)->tcp_mode = ISC_TRUE; 1331 } else { 1332 (*lookup)->rdtype = rdtype; 1333 (*lookup)->rdtypeset = ISC_TRUE; 1334 if (rdtype == dns_rdatatype_axfr) { 1335 (*lookup)->section_question = plusquest; 1336 (*lookup)->comments = pluscomm; 1337 } 1338 (*lookup)->ixfr_serial = ISC_FALSE; 1339 } 1340 } else 1341 fprintf(stderr, ";; Warning, ignoring " 1342 "invalid type %s\n", 1343 value); 1344 return (value_from_next); 1345 case 'y': 1346 ptr = next_token(&value,":"); /* hmac type or name */ 1347 if (ptr == NULL) { 1348 usage(); 1349 } 1350 ptr2 = next_token(&value, ":"); /* name or secret */ 1351 if (ptr2 == NULL) 1352 usage(); 1353 ptr3 = next_token(&value,":"); /* secret or NULL */ 1354 if (ptr3 != NULL) { 1355 parse_hmac(ptr); 1356 ptr = ptr2; 1357 ptr2 = ptr3; 1358 } else { 1359 hmacname = DNS_TSIG_HMACMD5_NAME; 1360 digestbits = 0; 1361 } 1362 strncpy(keynametext, ptr, sizeof(keynametext)); 1363 keynametext[sizeof(keynametext)-1]=0; 1364 strncpy(keysecret, ptr2, sizeof(keysecret)); 1365 keysecret[sizeof(keysecret)-1]=0; 1366 return (value_from_next); 1367 case 'x': 1368 if (*need_clone) 1369 *lookup = clone_lookup(default_lookup, ISC_TRUE); 1370 *need_clone = ISC_TRUE; 1371 if (get_reverse(textname, sizeof(textname), value, 1372 ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { 1373 strncpy((*lookup)->textname, textname, 1374 sizeof((*lookup)->textname)); 1375 debug("looking up %s", (*lookup)->textname); 1376 (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1377 (*lookup)->ns_search_only); 1378 (*lookup)->ip6_int = ip6_int; 1379 if (!(*lookup)->rdtypeset) 1380 (*lookup)->rdtype = dns_rdatatype_ptr; 1381 if (!(*lookup)->rdclassset) 1382 (*lookup)->rdclass = dns_rdataclass_in; 1383 (*lookup)->new_search = ISC_TRUE; 1384 if (*firstarg) { 1385 printgreeting(argc, argv, *lookup); 1386 *firstarg = ISC_FALSE; 1387 } 1388 ISC_LIST_APPEND(lookup_list, *lookup, link); 1389 } else { 1390 fprintf(stderr, "Invalid IP address %s\n", value); 1391 exit(1); 1392 } 1393 return (value_from_next); 1394 invalid_option: 1395 default: 1396 fprintf(stderr, "Invalid option: -%s\n", option); 1397 usage(); 1398 } 1399 /* NOTREACHED */ 1400 return (ISC_FALSE); 1401} 1402 1403/*% 1404 * Because we may be trying to do memory allocation recording, we're going 1405 * to need to parse the arguments for the -m *before* we start the main 1406 * argument parsing routine. 1407 * 1408 * I'd prefer not to have to do this, but I am not quite sure how else to 1409 * fix the problem. Argument parsing in dig involves memory allocation 1410 * by its nature, so it can't be done in the main argument parser. 1411 */ 1412static void 1413preparse_args(int argc, char **argv) { 1414 int rc; 1415 char **rv; 1416 char *option; 1417 1418 rc = argc; 1419 rv = argv; 1420 for (rc--, rv++; rc > 0; rc--, rv++) { 1421 if (rv[0][0] != '-') 1422 continue; 1423 option = &rv[0][1]; 1424 while (strpbrk(option, single_dash_opts) == &option[0]) { 1425 if (option[0] == 'm') { 1426 memdebugging = ISC_TRUE; 1427 isc_mem_debugging = ISC_MEM_DEBUGTRACE | 1428 ISC_MEM_DEBUGRECORD; 1429 return; 1430 } 1431 option = &option[1]; 1432 } 1433 } 1434} 1435 1436static void 1437parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, 1438 int argc, char **argv) { 1439 isc_result_t result; 1440 isc_textregion_t tr; 1441 isc_boolean_t firstarg = ISC_TRUE; 1442 dig_lookup_t *lookup = NULL; 1443 dns_rdatatype_t rdtype; 1444 dns_rdataclass_t rdclass; 1445 isc_boolean_t open_type_class = ISC_TRUE; 1446 char batchline[MXNAME]; 1447 int bargc; 1448 char *bargv[64]; 1449 int rc; 1450 char **rv; 1451#ifndef NOPOSIX 1452 char *homedir; 1453 char rcfile[256]; 1454#endif 1455 char *input; 1456 int i; 1457 isc_boolean_t need_clone = ISC_TRUE; 1458 1459 /* 1460 * The semantics for parsing the args is a bit complex; if 1461 * we don't have a host yet, make the arg apply globally, 1462 * otherwise make it apply to the latest host. This is 1463 * a bit different than the previous versions, but should 1464 * form a consistent user interface. 1465 * 1466 * First, create a "default lookup" which won't actually be used 1467 * anywhere, except for cloning into new lookups 1468 */ 1469 1470 debug("parse_args()"); 1471 if (!is_batchfile) { 1472 debug("making new lookup"); 1473 default_lookup = make_empty_lookup(); 1474 1475#ifndef NOPOSIX 1476 /* 1477 * Treat ${HOME}/.digrc as a special batchfile 1478 */ 1479 INSIST(batchfp == NULL); 1480 homedir = getenv("HOME"); 1481 if (homedir != NULL) { 1482 unsigned int n; 1483 n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc", 1484 homedir); 1485 if (n < sizeof(rcfile)) 1486 batchfp = fopen(rcfile, "r"); 1487 } 1488 if (batchfp != NULL) { 1489 while (fgets(batchline, sizeof(batchline), 1490 batchfp) != 0) { 1491 debug("config line %s", batchline); 1492 bargc = 1; 1493 input = batchline; 1494 bargv[bargc] = next_token(&input, " \t\r\n"); 1495 while ((bargv[bargc] != NULL) && 1496 (bargc < 62)) { 1497 bargc++; 1498 bargv[bargc] = 1499 next_token(&input, " \t\r\n"); 1500 } 1501 1502 bargv[0] = argv[0]; 1503 argv0 = argv[0]; 1504 1505 for(i = 0; i < bargc; i++) 1506 debug(".digrc argv %d: %s", 1507 i, bargv[i]); 1508 parse_args(ISC_TRUE, ISC_TRUE, bargc, 1509 (char **)bargv); 1510 } 1511 fclose(batchfp); 1512 } 1513#endif 1514 } 1515 1516 if (is_batchfile && !config_only) { 1517 /* Processing '-f batchfile'. */ 1518 lookup = clone_lookup(default_lookup, ISC_TRUE); 1519 need_clone = ISC_FALSE; 1520 } else 1521 lookup = default_lookup; 1522 1523 rc = argc; 1524 rv = argv; 1525 for (rc--, rv++; rc > 0; rc--, rv++) { 1526 debug("main parsing %s", rv[0]); 1527 if (strncmp(rv[0], "%", 1) == 0) 1528 break; 1529 if (strncmp(rv[0], "@", 1) == 0) { 1530 addresscount = getaddresses(lookup, &rv[0][1], NULL); 1531 } else if (rv[0][0] == '+') { 1532 plus_option(&rv[0][1], is_batchfile, 1533 lookup); 1534 } else if (rv[0][0] == '-') { 1535 if (rc <= 1) { 1536 if (dash_option(&rv[0][1], NULL, 1537 &lookup, &open_type_class, 1538 &need_clone, config_only, 1539 argc, argv, &firstarg)) { 1540 rc--; 1541 rv++; 1542 } 1543 } else { 1544 if (dash_option(&rv[0][1], rv[1], 1545 &lookup, &open_type_class, 1546 &need_clone, config_only, 1547 argc, argv, &firstarg)) { 1548 rc--; 1549 rv++; 1550 } 1551 } 1552 } else { 1553 /* 1554 * Anything which isn't an option 1555 */ 1556 if (open_type_class) { 1557 if (strncasecmp(rv[0], "ixfr=", 5) == 0) { 1558 rdtype = dns_rdatatype_ixfr; 1559 result = ISC_R_SUCCESS; 1560 } else { 1561 tr.base = rv[0]; 1562 tr.length = strlen(rv[0]); 1563 result = dns_rdatatype_fromtext(&rdtype, 1564 (isc_textregion_t *)&tr); 1565 if (result == ISC_R_SUCCESS && 1566 rdtype == dns_rdatatype_ixfr) { 1567 fprintf(stderr, ";; Warning, " 1568 "ixfr requires a " 1569 "serial number\n"); 1570 continue; 1571 } 1572 } 1573 if (result == ISC_R_SUCCESS) { 1574 if (lookup->rdtypeset) { 1575 fprintf(stderr, ";; Warning, " 1576 "extra type option\n"); 1577 } 1578 if (rdtype == dns_rdatatype_ixfr) { 1579 isc_uint32_t serial; 1580 lookup->rdtype = 1581 dns_rdatatype_ixfr; 1582 lookup->rdtypeset = ISC_TRUE; 1583 result = parse_uint(&serial, 1584 &rv[0][5], 1585 MAXSERIAL, 1586 "serial number"); 1587 if (result != ISC_R_SUCCESS) 1588 fatal("Couldn't parse " 1589 "serial number"); 1590 lookup->ixfr_serial = serial; 1591 lookup->section_question = 1592 plusquest; 1593 lookup->comments = pluscomm; 1594 lookup->tcp_mode = ISC_TRUE; 1595 } else { 1596 lookup->rdtype = rdtype; 1597 lookup->rdtypeset = ISC_TRUE; 1598 if (rdtype == 1599 dns_rdatatype_axfr) { 1600 lookup->section_question = 1601 plusquest; 1602 lookup->comments = pluscomm; 1603 } 1604 lookup->ixfr_serial = ISC_FALSE; 1605 } 1606 continue; 1607 } 1608 result = dns_rdataclass_fromtext(&rdclass, 1609 (isc_textregion_t *)&tr); 1610 if (result == ISC_R_SUCCESS) { 1611 if (lookup->rdclassset) { 1612 fprintf(stderr, ";; Warning, " 1613 "extra class option\n"); 1614 } 1615 lookup->rdclass = rdclass; 1616 lookup->rdclassset = ISC_TRUE; 1617 continue; 1618 } 1619 } 1620 1621 if (!config_only) { 1622 if (need_clone) 1623 lookup = clone_lookup(default_lookup, 1624 ISC_TRUE); 1625 need_clone = ISC_TRUE; 1626 strncpy(lookup->textname, rv[0], 1627 sizeof(lookup->textname)); 1628 lookup->textname[sizeof(lookup->textname)-1]=0; 1629 lookup->trace_root = ISC_TF(lookup->trace || 1630 lookup->ns_search_only); 1631 lookup->new_search = ISC_TRUE; 1632 if (firstarg) { 1633 printgreeting(argc, argv, lookup); 1634 firstarg = ISC_FALSE; 1635 } 1636 ISC_LIST_APPEND(lookup_list, lookup, link); 1637 debug("looking up %s", lookup->textname); 1638 } 1639 /* XXX Error message */ 1640 } 1641 } 1642 1643 /* 1644 * If we have a batchfile, seed the lookup list with the 1645 * first entry, then trust the callback in dighost_shutdown 1646 * to get the rest 1647 */ 1648 if ((batchname != NULL) && !(is_batchfile)) { 1649 if (strcmp(batchname, "-") == 0) 1650 batchfp = stdin; 1651 else 1652 batchfp = fopen(batchname, "r"); 1653 if (batchfp == NULL) { 1654 perror(batchname); 1655 if (exitcode < 8) 1656 exitcode = 8; 1657 fatal("couldn't open specified batch file"); 1658 } 1659 /* XXX Remove code dup from shutdown code */ 1660 next_line: 1661 if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 1662 bargc = 1; 1663 debug("batch line %s", batchline); 1664 if (batchline[0] == '\r' || batchline[0] == '\n' 1665 || batchline[0] == '#' || batchline[0] == ';') 1666 goto next_line; 1667 input = batchline; 1668 bargv[bargc] = next_token(&input, " \t\r\n"); 1669 while ((bargv[bargc] != NULL) && (bargc < 14)) { 1670 bargc++; 1671 bargv[bargc] = next_token(&input, " \t\r\n"); 1672 } 1673 1674 bargv[0] = argv[0]; 1675 argv0 = argv[0]; 1676 1677 for(i = 0; i < bargc; i++) 1678 debug("batch argv %d: %s", i, bargv[i]); 1679 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 1680 return; 1681 } 1682 return; 1683 } 1684 /* 1685 * If no lookup specified, search for root 1686 */ 1687 if ((lookup_list.head == NULL) && !config_only) { 1688 if (need_clone) 1689 lookup = clone_lookup(default_lookup, ISC_TRUE); 1690 need_clone = ISC_TRUE; 1691 lookup->trace_root = ISC_TF(lookup->trace || 1692 lookup->ns_search_only); 1693 lookup->new_search = ISC_TRUE; 1694 strcpy(lookup->textname, "."); 1695 lookup->rdtype = dns_rdatatype_ns; 1696 lookup->rdtypeset = ISC_TRUE; 1697 if (firstarg) { 1698 printgreeting(argc, argv, lookup); 1699 firstarg = ISC_FALSE; 1700 } 1701 ISC_LIST_APPEND(lookup_list, lookup, link); 1702 } 1703 if (!need_clone) 1704 destroy_lookup(lookup); 1705} 1706 1707/* 1708 * Callback from dighost.c to allow program-specific shutdown code. 1709 * Here, we're possibly reading from a batch file, then shutting down 1710 * for real if there's nothing in the batch file to read. 1711 */ 1712void 1713dighost_shutdown(void) { 1714 char batchline[MXNAME]; 1715 int bargc; 1716 char *bargv[16]; 1717 char *input; 1718 int i; 1719 1720 if (batchname == NULL) { 1721 isc_app_shutdown(); 1722 return; 1723 } 1724 1725 fflush(stdout); 1726 if (feof(batchfp)) { 1727 batchname = NULL; 1728 isc_app_shutdown(); 1729 if (batchfp != stdin) 1730 fclose(batchfp); 1731 return; 1732 } 1733 1734 if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 1735 debug("batch line %s", batchline); 1736 bargc = 1; 1737 input = batchline; 1738 bargv[bargc] = next_token(&input, " \t\r\n"); 1739 while ((bargv[bargc] != NULL) && (bargc < 14)) { 1740 bargc++; 1741 bargv[bargc] = next_token(&input, " \t\r\n"); 1742 } 1743 1744 bargv[0] = argv0; 1745 1746 for(i = 0; i < bargc; i++) 1747 debug("batch argv %d: %s", i, bargv[i]); 1748 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 1749 start_lookup(); 1750 } else { 1751 batchname = NULL; 1752 if (batchfp != stdin) 1753 fclose(batchfp); 1754 isc_app_shutdown(); 1755 return; 1756 } 1757} 1758 1759/*% Main processing routine for dig */ 1760int 1761main(int argc, char **argv) { 1762 isc_result_t result; 1763 1764 ISC_LIST_INIT(lookup_list); 1765 ISC_LIST_INIT(server_list); 1766 ISC_LIST_INIT(search_list); 1767 1768 debug("main()"); 1769 preparse_args(argc, argv); 1770 progname = argv[0]; 1771 result = isc_app_start(); 1772 check_result(result, "isc_app_start"); 1773 setup_libs(); 1774 parse_args(ISC_FALSE, ISC_FALSE, argc, argv); 1775 setup_system(); 1776 if (domainopt[0] != '\0') { 1777 set_search_domain(domainopt); 1778 usesearch = ISC_TRUE; 1779 } 1780 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); 1781 check_result(result, "isc_app_onrun"); 1782 isc_app_run(); 1783 destroy_lookup(default_lookup); 1784 if (batchname != NULL) { 1785 if (batchfp != stdin) 1786 fclose(batchfp); 1787 batchname = NULL; 1788 } 1789#ifdef DIG_SIGCHASE 1790 clean_trustedkey(); 1791#endif 1792 cancel_all(); 1793 destroy_libs(); 1794 isc_app_finish(); 1795 return (exitcode); 1796} 1797