1 /* $NetBSD: dig.c,v 1.1.1.1 2018/08/12 12:07:09 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * See the COPYRIGHT file distributed with this work for additional 11 * information regarding copyright ownership. 12 */ 13 14 /*! \file */ 15 16 #include <config.h> 17 #include <stdlib.h> 18 #include <time.h> 19 #include <ctype.h> 20 21 #include <isc/app.h> 22 #include <isc/netaddr.h> 23 #include <isc/parseint.h> 24 #include <isc/platform.h> 25 #include <isc/print.h> 26 #include <isc/string.h> 27 #include <isc/task.h> 28 #include <isc/util.h> 29 30 #include <pk11/site.h> 31 32 #include <dns/byaddr.h> 33 #include <dns/fixedname.h> 34 #include <dns/masterdump.h> 35 #include <dns/message.h> 36 #include <dns/name.h> 37 #include <dns/rcode.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 #include <dns/tsig.h> 44 45 #include <dig/dig.h> 46 47 #define ADD_STRING(b, s) { \ 48 if (strlen(s) >= isc_buffer_availablelength(b)) \ 49 return (ISC_R_NOSPACE); \ 50 else \ 51 isc_buffer_putstr(b, s); \ 52 } 53 54 #define DIG_MAX_ADDRESSES 20 55 56 dig_lookup_t *default_lookup = NULL; 57 58 static char *batchname = NULL; 59 static FILE *batchfp = NULL; 60 static char *argv0; 61 static int addresscount = 0; 62 63 static char domainopt[DNS_NAME_MAXTEXT]; 64 static char hexcookie[81]; 65 66 static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE, 67 ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE, 68 ipv4only = ISC_FALSE, ipv6only = ISC_FALSE; 69 static isc_uint32_t splitwidth = 0xffffffff; 70 71 /*% opcode text */ 72 static const char * const opcodetext[] = { 73 "QUERY", 74 "IQUERY", 75 "STATUS", 76 "RESERVED3", 77 "NOTIFY", 78 "UPDATE", 79 "RESERVED6", 80 "RESERVED7", 81 "RESERVED8", 82 "RESERVED9", 83 "RESERVED10", 84 "RESERVED11", 85 "RESERVED12", 86 "RESERVED13", 87 "RESERVED14", 88 "RESERVED15" 89 }; 90 91 static const char * 92 rcode_totext(dns_rcode_t rcode) { 93 static char buf[64]; 94 isc_buffer_t b; 95 isc_result_t result; 96 97 memset(buf, 0, sizeof(buf)); 98 isc_buffer_init(&b, buf + 1, sizeof(buf) - 2); 99 result = dns_rcode_totext(rcode, &b); 100 RUNTIME_CHECK(result == ISC_R_SUCCESS); 101 if (strspn(buf + 1, "0123456789") == strlen(buf + 1)) { 102 buf[0] = '?'; 103 return(buf); 104 } 105 return (buf + 1); 106 } 107 108 /*% print usage */ 109 static void 110 print_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 117 #if TARGET_OS_IPHONE 118 static void usage(void) { 119 fprintf(stderr, "Press <Help> for complete list of options\n"); 120 } 121 #else 122 ISC_PLATFORM_NORETURN_PRE static void 123 usage(void) ISC_PLATFORM_NORETURN_POST; 124 125 static void 126 usage(void) { 127 print_usage(stderr); 128 fputs("\nUse \"dig -h\" (or \"dig -h | more\") " 129 "for complete list of options\n", stderr); 130 exit(1); 131 } 132 #endif 133 134 /*% version */ 135 static void 136 version(void) { 137 fputs("DiG " VERSION "\n", stderr); 138 } 139 140 /*% help */ 141 static void 142 help(void) { 143 print_usage(stdout); 144 fputs( 145 "Where: domain is in the Domain Name System\n" 146 " q-class is one of (in,hs,ch,...) [default: in]\n" 147 " q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) [default:a]\n" 148 " (Use ixfr=version for type ixfr)\n" 149 " q-opt is one of:\n" 150 " -4 (use IPv4 query transport only)\n" 151 " -6 (use IPv6 query transport only)\n" 152 " -b address[#port] (bind to source address/port)\n" 153 " -c class (specify query class)\n" 154 " -f filename (batch mode)\n" 155 " -i (use IP6.INT for IPv6 reverse lookups)\n" 156 " -k keyfile (specify tsig key file)\n" 157 " -m (enable memory usage debugging)\n" 158 " -p port (specify port number)\n" 159 " -q name (specify query name)\n" 160 " -t type (specify query type)\n" 161 " -u (display times in usec instead of msec)\n" 162 " -x dot-notation (shortcut for reverse lookups)\n" 163 " -y [hmac:]name:key (specify named base64 tsig key)\n" 164 " d-opt is of the form +keyword[=value], where keyword is:\n" 165 " +[no]aaflag (Set AA flag in query (+[no]aaflag))\n" 166 " +[no]aaonly (Set AA flag in query (+[no]aaflag))\n" 167 " +[no]additional (Control display of additional section)\n" 168 " +[no]adflag (Set AD flag in query (default on))\n" 169 " +[no]all (Set or clear all display flags)\n" 170 " +[no]answer (Control display of answer section)\n" 171 " +[no]authority (Control display of authority section)\n" 172 " +[no]badcookie (Retry BADCOOKIE responses)\n" 173 " +[no]besteffort (Try to parse even illegal messages)\n" 174 " +bufsize=### (Set EDNS0 Max UDP packet size)\n" 175 " +[no]cdflag (Set checking disabled flag in query)\n" 176 " +[no]class (Control display of class in records)\n" 177 " +[no]cmd (Control display of command line)\n" 178 " +[no]comments (Control display of comment lines)\n" 179 " +[no]cookie (Add a COOKIE option to the request)\n" 180 " +[no]crypto (Control display of cryptographic " 181 "fields in records)\n" 182 " +[no]defname (Use search list (+[no]search))\n" 183 " +[no]dnssec (Request DNSSEC records)\n" 184 " +domain=### (Set default domainname)\n" 185 " +[no]dscp[=###] (Set the DSCP value to ### [0..63])\n" 186 " +[no]edns[=###] (Set EDNS version) [0]\n" 187 " +ednsflags=### (Set EDNS flag bits)\n" 188 " +[no]ednsnegotiation (Set EDNS version negotiation)\n" 189 " +ednsopt=###[:value] (Send specified EDNS option)\n" 190 " +noednsopt (Clear list of +ednsopt options)\n" 191 " +[no]expire (Request time to expire)\n" 192 " +[no]fail (Don't try next server on SERVFAIL)\n" 193 " +[no]header-only (Send query without a question section)\n" 194 " +[no]identify (ID responders in short answers)\n" 195 " +[no]idnin (Parse IDN names)\n" 196 " +[no]idnout (Convert IDN response)\n" 197 " +[no]ignore (Don't revert to TCP for TC responses.)\n" 198 " +[no]keepalive (Request EDNS TCP keepalive)\n" 199 " +[no]keepopen (Keep the TCP socket open between queries)\n" 200 " +[no]mapped (Allow mapped IPv4 over IPv6)\n" 201 " +[no]multiline (Print records in an expanded format)\n" 202 " +ndots=### (Set search NDOTS value)\n" 203 " +[no]nsid (Request Name Server ID)\n" 204 " +[no]nssearch (Search all authoritative nameservers)\n" 205 " +[no]onesoa (AXFR prints only one soa record)\n" 206 " +[no]opcode=### (Set the opcode of the request)\n" 207 " +padding=### (Set padding block size [0])\n" 208 " +[no]qr (Print question before sending)\n" 209 " +[no]question (Control display of question section)\n" 210 " +[no]rdflag (Recursive mode (+[no]recurse))\n" 211 " +[no]recurse (Recursive mode (+[no]rdflag))\n" 212 " +retry=### (Set number of UDP retries) [2]\n" 213 " +[no]rrcomments (Control display of per-record " 214 "comments)\n" 215 " +[no]search (Set whether to use searchlist)\n" 216 " +[no]short (Display nothing except short\n" 217 " form of answer)\n" 218 " +[no]showsearch (Search with intermediate results)\n" 219 " +[no]split=## (Split hex/base64 fields into chunks)\n" 220 " +[no]stats (Control display of statistics)\n" 221 " +subnet=addr (Set edns-client-subnet option)\n" 222 " +[no]tcp (TCP mode (+[no]vc))\n" 223 " +timeout=### (Set query timeout) [5]\n" 224 " +[no]trace (Trace delegation down from root [+dnssec])\n" 225 " +tries=### (Set number of UDP attempts) [3]\n" 226 " +[no]ttlid (Control display of ttls in records)\n" 227 " +[no]ttlunits (Display TTLs in human-readable units)\n" 228 " +[no]unknownformat (Print RDATA in RFC 3597 \"unknown\" format)\n" 229 " +[no]vc (TCP mode (+[no]tcp))\n" 230 " +[no]zflag (Set Z flag in query)\n" 231 " global d-opts and servers (before host name) affect all queries.\n" 232 " local d-opts and servers (after host name) affect only that lookup.\n" 233 " -h (print help and exit)\n" 234 " -v (print version and exit)\n", 235 stdout); 236 } 237 238 /*% 239 * Callback from dighost.c to print the received message. 240 */ 241 static void 242 received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { 243 isc_uint64_t diff; 244 time_t tnow; 245 struct tm tmnow; 246 #ifdef WIN32 247 wchar_t time_str[100]; 248 #else 249 char time_str[100]; 250 #endif 251 char fromtext[ISC_SOCKADDR_FORMATSIZE]; 252 253 isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 254 255 if (query->lookup->stats && !short_form) { 256 diff = isc_time_microdiff(&query->time_recv, &query->time_sent); 257 if (query->lookup->use_usec) 258 printf(";; Query time: %ld usec\n", (long) diff); 259 else 260 printf(";; Query time: %ld msec\n", (long) diff / 1000); 261 printf(";; SERVER: %s(%s)\n", fromtext, query->servname); 262 time(&tnow); 263 #if defined(ISC_PLATFORM_USETHREADS) && !defined(WIN32) 264 (void)localtime_r(&tnow, &tmnow); 265 #else 266 tmnow = *localtime(&tnow); 267 #endif 268 269 #ifdef WIN32 270 /* 271 * On Windows, time zone name ("%Z") may be a localized 272 * wide-character string, which strftime() handles incorrectly. 273 */ 274 if (wcsftime(time_str, sizeof(time_str)/sizeof(time_str[0]), 275 L"%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U) 276 printf(";; WHEN: %ls\n", time_str); 277 #else 278 if (strftime(time_str, sizeof(time_str), 279 "%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U) 280 printf(";; WHEN: %s\n", time_str); 281 #endif 282 if (query->lookup->doing_xfr) { 283 printf(";; XFR size: %u records (messages %u, " 284 "bytes %" ISC_PRINT_QUADFORMAT "u)\n", 285 query->rr_count, query->msg_count, 286 query->byte_count); 287 } else { 288 printf(";; MSG SIZE rcvd: %u\n", bytes); 289 } 290 if (tsigkey != NULL) { 291 if (!validated) 292 puts(";; WARNING -- Some TSIG could not " 293 "be validated"); 294 } 295 if ((tsigkey == NULL) && (keysecret[0] != 0)) { 296 puts(";; WARNING -- TSIG key was not used."); 297 } 298 puts(""); 299 } else if (query->lookup->identify && !short_form) { 300 diff = isc_time_microdiff(&query->time_recv, &query->time_sent); 301 if (query->lookup->use_usec) 302 printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes " 303 "from %s(%s) in %ld us\n\n", 304 query->lookup->doing_xfr 305 ? query->byte_count 306 : (isc_uint64_t)bytes, 307 fromtext, query->userarg, (long) diff); 308 else 309 printf(";; Received %" ISC_PRINT_QUADFORMAT "u bytes " 310 "from %s(%s) in %ld ms\n\n", 311 query->lookup->doing_xfr 312 ? query->byte_count 313 : (isc_uint64_t)bytes, 314 fromtext, query->userarg, (long) diff / 1000); 315 } 316 } 317 318 /* 319 * Callback from dighost.c to print that it is trying a server. 320 * Not used in dig. 321 * XXX print_trying 322 */ 323 static void 324 trying(char *frm, dig_lookup_t *lookup) { 325 UNUSED(frm); 326 UNUSED(lookup); 327 } 328 329 /*% 330 * Internal print routine used to print short form replies. 331 */ 332 static isc_result_t 333 say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { 334 isc_result_t result; 335 isc_uint64_t diff; 336 char store[sizeof(" in 18446744073709551616 us.")]; 337 unsigned int styleflags = 0; 338 339 if (query->lookup->trace || query->lookup->ns_search_only) { 340 result = dns_rdatatype_totext(rdata->type, buf); 341 if (result != ISC_R_SUCCESS) 342 return (result); 343 ADD_STRING(buf, " "); 344 } 345 346 /* Turn on rrcomments if explicitly enabled */ 347 if (query->lookup->rrcomments > 0) 348 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 349 if (query->lookup->nocrypto) 350 styleflags |= DNS_STYLEFLAG_NOCRYPTO; 351 if (query->lookup->print_unknown_format) 352 styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT; 353 result = dns_rdata_tofmttext(rdata, NULL, styleflags, 0, 354 splitwidth, " ", buf); 355 if (result == ISC_R_NOSPACE) 356 return (result); 357 check_result(result, "dns_rdata_totext"); 358 if (query->lookup->identify) { 359 360 diff = isc_time_microdiff(&query->time_recv, &query->time_sent); 361 ADD_STRING(buf, " from server "); 362 ADD_STRING(buf, query->servname); 363 if (query->lookup->use_usec) 364 snprintf(store, sizeof(store), " in %" ISC_PLATFORM_QUADFORMAT "u us.", diff); 365 else 366 snprintf(store, sizeof(store), " in %" ISC_PLATFORM_QUADFORMAT "u ms.", diff / 1000); 367 ADD_STRING(buf, store); 368 } 369 ADD_STRING(buf, "\n"); 370 return (ISC_R_SUCCESS); 371 } 372 373 /*% 374 * short_form message print handler. Calls above say_message() 375 */ 376 static isc_result_t 377 short_answer(dns_message_t *msg, dns_messagetextflag_t flags, 378 isc_buffer_t *buf, dig_query_t *query) 379 { 380 dns_name_t *name; 381 dns_rdataset_t *rdataset; 382 isc_result_t result, loopresult; 383 dns_name_t empty_name; 384 dns_rdata_t rdata = DNS_RDATA_INIT; 385 386 UNUSED(flags); 387 388 dns_name_init(&empty_name, NULL); 389 result = dns_message_firstname(msg, DNS_SECTION_ANSWER); 390 if (result == ISC_R_NOMORE) 391 return (ISC_R_SUCCESS); 392 else if (result != ISC_R_SUCCESS) 393 return (result); 394 395 for (;;) { 396 name = NULL; 397 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); 398 399 for (rdataset = ISC_LIST_HEAD(name->list); 400 rdataset != NULL; 401 rdataset = ISC_LIST_NEXT(rdataset, link)) { 402 loopresult = dns_rdataset_first(rdataset); 403 while (loopresult == ISC_R_SUCCESS) { 404 dns_rdataset_current(rdataset, &rdata); 405 result = say_message(&rdata, query, 406 buf); 407 if (result == ISC_R_NOSPACE) 408 return (result); 409 check_result(result, "say_message"); 410 loopresult = dns_rdataset_next(rdataset); 411 dns_rdata_reset(&rdata); 412 } 413 } 414 result = dns_message_nextname(msg, DNS_SECTION_ANSWER); 415 if (result == ISC_R_NOMORE) 416 break; 417 else if (result != ISC_R_SUCCESS) 418 return (result); 419 } 420 421 return (ISC_R_SUCCESS); 422 } 423 424 static isc_boolean_t 425 isdotlocal(dns_message_t *msg) { 426 isc_result_t result; 427 static unsigned char local_ndata[] = { "\005local\0" }; 428 static unsigned char local_offsets[] = { 0, 6 }; 429 static dns_name_t local = 430 DNS_NAME_INITABSOLUTE(local_ndata, local_offsets); 431 432 for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION); 433 result == ISC_R_SUCCESS; 434 result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) 435 { 436 dns_name_t *name = NULL; 437 dns_message_currentname(msg, DNS_SECTION_QUESTION, &name); 438 if (dns_name_issubdomain(name, &local)) 439 return (ISC_TRUE); 440 } 441 return (ISC_FALSE); 442 } 443 444 /* 445 * Callback from dighost.c to print the reply from a server 446 */ 447 static isc_result_t 448 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 449 isc_result_t result; 450 dns_messagetextflag_t flags; 451 isc_buffer_t *buf = NULL; 452 unsigned int len = OUTPUTBUF; 453 dns_master_style_t *style = NULL; 454 unsigned int styleflags = 0; 455 456 styleflags |= DNS_STYLEFLAG_REL_OWNER; 457 if (query->lookup->comments) 458 styleflags |= DNS_STYLEFLAG_COMMENT; 459 if (query->lookup->print_unknown_format) 460 styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT; 461 /* Turn on rrcomments if explicitly enabled */ 462 if (query->lookup->rrcomments > 0) 463 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 464 if (query->lookup->ttlunits) 465 styleflags |= DNS_STYLEFLAG_TTL_UNITS; 466 if (query->lookup->nottl) 467 styleflags |= DNS_STYLEFLAG_NO_TTL; 468 if (query->lookup->noclass) 469 styleflags |= DNS_STYLEFLAG_NO_CLASS; 470 if (query->lookup->nocrypto) 471 styleflags |= DNS_STYLEFLAG_NOCRYPTO; 472 if (query->lookup->multiline) { 473 styleflags |= DNS_STYLEFLAG_OMIT_OWNER; 474 styleflags |= DNS_STYLEFLAG_OMIT_CLASS; 475 styleflags |= DNS_STYLEFLAG_REL_DATA; 476 styleflags |= DNS_STYLEFLAG_OMIT_TTL; 477 styleflags |= DNS_STYLEFLAG_TTL; 478 styleflags |= DNS_STYLEFLAG_MULTILINE; 479 /* Turn on rrcomments unless explicitly disabled */ 480 if (query->lookup->rrcomments >= 0) 481 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 482 } 483 if (query->lookup->multiline || 484 (query->lookup->nottl && query->lookup->noclass)) 485 result = dns_master_stylecreate2(&style, styleflags, 486 24, 24, 24, 32, 80, 8, 487 splitwidth, mctx); 488 else if (query->lookup->nottl || query->lookup->noclass) 489 result = dns_master_stylecreate2(&style, styleflags, 490 24, 24, 32, 40, 80, 8, 491 splitwidth, mctx); 492 else 493 result = dns_master_stylecreate2(&style, styleflags, 494 24, 32, 40, 48, 80, 8, 495 splitwidth, mctx); 496 check_result(result, "dns_master_stylecreate"); 497 498 if (query->lookup->cmdline[0] != 0) { 499 if (!short_form) 500 fputs(query->lookup->cmdline, stdout); 501 query->lookup->cmdline[0]=0; 502 } 503 debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", 504 query->lookup->comments ? "comments" : "nocomments", 505 short_form ? "short_form" : "long_form"); 506 507 flags = 0; 508 if (!headers) { 509 flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; 510 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 511 } 512 if (query->lookup->onesoa && 513 query->lookup->rdtype == dns_rdatatype_axfr) 514 flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA : 515 DNS_MESSAGETEXTFLAG_OMITSOA; 516 if (!query->lookup->comments) 517 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 518 519 result = isc_buffer_allocate(mctx, &buf, len); 520 check_result(result, "isc_buffer_allocate"); 521 522 if (query->lookup->comments && !short_form) { 523 if (query->lookup->cmdline[0] != 0) 524 printf("; %s\n", query->lookup->cmdline); 525 if (msg == query->lookup->sendmsg) 526 printf(";; Sending:\n"); 527 else 528 printf(";; Got answer:\n"); 529 530 if (headers) { 531 if (isdotlocal(msg)) { 532 printf(";; WARNING: .local is reserved for " 533 "Multicast DNS\n;; You are currently " 534 "testing what happens when an mDNS " 535 "query is leaked to DNS\n"); 536 } 537 printf(";; ->>HEADER<<- opcode: %s, status: %s, " 538 "id: %u\n", 539 opcodetext[msg->opcode], 540 rcode_totext(msg->rcode), 541 msg->id); 542 printf(";; flags:"); 543 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 544 printf(" qr"); 545 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) 546 printf(" aa"); 547 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) 548 printf(" tc"); 549 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) 550 printf(" rd"); 551 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) 552 printf(" ra"); 553 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) 554 printf(" ad"); 555 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) 556 printf(" cd"); 557 if ((msg->flags & 0x0040U) != 0) 558 printf("; MBZ: 0x4"); 559 560 printf("; QUERY: %u, ANSWER: %u, " 561 "AUTHORITY: %u, ADDITIONAL: %u\n", 562 msg->counts[DNS_SECTION_QUESTION], 563 msg->counts[DNS_SECTION_ANSWER], 564 msg->counts[DNS_SECTION_AUTHORITY], 565 msg->counts[DNS_SECTION_ADDITIONAL]); 566 567 if (msg != query->lookup->sendmsg && 568 (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && 569 (msg->flags & DNS_MESSAGEFLAG_RA) == 0) 570 printf(";; WARNING: recursion requested " 571 "but not available\n"); 572 } 573 if (msg != query->lookup->sendmsg && 574 query->lookup->edns != -1 && msg->opt == NULL && 575 (msg->rcode == dns_rcode_formerr || 576 msg->rcode == dns_rcode_notimp)) 577 printf("\n;; WARNING: EDNS query returned status " 578 "%s - retry with '%s+noedns'\n", 579 rcode_totext(msg->rcode), 580 query->lookup->dnssec ? "+nodnssec ": ""); 581 if (msg != query->lookup->sendmsg && extrabytes != 0U) 582 printf(";; WARNING: Message has %u extra byte%s at " 583 "end\n", extrabytes, extrabytes != 0 ? "s" : ""); 584 } 585 586 repopulate_buffer: 587 588 if (query->lookup->comments && headers && !short_form) { 589 result = dns_message_pseudosectiontotext(msg, 590 DNS_PSEUDOSECTION_OPT, 591 style, flags, buf); 592 if (result == ISC_R_NOSPACE) { 593 buftoosmall: 594 len += OUTPUTBUF; 595 isc_buffer_free(&buf); 596 result = isc_buffer_allocate(mctx, &buf, len); 597 if (result == ISC_R_SUCCESS) 598 goto repopulate_buffer; 599 else 600 goto cleanup; 601 } 602 check_result(result, 603 "dns_message_pseudosectiontotext"); 604 } 605 606 if (query->lookup->section_question && headers) { 607 if (!short_form) { 608 result = dns_message_sectiontotext(msg, 609 DNS_SECTION_QUESTION, 610 style, flags, buf); 611 if (result == ISC_R_NOSPACE) 612 goto buftoosmall; 613 check_result(result, "dns_message_sectiontotext"); 614 } 615 } 616 if (query->lookup->section_answer) { 617 if (!short_form) { 618 result = dns_message_sectiontotext(msg, 619 DNS_SECTION_ANSWER, 620 style, flags, buf); 621 if (result == ISC_R_NOSPACE) 622 goto buftoosmall; 623 check_result(result, "dns_message_sectiontotext"); 624 } else { 625 result = short_answer(msg, flags, buf, query); 626 if (result == ISC_R_NOSPACE) 627 goto buftoosmall; 628 check_result(result, "short_answer"); 629 } 630 } 631 if (query->lookup->section_authority) { 632 if (!short_form) { 633 result = dns_message_sectiontotext(msg, 634 DNS_SECTION_AUTHORITY, 635 style, flags, buf); 636 if (result == ISC_R_NOSPACE) 637 goto buftoosmall; 638 check_result(result, "dns_message_sectiontotext"); 639 } 640 } 641 if (query->lookup->section_additional) { 642 if (!short_form) { 643 result = dns_message_sectiontotext(msg, 644 DNS_SECTION_ADDITIONAL, 645 style, flags, buf); 646 if (result == ISC_R_NOSPACE) 647 goto buftoosmall; 648 check_result(result, "dns_message_sectiontotext"); 649 /* 650 * Only print the signature on the first record. 651 */ 652 if (headers) { 653 result = dns_message_pseudosectiontotext( 654 msg, 655 DNS_PSEUDOSECTION_TSIG, 656 style, flags, buf); 657 if (result == ISC_R_NOSPACE) 658 goto buftoosmall; 659 check_result(result, 660 "dns_message_pseudosectiontotext"); 661 result = dns_message_pseudosectiontotext( 662 msg, 663 DNS_PSEUDOSECTION_SIG0, 664 style, flags, buf); 665 if (result == ISC_R_NOSPACE) 666 goto buftoosmall; 667 check_result(result, 668 "dns_message_pseudosectiontotext"); 669 } 670 } 671 } 672 673 if (headers && query->lookup->comments && !short_form) 674 printf("\n"); 675 676 printf("%.*s", (int)isc_buffer_usedlength(buf), 677 (char *)isc_buffer_base(buf)); 678 isc_buffer_free(&buf); 679 680 cleanup: 681 if (style != NULL) 682 dns_master_styledestroy(&style, mctx); 683 return (result); 684 } 685 686 /*% 687 * print the greeting message when the program first starts up. 688 */ 689 static void 690 printgreeting(int argc, char **argv, dig_lookup_t *lookup) { 691 int i; 692 static isc_boolean_t first = ISC_TRUE; 693 char append[MXNAME]; 694 695 if (printcmd) { 696 snprintf(lookup->cmdline, sizeof(lookup->cmdline), 697 "%s; <<>> DiG " VERSION " <<>>", 698 first?"\n":""); 699 i = 1; 700 while (i < argc) { 701 snprintf(append, sizeof(append), " %s", argv[i++]); 702 strlcat(lookup->cmdline, append, 703 sizeof(lookup->cmdline)); 704 } 705 strlcat(lookup->cmdline, "\n", sizeof(lookup->cmdline)); 706 if (first && addresscount != 0) { 707 snprintf(append, sizeof(append), 708 "; (%d server%s found)\n", 709 addresscount, 710 addresscount > 1 ? "s" : ""); 711 strlcat(lookup->cmdline, append, 712 sizeof(lookup->cmdline)); 713 } 714 if (first) { 715 snprintf(append, sizeof(append), 716 ";; global options:%s%s\n", 717 short_form ? " +short" : "", 718 printcmd ? " +cmd" : ""); 719 first = ISC_FALSE; 720 strlcat(lookup->cmdline, append, 721 sizeof(lookup->cmdline)); 722 } 723 } 724 } 725 726 /*% 727 * We're not using isc_commandline_parse() here since the command line 728 * syntax of dig is quite a bit different from that which can be described 729 * by that routine. 730 * XXX doc options 731 */ 732 733 static void 734 plus_option(const char *option, isc_boolean_t is_batchfile, 735 dig_lookup_t *lookup) 736 { 737 isc_result_t result; 738 char option_store[256]; 739 char *cmd, *value, *ptr, *code; 740 isc_uint32_t num; 741 isc_boolean_t state = ISC_TRUE; 742 size_t n; 743 744 strlcpy(option_store, option, sizeof(option_store)); 745 ptr = option_store; 746 cmd = next_token(&ptr, "="); 747 if (cmd == NULL) { 748 printf(";; Invalid option %s\n", option_store); 749 return; 750 } 751 value = ptr; 752 if (strncasecmp(cmd, "no", 2)==0) { 753 cmd += 2; 754 state = ISC_FALSE; 755 } 756 757 #define FULLCHECK(A) \ 758 do { \ 759 size_t _l = strlen(cmd); \ 760 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 761 goto invalid_option; \ 762 } while (0) 763 #define FULLCHECK2(A, B) \ 764 do { \ 765 size_t _l = strlen(cmd); \ 766 if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ 767 (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ 768 goto invalid_option; \ 769 } while (0) 770 771 switch (cmd[0]) { 772 case 'a': 773 switch (cmd[1]) { 774 case 'a': /* aaonly / aaflag */ 775 FULLCHECK2("aaonly", "aaflag"); 776 lookup->aaonly = state; 777 break; 778 case 'd': 779 switch (cmd[2]) { 780 case 'd': /* additional */ 781 FULLCHECK("additional"); 782 lookup->section_additional = state; 783 break; 784 case 'f': /* adflag */ 785 case '\0': /* +ad is a synonym for +adflag */ 786 FULLCHECK("adflag"); 787 lookup->adflag = state; 788 break; 789 default: 790 goto invalid_option; 791 } 792 break; 793 case 'l': /* all */ 794 FULLCHECK("all"); 795 lookup->section_question = state; 796 lookup->section_authority = state; 797 lookup->section_answer = state; 798 lookup->section_additional = state; 799 lookup->comments = state; 800 lookup->stats = state; 801 printcmd = state; 802 break; 803 case 'n': /* answer */ 804 FULLCHECK("answer"); 805 lookup->section_answer = state; 806 break; 807 case 'u': /* authority */ 808 FULLCHECK("authority"); 809 lookup->section_authority = state; 810 break; 811 default: 812 goto invalid_option; 813 } 814 break; 815 case 'b': 816 switch (cmd[1]) { 817 case 'a':/* badcookie */ 818 FULLCHECK("badcookie"); 819 lookup->badcookie = state; 820 break; 821 case 'e':/* besteffort */ 822 FULLCHECK("besteffort"); 823 lookup->besteffort = state; 824 break; 825 case 'u':/* bufsize */ 826 FULLCHECK("bufsize"); 827 if (value == NULL) 828 goto need_value; 829 if (!state) 830 goto invalid_option; 831 result = parse_uint(&num, value, COMMSIZE, 832 "buffer size"); 833 if (result != ISC_R_SUCCESS) { 834 warn("Couldn't parse buffer size"); 835 goto exit_or_usage; 836 } 837 lookup->udpsize = num; 838 break; 839 default: 840 goto invalid_option; 841 } 842 break; 843 case 'c': 844 switch (cmd[1]) { 845 case 'd':/* cdflag */ 846 switch (cmd[2]) { 847 case 'f': /* cdflag */ 848 case '\0': /* +cd is a synonym for +cdflag */ 849 FULLCHECK("cdflag"); 850 lookup->cdflag = state; 851 break; 852 default: 853 goto invalid_option; 854 } 855 break; 856 case 'l': /* class */ 857 /* keep +cl for backwards compatibility */ 858 FULLCHECK2("cl", "class"); 859 lookup->noclass = ISC_TF(!state); 860 break; 861 case 'm': /* cmd */ 862 FULLCHECK("cmd"); 863 printcmd = state; 864 break; 865 case 'o': /* comments */ 866 switch (cmd[2]) { 867 case 'm': 868 FULLCHECK("comments"); 869 lookup->comments = state; 870 if (lookup == default_lookup) 871 pluscomm = state; 872 break; 873 case 'o': /* cookie */ 874 FULLCHECK("cookie"); 875 if (state && lookup->edns == -1) 876 lookup->edns = 0; 877 lookup->sendcookie = state; 878 if (value != NULL) { 879 n = strlcpy(hexcookie, value, 880 sizeof(hexcookie)); 881 if (n >= sizeof(hexcookie)) { 882 warn("COOKIE data too large"); 883 goto exit_or_usage; 884 } 885 lookup->cookie = hexcookie; 886 } else 887 lookup->cookie = NULL; 888 break; 889 default: 890 goto invalid_option; 891 } 892 break; 893 case 'r': 894 FULLCHECK("crypto"); 895 lookup->nocrypto = ISC_TF(!state); 896 break; 897 default: 898 goto invalid_option; 899 } 900 break; 901 case 'd': 902 switch (cmd[1]) { 903 case 'e': /* defname */ 904 FULLCHECK("defname"); 905 if (!lookup->trace) { 906 usesearch = state; 907 } 908 break; 909 case 'n': /* dnssec */ 910 FULLCHECK("dnssec"); 911 dnssec: 912 if (state && lookup->edns == -1) 913 lookup->edns = 0; 914 lookup->dnssec = state; 915 break; 916 case 'o': /* domain ... but treat "do" as synonym for dnssec */ 917 if (cmd[2] == '\0') 918 goto dnssec; 919 FULLCHECK("domain"); 920 if (value == NULL) 921 goto need_value; 922 if (!state) 923 goto invalid_option; 924 strlcpy(domainopt, value, sizeof(domainopt)); 925 break; 926 case 's': /* dscp */ 927 FULLCHECK("dscp"); 928 if (!state) { 929 lookup->dscp = -1; 930 break; 931 } 932 if (value == NULL) 933 goto need_value; 934 result = parse_uint(&num, value, 0x3f, "DSCP"); 935 if (result != ISC_R_SUCCESS) { 936 warn("Couldn't parse DSCP value"); 937 goto exit_or_usage; 938 } 939 lookup->dscp = num; 940 break; 941 default: 942 goto invalid_option; 943 } 944 break; 945 case 'e': 946 switch (cmd[1]) { 947 case 'd': 948 switch(cmd[2]) { 949 case 'n': 950 switch (cmd[3]) { 951 case 's': 952 switch (cmd[4]) { 953 case 0: 954 FULLCHECK("edns"); 955 if (!state) { 956 lookup->edns = -1; 957 break; 958 } 959 if (value == NULL) { 960 lookup->edns = 0; 961 break; 962 } 963 result = parse_uint(&num, 964 value, 965 255, 966 "edns"); 967 if (result != ISC_R_SUCCESS) { 968 warn("Couldn't parse " 969 "edns"); 970 goto exit_or_usage; 971 } 972 lookup->edns = num; 973 break; 974 case 'f': 975 FULLCHECK("ednsflags"); 976 if (!state) { 977 lookup->ednsflags = 0; 978 break; 979 } 980 if (value == NULL) { 981 lookup->ednsflags = 0; 982 break; 983 } 984 result = parse_xint(&num, 985 value, 986 0xffff, 987 "ednsflags"); 988 if (result != ISC_R_SUCCESS) { 989 warn("Couldn't parse " 990 "ednsflags"); 991 goto exit_or_usage; 992 } 993 lookup->ednsflags = num; 994 break; 995 case 'n': 996 FULLCHECK("ednsnegotiation"); 997 lookup->ednsneg = state; 998 break; 999 case 'o': 1000 FULLCHECK("ednsopt"); 1001 if (!state) { 1002 lookup->ednsoptscnt = 0; 1003 break; 1004 } 1005 if (value == NULL) { 1006 warn("ednsopt no " 1007 "code point " 1008 "specified"); 1009 goto exit_or_usage; 1010 } 1011 code = next_token(&value, ":"); 1012 save_opt(lookup, code, value); 1013 break; 1014 default: 1015 goto invalid_option; 1016 } 1017 break; 1018 default: 1019 goto invalid_option; 1020 } 1021 break; 1022 default: 1023 goto invalid_option; 1024 } 1025 break; 1026 case 'x': 1027 FULLCHECK("expire"); 1028 lookup->expire = state; 1029 break; 1030 default: 1031 goto invalid_option; 1032 } 1033 break; 1034 case 'f': /* fail */ 1035 FULLCHECK("fail"); 1036 lookup->servfail_stops = state; 1037 break; 1038 case 'h': 1039 FULLCHECK("header-only"); 1040 lookup->header_only = state; 1041 break; 1042 case 'i': 1043 switch (cmd[1]) { 1044 case 'd': /* identify */ 1045 switch (cmd[2]) { 1046 case 'e': 1047 FULLCHECK("identify"); 1048 lookup->identify = state; 1049 break; 1050 case 'n': 1051 switch (cmd[3]) { 1052 case 'i': 1053 FULLCHECK("idnin"); 1054 #ifndef WITH_IDN_SUPPORT 1055 fprintf(stderr, ";; IDN input support" 1056 " not enabled\n"); 1057 #else 1058 lookup->idnin = state; 1059 #endif 1060 break; 1061 case 'o': 1062 FULLCHECK("idnout"); 1063 #ifndef WITH_IDN_OUT_SUPPORT 1064 fprintf(stderr, ";; IDN output support" 1065 " not enabled\n"); 1066 #else 1067 lookup->idnout = state; 1068 #endif 1069 break; 1070 default: 1071 goto invalid_option; 1072 } 1073 break; 1074 default: 1075 goto invalid_option; 1076 } 1077 break; 1078 case 'g': /* ignore */ 1079 default: /* 1080 * Inherits default for compatibility (+[no]i*). 1081 */ 1082 FULLCHECK("ignore"); 1083 lookup->ignore = state; 1084 } 1085 break; 1086 case 'k': 1087 switch (cmd[1]) { 1088 case 'e': 1089 switch (cmd[2]) { 1090 case 'e': 1091 switch (cmd[3]) { 1092 case 'p': 1093 switch (cmd[4]) { 1094 case 'a': 1095 FULLCHECK("keepalive"); 1096 lookup->tcp_keepalive = state; 1097 break; 1098 case 'o': 1099 FULLCHECK("keepopen"); 1100 keep_open = state; 1101 break; 1102 default: 1103 goto invalid_option; 1104 } 1105 break; 1106 default: 1107 goto invalid_option; 1108 } 1109 break; 1110 default: 1111 goto invalid_option; 1112 } 1113 break; 1114 default: 1115 goto invalid_option; 1116 } 1117 break; 1118 case 'm': /* multiline */ 1119 switch (cmd[1]) { 1120 case 'a': 1121 FULLCHECK("mapped"); 1122 lookup->mapped = state; 1123 break; 1124 case 'u': 1125 FULLCHECK("multiline"); 1126 lookup->multiline = state; 1127 break; 1128 default: 1129 goto invalid_option; 1130 } 1131 break; 1132 case 'n': 1133 switch (cmd[1]) { 1134 case 'd': /* ndots */ 1135 FULLCHECK("ndots"); 1136 if (value == NULL) 1137 goto need_value; 1138 if (!state) 1139 goto invalid_option; 1140 result = parse_uint(&num, value, MAXNDOTS, "ndots"); 1141 if (result != ISC_R_SUCCESS) { 1142 warn("Couldn't parse ndots"); 1143 goto exit_or_usage; 1144 } 1145 ndots = num; 1146 break; 1147 case 's': 1148 switch (cmd[2]) { 1149 case 'i': /* nsid */ 1150 FULLCHECK("nsid"); 1151 if (state && lookup->edns == -1) 1152 lookup->edns = 0; 1153 lookup->nsid = state; 1154 break; 1155 case 's': /* nssearch */ 1156 FULLCHECK("nssearch"); 1157 lookup->ns_search_only = state; 1158 if (state) { 1159 lookup->trace_root = ISC_TRUE; 1160 lookup->recurse = ISC_TRUE; 1161 lookup->identify = ISC_TRUE; 1162 lookup->stats = ISC_FALSE; 1163 lookup->comments = ISC_FALSE; 1164 lookup->section_additional = ISC_FALSE; 1165 lookup->section_authority = ISC_FALSE; 1166 lookup->section_question = ISC_FALSE; 1167 lookup->rdtype = dns_rdatatype_ns; 1168 lookup->rdtypeset = ISC_TRUE; 1169 short_form = ISC_TRUE; 1170 lookup->rrcomments = 0; 1171 } 1172 break; 1173 default: 1174 goto invalid_option; 1175 } 1176 break; 1177 default: 1178 goto invalid_option; 1179 } 1180 break; 1181 case 'o': 1182 switch (cmd[1]) { 1183 case 'n': 1184 FULLCHECK("onesoa"); 1185 lookup->onesoa = state; 1186 break; 1187 case 'p': 1188 FULLCHECK("opcode"); 1189 if (!state) { 1190 lookup->opcode = 0; /* default - query */ 1191 break; 1192 } 1193 if (value == NULL) 1194 goto need_value; 1195 for (num = 0; 1196 num < sizeof(opcodetext)/sizeof(opcodetext[0]); 1197 num++) { 1198 if (strcasecmp(opcodetext[num], value) == 0) 1199 break; 1200 } 1201 if (num < 16) { 1202 lookup->opcode = (dns_opcode_t)num; 1203 break; 1204 } 1205 result = parse_uint(&num, value, 15, "opcode"); 1206 if (result != ISC_R_SUCCESS) { 1207 warn("Couldn't parse opcode"); 1208 goto exit_or_usage; 1209 } 1210 lookup->opcode = (dns_opcode_t)num; 1211 break; 1212 default: 1213 goto invalid_option; 1214 } 1215 break; 1216 case 'p': 1217 FULLCHECK("padding"); 1218 if (state && lookup->edns == -1) 1219 lookup->edns = 0; 1220 if (value == NULL) 1221 goto need_value; 1222 result = parse_uint(&num, value, 512, "padding"); 1223 if (result != ISC_R_SUCCESS) { 1224 warn("Couldn't parse padding"); 1225 goto exit_or_usage; 1226 } 1227 lookup->padding = (isc_uint16_t)num; 1228 break; 1229 case 'q': 1230 switch (cmd[1]) { 1231 case 'r': /* qr */ 1232 FULLCHECK("qr"); 1233 lookup->qr = state; 1234 break; 1235 case 'u': /* question */ 1236 FULLCHECK("question"); 1237 lookup->section_question = state; 1238 if (lookup == default_lookup) 1239 plusquest = state; 1240 break; 1241 default: 1242 goto invalid_option; 1243 } 1244 break; 1245 case 'r': 1246 switch (cmd[1]) { 1247 case 'd': /* rdflag */ 1248 FULLCHECK("rdflag"); 1249 lookup->recurse = state; 1250 break; 1251 case 'e': 1252 switch (cmd[2]) { 1253 case 'c': /* recurse */ 1254 FULLCHECK("recurse"); 1255 lookup->recurse = state; 1256 break; 1257 case 't': /* retry / retries */ 1258 FULLCHECK2("retry", "retries"); 1259 if (value == NULL) 1260 goto need_value; 1261 if (!state) 1262 goto invalid_option; 1263 result = parse_uint(&lookup->retries, value, 1264 MAXTRIES - 1, "retries"); 1265 if (result != ISC_R_SUCCESS) { 1266 warn("Couldn't parse retries"); 1267 goto exit_or_usage; 1268 } 1269 lookup->retries++; 1270 break; 1271 default: 1272 goto invalid_option; 1273 } 1274 break; 1275 case 'r': /* rrcomments */ 1276 FULLCHECK("rrcomments"); 1277 lookup->rrcomments = state ? 1 : -1; 1278 break; 1279 default: 1280 goto invalid_option; 1281 } 1282 break; 1283 case 's': 1284 switch (cmd[1]) { 1285 case 'e': /* search */ 1286 FULLCHECK("search"); 1287 if (!lookup->trace) { 1288 usesearch = state; 1289 } 1290 break; 1291 case 'h': 1292 if (cmd[2] != 'o') 1293 goto invalid_option; 1294 switch (cmd[3]) { 1295 case 'r': /* short */ 1296 FULLCHECK("short"); 1297 short_form = state; 1298 if (state) { 1299 printcmd = ISC_FALSE; 1300 lookup->section_additional = ISC_FALSE; 1301 lookup->section_answer = ISC_TRUE; 1302 lookup->section_authority = ISC_FALSE; 1303 lookup->section_question = ISC_FALSE; 1304 lookup->comments = ISC_FALSE; 1305 lookup->stats = ISC_FALSE; 1306 lookup->rrcomments = -1; 1307 } 1308 break; 1309 case 'w': /* showsearch */ 1310 FULLCHECK("showsearch"); 1311 if (!lookup->trace) { 1312 showsearch = state; 1313 usesearch = state; 1314 } 1315 break; 1316 default: 1317 goto invalid_option; 1318 } 1319 break; 1320 case 'i': /* sigchase */ 1321 FULLCHECK("sigchase"); 1322 fprintf(stderr, ";; +sigchase option is deprecated"); 1323 break; 1324 case 'p': /* split */ 1325 FULLCHECK("split"); 1326 if (value != NULL && !state) 1327 goto invalid_option; 1328 if (!state) { 1329 splitwidth = 0; 1330 break; 1331 } else if (value == NULL) 1332 break; 1333 1334 result = parse_uint(&splitwidth, value, 1335 1023, "split"); 1336 if ((splitwidth % 4) != 0U) { 1337 splitwidth = ((splitwidth + 3) / 4) * 4; 1338 fprintf(stderr, ";; Warning, split must be " 1339 "a multiple of 4; adjusting " 1340 "to %u\n", splitwidth); 1341 } 1342 /* 1343 * There is an adjustment done in the 1344 * totext_<rrtype>() functions which causes 1345 * splitwidth to shrink. This is okay when we're 1346 * using the default width but incorrect in this 1347 * case, so we correct for it 1348 */ 1349 if (splitwidth) 1350 splitwidth += 3; 1351 if (result != ISC_R_SUCCESS) { 1352 warn("Couldn't parse split"); 1353 goto exit_or_usage; 1354 } 1355 break; 1356 case 't': /* stats */ 1357 FULLCHECK("stats"); 1358 lookup->stats = state; 1359 break; 1360 case 'u': /* subnet */ 1361 FULLCHECK("subnet"); 1362 if (state && value == NULL) 1363 goto need_value; 1364 if (!state) { 1365 if (lookup->ecs_addr != NULL) { 1366 isc_mem_free(mctx, lookup->ecs_addr); 1367 lookup->ecs_addr = NULL; 1368 } 1369 break; 1370 } 1371 if (lookup->edns == -1) 1372 lookup->edns = 0; 1373 if (lookup->ecs_addr != NULL) { 1374 isc_mem_free(mctx, lookup->ecs_addr); 1375 lookup->ecs_addr = NULL; 1376 } 1377 result = parse_netprefix(&lookup->ecs_addr, value); 1378 if (result != ISC_R_SUCCESS) { 1379 warn("Couldn't parse client"); 1380 goto exit_or_usage; 1381 } 1382 break; 1383 default: 1384 goto invalid_option; 1385 } 1386 break; 1387 case 't': 1388 switch (cmd[1]) { 1389 case 'c': /* tcp */ 1390 FULLCHECK("tcp"); 1391 if (!is_batchfile) { 1392 lookup->tcp_mode = state; 1393 lookup->tcp_mode_set = ISC_TRUE; 1394 } 1395 break; 1396 case 'i': /* timeout */ 1397 FULLCHECK("timeout"); 1398 if (value == NULL) 1399 goto need_value; 1400 if (!state) 1401 goto invalid_option; 1402 result = parse_uint(&timeout, value, MAXTIMEOUT, 1403 "timeout"); 1404 if (result != ISC_R_SUCCESS) { 1405 warn("Couldn't parse timeout"); 1406 goto exit_or_usage; 1407 } 1408 if (timeout == 0) 1409 timeout = 1; 1410 break; 1411 case 'o': 1412 FULLCHECK("topdown"); 1413 fprintf(stderr, ";; +topdown option is deprecated"); 1414 break; 1415 case 'r': 1416 switch (cmd[2]) { 1417 case 'a': /* trace */ 1418 FULLCHECK("trace"); 1419 lookup->trace = state; 1420 lookup->trace_root = state; 1421 if (state) { 1422 lookup->recurse = ISC_FALSE; 1423 lookup->identify = ISC_TRUE; 1424 lookup->comments = ISC_FALSE; 1425 lookup->rrcomments = 0; 1426 lookup->stats = ISC_FALSE; 1427 lookup->section_additional = ISC_FALSE; 1428 lookup->section_authority = ISC_TRUE; 1429 lookup->section_question = ISC_FALSE; 1430 lookup->dnssec = ISC_TRUE; 1431 lookup->sendcookie = ISC_TRUE; 1432 usesearch = ISC_FALSE; 1433 } 1434 break; 1435 case 'i': /* tries */ 1436 FULLCHECK("tries"); 1437 if (value == NULL) 1438 goto need_value; 1439 if (!state) 1440 goto invalid_option; 1441 result = parse_uint(&lookup->retries, value, 1442 MAXTRIES, "tries"); 1443 if (result != ISC_R_SUCCESS) { 1444 warn("Couldn't parse tries"); 1445 goto exit_or_usage; 1446 } 1447 if (lookup->retries == 0) 1448 lookup->retries = 1; 1449 break; 1450 case 'u': /* trusted-key */ 1451 FULLCHECK("trusted-key"); 1452 fprintf(stderr, ";; +trusted-key option is " 1453 "deprecated"); 1454 break; 1455 default: 1456 goto invalid_option; 1457 } 1458 break; 1459 case 't': 1460 switch (cmd[2]) { 1461 case 'l': 1462 switch (cmd[3]) { 1463 case 0: 1464 case 'i': /* ttlid */ 1465 FULLCHECK2("ttl", "ttlid"); 1466 lookup->nottl = ISC_TF(!state); 1467 break; 1468 case 'u': /* ttlunits */ 1469 FULLCHECK("ttlunits"); 1470 lookup->nottl = ISC_FALSE; 1471 lookup->ttlunits = ISC_TF(state); 1472 break; 1473 default: 1474 goto invalid_option; 1475 } 1476 break; 1477 default: 1478 goto invalid_option; 1479 } 1480 break; 1481 default: 1482 goto invalid_option; 1483 } 1484 break; 1485 case 'u': 1486 FULLCHECK("unknownformat"); 1487 lookup->print_unknown_format = state; 1488 break; 1489 case 'v': 1490 FULLCHECK("vc"); 1491 if (!is_batchfile) { 1492 lookup->tcp_mode = state; 1493 lookup->tcp_mode_set = ISC_TRUE; 1494 } 1495 break; 1496 case 'z': /* zflag */ 1497 FULLCHECK("zflag"); 1498 lookup->zflag = state; 1499 break; 1500 default: 1501 invalid_option: 1502 need_value: 1503 #if TARGET_OS_IPHONE 1504 exit_or_usage: 1505 #endif 1506 fprintf(stderr, "Invalid option: +%s\n", 1507 option); 1508 usage(); 1509 } 1510 return; 1511 1512 #if ! TARGET_OS_IPHONE 1513 exit_or_usage: 1514 digexit(); 1515 #endif 1516 } 1517 1518 /*% 1519 * #ISC_TRUE returned if value was used 1520 */ 1521 static const char *single_dash_opts = "46dhimnuv"; 1522 static const char *dash_opts = "46bcdfhikmnptvyx"; 1523 static isc_boolean_t 1524 dash_option(char *option, char *next, dig_lookup_t **lookup, 1525 isc_boolean_t *open_type_class, isc_boolean_t *need_clone, 1526 isc_boolean_t config_only, int argc, char **argv, 1527 isc_boolean_t *firstarg) 1528 { 1529 char opt, *value, *ptr, *ptr2, *ptr3; 1530 isc_result_t result; 1531 isc_boolean_t value_from_next; 1532 isc_textregion_t tr; 1533 dns_rdatatype_t rdtype; 1534 dns_rdataclass_t rdclass; 1535 char textname[MXNAME]; 1536 struct in_addr in4; 1537 struct in6_addr in6; 1538 in_port_t srcport; 1539 char *hash, *cmd; 1540 isc_uint32_t num; 1541 1542 while (strpbrk(option, single_dash_opts) == &option[0]) { 1543 /* 1544 * Since the -[46dhimnuv] options do not take an argument, 1545 * account for them (in any number and/or combination) 1546 * if they appear as the first character(s) of a q-opt. 1547 */ 1548 opt = option[0]; 1549 switch (opt) { 1550 case '4': 1551 if (have_ipv4) { 1552 isc_net_disableipv6(); 1553 have_ipv6 = ISC_FALSE; 1554 } else { 1555 fatal("can't find IPv4 networking"); 1556 /* NOTREACHED */ 1557 return (ISC_FALSE); 1558 } 1559 break; 1560 case '6': 1561 if (have_ipv6) { 1562 isc_net_disableipv4(); 1563 have_ipv4 = ISC_FALSE; 1564 } else { 1565 fatal("can't find IPv6 networking"); 1566 /* NOTREACHED */ 1567 return (ISC_FALSE); 1568 } 1569 break; 1570 case 'd': 1571 ptr = strpbrk(&option[1], dash_opts); 1572 if (ptr != &option[1]) { 1573 cmd = option; 1574 FULLCHECK("debug"); 1575 debugging = ISC_TRUE; 1576 return (ISC_FALSE); 1577 } else 1578 debugging = ISC_TRUE; 1579 break; 1580 case 'h': 1581 help(); 1582 exit(0); 1583 break; 1584 case 'i': 1585 ip6_int = ISC_TRUE; 1586 break; 1587 case 'm': /* memdebug */ 1588 /* memdebug is handled in preparse_args() */ 1589 break; 1590 case 'n': 1591 /* deprecated */ 1592 break; 1593 case 'u': 1594 (*lookup)->use_usec = ISC_TRUE; 1595 break; 1596 case 'v': 1597 version(); 1598 exit(0); 1599 break; 1600 } 1601 if (strlen(option) > 1U) 1602 option = &option[1]; 1603 else 1604 return (ISC_FALSE); 1605 } 1606 opt = option[0]; 1607 if (strlen(option) > 1U) { 1608 value_from_next = ISC_FALSE; 1609 value = &option[1]; 1610 } else { 1611 value_from_next = ISC_TRUE; 1612 value = next; 1613 } 1614 if (value == NULL) 1615 goto invalid_option; 1616 switch (opt) { 1617 case 'b': 1618 hash = strchr(value, '#'); 1619 if (hash != NULL) { 1620 result = parse_uint(&num, hash + 1, MAXPORT, 1621 "port number"); 1622 if (result != ISC_R_SUCCESS) 1623 fatal("Couldn't parse port number"); 1624 srcport = num; 1625 *hash = '\0'; 1626 } else 1627 srcport = 0; 1628 if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { 1629 isc_sockaddr_fromin6(&bind_address, &in6, srcport); 1630 isc_net_disableipv4(); 1631 } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { 1632 isc_sockaddr_fromin(&bind_address, &in4, srcport); 1633 isc_net_disableipv6(); 1634 } else { 1635 if (hash != NULL) 1636 *hash = '#'; 1637 fatal("invalid address %s", value); 1638 } 1639 if (hash != NULL) 1640 *hash = '#'; 1641 specified_source = ISC_TRUE; 1642 return (value_from_next); 1643 case 'c': 1644 if ((*lookup)->rdclassset) { 1645 fprintf(stderr, ";; Warning, extra class option\n"); 1646 } 1647 *open_type_class = ISC_FALSE; 1648 tr.base = value; 1649 tr.length = (unsigned int) strlen(value); 1650 result = dns_rdataclass_fromtext(&rdclass, 1651 (isc_textregion_t *)&tr); 1652 if (result == ISC_R_SUCCESS) { 1653 (*lookup)->rdclass = rdclass; 1654 (*lookup)->rdclassset = ISC_TRUE; 1655 } else 1656 fprintf(stderr, ";; Warning, ignoring " 1657 "invalid class %s\n", 1658 value); 1659 return (value_from_next); 1660 case 'f': 1661 batchname = value; 1662 return (value_from_next); 1663 case 'k': 1664 strlcpy(keyfile, value, sizeof(keyfile)); 1665 return (value_from_next); 1666 case 'p': 1667 result = parse_uint(&num, value, MAXPORT, "port number"); 1668 if (result != ISC_R_SUCCESS) 1669 fatal("Couldn't parse port number"); 1670 port = num; 1671 return (value_from_next); 1672 case 'q': 1673 if (!config_only) { 1674 if (*need_clone) 1675 (*lookup) = clone_lookup(default_lookup, 1676 ISC_TRUE); 1677 *need_clone = ISC_TRUE; 1678 strlcpy((*lookup)->textname, value, 1679 sizeof((*lookup)->textname)); 1680 (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1681 (*lookup)->ns_search_only); 1682 (*lookup)->new_search = ISC_TRUE; 1683 if (*firstarg) { 1684 printgreeting(argc, argv, *lookup); 1685 *firstarg = ISC_FALSE; 1686 } 1687 ISC_LIST_APPEND(lookup_list, (*lookup), link); 1688 debug("looking up %s", (*lookup)->textname); 1689 } 1690 return (value_from_next); 1691 case 't': 1692 *open_type_class = ISC_FALSE; 1693 if (strncasecmp(value, "ixfr=", 5) == 0) { 1694 rdtype = dns_rdatatype_ixfr; 1695 result = ISC_R_SUCCESS; 1696 } else { 1697 tr.base = value; 1698 tr.length = (unsigned int) strlen(value); 1699 result = dns_rdatatype_fromtext(&rdtype, 1700 (isc_textregion_t *)&tr); 1701 if (result == ISC_R_SUCCESS && 1702 rdtype == dns_rdatatype_ixfr) { 1703 result = DNS_R_UNKNOWN; 1704 } 1705 } 1706 if (result == ISC_R_SUCCESS) { 1707 if ((*lookup)->rdtypeset) { 1708 fprintf(stderr, ";; Warning, " 1709 "extra type option\n"); 1710 } 1711 if (rdtype == dns_rdatatype_ixfr) { 1712 isc_uint32_t serial; 1713 (*lookup)->rdtype = dns_rdatatype_ixfr; 1714 (*lookup)->rdtypeset = ISC_TRUE; 1715 result = parse_uint(&serial, &value[5], 1716 MAXSERIAL, "serial number"); 1717 if (result != ISC_R_SUCCESS) 1718 fatal("Couldn't parse serial number"); 1719 (*lookup)->ixfr_serial = serial; 1720 (*lookup)->section_question = plusquest; 1721 (*lookup)->comments = pluscomm; 1722 if (!(*lookup)->tcp_mode_set) 1723 (*lookup)->tcp_mode = ISC_TRUE; 1724 } else { 1725 (*lookup)->rdtype = rdtype; 1726 if (!config_only) 1727 (*lookup)->rdtypeset = ISC_TRUE; 1728 if (rdtype == dns_rdatatype_axfr) { 1729 (*lookup)->section_question = plusquest; 1730 (*lookup)->comments = pluscomm; 1731 } else if (rdtype == dns_rdatatype_any) { 1732 if (!(*lookup)->tcp_mode_set) 1733 (*lookup)->tcp_mode = ISC_TRUE; 1734 } 1735 (*lookup)->ixfr_serial = ISC_FALSE; 1736 } 1737 } else 1738 fprintf(stderr, ";; Warning, ignoring " 1739 "invalid type %s\n", 1740 value); 1741 return (value_from_next); 1742 case 'y': 1743 ptr = next_token(&value, ":"); /* hmac type or name */ 1744 if (ptr == NULL) { 1745 usage(); 1746 } 1747 ptr2 = next_token(&value, ":"); /* name or secret */ 1748 if (ptr2 == NULL) 1749 usage(); 1750 ptr3 = next_token(&value, ":"); /* secret or NULL */ 1751 if (ptr3 != NULL) { 1752 parse_hmac(ptr); 1753 ptr = ptr2; 1754 ptr2 = ptr3; 1755 } else { 1756 #ifndef PK11_MD5_DISABLE 1757 hmacname = DNS_TSIG_HMACMD5_NAME; 1758 #else 1759 hmacname = DNS_TSIG_HMACSHA256_NAME; 1760 #endif 1761 digestbits = 0; 1762 } 1763 strlcpy(keynametext, ptr, sizeof(keynametext)); 1764 strlcpy(keysecret, ptr2, sizeof(keysecret)); 1765 return (value_from_next); 1766 case 'x': 1767 if (*need_clone) 1768 *lookup = clone_lookup(default_lookup, ISC_TRUE); 1769 *need_clone = ISC_TRUE; 1770 if (get_reverse(textname, sizeof(textname), value, 1771 ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { 1772 strlcpy((*lookup)->textname, textname, 1773 sizeof((*lookup)->textname)); 1774 debug("looking up %s", (*lookup)->textname); 1775 (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1776 (*lookup)->ns_search_only); 1777 (*lookup)->ip6_int = ip6_int; 1778 if (!(*lookup)->rdtypeset) 1779 (*lookup)->rdtype = dns_rdatatype_ptr; 1780 if (!(*lookup)->rdclassset) 1781 (*lookup)->rdclass = dns_rdataclass_in; 1782 (*lookup)->new_search = ISC_TRUE; 1783 if (*firstarg) { 1784 printgreeting(argc, argv, *lookup); 1785 *firstarg = ISC_FALSE; 1786 } 1787 ISC_LIST_APPEND(lookup_list, *lookup, link); 1788 } else { 1789 fprintf(stderr, "Invalid IP address %s\n", value); 1790 exit(1); 1791 } 1792 return (value_from_next); 1793 invalid_option: 1794 default: 1795 fprintf(stderr, "Invalid option: -%s\n", option); 1796 usage(); 1797 } 1798 /* NOTREACHED */ 1799 return (ISC_FALSE); 1800 } 1801 1802 /*% 1803 * Because we may be trying to do memory allocation recording, we're going 1804 * to need to parse the arguments for the -m *before* we start the main 1805 * argument parsing routine. 1806 * 1807 * I'd prefer not to have to do this, but I am not quite sure how else to 1808 * fix the problem. Argument parsing in dig involves memory allocation 1809 * by its nature, so it can't be done in the main argument parser. 1810 */ 1811 static void 1812 preparse_args(int argc, char **argv) { 1813 int rc; 1814 char **rv; 1815 char *option; 1816 1817 rc = argc; 1818 rv = argv; 1819 for (rc--, rv++; rc > 0; rc--, rv++) { 1820 if (rv[0][0] != '-') 1821 continue; 1822 option = &rv[0][1]; 1823 while (strpbrk(option, single_dash_opts) == &option[0]) { 1824 switch (option[0]) { 1825 case 'm': 1826 memdebugging = ISC_TRUE; 1827 isc_mem_debugging = ISC_MEM_DEBUGTRACE | 1828 ISC_MEM_DEBUGRECORD; 1829 break; 1830 case '4': 1831 if (ipv6only) 1832 fatal("only one of -4 and -6 allowed"); 1833 ipv4only = ISC_TRUE; 1834 break; 1835 case '6': 1836 if (ipv4only) 1837 fatal("only one of -4 and -6 allowed"); 1838 ipv6only = ISC_TRUE; 1839 break; 1840 } 1841 option = &option[1]; 1842 } 1843 } 1844 } 1845 1846 static void 1847 parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, 1848 int argc, char **argv) 1849 { 1850 isc_result_t result; 1851 isc_textregion_t tr; 1852 isc_boolean_t firstarg = ISC_TRUE; 1853 dig_lookup_t *lookup = NULL; 1854 dns_rdatatype_t rdtype; 1855 dns_rdataclass_t rdclass; 1856 isc_boolean_t open_type_class = ISC_TRUE; 1857 char batchline[MXNAME]; 1858 int bargc; 1859 char *bargv[64]; 1860 int rc; 1861 char **rv; 1862 #ifndef NOPOSIX 1863 char *homedir; 1864 char rcfile[256]; 1865 #endif 1866 char *input; 1867 int i; 1868 isc_boolean_t need_clone = ISC_TRUE; 1869 1870 /* 1871 * The semantics for parsing the args is a bit complex; if 1872 * we don't have a host yet, make the arg apply globally, 1873 * otherwise make it apply to the latest host. This is 1874 * a bit different than the previous versions, but should 1875 * form a consistent user interface. 1876 * 1877 * First, create a "default lookup" which won't actually be used 1878 * anywhere, except for cloning into new lookups 1879 */ 1880 1881 debug("parse_args()"); 1882 if (!is_batchfile) { 1883 debug("making new lookup"); 1884 default_lookup = make_empty_lookup(); 1885 default_lookup->adflag = ISC_TRUE; 1886 default_lookup->edns = 0; 1887 default_lookup->sendcookie = ISC_TRUE; 1888 1889 #ifndef NOPOSIX 1890 /* 1891 * Treat ${HOME}/.digrc as a special batchfile 1892 */ 1893 INSIST(batchfp == NULL); 1894 homedir = getenv("HOME"); 1895 if (homedir != NULL) { 1896 unsigned int n; 1897 n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc", 1898 homedir); 1899 if (n < sizeof(rcfile)) 1900 batchfp = fopen(rcfile, "r"); 1901 } 1902 if (batchfp != NULL) { 1903 while (fgets(batchline, sizeof(batchline), 1904 batchfp) != 0) { 1905 debug("config line %s", batchline); 1906 bargc = 1; 1907 input = batchline; 1908 bargv[bargc] = next_token(&input, " \t\r\n"); 1909 while ((bargc < 62) && (bargv[bargc] != NULL)) { 1910 bargc++; 1911 bargv[bargc] = 1912 next_token(&input, " \t\r\n"); 1913 } 1914 1915 bargv[0] = argv[0]; 1916 argv0 = argv[0]; 1917 1918 for(i = 0; i < bargc; i++) 1919 debug(".digrc argv %d: %s", 1920 i, bargv[i]); 1921 parse_args(ISC_TRUE, ISC_TRUE, bargc, 1922 (char **)bargv); 1923 } 1924 fclose(batchfp); 1925 } 1926 #endif 1927 } 1928 1929 if (is_batchfile && !config_only) { 1930 /* Processing '-f batchfile'. */ 1931 lookup = clone_lookup(default_lookup, ISC_TRUE); 1932 need_clone = ISC_FALSE; 1933 } else 1934 lookup = default_lookup; 1935 1936 rc = argc; 1937 rv = argv; 1938 for (rc--, rv++; rc > 0; rc--, rv++) { 1939 debug("main parsing %s", rv[0]); 1940 if (strncmp(rv[0], "%", 1) == 0) 1941 break; 1942 if (rv[0][0] == '@') { 1943 1944 if (is_batchfile && !config_only) { 1945 addresscount = getaddresses(lookup, &rv[0][1], 1946 &result); 1947 if (addresscount == 0) { 1948 fprintf(stderr, "couldn't get address " 1949 "for '%s': %s: skipping " 1950 "lookup\n", &rv[0][1], 1951 isc_result_totext(result)); 1952 if (ISC_LINK_LINKED(lookup, link)) 1953 ISC_LIST_DEQUEUE(lookup_list, 1954 lookup, link); 1955 destroy_lookup(lookup); 1956 return; 1957 } 1958 } else { 1959 addresscount = getaddresses(lookup, &rv[0][1], 1960 NULL); 1961 if (addresscount == 0) 1962 fatal("no valid addresses for '%s'\n", 1963 &rv[0][1]); 1964 } 1965 } else if (rv[0][0] == '+') { 1966 plus_option(&rv[0][1], is_batchfile, 1967 lookup); 1968 } else if (rv[0][0] == '-') { 1969 if (rc <= 1) { 1970 if (dash_option(&rv[0][1], NULL, 1971 &lookup, &open_type_class, 1972 &need_clone, config_only, 1973 argc, argv, &firstarg)) { 1974 rc--; 1975 rv++; 1976 } 1977 } else { 1978 if (dash_option(&rv[0][1], rv[1], 1979 &lookup, &open_type_class, 1980 &need_clone, config_only, 1981 argc, argv, &firstarg)) { 1982 rc--; 1983 rv++; 1984 } 1985 } 1986 } else { 1987 /* 1988 * Anything which isn't an option 1989 */ 1990 if (open_type_class) { 1991 if (strncasecmp(rv[0], "ixfr=", 5) == 0) { 1992 rdtype = dns_rdatatype_ixfr; 1993 result = ISC_R_SUCCESS; 1994 } else { 1995 tr.base = rv[0]; 1996 tr.length = 1997 (unsigned int) strlen(rv[0]); 1998 result = dns_rdatatype_fromtext(&rdtype, 1999 (isc_textregion_t *)&tr); 2000 if (result == ISC_R_SUCCESS && 2001 rdtype == dns_rdatatype_ixfr) { 2002 fprintf(stderr, ";; Warning, " 2003 "ixfr requires a " 2004 "serial number\n"); 2005 continue; 2006 } 2007 } 2008 if (result == ISC_R_SUCCESS) { 2009 if (lookup->rdtypeset) { 2010 fprintf(stderr, ";; Warning, " 2011 "extra type option\n"); 2012 } 2013 if (rdtype == dns_rdatatype_ixfr) { 2014 isc_uint32_t serial; 2015 lookup->rdtype = 2016 dns_rdatatype_ixfr; 2017 lookup->rdtypeset = ISC_TRUE; 2018 result = parse_uint(&serial, 2019 &rv[0][5], 2020 MAXSERIAL, 2021 "serial number"); 2022 if (result != ISC_R_SUCCESS) 2023 fatal("Couldn't parse " 2024 "serial number"); 2025 lookup->ixfr_serial = serial; 2026 lookup->section_question = 2027 plusquest; 2028 lookup->comments = pluscomm; 2029 if (!lookup->tcp_mode_set) 2030 lookup->tcp_mode = ISC_TRUE; 2031 } else { 2032 lookup->rdtype = rdtype; 2033 lookup->rdtypeset = ISC_TRUE; 2034 if (rdtype == 2035 dns_rdatatype_axfr) { 2036 lookup->section_question = 2037 plusquest; 2038 lookup->comments = pluscomm; 2039 } 2040 if (rdtype == 2041 dns_rdatatype_any && 2042 !lookup->tcp_mode_set) 2043 lookup->tcp_mode = ISC_TRUE; 2044 lookup->ixfr_serial = ISC_FALSE; 2045 } 2046 continue; 2047 } 2048 result = dns_rdataclass_fromtext(&rdclass, 2049 (isc_textregion_t *)&tr); 2050 if (result == ISC_R_SUCCESS) { 2051 if (lookup->rdclassset) { 2052 fprintf(stderr, ";; Warning, " 2053 "extra class option\n"); 2054 } 2055 lookup->rdclass = rdclass; 2056 lookup->rdclassset = ISC_TRUE; 2057 continue; 2058 } 2059 } 2060 2061 if (!config_only) { 2062 if (need_clone) 2063 lookup = clone_lookup(default_lookup, 2064 ISC_TRUE); 2065 need_clone = ISC_TRUE; 2066 strlcpy(lookup->textname, rv[0], 2067 sizeof(lookup->textname)); 2068 lookup->trace_root = ISC_TF(lookup->trace || 2069 lookup->ns_search_only); 2070 lookup->new_search = ISC_TRUE; 2071 if (firstarg) { 2072 printgreeting(argc, argv, lookup); 2073 firstarg = ISC_FALSE; 2074 } 2075 ISC_LIST_APPEND(lookup_list, lookup, link); 2076 debug("looking up %s", lookup->textname); 2077 } 2078 /* XXX Error message */ 2079 } 2080 } 2081 2082 /* 2083 * If we have a batchfile, seed the lookup list with the 2084 * first entry, then trust the callback in dighost_shutdown 2085 * to get the rest 2086 */ 2087 if ((batchname != NULL) && !(is_batchfile)) { 2088 if (strcmp(batchname, "-") == 0) 2089 batchfp = stdin; 2090 else 2091 batchfp = fopen(batchname, "r"); 2092 if (batchfp == NULL) { 2093 perror(batchname); 2094 if (exitcode < 8) 2095 exitcode = 8; 2096 fatal("couldn't open specified batch file"); 2097 } 2098 /* XXX Remove code dup from shutdown code */ 2099 next_line: 2100 if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 2101 bargc = 1; 2102 debug("batch line %s", batchline); 2103 if (batchline[0] == '\r' || batchline[0] == '\n' 2104 || batchline[0] == '#' || batchline[0] == ';') 2105 goto next_line; 2106 input = batchline; 2107 bargv[bargc] = next_token(&input, " \t\r\n"); 2108 while ((bargc < 14) && (bargv[bargc] != NULL)) { 2109 bargc++; 2110 bargv[bargc] = next_token(&input, " \t\r\n"); 2111 } 2112 2113 bargv[0] = argv[0]; 2114 argv0 = argv[0]; 2115 2116 for(i = 0; i < bargc; i++) 2117 debug("batch argv %d: %s", i, bargv[i]); 2118 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 2119 return; 2120 } 2121 return; 2122 } 2123 /* 2124 * If no lookup specified, search for root 2125 */ 2126 if ((lookup_list.head == NULL) && !config_only) { 2127 if (need_clone) 2128 lookup = clone_lookup(default_lookup, ISC_TRUE); 2129 need_clone = ISC_TRUE; 2130 lookup->trace_root = ISC_TF(lookup->trace || 2131 lookup->ns_search_only); 2132 lookup->new_search = ISC_TRUE; 2133 strlcpy(lookup->textname, ".", sizeof(lookup->textname)); 2134 lookup->rdtype = dns_rdatatype_ns; 2135 lookup->rdtypeset = ISC_TRUE; 2136 if (firstarg) { 2137 printgreeting(argc, argv, lookup); 2138 firstarg = ISC_FALSE; 2139 } 2140 ISC_LIST_APPEND(lookup_list, lookup, link); 2141 } 2142 if (!need_clone) 2143 destroy_lookup(lookup); 2144 } 2145 2146 /* 2147 * Callback from dighost.c to allow program-specific shutdown code. 2148 * Here, we're possibly reading from a batch file, then shutting down 2149 * for real if there's nothing in the batch file to read. 2150 */ 2151 static void 2152 query_finished(void) { 2153 char batchline[MXNAME]; 2154 int bargc; 2155 char *bargv[16]; 2156 char *input; 2157 int i; 2158 2159 if (batchname == NULL) { 2160 isc_app_shutdown(); 2161 return; 2162 } 2163 2164 fflush(stdout); 2165 if (feof(batchfp)) { 2166 batchname = NULL; 2167 isc_app_shutdown(); 2168 if (batchfp != stdin) 2169 fclose(batchfp); 2170 return; 2171 } 2172 2173 if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 2174 debug("batch line %s", batchline); 2175 bargc = 1; 2176 input = batchline; 2177 bargv[bargc] = next_token(&input, " \t\r\n"); 2178 while ((bargc < 14) && (bargv[bargc] != NULL)) { 2179 bargc++; 2180 bargv[bargc] = next_token(&input, " \t\r\n"); 2181 } 2182 2183 bargv[0] = argv0; 2184 2185 for(i = 0; i < bargc; i++) 2186 debug("batch argv %d: %s", i, bargv[i]); 2187 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 2188 start_lookup(); 2189 } else { 2190 batchname = NULL; 2191 if (batchfp != stdin) 2192 fclose(batchfp); 2193 isc_app_shutdown(); 2194 return; 2195 } 2196 } 2197 2198 void dig_setup(int argc, char **argv) 2199 { 2200 isc_result_t result; 2201 2202 ISC_LIST_INIT(lookup_list); 2203 ISC_LIST_INIT(server_list); 2204 ISC_LIST_INIT(search_list); 2205 2206 debug("dig_setup()"); 2207 2208 /* setup dighost callbacks */ 2209 dighost_printmessage = printmessage; 2210 dighost_received = received; 2211 dighost_trying = trying; 2212 dighost_shutdown = query_finished; 2213 2214 progname = argv[0]; 2215 preparse_args(argc, argv); 2216 2217 result = isc_app_start(); 2218 check_result(result, "isc_app_start"); 2219 2220 setup_libs(); 2221 setup_system(ipv4only, ipv6only); 2222 } 2223 2224 void dig_query_setup(isc_boolean_t is_batchfile, isc_boolean_t config_only, 2225 int argc, char **argv) 2226 { 2227 debug("dig_query_setup"); 2228 2229 parse_args(is_batchfile, config_only, argc, argv); 2230 if (keyfile[0] != 0) 2231 setup_file_key(); 2232 else if (keysecret[0] != 0) 2233 setup_text_key(); 2234 if (domainopt[0] != '\0') { 2235 set_search_domain(domainopt); 2236 usesearch = ISC_TRUE; 2237 } 2238 } 2239 2240 void dig_startup() { 2241 isc_result_t result; 2242 2243 debug("dig_startup()"); 2244 2245 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); 2246 check_result(result, "isc_app_onrun"); 2247 isc_app_run(); 2248 } 2249 2250 void dig_query_start() 2251 { 2252 start_lookup(); 2253 } 2254 2255 void 2256 dig_shutdown() { 2257 destroy_lookup(default_lookup); 2258 if (batchname != NULL) { 2259 if (batchfp != stdin) 2260 fclose(batchfp); 2261 batchname = NULL; 2262 } 2263 cancel_all(); 2264 destroy_libs(); 2265 isc_app_finish(); 2266 } 2267 2268 /*% Main processing routine for dig */ 2269 int 2270 main(int argc, char **argv) { 2271 2272 dig_setup(argc, argv); 2273 dig_query_setup(ISC_FALSE, ISC_FALSE, argc, argv); 2274 dig_startup(); 2275 dig_shutdown(); 2276 2277 return (exitcode); 2278 } 2279