1 /* $NetBSD: dig.c,v 1.5 2020/05/24 19:46:11 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 <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 isc_time_formatISO8601ms(&query->time_sent, tbuf, 672 sizeof(tbuf)); 673 printf(" query_time: !!timestamp %s\n", tbuf); 674 } 675 676 if (!isquery && !isc_time_isepoch(&query->time_recv)) { 677 char tbuf[100]; 678 isc_time_formatISO8601ms(&query->time_recv, tbuf, 679 sizeof(tbuf)); 680 printf(" response_time: !!timestamp %s\n", tbuf); 681 } 682 683 printf(" message_size: %ub\n", 684 isc_buffer_usedlength(msgbuf)); 685 686 pf = isc_sockaddr_pf(&query->sockaddr); 687 if (pf == PF_INET || pf == PF_INET6) { 688 printf(" socket_family: %s\n", 689 pf == PF_INET ? "INET" : "INET6"); 690 691 printf(" socket_protocol: %s\n", 692 query->lookup->tcp_mode ? "TCP" : "UDP"); 693 694 sport = isc_sockaddr_getport(&query->sockaddr); 695 isc_sockaddr_format(&query->sockaddr, sockstr, 696 sizeof(sockstr)); 697 hash = strchr(sockstr, '#'); 698 if (hash != NULL) { 699 *hash = '\0'; 700 } 701 if (strcmp(sockstr, "::") == 0) { 702 strlcat(sockstr, "0", sizeof(sockstr)); 703 } 704 705 printf(" response_address: %s\n", sockstr); 706 printf(" response_port: %u\n", sport); 707 } 708 709 if (query->sock != NULL && 710 isc_socket_getsockname(query->sock, &saddr) == 711 ISC_R_SUCCESS) 712 { 713 sport = isc_sockaddr_getport(&saddr); 714 isc_sockaddr_format(&saddr, sockstr, sizeof(sockstr)); 715 hash = strchr(sockstr, '#'); 716 if (hash != NULL) { 717 *hash = '\0'; 718 } 719 if (strcmp(sockstr, "::") == 0) { 720 strlcat(sockstr, "0", sizeof(sockstr)); 721 } 722 723 printf(" query_address: %s\n", sockstr); 724 printf(" query_port: %u\n", sport); 725 } 726 727 printf(" %s:\n", isquery ? "query_message_data" 728 : "response_message_data"); 729 result = dns_message_headertotext(msg, style, flags, buf); 730 } else if (query->lookup->comments && !short_form) { 731 if (query->lookup->cmdline[0] != '\0' && printcmd) { 732 printf("; %s\n", query->lookup->cmdline); 733 } 734 if (msg == query->lookup->sendmsg) { 735 printf(";; Sending:\n"); 736 } else { 737 printf(";; Got answer:\n"); 738 } 739 740 if (headers) { 741 if (isdotlocal(msg)) { 742 printf(";; WARNING: .local is reserved for " 743 "Multicast DNS\n;; You are currently " 744 "testing what happens when an mDNS " 745 "query is leaked to DNS\n"); 746 } 747 printf(";; ->>HEADER<<- opcode: %s, status: %s, " 748 "id: %u\n", 749 opcodetext[msg->opcode], 750 rcode_totext(msg->rcode), msg->id); 751 printf(";; flags:"); 752 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) { 753 printf(" qr"); 754 } 755 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) { 756 printf(" aa"); 757 } 758 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) { 759 printf(" tc"); 760 } 761 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) { 762 printf(" rd"); 763 } 764 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) { 765 printf(" ra"); 766 } 767 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) { 768 printf(" ad"); 769 } 770 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) { 771 printf(" cd"); 772 } 773 if ((msg->flags & 0x0040U) != 0) { 774 printf("; MBZ: 0x4"); 775 } 776 777 printf("; QUERY: %u, ANSWER: %u, " 778 "AUTHORITY: %u, ADDITIONAL: %u\n", 779 msg->counts[DNS_SECTION_QUESTION], 780 msg->counts[DNS_SECTION_ANSWER], 781 msg->counts[DNS_SECTION_AUTHORITY], 782 msg->counts[DNS_SECTION_ADDITIONAL]); 783 784 if (msg != query->lookup->sendmsg && 785 (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && 786 (msg->flags & DNS_MESSAGEFLAG_RA) == 0) 787 { 788 printf(";; WARNING: recursion requested " 789 "but not available\n"); 790 } 791 } 792 if (msg != query->lookup->sendmsg && 793 query->lookup->edns != -1 && msg->opt == NULL && 794 (msg->rcode == dns_rcode_formerr || 795 msg->rcode == dns_rcode_notimp)) 796 { 797 printf("\n;; WARNING: EDNS query returned status " 798 "%s - retry with '%s+noedns'\n", 799 rcode_totext(msg->rcode), 800 query->lookup->dnssec ? "+nodnssec " : ""); 801 } 802 if (msg != query->lookup->sendmsg && extrabytes != 0U) { 803 printf(";; WARNING: Message has %u extra byte%s at " 804 "end\n", 805 extrabytes, extrabytes != 0 ? "s" : ""); 806 } 807 } 808 809 repopulate_buffer: 810 811 if (query->lookup->comments && headers && !short_form) { 812 result = dns_message_pseudosectiontotext( 813 msg, DNS_PSEUDOSECTION_OPT, style, flags, buf); 814 if (result == ISC_R_NOSPACE) { 815 buftoosmall: 816 len += OUTPUTBUF; 817 isc_buffer_free(&buf); 818 isc_buffer_allocate(mctx, &buf, len); 819 goto repopulate_buffer; 820 } 821 check_result(result, "dns_message_pseudosectiontotext"); 822 } 823 824 if (query->lookup->section_question && headers) { 825 if (!short_form) { 826 result = dns_message_sectiontotext( 827 msg, DNS_SECTION_QUESTION, style, flags, buf); 828 if (result == ISC_R_NOSPACE) { 829 goto buftoosmall; 830 } 831 check_result(result, "dns_message_sectiontotext"); 832 } 833 } 834 if (query->lookup->section_answer) { 835 if (!short_form) { 836 result = dns_message_sectiontotext( 837 msg, DNS_SECTION_ANSWER, style, flags, buf); 838 if (result == ISC_R_NOSPACE) { 839 goto buftoosmall; 840 } 841 check_result(result, "dns_message_sectiontotext"); 842 } else { 843 result = short_answer(msg, flags, buf, query); 844 if (result == ISC_R_NOSPACE) { 845 goto buftoosmall; 846 } 847 check_result(result, "short_answer"); 848 } 849 } 850 if (query->lookup->section_authority) { 851 if (!short_form) { 852 result = dns_message_sectiontotext( 853 msg, DNS_SECTION_AUTHORITY, style, flags, buf); 854 if (result == ISC_R_NOSPACE) { 855 goto buftoosmall; 856 } 857 check_result(result, "dns_message_sectiontotext"); 858 } 859 } 860 if (query->lookup->section_additional) { 861 if (!short_form) { 862 result = dns_message_sectiontotext( 863 msg, DNS_SECTION_ADDITIONAL, style, flags, buf); 864 if (result == ISC_R_NOSPACE) { 865 goto buftoosmall; 866 } 867 check_result(result, "dns_message_sectiontotext"); 868 /* 869 * Only print the signature on the first record. 870 */ 871 if (headers) { 872 result = dns_message_pseudosectiontotext( 873 msg, DNS_PSEUDOSECTION_TSIG, style, 874 flags, buf); 875 if (result == ISC_R_NOSPACE) { 876 goto buftoosmall; 877 } 878 check_result(result, "dns_message_" 879 "pseudosectiontotext"); 880 result = dns_message_pseudosectiontotext( 881 msg, DNS_PSEUDOSECTION_SIG0, style, 882 flags, buf); 883 if (result == ISC_R_NOSPACE) { 884 goto buftoosmall; 885 } 886 check_result(result, "dns_message_" 887 "pseudosectiontotext"); 888 } 889 } 890 } 891 892 if (headers && query->lookup->comments && !short_form && !yaml) { 893 printf("\n"); 894 } 895 896 printf("%.*s", (int)isc_buffer_usedlength(buf), 897 (char *)isc_buffer_base(buf)); 898 isc_buffer_free(&buf); 899 900 if (style != NULL) { 901 dns_master_styledestroy(&style, mctx); 902 } 903 return (result); 904 } 905 906 /*% 907 * print the greeting message when the program first starts up. 908 */ 909 static void 910 printgreeting(int argc, char **argv, dig_lookup_t *lookup) { 911 int i; 912 static bool first = true; 913 char append[MXNAME]; 914 915 if (printcmd) { 916 snprintf(lookup->cmdline, sizeof(lookup->cmdline), 917 "%s; <<>> DiG " VERSION " <<>>", first ? "\n" : ""); 918 i = 1; 919 while (i < argc) { 920 snprintf(append, sizeof(append), " %s", argv[i++]); 921 strlcat(lookup->cmdline, append, 922 sizeof(lookup->cmdline)); 923 } 924 strlcat(lookup->cmdline, "\n", sizeof(lookup->cmdline)); 925 if (first && addresscount != 0) { 926 snprintf(append, sizeof(append), 927 "; (%d server%s found)\n", addresscount, 928 addresscount > 1 ? "s" : ""); 929 strlcat(lookup->cmdline, append, 930 sizeof(lookup->cmdline)); 931 } 932 if (first) { 933 snprintf(append, sizeof(append), 934 ";; global options:%s%s\n", 935 short_form ? " +short" : "", 936 printcmd ? " +cmd" : ""); 937 first = false; 938 strlcat(lookup->cmdline, append, 939 sizeof(lookup->cmdline)); 940 } 941 } 942 } 943 944 /*% 945 * We're not using isc_commandline_parse() here since the command line 946 * syntax of dig is quite a bit different from that which can be described 947 * by that routine. 948 * XXX doc options 949 */ 950 951 static void 952 plus_option(char *option, bool is_batchfile, dig_lookup_t *lookup) { 953 isc_result_t result; 954 char *cmd, *value, *last = NULL, *code, *extra; 955 uint32_t num; 956 bool state = true; 957 size_t n; 958 959 INSIST(option != NULL); 960 961 if ((cmd = strtok_r(option, "=", &last)) == NULL) { 962 printf(";; Invalid option %s\n", option); 963 return; 964 } 965 if (strncasecmp(cmd, "no", 2) == 0) { 966 cmd += 2; 967 state = false; 968 } 969 /* parse the rest of the string */ 970 value = strtok_r(NULL, "", &last); 971 972 #define FULLCHECK(A) \ 973 do { \ 974 size_t _l = strlen(cmd); \ 975 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 976 goto invalid_option; \ 977 } while (/*CONSTCOND*/0) 978 #define FULLCHECK2(A, B) \ 979 do { \ 980 size_t _l = strlen(cmd); \ 981 if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ 982 (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ 983 goto invalid_option; \ 984 } while (/*CONSTCOND*/0) 985 986 switch (cmd[0]) { 987 case 'a': 988 switch (cmd[1]) { 989 case 'a': /* aaonly / aaflag */ 990 FULLCHECK2("aaonly", "aaflag"); 991 lookup->aaonly = state; 992 break; 993 case 'd': 994 switch (cmd[2]) { 995 case 'd': /* additional */ 996 FULLCHECK("additional"); 997 lookup->section_additional = state; 998 break; 999 case 'f': /* adflag */ 1000 case '\0': /* +ad is a synonym for +adflag */ 1001 FULLCHECK("adflag"); 1002 lookup->adflag = state; 1003 break; 1004 default: 1005 goto invalid_option; 1006 } 1007 break; 1008 case 'l': /* all */ 1009 FULLCHECK("all"); 1010 lookup->section_question = state; 1011 lookup->section_authority = state; 1012 lookup->section_answer = state; 1013 lookup->section_additional = state; 1014 lookup->comments = state; 1015 lookup->stats = state; 1016 printcmd = state; 1017 break; 1018 case 'n': /* answer */ 1019 FULLCHECK("answer"); 1020 lookup->section_answer = state; 1021 break; 1022 case 'u': /* authority */ 1023 FULLCHECK("authority"); 1024 lookup->section_authority = state; 1025 break; 1026 default: 1027 goto invalid_option; 1028 } 1029 break; 1030 case 'b': 1031 switch (cmd[1]) { 1032 case 'a': /* badcookie */ 1033 FULLCHECK("badcookie"); 1034 lookup->badcookie = state; 1035 break; 1036 case 'e': /* besteffort */ 1037 FULLCHECK("besteffort"); 1038 lookup->besteffort = state; 1039 break; 1040 case 'u': /* bufsize */ 1041 FULLCHECK("bufsize"); 1042 if (value == NULL) { 1043 goto need_value; 1044 } 1045 if (!state) { 1046 goto invalid_option; 1047 } 1048 result = parse_uint(&num, value, COMMSIZE, 1049 "buffer size"); 1050 if (result != ISC_R_SUCCESS) { 1051 warn("Couldn't parse buffer size"); 1052 goto exit_or_usage; 1053 } 1054 lookup->udpsize = num; 1055 break; 1056 default: 1057 goto invalid_option; 1058 } 1059 break; 1060 case 'c': 1061 switch (cmd[1]) { 1062 case 'd': /* cdflag */ 1063 switch (cmd[2]) { 1064 case 'f': /* cdflag */ 1065 case '\0': /* +cd is a synonym for +cdflag */ 1066 FULLCHECK("cdflag"); 1067 lookup->cdflag = state; 1068 break; 1069 default: 1070 goto invalid_option; 1071 } 1072 break; 1073 case 'l': /* class */ 1074 /* keep +cl for backwards compatibility */ 1075 FULLCHECK2("cl", "class"); 1076 lookup->noclass = !state; 1077 break; 1078 case 'm': /* cmd */ 1079 FULLCHECK("cmd"); 1080 printcmd = state; 1081 break; 1082 case 'o': /* comments */ 1083 switch (cmd[2]) { 1084 case 'm': 1085 FULLCHECK("comments"); 1086 lookup->comments = state; 1087 if (lookup == default_lookup) { 1088 pluscomm = state; 1089 } 1090 break; 1091 case 'o': /* cookie */ 1092 FULLCHECK("cookie"); 1093 if (state && lookup->edns == -1) { 1094 lookup->edns = 0; 1095 } 1096 lookup->sendcookie = state; 1097 if (value != NULL) { 1098 n = strlcpy(hexcookie, value, 1099 sizeof(hexcookie)); 1100 if (n >= sizeof(hexcookie)) { 1101 warn("COOKIE data too large"); 1102 goto exit_or_usage; 1103 } 1104 lookup->cookie = hexcookie; 1105 } else { 1106 lookup->cookie = NULL; 1107 } 1108 break; 1109 default: 1110 goto invalid_option; 1111 } 1112 break; 1113 case 'r': 1114 FULLCHECK("crypto"); 1115 lookup->nocrypto = !state; 1116 break; 1117 default: 1118 goto invalid_option; 1119 } 1120 break; 1121 case 'd': 1122 switch (cmd[1]) { 1123 case 'e': /* defname */ 1124 FULLCHECK("defname"); 1125 if (!lookup->trace) { 1126 usesearch = state; 1127 } 1128 break; 1129 case 'n': /* dnssec */ 1130 FULLCHECK("dnssec"); 1131 dnssec: 1132 if (state && lookup->edns == -1) { 1133 lookup->edns = 0; 1134 } 1135 lookup->dnssec = state; 1136 break; 1137 case 'o': /* domain ... but treat "do" as synonym for dnssec */ 1138 if (cmd[2] == '\0') { 1139 goto dnssec; 1140 } 1141 FULLCHECK("domain"); 1142 if (value == NULL) { 1143 goto need_value; 1144 } 1145 if (!state) { 1146 goto invalid_option; 1147 } 1148 strlcpy(domainopt, value, sizeof(domainopt)); 1149 break; 1150 case 's': /* dscp */ 1151 FULLCHECK("dscp"); 1152 if (!state) { 1153 lookup->dscp = -1; 1154 break; 1155 } 1156 if (value == NULL) { 1157 goto need_value; 1158 } 1159 result = parse_uint(&num, value, 0x3f, "DSCP"); 1160 if (result != ISC_R_SUCCESS) { 1161 warn("Couldn't parse DSCP value"); 1162 goto exit_or_usage; 1163 } 1164 lookup->dscp = num; 1165 break; 1166 default: 1167 goto invalid_option; 1168 } 1169 break; 1170 case 'e': 1171 switch (cmd[1]) { 1172 case 'd': 1173 switch (cmd[2]) { 1174 case 'n': 1175 switch (cmd[3]) { 1176 case 's': 1177 switch (cmd[4]) { 1178 case 0: 1179 FULLCHECK("edns"); 1180 if (!state) { 1181 lookup->edns = -1; 1182 break; 1183 } 1184 if (value == NULL) { 1185 lookup->edns = 0; 1186 break; 1187 } 1188 result = parse_uint(&num, value, 1189 255, 1190 "edns"); 1191 if (result != ISC_R_SUCCESS) { 1192 warn("Couldn't parse " 1193 "edns"); 1194 goto exit_or_usage; 1195 } 1196 lookup->edns = num; 1197 break; 1198 case 'f': 1199 FULLCHECK("ednsflags"); 1200 if (!state) { 1201 lookup->ednsflags = 0; 1202 break; 1203 } 1204 if (value == NULL) { 1205 lookup->ednsflags = 0; 1206 break; 1207 } 1208 result = parse_xint( 1209 &num, value, 0xffff, 1210 "ednsflags"); 1211 if (result != ISC_R_SUCCESS) { 1212 warn("Couldn't parse " 1213 "ednsflags"); 1214 goto exit_or_usage; 1215 } 1216 lookup->ednsflags = num; 1217 break; 1218 case 'n': 1219 FULLCHECK("ednsnegotiation"); 1220 lookup->ednsneg = state; 1221 break; 1222 case 'o': 1223 FULLCHECK("ednsopt"); 1224 if (!state) { 1225 lookup->ednsoptscnt = 0; 1226 break; 1227 } 1228 code = NULL; 1229 if (value != NULL) { 1230 code = strtok_r(value, 1231 ":", 1232 &last); 1233 } 1234 if (code == NULL) { 1235 warn("ednsopt no " 1236 "code point " 1237 "specified"); 1238 goto exit_or_usage; 1239 } 1240 extra = strtok_r(NULL, "\0", 1241 &last); 1242 save_opt(lookup, code, extra); 1243 break; 1244 default: 1245 goto invalid_option; 1246 } 1247 break; 1248 default: 1249 goto invalid_option; 1250 } 1251 break; 1252 default: 1253 goto invalid_option; 1254 } 1255 break; 1256 case 'x': 1257 switch (cmd[2]) { 1258 case 'p': 1259 switch (cmd[3]) { 1260 case 'a': 1261 FULLCHECK("expandaaaa"); 1262 lookup->expandaaaa = state; 1263 break; 1264 case 'i': 1265 FULLCHECK("expire"); 1266 lookup->expire = state; 1267 break; 1268 default: 1269 goto invalid_option; 1270 } 1271 break; 1272 default: 1273 goto invalid_option; 1274 } 1275 break; 1276 default: 1277 goto invalid_option; 1278 } 1279 break; 1280 case 'f': /* fail */ 1281 FULLCHECK("fail"); 1282 lookup->servfail_stops = state; 1283 break; 1284 case 'h': 1285 FULLCHECK("header-only"); 1286 lookup->header_only = state; 1287 break; 1288 case 'i': 1289 switch (cmd[1]) { 1290 case 'd': /* identify */ 1291 switch (cmd[2]) { 1292 case 'e': 1293 FULLCHECK("identify"); 1294 lookup->identify = state; 1295 break; 1296 case 'n': 1297 switch (cmd[3]) { 1298 case 'i': 1299 FULLCHECK("idnin"); 1300 #ifndef HAVE_LIBIDN2 1301 fprintf(stderr, ";; IDN input support" 1302 " not enabled\n"); 1303 #else /* ifndef HAVE_LIBIDN2 */ 1304 lookup->idnin = state; 1305 #endif /* ifndef HAVE_LIBIDN2 */ 1306 break; 1307 case 'o': 1308 FULLCHECK("idnout"); 1309 #ifndef HAVE_LIBIDN2 1310 fprintf(stderr, ";; IDN output support" 1311 " not enabled\n"); 1312 #else /* ifndef HAVE_LIBIDN2 */ 1313 lookup->idnout = state; 1314 #endif /* ifndef HAVE_LIBIDN2 */ 1315 break; 1316 default: 1317 goto invalid_option; 1318 } 1319 break; 1320 default: 1321 goto invalid_option; 1322 } 1323 break; 1324 case 'g': /* ignore */ 1325 default: /* 1326 * Inherits default for compatibility (+[no]i*). 1327 */ 1328 FULLCHECK("ignore"); 1329 lookup->ignore = state; 1330 } 1331 break; 1332 case 'k': 1333 switch (cmd[1]) { 1334 case 'e': 1335 switch (cmd[2]) { 1336 case 'e': 1337 switch (cmd[3]) { 1338 case 'p': 1339 switch (cmd[4]) { 1340 case 'a': 1341 FULLCHECK("keepalive"); 1342 lookup->tcp_keepalive = state; 1343 break; 1344 case 'o': 1345 FULLCHECK("keepopen"); 1346 keep_open = state; 1347 break; 1348 default: 1349 goto invalid_option; 1350 } 1351 break; 1352 default: 1353 goto invalid_option; 1354 } 1355 break; 1356 default: 1357 goto invalid_option; 1358 } 1359 break; 1360 default: 1361 goto invalid_option; 1362 } 1363 break; 1364 case 'm': /* multiline */ 1365 switch (cmd[1]) { 1366 case 'a': 1367 FULLCHECK("mapped"); 1368 lookup->mapped = state; 1369 break; 1370 case 'u': 1371 FULLCHECK("multiline"); 1372 lookup->multiline = state; 1373 break; 1374 default: 1375 goto invalid_option; 1376 } 1377 break; 1378 case 'n': 1379 switch (cmd[1]) { 1380 case 'd': /* ndots */ 1381 FULLCHECK("ndots"); 1382 if (value == NULL) { 1383 goto need_value; 1384 } 1385 if (!state) { 1386 goto invalid_option; 1387 } 1388 result = parse_uint(&num, value, MAXNDOTS, "ndots"); 1389 if (result != ISC_R_SUCCESS) { 1390 warn("Couldn't parse ndots"); 1391 goto exit_or_usage; 1392 } 1393 ndots = num; 1394 break; 1395 case 's': 1396 switch (cmd[2]) { 1397 case 'i': /* nsid */ 1398 FULLCHECK("nsid"); 1399 if (state && lookup->edns == -1) { 1400 lookup->edns = 0; 1401 } 1402 lookup->nsid = state; 1403 break; 1404 case 's': /* nssearch */ 1405 FULLCHECK("nssearch"); 1406 lookup->ns_search_only = state; 1407 if (state) { 1408 lookup->trace_root = true; 1409 lookup->recurse = true; 1410 lookup->identify = true; 1411 lookup->stats = false; 1412 lookup->comments = false; 1413 lookup->section_additional = false; 1414 lookup->section_authority = false; 1415 lookup->section_question = false; 1416 lookup->rdtype = dns_rdatatype_ns; 1417 lookup->rdtypeset = true; 1418 short_form = true; 1419 lookup->rrcomments = 0; 1420 } 1421 break; 1422 default: 1423 goto invalid_option; 1424 } 1425 break; 1426 default: 1427 goto invalid_option; 1428 } 1429 break; 1430 case 'o': 1431 switch (cmd[1]) { 1432 case 'n': 1433 FULLCHECK("onesoa"); 1434 lookup->onesoa = state; 1435 break; 1436 case 'p': 1437 FULLCHECK("opcode"); 1438 if (!state) { 1439 lookup->opcode = 0; /* default - query */ 1440 break; 1441 } 1442 if (value == NULL) { 1443 goto need_value; 1444 } 1445 for (num = 0; 1446 num < sizeof(opcodetext) / sizeof(opcodetext[0]); 1447 num++) { 1448 if (strcasecmp(opcodetext[num], value) == 0) { 1449 break; 1450 } 1451 } 1452 if (num < 16) { 1453 lookup->opcode = (dns_opcode_t)num; 1454 break; 1455 } 1456 result = parse_uint(&num, value, 15, "opcode"); 1457 if (result != ISC_R_SUCCESS) { 1458 warn("Couldn't parse opcode"); 1459 goto exit_or_usage; 1460 } 1461 lookup->opcode = (dns_opcode_t)num; 1462 break; 1463 default: 1464 goto invalid_option; 1465 } 1466 break; 1467 case 'p': 1468 FULLCHECK("padding"); 1469 if (state && lookup->edns == -1) { 1470 lookup->edns = 0; 1471 } 1472 if (value == NULL) { 1473 goto need_value; 1474 } 1475 result = parse_uint(&num, value, 512, "padding"); 1476 if (result != ISC_R_SUCCESS) { 1477 warn("Couldn't parse padding"); 1478 goto exit_or_usage; 1479 } 1480 lookup->padding = (uint16_t)num; 1481 break; 1482 case 'q': 1483 switch (cmd[1]) { 1484 case 'r': /* qr */ 1485 FULLCHECK("qr"); 1486 lookup->qr = state; 1487 break; 1488 case 'u': /* question */ 1489 FULLCHECK("question"); 1490 lookup->section_question = state; 1491 if (lookup == default_lookup) { 1492 plusquest = state; 1493 } 1494 break; 1495 default: 1496 goto invalid_option; 1497 } 1498 break; 1499 case 'r': 1500 switch (cmd[1]) { 1501 case 'a': /* raflag */ 1502 FULLCHECK("raflag"); 1503 lookup->raflag = state; 1504 break; 1505 case 'd': /* rdflag */ 1506 FULLCHECK("rdflag"); 1507 lookup->recurse = state; 1508 break; 1509 case 'e': 1510 switch (cmd[2]) { 1511 case 'c': /* recurse */ 1512 FULLCHECK("recurse"); 1513 lookup->recurse = state; 1514 break; 1515 case 't': /* retry / retries */ 1516 FULLCHECK2("retry", "retries"); 1517 if (value == NULL) { 1518 goto need_value; 1519 } 1520 if (!state) { 1521 goto invalid_option; 1522 } 1523 result = parse_uint(&lookup->retries, value, 1524 MAXTRIES - 1, "retries"); 1525 if (result != ISC_R_SUCCESS) { 1526 warn("Couldn't parse retries"); 1527 goto exit_or_usage; 1528 } 1529 lookup->retries++; 1530 break; 1531 default: 1532 goto invalid_option; 1533 } 1534 break; 1535 case 'r': /* rrcomments */ 1536 FULLCHECK("rrcomments"); 1537 lookup->rrcomments = state ? 1 : -1; 1538 break; 1539 default: 1540 goto invalid_option; 1541 } 1542 break; 1543 case 's': 1544 switch (cmd[1]) { 1545 case 'e': /* search */ 1546 FULLCHECK("search"); 1547 if (!lookup->trace) { 1548 usesearch = state; 1549 } 1550 break; 1551 case 'h': 1552 if (cmd[2] != 'o') { 1553 goto invalid_option; 1554 } 1555 switch (cmd[3]) { 1556 case 'r': /* short */ 1557 FULLCHECK("short"); 1558 short_form = state; 1559 if (state) { 1560 printcmd = false; 1561 lookup->section_additional = false; 1562 lookup->section_answer = true; 1563 lookup->section_authority = false; 1564 lookup->section_question = false; 1565 lookup->comments = false; 1566 lookup->stats = false; 1567 lookup->rrcomments = -1; 1568 } 1569 break; 1570 case 'w': /* showsearch */ 1571 FULLCHECK("showsearch"); 1572 if (!lookup->trace) { 1573 showsearch = state; 1574 usesearch = state; 1575 } 1576 break; 1577 default: 1578 goto invalid_option; 1579 } 1580 break; 1581 case 'i': /* sigchase */ 1582 FULLCHECK("sigchase"); 1583 fprintf(stderr, ";; +sigchase option is deprecated"); 1584 break; 1585 case 'p': /* split */ 1586 FULLCHECK("split"); 1587 if (value != NULL && !state) { 1588 goto invalid_option; 1589 } 1590 if (!state) { 1591 splitwidth = 0; 1592 break; 1593 } else if (value == NULL) { 1594 break; 1595 } 1596 1597 result = parse_uint(&splitwidth, value, 1023, "split"); 1598 if ((splitwidth % 4) != 0U) { 1599 splitwidth = ((splitwidth + 3) / 4) * 4; 1600 fprintf(stderr, 1601 ";; Warning, split must be " 1602 "a multiple of 4; adjusting " 1603 "to %u\n", 1604 splitwidth); 1605 } 1606 /* 1607 * There is an adjustment done in the 1608 * totext_<rrtype>() functions which causes 1609 * splitwidth to shrink. This is okay when we're 1610 * using the default width but incorrect in this 1611 * case, so we correct for it 1612 */ 1613 if (splitwidth) { 1614 splitwidth += 3; 1615 } 1616 if (result != ISC_R_SUCCESS) { 1617 warn("Couldn't parse split"); 1618 goto exit_or_usage; 1619 } 1620 break; 1621 case 't': /* stats */ 1622 FULLCHECK("stats"); 1623 lookup->stats = state; 1624 break; 1625 case 'u': /* subnet */ 1626 FULLCHECK("subnet"); 1627 if (state && value == NULL) { 1628 goto need_value; 1629 } 1630 if (!state) { 1631 if (lookup->ecs_addr != NULL) { 1632 isc_mem_free(mctx, lookup->ecs_addr); 1633 lookup->ecs_addr = NULL; 1634 } 1635 break; 1636 } 1637 if (lookup->edns == -1) { 1638 lookup->edns = 0; 1639 } 1640 if (lookup->ecs_addr != NULL) { 1641 isc_mem_free(mctx, lookup->ecs_addr); 1642 lookup->ecs_addr = NULL; 1643 } 1644 result = parse_netprefix(&lookup->ecs_addr, value); 1645 if (result != ISC_R_SUCCESS) { 1646 warn("Couldn't parse client"); 1647 goto exit_or_usage; 1648 } 1649 break; 1650 default: 1651 goto invalid_option; 1652 } 1653 break; 1654 case 't': 1655 switch (cmd[1]) { 1656 case 'c': /* tcp */ 1657 switch (cmd[2]) { 1658 case 'f': 1659 FULLCHECK("tcflag"); 1660 lookup->tcflag = state; 1661 break; 1662 case 'p': 1663 FULLCHECK("tcp"); 1664 if (!is_batchfile) { 1665 lookup->tcp_mode = state; 1666 lookup->tcp_mode_set = true; 1667 } 1668 break; 1669 default: 1670 goto invalid_option; 1671 } 1672 break; 1673 case 'i': /* timeout */ 1674 FULLCHECK("timeout"); 1675 if (value == NULL) { 1676 goto need_value; 1677 } 1678 if (!state) { 1679 goto invalid_option; 1680 } 1681 result = parse_uint(&timeout, value, MAXTIMEOUT, 1682 "timeout"); 1683 if (result != ISC_R_SUCCESS) { 1684 warn("Couldn't parse timeout"); 1685 goto exit_or_usage; 1686 } 1687 if (timeout == 0) { 1688 timeout = 1; 1689 } 1690 break; 1691 case 'o': 1692 FULLCHECK("topdown"); 1693 fprintf(stderr, ";; +topdown option is deprecated"); 1694 break; 1695 case 'r': 1696 switch (cmd[2]) { 1697 case 'a': /* trace */ 1698 FULLCHECK("trace"); 1699 lookup->trace = state; 1700 lookup->trace_root = state; 1701 if (state) { 1702 lookup->recurse = true; 1703 lookup->identify = true; 1704 lookup->comments = false; 1705 lookup->rrcomments = 0; 1706 lookup->stats = false; 1707 lookup->section_additional = false; 1708 lookup->section_authority = true; 1709 lookup->section_question = false; 1710 lookup->dnssec = true; 1711 lookup->sendcookie = true; 1712 usesearch = false; 1713 } 1714 break; 1715 case 'i': /* tries */ 1716 FULLCHECK("tries"); 1717 if (value == NULL) { 1718 goto need_value; 1719 } 1720 if (!state) { 1721 goto invalid_option; 1722 } 1723 result = parse_uint(&lookup->retries, value, 1724 MAXTRIES, "tries"); 1725 if (result != ISC_R_SUCCESS) { 1726 warn("Couldn't parse tries"); 1727 goto exit_or_usage; 1728 } 1729 if (lookup->retries == 0) { 1730 lookup->retries = 1; 1731 } 1732 break; 1733 case 'u': /* trusted-key */ 1734 FULLCHECK("trusted-key"); 1735 fprintf(stderr, ";; +trusted-key option is " 1736 "deprecated"); 1737 break; 1738 default: 1739 goto invalid_option; 1740 } 1741 break; 1742 case 't': 1743 switch (cmd[2]) { 1744 case 'l': 1745 switch (cmd[3]) { 1746 case 0: 1747 case 'i': /* ttlid */ 1748 FULLCHECK2("ttl", "ttlid"); 1749 lookup->nottl = !state; 1750 break; 1751 case 'u': /* ttlunits */ 1752 FULLCHECK("ttlunits"); 1753 lookup->nottl = false; 1754 lookup->ttlunits = state; 1755 break; 1756 default: 1757 goto invalid_option; 1758 } 1759 break; 1760 default: 1761 goto invalid_option; 1762 } 1763 break; 1764 default: 1765 goto invalid_option; 1766 } 1767 break; 1768 case 'u': 1769 switch (cmd[1]) { 1770 case 'n': 1771 switch (cmd[2]) { 1772 case 'e': 1773 FULLCHECK("unexpected"); 1774 lookup->accept_reply_unexpected_src = state; 1775 break; 1776 case 'k': 1777 FULLCHECK("unknownformat"); 1778 lookup->print_unknown_format = state; 1779 break; 1780 default: 1781 goto invalid_option; 1782 } 1783 break; 1784 default: 1785 goto invalid_option; 1786 } 1787 1788 break; 1789 case 'v': 1790 FULLCHECK("vc"); 1791 if (!is_batchfile) { 1792 lookup->tcp_mode = state; 1793 lookup->tcp_mode_set = true; 1794 } 1795 break; 1796 case 'y': /* yaml */ 1797 FULLCHECK("yaml"); 1798 yaml = state; 1799 if (state) { 1800 printcmd = false; 1801 lookup->stats = false; 1802 lookup->rrcomments = -1; 1803 } 1804 break; 1805 case 'z': /* zflag */ 1806 FULLCHECK("zflag"); 1807 lookup->zflag = state; 1808 break; 1809 default: 1810 invalid_option: 1811 need_value: 1812 #if TARGET_OS_IPHONE 1813 exit_or_usage: 1814 #endif /* if TARGET_OS_IPHONE */ 1815 fprintf(stderr, "Invalid option: +%s\n", option); 1816 usage(); 1817 } 1818 return; 1819 1820 #if !TARGET_OS_IPHONE 1821 exit_or_usage: 1822 digexit(); 1823 #endif /* if !TARGET_OS_IPHONE */ 1824 } 1825 1826 /*% 1827 * #true returned if value was used 1828 */ 1829 static const char *single_dash_opts = "46dhimnruv"; 1830 static const char *dash_opts = "46bcdfhikmnpqrtvyx"; 1831 static bool 1832 dash_option(char *option, char *next, dig_lookup_t **lookup, 1833 bool *open_type_class, bool *need_clone, bool config_only, int argc, 1834 char **argv, bool *firstarg) { 1835 char opt, *value, *ptr, *ptr2, *ptr3, *last; 1836 isc_result_t result; 1837 bool value_from_next; 1838 isc_textregion_t tr; 1839 dns_rdatatype_t rdtype; 1840 dns_rdataclass_t rdclass; 1841 char textname[MXNAME]; 1842 struct in_addr in4; 1843 struct in6_addr in6; 1844 in_port_t srcport; 1845 char *hash, *cmd; 1846 uint32_t num; 1847 1848 while (strpbrk(option, single_dash_opts) == &option[0]) { 1849 /* 1850 * Since the -[46dhimnuv] options do not take an argument, 1851 * account for them (in any number and/or combination) 1852 * if they appear as the first character(s) of a q-opt. 1853 */ 1854 opt = option[0]; 1855 switch (opt) { 1856 case '4': 1857 if (have_ipv4) { 1858 isc_net_disableipv6(); 1859 have_ipv6 = false; 1860 } else { 1861 fatal("can't find IPv4 networking"); 1862 /* NOTREACHED */ 1863 return (false); 1864 } 1865 break; 1866 case '6': 1867 if (have_ipv6) { 1868 isc_net_disableipv4(); 1869 have_ipv4 = false; 1870 } else { 1871 fatal("can't find IPv6 networking"); 1872 /* NOTREACHED */ 1873 return (false); 1874 } 1875 break; 1876 case 'd': 1877 ptr = strpbrk(&option[1], dash_opts); 1878 if (ptr != &option[1]) { 1879 cmd = option; 1880 FULLCHECK("debug"); 1881 debugging = true; 1882 return (false); 1883 } else { 1884 debugging = true; 1885 } 1886 break; 1887 case 'h': 1888 help(); 1889 exit(0); 1890 break; 1891 case 'i': 1892 /* deprecated */ 1893 break; 1894 case 'm': /* memdebug */ 1895 /* memdebug is handled in preparse_args() */ 1896 break; 1897 case 'n': 1898 /* deprecated */ 1899 break; 1900 case 'r': 1901 debug("digrc (late)"); 1902 digrc = false; 1903 break; 1904 case 'u': 1905 (*lookup)->use_usec = true; 1906 break; 1907 case 'v': 1908 version(); 1909 exit(0); 1910 break; 1911 } 1912 if (strlen(option) > 1U) { 1913 option = &option[1]; 1914 } else { 1915 return (false); 1916 } 1917 } 1918 opt = option[0]; 1919 if (strlen(option) > 1U) { 1920 value_from_next = false; 1921 value = &option[1]; 1922 } else { 1923 value_from_next = true; 1924 value = next; 1925 } 1926 if (value == NULL) { 1927 goto invalid_option; 1928 } 1929 switch (opt) { 1930 case 'b': 1931 hash = strchr(value, '#'); 1932 if (hash != NULL) { 1933 result = parse_uint(&num, hash + 1, MAXPORT, 1934 "port number"); 1935 if (result != ISC_R_SUCCESS) { 1936 fatal("Couldn't parse port number"); 1937 } 1938 srcport = num; 1939 *hash = '\0'; 1940 } else { 1941 srcport = 0; 1942 } 1943 if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { 1944 isc_sockaddr_fromin6(&bind_address, &in6, srcport); 1945 isc_net_disableipv4(); 1946 } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { 1947 isc_sockaddr_fromin(&bind_address, &in4, srcport); 1948 isc_net_disableipv6(); 1949 } else { 1950 if (hash != NULL) { 1951 *hash = '#'; 1952 } 1953 fatal("invalid address %s", value); 1954 } 1955 if (hash != NULL) { 1956 *hash = '#'; 1957 } 1958 specified_source = true; 1959 return (value_from_next); 1960 case 'c': 1961 if ((*lookup)->rdclassset) { 1962 fprintf(stderr, ";; Warning, extra class option\n"); 1963 } 1964 *open_type_class = false; 1965 tr.base = value; 1966 tr.length = (unsigned int)strlen(value); 1967 result = dns_rdataclass_fromtext(&rdclass, 1968 (isc_textregion_t *)&tr); 1969 if (result == ISC_R_SUCCESS) { 1970 (*lookup)->rdclass = rdclass; 1971 (*lookup)->rdclassset = true; 1972 } else { 1973 fprintf(stderr, 1974 ";; Warning, ignoring " 1975 "invalid class %s\n", 1976 value); 1977 } 1978 return (value_from_next); 1979 case 'f': 1980 atomic_store(&batchname, (uintptr_t)value); 1981 return (value_from_next); 1982 case 'k': 1983 strlcpy(keyfile, value, sizeof(keyfile)); 1984 return (value_from_next); 1985 case 'p': 1986 result = parse_uint(&num, value, MAXPORT, "port number"); 1987 if (result != ISC_R_SUCCESS) { 1988 fatal("Couldn't parse port number"); 1989 } 1990 port = num; 1991 return (value_from_next); 1992 case 'q': 1993 if (!config_only) { 1994 if (*need_clone) { 1995 (*lookup) = clone_lookup(default_lookup, true); 1996 } 1997 *need_clone = true; 1998 strlcpy((*lookup)->textname, value, 1999 sizeof((*lookup)->textname)); 2000 (*lookup)->trace_root = ((*lookup)->trace || 2001 (*lookup)->ns_search_only); 2002 (*lookup)->new_search = true; 2003 if (*firstarg) { 2004 printgreeting(argc, argv, *lookup); 2005 *firstarg = false; 2006 } 2007 ISC_LIST_APPEND(lookup_list, (*lookup), link); 2008 debug("looking up %s", (*lookup)->textname); 2009 } 2010 return (value_from_next); 2011 case 't': 2012 *open_type_class = false; 2013 if (strncasecmp(value, "ixfr=", 5) == 0) { 2014 rdtype = dns_rdatatype_ixfr; 2015 result = ISC_R_SUCCESS; 2016 } else { 2017 tr.base = value; 2018 tr.length = (unsigned int)strlen(value); 2019 result = dns_rdatatype_fromtext( 2020 &rdtype, (isc_textregion_t *)&tr); 2021 if (result == ISC_R_SUCCESS && 2022 rdtype == dns_rdatatype_ixfr) { 2023 result = DNS_R_UNKNOWN; 2024 } 2025 } 2026 if (result == ISC_R_SUCCESS) { 2027 if ((*lookup)->rdtypeset) { 2028 fprintf(stderr, ";; Warning, " 2029 "extra type option\n"); 2030 } 2031 if (rdtype == dns_rdatatype_ixfr) { 2032 uint32_t serial; 2033 (*lookup)->rdtype = dns_rdatatype_ixfr; 2034 (*lookup)->rdtypeset = true; 2035 result = parse_uint(&serial, &value[5], 2036 MAXSERIAL, "serial number"); 2037 if (result != ISC_R_SUCCESS) { 2038 fatal("Couldn't parse serial number"); 2039 } 2040 (*lookup)->ixfr_serial = serial; 2041 (*lookup)->section_question = plusquest; 2042 (*lookup)->comments = pluscomm; 2043 if (!(*lookup)->tcp_mode_set) { 2044 (*lookup)->tcp_mode = true; 2045 } 2046 } else { 2047 (*lookup)->rdtype = rdtype; 2048 if (!config_only) { 2049 (*lookup)->rdtypeset = true; 2050 } 2051 if (rdtype == dns_rdatatype_axfr) { 2052 (*lookup)->section_question = plusquest; 2053 (*lookup)->comments = pluscomm; 2054 } else if (rdtype == dns_rdatatype_any) { 2055 if (!(*lookup)->tcp_mode_set) { 2056 (*lookup)->tcp_mode = true; 2057 } 2058 } 2059 (*lookup)->ixfr_serial = false; 2060 } 2061 } else { 2062 fprintf(stderr, 2063 ";; Warning, ignoring " 2064 "invalid type %s\n", 2065 value); 2066 } 2067 return (value_from_next); 2068 case 'y': 2069 if ((ptr = strtok_r(value, ":", &last)) == NULL) { 2070 usage(); 2071 } 2072 if ((ptr2 = strtok_r(NULL, ":", &last)) == NULL) { /* name or 2073 * secret */ 2074 usage(); 2075 } 2076 if ((ptr3 = strtok_r(NULL, ":", &last)) != NULL) { /* secret or 2077 * NULL */ 2078 parse_hmac(ptr); 2079 ptr = ptr2; 2080 ptr2 = ptr3; 2081 } else { 2082 hmacname = DNS_TSIG_HMACMD5_NAME; 2083 digestbits = 0; 2084 } 2085 /* XXXONDREJ: FIXME */ 2086 strlcpy(keynametext, ptr, sizeof(keynametext)); 2087 strlcpy(keysecret, ptr2, sizeof(keysecret)); 2088 return (value_from_next); 2089 case 'x': 2090 if (*need_clone) { 2091 *lookup = clone_lookup(default_lookup, true); 2092 } 2093 *need_clone = true; 2094 if (get_reverse(textname, sizeof(textname), value, false) == 2095 ISC_R_SUCCESS) { 2096 strlcpy((*lookup)->textname, textname, 2097 sizeof((*lookup)->textname)); 2098 debug("looking up %s", (*lookup)->textname); 2099 (*lookup)->trace_root = ((*lookup)->trace || 2100 (*lookup)->ns_search_only); 2101 if (!(*lookup)->rdtypeset) { 2102 (*lookup)->rdtype = dns_rdatatype_ptr; 2103 } 2104 if (!(*lookup)->rdclassset) { 2105 (*lookup)->rdclass = dns_rdataclass_in; 2106 } 2107 (*lookup)->new_search = true; 2108 if (*firstarg) { 2109 printgreeting(argc, argv, *lookup); 2110 *firstarg = false; 2111 } 2112 ISC_LIST_APPEND(lookup_list, *lookup, link); 2113 } else { 2114 fprintf(stderr, "Invalid IP address %s\n", value); 2115 exit(1); 2116 } 2117 return (value_from_next); 2118 invalid_option: 2119 default: 2120 fprintf(stderr, "Invalid option: -%s\n", option); 2121 usage(); 2122 } 2123 /* NOTREACHED */ 2124 return (false); 2125 } 2126 2127 /*% 2128 * Because we may be trying to do memory allocation recording, we're going 2129 * to need to parse the arguments for the -m *before* we start the main 2130 * argument parsing routine. 2131 * 2132 * I'd prefer not to have to do this, but I am not quite sure how else to 2133 * fix the problem. Argument parsing in dig involves memory allocation 2134 * by its nature, so it can't be done in the main argument parser. 2135 */ 2136 static void 2137 preparse_args(int argc, char **argv) { 2138 int rc; 2139 char **rv; 2140 char *option; 2141 2142 rc = argc; 2143 rv = argv; 2144 for (rc--, rv++; rc > 0; rc--, rv++) { 2145 if (rv[0][0] != '-') { 2146 continue; 2147 } 2148 option = &rv[0][1]; 2149 while (strpbrk(option, single_dash_opts) == &option[0]) { 2150 switch (option[0]) { 2151 case 'd': 2152 /* For debugging early startup */ 2153 debugging = true; 2154 break; 2155 case 'm': 2156 memdebugging = true; 2157 isc_mem_debugging = ISC_MEM_DEBUGTRACE | 2158 ISC_MEM_DEBUGRECORD; 2159 break; 2160 case 'r': 2161 /* 2162 * Must be done early, because ~/.digrc 2163 * is read before command line parsing 2164 */ 2165 debug("digrc (early)"); 2166 digrc = false; 2167 break; 2168 case '4': 2169 if (ipv6only) { 2170 fatal("only one of -4 and -6 allowed"); 2171 } 2172 ipv4only = true; 2173 break; 2174 case '6': 2175 if (ipv4only) { 2176 fatal("only one of -4 and -6 allowed"); 2177 } 2178 ipv6only = true; 2179 break; 2180 } 2181 option = &option[1]; 2182 } 2183 if (strlen(option) == 0U) { 2184 continue; 2185 } 2186 /* Look for dash value option. */ 2187 if (strpbrk(option, dash_opts) != &option[0] || 2188 strlen(option) > 1U) { 2189 /* Error or value in option. */ 2190 continue; 2191 } 2192 /* Dash value is next argument so we need to skip it. */ 2193 rc--, rv++; 2194 /* Handle missing argument */ 2195 if (rc == 0) { 2196 break; 2197 } 2198 } 2199 } 2200 2201 static int 2202 split_batchline(char *batchline, char **bargv, int len, const char *msg) { 2203 int bargc; 2204 char *last = NULL; 2205 2206 REQUIRE(batchline != NULL); 2207 2208 for (bargc = 1, bargv[bargc] = strtok_r(batchline, " \t\r\n", &last); 2209 bargc < len && bargv[bargc]; 2210 bargv[++bargc] = strtok_r(NULL, " \t\r\n", &last)) 2211 { 2212 debug("%s %d: %s", msg, bargc, bargv[bargc]); 2213 } 2214 return (bargc); 2215 } 2216 2217 static void 2218 parse_args(bool is_batchfile, bool config_only, int argc, char **argv) { 2219 isc_result_t result; 2220 isc_textregion_t tr; 2221 bool firstarg = true; 2222 dig_lookup_t *lookup = NULL; 2223 dns_rdatatype_t rdtype; 2224 dns_rdataclass_t rdclass; 2225 bool open_type_class = true; 2226 char batchline[MXNAME]; 2227 int bargc; 2228 char *bargv[64]; 2229 int rc; 2230 char **rv; 2231 #ifndef NOPOSIX 2232 char *homedir; 2233 char rcfile[PATH_MAX]; 2234 #endif /* ifndef NOPOSIX */ 2235 bool need_clone = true; 2236 2237 /* 2238 * The semantics for parsing the args is a bit complex; if 2239 * we don't have a host yet, make the arg apply globally, 2240 * otherwise make it apply to the latest host. This is 2241 * a bit different than the previous versions, but should 2242 * form a consistent user interface. 2243 * 2244 * First, create a "default lookup" which won't actually be used 2245 * anywhere, except for cloning into new lookups 2246 */ 2247 2248 debug("parse_args()"); 2249 if (!is_batchfile) { 2250 debug("making new lookup"); 2251 default_lookup = make_empty_lookup(); 2252 default_lookup->adflag = true; 2253 default_lookup->edns = 0; 2254 default_lookup->sendcookie = true; 2255 2256 #ifndef NOPOSIX 2257 /* 2258 * Treat ${HOME}/.digrc as a special batchfile 2259 */ 2260 INSIST(batchfp == NULL); 2261 homedir = getenv("HOME"); 2262 if (homedir != NULL && digrc) { 2263 unsigned int n; 2264 debug("digrc (open)"); 2265 n = snprintf(rcfile, sizeof(rcfile), "%s/.digrc", 2266 homedir); 2267 if (n < sizeof(rcfile)) { 2268 batchfp = fopen(rcfile, "r"); 2269 } 2270 } 2271 if (batchfp != NULL) { 2272 while (fgets(batchline, sizeof(batchline), batchfp) != 2273 0) { 2274 debug("config line %s", batchline); 2275 bargc = split_batchline(batchline, bargv, 62, 2276 ".digrc argv"); 2277 bargv[0] = argv[0]; 2278 argv0 = argv[0]; 2279 parse_args(true, true, bargc, (char **)bargv); 2280 } 2281 fclose(batchfp); 2282 } 2283 #endif /* ifndef NOPOSIX */ 2284 } 2285 2286 if (is_batchfile && !config_only) { 2287 /* Processing '-f batchfile'. */ 2288 lookup = clone_lookup(default_lookup, true); 2289 need_clone = false; 2290 } else { 2291 lookup = default_lookup; 2292 } 2293 2294 rc = argc; 2295 rv = argv; 2296 for (rc--, rv++; rc > 0; rc--, rv++) { 2297 debug("main parsing %s", rv[0]); 2298 if (strncmp(rv[0], "%", 1) == 0) { 2299 break; 2300 } 2301 if (rv[0][0] == '@') { 2302 if (is_batchfile && !config_only) { 2303 addresscount = getaddresses(lookup, &rv[0][1], 2304 &result); 2305 if (addresscount == 0) { 2306 fprintf(stderr, 2307 "couldn't get address " 2308 "for '%s': %s: skipping " 2309 "lookup\n", 2310 &rv[0][1], 2311 isc_result_totext(result)); 2312 if (ISC_LINK_LINKED(lookup, link)) { 2313 ISC_LIST_DEQUEUE(lookup_list, 2314 lookup, link); 2315 } 2316 destroy_lookup(lookup); 2317 return; 2318 } 2319 } else { 2320 addresscount = getaddresses(lookup, &rv[0][1], 2321 NULL); 2322 if (addresscount == 0) { 2323 fatal("no valid addresses for '%s'\n", 2324 &rv[0][1]); 2325 } 2326 } 2327 } else if (rv[0][0] == '+') { 2328 plus_option(&rv[0][1], is_batchfile, lookup); 2329 } else if (rv[0][0] == '-') { 2330 if (rc <= 1) { 2331 if (dash_option(&rv[0][1], NULL, &lookup, 2332 &open_type_class, &need_clone, 2333 config_only, argc, argv, 2334 &firstarg)) 2335 { 2336 rc--; 2337 rv++; 2338 } 2339 } else { 2340 if (dash_option(&rv[0][1], rv[1], &lookup, 2341 &open_type_class, &need_clone, 2342 config_only, argc, argv, 2343 &firstarg)) 2344 { 2345 rc--; 2346 rv++; 2347 } 2348 } 2349 } else { 2350 /* 2351 * Anything which isn't an option 2352 */ 2353 if (open_type_class) { 2354 if (strncasecmp(rv[0], "ixfr=", 5) == 0) { 2355 rdtype = dns_rdatatype_ixfr; 2356 result = ISC_R_SUCCESS; 2357 } else { 2358 tr.base = rv[0]; 2359 tr.length = (unsigned int)strlen(rv[0]); 2360 result = dns_rdatatype_fromtext( 2361 &rdtype, 2362 (isc_textregion_t *)&tr); 2363 if (result == ISC_R_SUCCESS && 2364 rdtype == dns_rdatatype_ixfr) { 2365 fprintf(stderr, ";; Warning, " 2366 "ixfr requires " 2367 "a " 2368 "serial " 2369 "number\n"); 2370 continue; 2371 } 2372 } 2373 if (result == ISC_R_SUCCESS) { 2374 if (lookup->rdtypeset) { 2375 fprintf(stderr, ";; Warning, " 2376 "extra type " 2377 "option\n"); 2378 } 2379 if (rdtype == dns_rdatatype_ixfr) { 2380 uint32_t serial; 2381 lookup->rdtype = 2382 dns_rdatatype_ixfr; 2383 lookup->rdtypeset = true; 2384 result = parse_uint(&serial, 2385 &rv[0][5], 2386 MAXSERIAL, 2387 "serial " 2388 "number"); 2389 if (result != ISC_R_SUCCESS) { 2390 fatal("Couldn't parse " 2391 "serial number"); 2392 } 2393 lookup->ixfr_serial = serial; 2394 lookup->section_question = 2395 plusquest; 2396 lookup->comments = pluscomm; 2397 if (!lookup->tcp_mode_set) { 2398 lookup->tcp_mode = true; 2399 } 2400 } else { 2401 lookup->rdtype = rdtype; 2402 lookup->rdtypeset = true; 2403 if (rdtype == 2404 dns_rdatatype_axfr) { 2405 lookup->section_question = 2406 plusquest; 2407 lookup->comments = 2408 pluscomm; 2409 } 2410 if (rdtype == 2411 dns_rdatatype_any && 2412 !lookup->tcp_mode_set) { 2413 lookup->tcp_mode = true; 2414 } 2415 lookup->ixfr_serial = false; 2416 } 2417 continue; 2418 } 2419 result = dns_rdataclass_fromtext( 2420 &rdclass, (isc_textregion_t *)&tr); 2421 if (result == ISC_R_SUCCESS) { 2422 if (lookup->rdclassset) { 2423 fprintf(stderr, ";; Warning, " 2424 "extra class " 2425 "option\n"); 2426 } 2427 lookup->rdclass = rdclass; 2428 lookup->rdclassset = true; 2429 continue; 2430 } 2431 } 2432 2433 if (!config_only) { 2434 if (need_clone) { 2435 lookup = clone_lookup(default_lookup, 2436 true); 2437 } 2438 need_clone = true; 2439 strlcpy(lookup->textname, rv[0], 2440 sizeof(lookup->textname)); 2441 lookup->trace_root = (lookup->trace || 2442 lookup->ns_search_only); 2443 lookup->new_search = true; 2444 if (firstarg) { 2445 printgreeting(argc, argv, lookup); 2446 firstarg = false; 2447 } 2448 ISC_LIST_APPEND(lookup_list, lookup, link); 2449 debug("looking up %s", lookup->textname); 2450 } 2451 /* XXX Error message */ 2452 } 2453 } 2454 2455 /* 2456 * If we have a batchfile, seed the lookup list with the 2457 * first entry, then trust the callback in dighost_shutdown 2458 * to get the rest 2459 */ 2460 char *filename = (char *)atomic_load(&batchname); 2461 if ((filename != NULL) && !(is_batchfile)) { 2462 if (strcmp(filename, "-") == 0) { 2463 batchfp = stdin; 2464 } else { 2465 batchfp = fopen(filename, "r"); 2466 } 2467 if (batchfp == NULL) { 2468 perror(filename); 2469 if (exitcode < 8) { 2470 exitcode = 8; 2471 } 2472 fatal("couldn't open specified batch file"); 2473 } 2474 /* XXX Remove code dup from shutdown code */ 2475 next_line: 2476 if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 2477 debug("batch line %s", batchline); 2478 if (batchline[0] == '\r' || batchline[0] == '\n' || 2479 batchline[0] == '#' || batchline[0] == ';') 2480 { 2481 goto next_line; 2482 } 2483 bargc = split_batchline(batchline, bargv, 14, 2484 "batch argv"); 2485 bargv[0] = argv[0]; 2486 argv0 = argv[0]; 2487 parse_args(true, false, bargc, (char **)bargv); 2488 return; 2489 } 2490 return; 2491 } 2492 /* 2493 * If no lookup specified, search for root 2494 */ 2495 if ((lookup_list.head == NULL) && !config_only) { 2496 if (need_clone) { 2497 lookup = clone_lookup(default_lookup, true); 2498 } 2499 need_clone = true; 2500 lookup->trace_root = (lookup->trace || lookup->ns_search_only); 2501 lookup->new_search = true; 2502 strlcpy(lookup->textname, ".", sizeof(lookup->textname)); 2503 lookup->rdtype = dns_rdatatype_ns; 2504 lookup->rdtypeset = true; 2505 if (firstarg) { 2506 printgreeting(argc, argv, lookup); 2507 firstarg = false; 2508 } 2509 ISC_LIST_APPEND(lookup_list, lookup, link); 2510 } 2511 if (!need_clone) { 2512 destroy_lookup(lookup); 2513 } 2514 } 2515 2516 /* 2517 * Callback from dighost.c to allow program-specific shutdown code. 2518 * Here, we're possibly reading from a batch file, then shutting down 2519 * for real if there's nothing in the batch file to read. 2520 */ 2521 static void 2522 query_finished(void) { 2523 char batchline[MXNAME]; 2524 int bargc; 2525 char *bargv[16]; 2526 2527 if (atomic_load(&batchname) == 0) { 2528 isc_app_shutdown(); 2529 return; 2530 } 2531 2532 fflush(stdout); 2533 if (feof(batchfp)) { 2534 atomic_store(&batchname, 0); 2535 isc_app_shutdown(); 2536 if (batchfp != stdin) { 2537 fclose(batchfp); 2538 } 2539 return; 2540 } 2541 2542 if (fgets(batchline, sizeof(batchline), batchfp) != 0) { 2543 debug("batch line %s", batchline); 2544 bargc = split_batchline(batchline, bargv, 14, "batch argv"); 2545 bargv[0] = argv0; 2546 parse_args(true, false, bargc, (char **)bargv); 2547 start_lookup(); 2548 } else { 2549 atomic_store(&batchname, 0); 2550 if (batchfp != stdin) { 2551 fclose(batchfp); 2552 } 2553 isc_app_shutdown(); 2554 return; 2555 } 2556 } 2557 2558 static void 2559 dig_error(const char *format, ...) { 2560 va_list args; 2561 2562 if (yaml) { 2563 printf("-\n"); 2564 printf(" type: DIG_ERROR\n"); 2565 2566 /* 2567 * Print an indent before a literal block quote. 2568 * Note: this will break if used to print more than 2569 * one line of text as only the first line would be 2570 * indented. 2571 */ 2572 printf(" message: |\n"); 2573 printf(" "); 2574 } else { 2575 printf(";; "); 2576 } 2577 2578 va_start(args, format); 2579 vprintf(format, args); 2580 va_end(args); 2581 2582 if (!yaml) { 2583 printf("\n"); 2584 } 2585 } 2586 2587 static void 2588 dig_warning(const char *format, ...) { 2589 va_list args; 2590 2591 if (!yaml) { 2592 printf(";; "); 2593 2594 va_start(args, format); 2595 vprintf(format, args); 2596 va_end(args); 2597 2598 printf("\n"); 2599 } 2600 } 2601 2602 static void 2603 dig_comments(dig_lookup_t *lookup, const char *format, ...) { 2604 va_list args; 2605 2606 if (lookup->comments && !yaml) { 2607 printf(";; "); 2608 2609 va_start(args, format); 2610 vprintf(format, args); 2611 va_end(args); 2612 2613 printf("\n"); 2614 } 2615 } 2616 2617 void 2618 dig_setup(int argc, char **argv) { 2619 isc_result_t result; 2620 2621 ISC_LIST_INIT(lookup_list); 2622 ISC_LIST_INIT(server_list); 2623 ISC_LIST_INIT(search_list); 2624 2625 debug("dig_setup()"); 2626 2627 /* setup dighost callbacks */ 2628 dighost_printmessage = printmessage; 2629 dighost_received = received; 2630 dighost_trying = trying; 2631 dighost_shutdown = query_finished; 2632 dighost_error = dig_error; 2633 dighost_warning = dig_warning; 2634 dighost_comments = dig_comments; 2635 2636 progname = argv[0]; 2637 preparse_args(argc, argv); 2638 2639 result = isc_app_start(); 2640 check_result(result, "isc_app_start"); 2641 2642 setup_libs(); 2643 setup_system(ipv4only, ipv6only); 2644 } 2645 2646 void 2647 dig_query_setup(bool is_batchfile, bool config_only, int argc, char **argv) { 2648 debug("dig_query_setup"); 2649 2650 parse_args(is_batchfile, config_only, argc, argv); 2651 if (keyfile[0] != 0) { 2652 setup_file_key(); 2653 } else if (keysecret[0] != 0) { 2654 setup_text_key(); 2655 } 2656 if (domainopt[0] != '\0') { 2657 set_search_domain(domainopt); 2658 usesearch = true; 2659 } 2660 } 2661 2662 void 2663 dig_startup() { 2664 isc_result_t result; 2665 2666 debug("dig_startup()"); 2667 2668 result = isc_app_onrun(mctx, global_task, onrun_callback, NULL); 2669 check_result(result, "isc_app_onrun"); 2670 isc_app_run(); 2671 } 2672 2673 void 2674 dig_query_start() { 2675 start_lookup(); 2676 } 2677 2678 void 2679 dig_shutdown() { 2680 destroy_lookup(default_lookup); 2681 if (atomic_load(&batchname) != 0) { 2682 if (batchfp != stdin) { 2683 fclose(batchfp); 2684 } 2685 atomic_store(&batchname, 0); 2686 } 2687 cancel_all(); 2688 destroy_libs(); 2689 isc_app_finish(); 2690 } 2691 2692 /*% Main processing routine for dig */ 2693 int 2694 main(int argc, char **argv) { 2695 dig_setup(argc, argv); 2696 dig_query_setup(false, false, argc, argv); 2697 dig_startup(); 2698 dig_shutdown(); 2699 2700 return (exitcode); 2701 } 2702