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