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