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