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