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