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