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