1 /* 2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 /* $Id: dig.c,v 1.12 2020/02/24 13:49:38 jsg Exp $ */ 18 19 /*! \file */ 20 #include <sys/cdefs.h> 21 22 #include <stdlib.h> 23 #include <time.h> 24 #include <unistd.h> 25 26 #include <isc/app.h> 27 28 #include <string.h> 29 #include <isc/util.h> 30 #include <isc/time.h> 31 32 #include <dns/fixedname.h> 33 #include <dns/masterdump.h> 34 #include <dns/message.h> 35 #include <dns/name.h> 36 #include <dns/rdata.h> 37 #include <dns/rdataset.h> 38 #include <dns/rdatatype.h> 39 #include <dns/rdataclass.h> 40 #include <dns/result.h> 41 #include <dns/tsig.h> 42 43 #include "dig.h" 44 45 #define ADD_STRING(b, s) { \ 46 if (strlen(s) >= isc_buffer_availablelength(b)) \ 47 return (ISC_R_NOSPACE); \ 48 else \ 49 isc_buffer_putstr(b, s); \ 50 } 51 52 dig_lookup_t *default_lookup = NULL; 53 54 static char *batchname = NULL; 55 static FILE *batchfp = NULL; 56 static char *argv0; 57 static int addresscount = 0; 58 59 static char domainopt[DNS_NAME_MAXTEXT]; 60 static char sitvalue[256]; 61 62 static isc_boolean_t short_form = ISC_FALSE, printcmd = ISC_TRUE, 63 ip6_int = ISC_FALSE, plusquest = ISC_FALSE, pluscomm = ISC_FALSE, 64 multiline = ISC_FALSE, nottl = ISC_FALSE, noclass = ISC_FALSE, 65 onesoa = ISC_FALSE, use_usec = ISC_FALSE, nocrypto = ISC_FALSE, 66 ipv4only = ISC_FALSE, ipv6only = ISC_FALSE; 67 static uint32_t splitwidth = 0xffffffff; 68 69 /*% rrcomments are neither explicitly enabled nor disabled by default */ 70 static int rrcomments = 0; 71 72 /*% opcode text */ 73 static const char * const opcodetext[] = { 74 "QUERY", 75 "IQUERY", 76 "STATUS", 77 "RESERVED3", 78 "NOTIFY", 79 "UPDATE", 80 "RESERVED6", 81 "RESERVED7", 82 "RESERVED8", 83 "RESERVED9", 84 "RESERVED10", 85 "RESERVED11", 86 "RESERVED12", 87 "RESERVED13", 88 "RESERVED14", 89 "RESERVED15" 90 }; 91 92 /*% return code text */ 93 static const char * const rcodetext[] = { 94 "NOERROR", 95 "FORMERR", 96 "SERVFAIL", 97 "NXDOMAIN", 98 "NOTIMP", 99 "REFUSED", 100 "YXDOMAIN", 101 "YXRRSET", 102 "NXRRSET", 103 "NOTAUTH", 104 "NOTZONE", 105 "RESERVED11", 106 "RESERVED12", 107 "RESERVED13", 108 "RESERVED14", 109 "RESERVED15", 110 "BADVERS" 111 }; 112 113 /*% safe rcodetext[] */ 114 static const char * 115 rcode_totext(dns_rcode_t rcode) 116 { 117 static char buf[sizeof("?65535")]; 118 119 if (rcode == dns_rcode_badcookie) 120 return ("BADCOOKIE"); 121 if (rcode >= (sizeof(rcodetext)/sizeof(rcodetext[0]))) { 122 snprintf(buf, sizeof(buf), "?%u", rcode); 123 return (buf); 124 } 125 return (rcodetext[rcode]); 126 } 127 128 /*% print usage */ 129 static void 130 print_usage(FILE *fp) { 131 fputs( 132 "usage: dig [@server] [-46hiuv] [-b sourceaddr[#port]] [-c class] [-f file]\n" 133 " [-k keyfile] [-p port] [-q name] [-t type] [-x addr]\n" 134 " [-y [hmac:]name:key] [name] [type] [class]\n" 135 " +[no]aaonly +[no]additional +[no]adflag +[no]all +[no]answer\n" 136 " +[no]authority +[no]besteffort +bufsize=# +[no]cdflag +[no]class\n" 137 " +[no]cmd +[no]comments +[no]cookie[=value] +[no]crypto +[no]dnssec\n" 138 " +domain=name +[no]edns[=#] +ednsflags[=#] +[no]ednsnegotiation\n" 139 " +[no]ednsopt[=code[:value]] +[no]expire +[no]fail +[no]identify\n" 140 " +[no]ignore +[no]keepopen +[no]multiline +ndots=# +[no]nsid\n" 141 " +[no]nssearch +[no]onesoa +[no]opcode=# +[no]qr +[no]question\n" 142 " +[no]recurse +retry=# +[no]rrcomments +[no]search +[no]short\n" 143 " +[no]showsearch +[no]split=# +[no]stats +[no]subnet=addr[/prefix]\n" 144 " +[no]tcp +timeout=# +[no]trace +tries=# +[no]ttlid +[no]vc\n", fp); 145 } 146 147 static __dead void 148 usage(void); 149 150 static void 151 usage(void) { 152 print_usage(stderr); 153 exit(1); 154 } 155 156 /*% version */ 157 static void 158 version(void) { 159 fputs("dig " VERSION "\n", stderr); 160 } 161 162 /*% help */ 163 static void 164 help(void) { 165 print_usage(stdout); 166 } 167 168 /*% 169 * Callback from dighost.c to print the received message. 170 */ 171 static void 172 received(unsigned int bytes, isc_sockaddr_t *from, dig_query_t *query) { 173 uint64_t diff; 174 time_t tnow; 175 struct tm tmnow; 176 char time_str[100]; 177 char fromtext[ISC_SOCKADDR_FORMATSIZE]; 178 179 isc_sockaddr_format(from, fromtext, sizeof(fromtext)); 180 181 if (query->lookup->stats && !short_form) { 182 diff = isc_time_microdiff(&query->time_recv, &query->time_sent); 183 if (use_usec) 184 printf(";; Query time: %ld usec\n", (long) diff); 185 else 186 printf(";; Query time: %ld msec\n", (long) diff / 1000); 187 printf(";; SERVER: %s(%s)\n", fromtext, query->servname); 188 time(&tnow); 189 tmnow = *localtime(&tnow); 190 191 if (strftime(time_str, sizeof(time_str), 192 "%a %b %d %H:%M:%S %Z %Y", &tmnow) > 0U) 193 printf(";; WHEN: %s\n", time_str); 194 if (query->lookup->doing_xfr) { 195 printf(";; XFR size: %u records (messages %u, " 196 "bytes %llu)\n", 197 query->rr_count, query->msg_count, 198 query->byte_count); 199 } else { 200 printf(";; MSG SIZE rcvd: %u\n", bytes); 201 } 202 if (tsigkey != NULL) { 203 if (!validated) 204 puts(";; WARNING -- Some TSIG could not " 205 "be validated"); 206 } 207 if ((tsigkey == NULL) && (keysecret[0] != 0)) { 208 puts(";; WARNING -- TSIG key was not used."); 209 } 210 puts(""); 211 } else if (query->lookup->identify && !short_form) { 212 diff = isc_time_microdiff(&query->time_recv, &query->time_sent); 213 if (use_usec) 214 printf(";; Received %llu bytes " 215 "from %s(%s) in %ld us\n\n", 216 query->lookup->doing_xfr 217 ? query->byte_count 218 : (uint64_t)bytes, 219 fromtext, query->userarg, (long) diff); 220 else 221 printf(";; Received %llu bytes " 222 "from %s(%s) in %ld ms\n\n", 223 query->lookup->doing_xfr 224 ? query->byte_count 225 : (uint64_t)bytes, 226 fromtext, query->userarg, (long) diff / 1000); 227 } 228 } 229 230 /* 231 * Callback from dighost.c to print that it is trying a server. 232 * Not used in dig. 233 * XXX print_trying 234 */ 235 static void 236 trying(char *frm, dig_lookup_t *lookup) { 237 UNUSED(frm); 238 UNUSED(lookup); 239 } 240 241 /*% 242 * Internal print routine used to print short form replies. 243 */ 244 static isc_result_t 245 say_message(dns_rdata_t *rdata, dig_query_t *query, isc_buffer_t *buf) { 246 isc_result_t result; 247 uint64_t diff; 248 char store[sizeof(" in 18446744073709551616 us.")]; 249 unsigned int styleflags = 0; 250 251 if (query->lookup->trace || query->lookup->ns_search_only) { 252 result = dns_rdatatype_totext(rdata->type, buf); 253 if (result != ISC_R_SUCCESS) 254 return (result); 255 ADD_STRING(buf, " "); 256 } 257 258 /* Turn on rrcomments if explicitly enabled */ 259 if (rrcomments > 0) 260 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 261 if (nocrypto) 262 styleflags |= DNS_STYLEFLAG_NOCRYPTO; 263 result = dns_rdata_tofmttext(rdata, NULL, styleflags, 0, 264 splitwidth, " ", buf); 265 if (result == ISC_R_NOSPACE) 266 return (result); 267 check_result(result, "dns_rdata_totext"); 268 if (query->lookup->identify) { 269 270 diff = isc_time_microdiff(&query->time_recv, &query->time_sent); 271 ADD_STRING(buf, " from server "); 272 ADD_STRING(buf, query->servname); 273 if (use_usec) 274 snprintf(store, sizeof(store), " in %llu us.", diff); 275 else 276 snprintf(store, sizeof(store), " in %llu ms.", diff / 1000); 277 ADD_STRING(buf, store); 278 } 279 ADD_STRING(buf, "\n"); 280 return (ISC_R_SUCCESS); 281 } 282 283 /*% 284 * short_form message print handler. Calls above say_message() 285 */ 286 static isc_result_t 287 short_answer(dns_message_t *msg, dns_messagetextflag_t flags, 288 isc_buffer_t *buf, dig_query_t *query) 289 { 290 dns_name_t *name; 291 dns_rdataset_t *rdataset; 292 isc_result_t result, loopresult; 293 dns_name_t empty_name; 294 dns_rdata_t rdata = DNS_RDATA_INIT; 295 296 UNUSED(flags); 297 298 dns_name_init(&empty_name, NULL); 299 result = dns_message_firstname(msg, DNS_SECTION_ANSWER); 300 if (result == ISC_R_NOMORE) 301 return (ISC_R_SUCCESS); 302 else if (result != ISC_R_SUCCESS) 303 return (result); 304 305 for (;;) { 306 name = NULL; 307 dns_message_currentname(msg, DNS_SECTION_ANSWER, &name); 308 309 for (rdataset = ISC_LIST_HEAD(name->list); 310 rdataset != NULL; 311 rdataset = ISC_LIST_NEXT(rdataset, link)) { 312 loopresult = dns_rdataset_first(rdataset); 313 while (loopresult == ISC_R_SUCCESS) { 314 dns_rdataset_current(rdataset, &rdata); 315 result = say_message(&rdata, query, 316 buf); 317 if (result == ISC_R_NOSPACE) 318 return (result); 319 check_result(result, "say_message"); 320 loopresult = dns_rdataset_next(rdataset); 321 dns_rdata_reset(&rdata); 322 } 323 } 324 result = dns_message_nextname(msg, DNS_SECTION_ANSWER); 325 if (result == ISC_R_NOMORE) 326 break; 327 else if (result != ISC_R_SUCCESS) 328 return (result); 329 } 330 331 return (ISC_R_SUCCESS); 332 } 333 334 static isc_boolean_t 335 isdotlocal(dns_message_t *msg) { 336 isc_result_t result; 337 static unsigned char local_ndata[] = { "\005local\0" }; 338 static unsigned char local_offsets[] = { 0, 6 }; 339 static dns_name_t local = 340 DNS_NAME_INITABSOLUTE(local_ndata, local_offsets); 341 342 for (result = dns_message_firstname(msg, DNS_SECTION_QUESTION); 343 result == ISC_R_SUCCESS; 344 result = dns_message_nextname(msg, DNS_SECTION_QUESTION)) 345 { 346 dns_name_t *name = NULL; 347 dns_message_currentname(msg, DNS_SECTION_QUESTION, &name); 348 if (dns_name_issubdomain(name, &local)) 349 return (ISC_TRUE); 350 } 351 return (ISC_FALSE); 352 } 353 354 /* 355 * Callback from dighost.c to print the reply from a server 356 */ 357 static isc_result_t 358 printmessage(dig_query_t *query, dns_message_t *msg, isc_boolean_t headers) { 359 isc_result_t result; 360 dns_messagetextflag_t flags; 361 isc_buffer_t *buf = NULL; 362 unsigned int len = OUTPUTBUF; 363 dns_master_style_t *style = NULL; 364 unsigned int styleflags = 0; 365 366 styleflags |= DNS_STYLEFLAG_REL_OWNER; 367 if (query->lookup->comments) 368 styleflags |= DNS_STYLEFLAG_COMMENT; 369 /* Turn on rrcomments if explicitly enabled */ 370 if (rrcomments > 0) 371 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 372 if (nottl) 373 styleflags |= DNS_STYLEFLAG_NO_TTL; 374 if (noclass) 375 styleflags |= DNS_STYLEFLAG_NO_CLASS; 376 if (nocrypto) 377 styleflags |= DNS_STYLEFLAG_NOCRYPTO; 378 if (multiline) { 379 styleflags |= DNS_STYLEFLAG_OMIT_OWNER; 380 styleflags |= DNS_STYLEFLAG_OMIT_CLASS; 381 styleflags |= DNS_STYLEFLAG_REL_DATA; 382 styleflags |= DNS_STYLEFLAG_OMIT_TTL; 383 styleflags |= DNS_STYLEFLAG_TTL; 384 styleflags |= DNS_STYLEFLAG_MULTILINE; 385 /* Turn on rrcomments unless explicitly disabled */ 386 if (rrcomments >= 0) 387 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 388 } 389 if (multiline || (nottl && noclass)) 390 result = dns_master_stylecreate2(&style, styleflags, 391 24, 24, 24, 32, 80, 8, 392 splitwidth); 393 else if (nottl || noclass) 394 result = dns_master_stylecreate2(&style, styleflags, 395 24, 24, 32, 40, 80, 8, 396 splitwidth); 397 else 398 result = dns_master_stylecreate2(&style, styleflags, 399 24, 32, 40, 48, 80, 8, 400 splitwidth); 401 check_result(result, "dns_master_stylecreate"); 402 403 if (query->lookup->cmdline[0] != 0) { 404 if (!short_form) 405 fputs(query->lookup->cmdline, stdout); 406 query->lookup->cmdline[0]=0; 407 } 408 debug("printmessage(%s %s %s)", headers ? "headers" : "noheaders", 409 query->lookup->comments ? "comments" : "nocomments", 410 short_form ? "short_form" : "long_form"); 411 412 flags = 0; 413 if (!headers) { 414 flags |= DNS_MESSAGETEXTFLAG_NOHEADERS; 415 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 416 } 417 if (onesoa && query->lookup->rdtype == dns_rdatatype_axfr) 418 flags |= (query->msg_count == 0) ? DNS_MESSAGETEXTFLAG_ONESOA : 419 DNS_MESSAGETEXTFLAG_OMITSOA; 420 if (!query->lookup->comments) 421 flags |= DNS_MESSAGETEXTFLAG_NOCOMMENTS; 422 423 result = isc_buffer_allocate(&buf, len); 424 check_result(result, "isc_buffer_allocate"); 425 426 if (query->lookup->comments && !short_form) { 427 if (query->lookup->cmdline[0] != 0) 428 printf("; %s\n", query->lookup->cmdline); 429 if (msg == query->lookup->sendmsg) 430 printf(";; Sending:\n"); 431 else 432 printf(";; Got answer:\n"); 433 434 if (headers) { 435 if (isdotlocal(msg)) { 436 printf(";; WARNING: .local is reserved for " 437 "Multicast DNS\n;; You are currently " 438 "testing what happens when an mDNS " 439 "query is leaked to DNS\n"); 440 } 441 printf(";; ->>HEADER<<- opcode: %s, status: %s, " 442 "id: %u\n", 443 opcodetext[msg->opcode], 444 rcode_totext(msg->rcode), 445 msg->id); 446 printf(";; flags:"); 447 if ((msg->flags & DNS_MESSAGEFLAG_QR) != 0) 448 printf(" qr"); 449 if ((msg->flags & DNS_MESSAGEFLAG_AA) != 0) 450 printf(" aa"); 451 if ((msg->flags & DNS_MESSAGEFLAG_TC) != 0) 452 printf(" tc"); 453 if ((msg->flags & DNS_MESSAGEFLAG_RD) != 0) 454 printf(" rd"); 455 if ((msg->flags & DNS_MESSAGEFLAG_RA) != 0) 456 printf(" ra"); 457 if ((msg->flags & DNS_MESSAGEFLAG_AD) != 0) 458 printf(" ad"); 459 if ((msg->flags & DNS_MESSAGEFLAG_CD) != 0) 460 printf(" cd"); 461 if ((msg->flags & 0x0040U) != 0) 462 printf("; MBZ: 0x4"); 463 464 printf("; QUERY: %u, ANSWER: %u, " 465 "AUTHORITY: %u, ADDITIONAL: %u\n", 466 msg->counts[DNS_SECTION_QUESTION], 467 msg->counts[DNS_SECTION_ANSWER], 468 msg->counts[DNS_SECTION_AUTHORITY], 469 msg->counts[DNS_SECTION_ADDITIONAL]); 470 471 if (msg != query->lookup->sendmsg && 472 (msg->flags & DNS_MESSAGEFLAG_RD) != 0 && 473 (msg->flags & DNS_MESSAGEFLAG_RA) == 0) 474 printf(";; WARNING: recursion requested " 475 "but not available\n"); 476 } 477 if (msg != query->lookup->sendmsg && 478 query->lookup->edns != -1 && msg->opt == NULL && 479 (msg->rcode == dns_rcode_formerr || 480 msg->rcode == dns_rcode_notimp)) 481 printf("\n;; WARNING: EDNS query returned status " 482 "%s - retry with '%s+noedns'\n", 483 rcode_totext(msg->rcode), 484 query->lookup->dnssec ? "+nodnssec ": ""); 485 if (msg != query->lookup->sendmsg && extrabytes != 0U) 486 printf(";; WARNING: Message has %u extra byte%s at " 487 "end\n", extrabytes, extrabytes != 0 ? "s" : ""); 488 } 489 490 repopulate_buffer: 491 492 if (query->lookup->comments && headers && !short_form) { 493 result = dns_message_pseudosectiontotext(msg, 494 DNS_PSEUDOSECTION_OPT, 495 style, flags, buf); 496 if (result == ISC_R_NOSPACE) { 497 buftoosmall: 498 len += OUTPUTBUF; 499 isc_buffer_free(&buf); 500 result = isc_buffer_allocate(&buf, len); 501 if (result == ISC_R_SUCCESS) 502 goto repopulate_buffer; 503 else 504 goto cleanup; 505 } 506 check_result(result, 507 "dns_message_pseudosectiontotext"); 508 } 509 510 if (query->lookup->section_question && headers) { 511 if (!short_form) { 512 result = dns_message_sectiontotext(msg, 513 DNS_SECTION_QUESTION, 514 style, flags, buf); 515 if (result == ISC_R_NOSPACE) 516 goto buftoosmall; 517 check_result(result, "dns_message_sectiontotext"); 518 } 519 } 520 if (query->lookup->section_answer) { 521 if (!short_form) { 522 result = dns_message_sectiontotext(msg, 523 DNS_SECTION_ANSWER, 524 style, flags, buf); 525 if (result == ISC_R_NOSPACE) 526 goto buftoosmall; 527 check_result(result, "dns_message_sectiontotext"); 528 } else { 529 result = short_answer(msg, flags, buf, query); 530 if (result == ISC_R_NOSPACE) 531 goto buftoosmall; 532 check_result(result, "short_answer"); 533 } 534 } 535 if (query->lookup->section_authority) { 536 if (!short_form) { 537 result = dns_message_sectiontotext(msg, 538 DNS_SECTION_AUTHORITY, 539 style, flags, buf); 540 if (result == ISC_R_NOSPACE) 541 goto buftoosmall; 542 check_result(result, "dns_message_sectiontotext"); 543 } 544 } 545 if (query->lookup->section_additional) { 546 if (!short_form) { 547 result = dns_message_sectiontotext(msg, 548 DNS_SECTION_ADDITIONAL, 549 style, flags, buf); 550 if (result == ISC_R_NOSPACE) 551 goto buftoosmall; 552 check_result(result, "dns_message_sectiontotext"); 553 /* 554 * Only print the signature on the first record. 555 */ 556 if (headers) { 557 result = dns_message_pseudosectiontotext( 558 msg, 559 DNS_PSEUDOSECTION_TSIG, 560 style, flags, buf); 561 if (result == ISC_R_NOSPACE) 562 goto buftoosmall; 563 check_result(result, 564 "dns_message_pseudosectiontotext"); 565 result = dns_message_pseudosectiontotext( 566 msg, 567 DNS_PSEUDOSECTION_SIG0, 568 style, flags, buf); 569 if (result == ISC_R_NOSPACE) 570 goto buftoosmall; 571 check_result(result, 572 "dns_message_pseudosectiontotext"); 573 } 574 } 575 } 576 577 if (headers && query->lookup->comments && !short_form) 578 printf("\n"); 579 580 printf("%.*s", (int)isc_buffer_usedlength(buf), 581 (char *)isc_buffer_base(buf)); 582 isc_buffer_free(&buf); 583 584 cleanup: 585 if (style != NULL) 586 dns_master_styledestroy(&style); 587 return (result); 588 } 589 590 /*% 591 * print the greeting message when the program first starts up. 592 */ 593 static void 594 printgreeting(int argc, char **argv, dig_lookup_t *lookup) { 595 int i; 596 static isc_boolean_t first = ISC_TRUE; 597 char append[MXNAME]; 598 599 if (printcmd) { 600 snprintf(lookup->cmdline, sizeof(lookup->cmdline), 601 "%s; <<>> dig " VERSION " <<>>", 602 first?"\n":""); 603 i = 1; 604 while (i < argc) { 605 snprintf(append, sizeof(append), " %s", argv[i++]); 606 strlcat(lookup->cmdline, append, 607 sizeof(lookup->cmdline)); 608 } 609 strlcat(lookup->cmdline, "\n", sizeof(lookup->cmdline)); 610 if (first && addresscount != 0) { 611 snprintf(append, sizeof(append), 612 "; (%d server%s found)\n", 613 addresscount, 614 addresscount > 1 ? "s" : ""); 615 strlcat(lookup->cmdline, append, 616 sizeof(lookup->cmdline)); 617 } 618 if (first) { 619 snprintf(append, sizeof(append), 620 ";; global options:%s%s\n", 621 short_form ? " +short" : "", 622 printcmd ? " +cmd" : ""); 623 first = ISC_FALSE; 624 strlcat(lookup->cmdline, append, 625 sizeof(lookup->cmdline)); 626 } 627 } 628 } 629 630 static void 631 plus_option(const char *option, isc_boolean_t is_batchfile, 632 dig_lookup_t *lookup) 633 { 634 isc_result_t result; 635 char option_store[256]; 636 char *cmd, *value, *ptr, *code; 637 uint32_t num; 638 isc_boolean_t state = ISC_TRUE; 639 size_t n; 640 641 strlcpy(option_store, option, sizeof(option_store)); 642 ptr = option_store; 643 cmd = next_token(&ptr, "="); 644 if (cmd == NULL) { 645 printf(";; Invalid option %s\n", option_store); 646 return; 647 } 648 value = ptr; 649 if (strncasecmp(cmd, "no", 2)==0) { 650 cmd += 2; 651 state = ISC_FALSE; 652 } 653 654 #define FULLCHECK(A) \ 655 do { \ 656 size_t _l = strlen(cmd); \ 657 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 658 goto invalid_option; \ 659 } while (0) 660 #define FULLCHECK2(A, B) \ 661 do { \ 662 size_t _l = strlen(cmd); \ 663 if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ 664 (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ 665 goto invalid_option; \ 666 } while (0) 667 668 switch (cmd[0]) { 669 case 'a': 670 switch (cmd[1]) { 671 case 'a': /* aaonly / aaflag */ 672 FULLCHECK2("aaonly", "aaflag"); 673 lookup->aaonly = state; 674 break; 675 case 'd': 676 switch (cmd[2]) { 677 case 'd': /* additional */ 678 FULLCHECK("additional"); 679 lookup->section_additional = state; 680 break; 681 case 'f': /* adflag */ 682 case '\0': /* +ad is a synonym for +adflag */ 683 FULLCHECK("adflag"); 684 lookup->adflag = state; 685 break; 686 default: 687 goto invalid_option; 688 } 689 break; 690 case 'l': /* all */ 691 FULLCHECK("all"); 692 lookup->section_question = state; 693 lookup->section_authority = state; 694 lookup->section_answer = state; 695 lookup->section_additional = state; 696 lookup->comments = state; 697 lookup->stats = state; 698 printcmd = state; 699 break; 700 case 'n': /* answer */ 701 FULLCHECK("answer"); 702 lookup->section_answer = state; 703 break; 704 case 'u': /* authority */ 705 FULLCHECK("authority"); 706 lookup->section_authority = state; 707 break; 708 default: 709 goto invalid_option; 710 } 711 break; 712 case 'b': 713 switch (cmd[1]) { 714 case 'e':/* besteffort */ 715 FULLCHECK("besteffort"); 716 lookup->besteffort = state; 717 break; 718 case 'u':/* bufsize */ 719 FULLCHECK("bufsize"); 720 if (value == NULL) 721 goto need_value; 722 if (!state) 723 goto invalid_option; 724 result = parse_uint(&num, value, COMMSIZE, 725 "buffer size"); 726 if (result != ISC_R_SUCCESS) 727 fatal("Couldn't parse buffer size"); 728 lookup->udpsize = num; 729 break; 730 default: 731 goto invalid_option; 732 } 733 break; 734 case 'c': 735 switch (cmd[1]) { 736 case 'd':/* cdflag */ 737 switch (cmd[2]) { 738 case 'f': /* cdflag */ 739 case '\0': /* +cd is a synonym for +cdflag */ 740 FULLCHECK("cdflag"); 741 lookup->cdflag = state; 742 break; 743 default: 744 goto invalid_option; 745 } 746 break; 747 case 'l': /* class */ 748 /* keep +cl for backwards compatibility */ 749 FULLCHECK2("cl", "class"); 750 noclass = ISC_TF(!state); 751 break; 752 case 'm': /* cmd */ 753 FULLCHECK("cmd"); 754 printcmd = state; 755 break; 756 case 'o': /* comments */ 757 switch (cmd[2]) { 758 case 'o': 759 FULLCHECK("cookie"); 760 goto sit; 761 case 'm': 762 FULLCHECK("comments"); 763 lookup->comments = state; 764 if (lookup == default_lookup) 765 pluscomm = state; 766 break; 767 default: 768 goto invalid_option; 769 } 770 break; 771 case 'r': 772 FULLCHECK("crypto"); 773 nocrypto = ISC_TF(!state); 774 break; 775 default: 776 goto invalid_option; 777 } 778 break; 779 case 'd': 780 switch (cmd[1]) { 781 case 'e': /* defname */ 782 FULLCHECK("defname"); 783 if (!lookup->trace) { 784 usesearch = state; 785 } 786 break; 787 case 'n': /* dnssec */ 788 FULLCHECK("dnssec"); 789 if (state && lookup->edns == -1) 790 lookup->edns = 0; 791 lookup->dnssec = state; 792 break; 793 case 'o': /* domain */ 794 FULLCHECK("domain"); 795 if (value == NULL) 796 goto need_value; 797 if (!state) 798 goto invalid_option; 799 strlcpy(domainopt, value, sizeof(domainopt)); 800 break; 801 default: 802 goto invalid_option; 803 } 804 break; 805 case 'e': 806 switch (cmd[1]) { 807 case 'd': 808 switch(cmd[2]) { 809 case 'n': 810 switch (cmd[3]) { 811 case 's': 812 switch (cmd[4]) { 813 case 0: 814 FULLCHECK("edns"); 815 if (!state) { 816 lookup->edns = -1; 817 break; 818 } 819 if (value == NULL) { 820 lookup->edns = 0; 821 break; 822 } 823 result = parse_uint(&num, 824 value, 825 255, 826 "edns"); 827 if (result != ISC_R_SUCCESS) 828 fatal("Couldn't parse " 829 "edns"); 830 lookup->edns = num; 831 break; 832 case 'f': 833 FULLCHECK("ednsflags"); 834 if (!state) { 835 lookup->ednsflags = 0; 836 break; 837 } 838 if (value == NULL) { 839 lookup->ednsflags = 0; 840 break; 841 } 842 result = parse_xint(&num, 843 value, 844 0xffff, 845 "ednsflags"); 846 if (result != ISC_R_SUCCESS) 847 fatal("Couldn't parse " 848 "ednsflags"); 849 lookup->ednsflags = num; 850 break; 851 case 'n': 852 FULLCHECK("ednsnegotiation"); 853 lookup->ednsneg = state; 854 break; 855 case 'o': 856 FULLCHECK("ednsopt"); 857 if (!state) { 858 lookup->ednsoptscnt = 0; 859 break; 860 } 861 if (value == NULL) 862 fatal("ednsopt no " 863 "code point " 864 "specified"); 865 code = next_token(&value, ":"); 866 save_opt(lookup, code, value); 867 break; 868 default: 869 goto invalid_option; 870 } 871 break; 872 default: 873 goto invalid_option; 874 } 875 break; 876 default: 877 goto invalid_option; 878 } 879 break; 880 case 'x': 881 FULLCHECK("expire"); 882 lookup->expire = state; 883 break; 884 default: 885 goto invalid_option; 886 } 887 break; 888 case 'f': /* fail */ 889 FULLCHECK("fail"); 890 lookup->servfail_stops = state; 891 break; 892 case 'i': 893 switch (cmd[1]) { 894 case 'd': /* identify */ 895 switch (cmd[2]) { 896 case 'e': 897 FULLCHECK("identify"); 898 lookup->identify = state; 899 break; 900 case 'n': 901 FULLCHECK("idnout"); 902 fprintf(stderr, ";; IDN support not enabled\n"); 903 break; 904 default: 905 goto invalid_option; 906 } 907 break; 908 case 'g': /* ignore */ 909 default: /* 910 * Inherits default for compatibility (+[no]i*). 911 */ 912 FULLCHECK("ignore"); 913 lookup->ignore = state; 914 } 915 break; 916 case 'k': 917 FULLCHECK("keepopen"); 918 keep_open = state; 919 break; 920 case 'm': /* multiline */ 921 FULLCHECK("multiline"); 922 multiline = state; 923 break; 924 case 'n': 925 switch (cmd[1]) { 926 case 'd': /* ndots */ 927 FULLCHECK("ndots"); 928 if (value == NULL) 929 goto need_value; 930 if (!state) 931 goto invalid_option; 932 result = parse_uint(&num, value, MAXNDOTS, "ndots"); 933 if (result != ISC_R_SUCCESS) 934 fatal("Couldn't parse ndots"); 935 ndots = num; 936 break; 937 case 's': 938 switch (cmd[2]) { 939 case 'i': /* nsid */ 940 FULLCHECK("nsid"); 941 if (state && lookup->edns == -1) 942 lookup->edns = 0; 943 lookup->nsid = state; 944 break; 945 case 's': /* nssearch */ 946 FULLCHECK("nssearch"); 947 lookup->ns_search_only = state; 948 if (state) { 949 lookup->trace_root = ISC_TRUE; 950 lookup->recurse = ISC_TRUE; 951 lookup->identify = ISC_TRUE; 952 lookup->stats = ISC_FALSE; 953 lookup->comments = ISC_FALSE; 954 lookup->section_additional = ISC_FALSE; 955 lookup->section_authority = ISC_FALSE; 956 lookup->section_question = ISC_FALSE; 957 lookup->rdtype = dns_rdatatype_ns; 958 lookup->rdtypeset = ISC_TRUE; 959 short_form = ISC_TRUE; 960 rrcomments = 0; 961 } 962 break; 963 default: 964 goto invalid_option; 965 } 966 break; 967 default: 968 goto invalid_option; 969 } 970 break; 971 case 'o': 972 switch (cmd[1]) { 973 case 'n': 974 FULLCHECK("onesoa"); 975 onesoa = state; 976 break; 977 case 'p': 978 FULLCHECK("opcode"); 979 if (!state) { 980 lookup->opcode = 0; /* default - query */ 981 break; 982 } 983 if (value == NULL) 984 goto need_value; 985 for (num = 0; 986 num < sizeof(opcodetext)/sizeof(opcodetext[0]); 987 num++) { 988 if (strcasecmp(opcodetext[num], value) == 0) 989 break; 990 } 991 if (num < 16) { 992 lookup->opcode = (dns_opcode_t)num; 993 break; 994 } 995 result = parse_uint(&num, value, 15, "opcode"); 996 if (result != ISC_R_SUCCESS) 997 fatal("Couldn't parse opcode"); 998 lookup->opcode = (dns_opcode_t)num; 999 break; 1000 default: 1001 goto invalid_option; 1002 } 1003 break; 1004 case 'q': 1005 switch (cmd[1]) { 1006 case 'r': /* qr */ 1007 FULLCHECK("qr"); 1008 qr = state; 1009 break; 1010 case 'u': /* question */ 1011 FULLCHECK("question"); 1012 lookup->section_question = state; 1013 if (lookup == default_lookup) 1014 plusquest = state; 1015 break; 1016 default: 1017 goto invalid_option; 1018 } 1019 break; 1020 case 'r': 1021 switch (cmd[1]) { 1022 case 'd': /* rdflag */ 1023 FULLCHECK("rdflag"); 1024 lookup->recurse = state; 1025 break; 1026 case 'e': 1027 switch (cmd[2]) { 1028 case 'c': /* recurse */ 1029 FULLCHECK("recurse"); 1030 lookup->recurse = state; 1031 break; 1032 case 't': /* retry / retries */ 1033 FULLCHECK2("retry", "retries"); 1034 if (value == NULL) 1035 goto need_value; 1036 if (!state) 1037 goto invalid_option; 1038 result = parse_uint(&lookup->retries, value, 1039 MAXTRIES - 1, "retries"); 1040 if (result != ISC_R_SUCCESS) 1041 fatal("Couldn't parse retries"); 1042 lookup->retries++; 1043 break; 1044 default: 1045 goto invalid_option; 1046 } 1047 break; 1048 case 'r': /* rrcomments */ 1049 FULLCHECK("rrcomments"); 1050 rrcomments = state ? 1 : -1; 1051 break; 1052 default: 1053 goto invalid_option; 1054 } 1055 break; 1056 case 's': 1057 switch (cmd[1]) { 1058 case 'e': /* search */ 1059 FULLCHECK("search"); 1060 if (!lookup->trace) { 1061 usesearch = state; 1062 } 1063 break; 1064 case 'h': 1065 if (cmd[2] != 'o') 1066 goto invalid_option; 1067 switch (cmd[3]) { 1068 case 'r': /* short */ 1069 FULLCHECK("short"); 1070 short_form = state; 1071 if (state) { 1072 printcmd = ISC_FALSE; 1073 lookup->section_additional = ISC_FALSE; 1074 lookup->section_answer = ISC_TRUE; 1075 lookup->section_authority = ISC_FALSE; 1076 lookup->section_question = ISC_FALSE; 1077 lookup->comments = ISC_FALSE; 1078 lookup->stats = ISC_FALSE; 1079 rrcomments = -1; 1080 } 1081 break; 1082 case 'w': /* showsearch */ 1083 FULLCHECK("showsearch"); 1084 if (!lookup->trace) { 1085 showsearch = state; 1086 usesearch = state; 1087 } 1088 break; 1089 default: 1090 goto invalid_option; 1091 } 1092 break; 1093 case 'i': 1094 switch (cmd[2]) { 1095 case 't': /* sit */ 1096 FULLCHECK("sit"); 1097 sit: 1098 if (state && lookup->edns == -1) 1099 lookup->edns = 0; 1100 lookup->sit = state; 1101 if (value != NULL) { 1102 n = strlcpy(sitvalue, value, 1103 sizeof(sitvalue)); 1104 if (n >= sizeof(sitvalue)) 1105 fatal("SIT data too large"); 1106 lookup->sitvalue = sitvalue; 1107 } else 1108 lookup->sitvalue = NULL; 1109 break; 1110 default: 1111 goto invalid_option; 1112 } 1113 break; 1114 case 'p': /* split */ 1115 FULLCHECK("split"); 1116 if (value != NULL && !state) 1117 goto invalid_option; 1118 if (!state) { 1119 splitwidth = 0; 1120 break; 1121 } else if (value == NULL) 1122 break; 1123 1124 result = parse_uint(&splitwidth, value, 1125 1023, "split"); 1126 if ((splitwidth % 4) != 0U) { 1127 splitwidth = ((splitwidth + 3) / 4) * 4; 1128 fprintf(stderr, ";; Warning, split must be " 1129 "a multiple of 4; adjusting " 1130 "to %u\n", splitwidth); 1131 } 1132 /* 1133 * There is an adjustment done in the 1134 * totext_<rrtype>() functions which causes 1135 * splitwidth to shrink. This is okay when we're 1136 * using the default width but incorrect in this 1137 * case, so we correct for it 1138 */ 1139 if (splitwidth) 1140 splitwidth += 3; 1141 if (result != ISC_R_SUCCESS) 1142 fatal("Couldn't parse split"); 1143 break; 1144 case 't': /* stats */ 1145 FULLCHECK("stats"); 1146 lookup->stats = state; 1147 break; 1148 case 'u': /* subnet */ 1149 FULLCHECK("subnet"); 1150 if (state && value == NULL) 1151 goto need_value; 1152 if (!state) { 1153 if (lookup->ecs_addr != NULL) { 1154 free(lookup->ecs_addr); 1155 lookup->ecs_addr = NULL; 1156 } 1157 break; 1158 } 1159 if (lookup->edns == -1) 1160 lookup->edns = 0; 1161 if (lookup->ecs_addr != NULL) { 1162 free(lookup->ecs_addr); 1163 lookup->ecs_addr = NULL; 1164 } 1165 result = parse_netprefix(&lookup->ecs_addr, value); 1166 if (result != ISC_R_SUCCESS) 1167 fatal("Couldn't parse client"); 1168 break; 1169 default: 1170 goto invalid_option; 1171 } 1172 break; 1173 case 't': 1174 switch (cmd[1]) { 1175 case 'c': /* tcp */ 1176 FULLCHECK("tcp"); 1177 if (!is_batchfile) { 1178 lookup->tcp_mode = state; 1179 lookup->tcp_mode_set = ISC_TRUE; 1180 } 1181 break; 1182 case 'i': /* timeout */ 1183 FULLCHECK("timeout"); 1184 if (value == NULL) 1185 goto need_value; 1186 if (!state) 1187 goto invalid_option; 1188 result = parse_uint(&timeout, value, MAXTIMEOUT, 1189 "timeout"); 1190 if (result != ISC_R_SUCCESS) 1191 fatal("Couldn't parse timeout"); 1192 if (timeout == 0) 1193 timeout = 1; 1194 break; 1195 case 'r': 1196 switch (cmd[2]) { 1197 case 'a': /* trace */ 1198 FULLCHECK("trace"); 1199 lookup->trace = state; 1200 lookup->trace_root = state; 1201 if (state) { 1202 lookup->recurse = ISC_FALSE; 1203 lookup->identify = ISC_TRUE; 1204 lookup->comments = ISC_FALSE; 1205 rrcomments = 0; 1206 lookup->stats = ISC_FALSE; 1207 lookup->section_additional = ISC_FALSE; 1208 lookup->section_authority = ISC_TRUE; 1209 lookup->section_question = ISC_FALSE; 1210 lookup->dnssec = ISC_TRUE; 1211 usesearch = ISC_FALSE; 1212 } 1213 break; 1214 case 'i': /* tries */ 1215 FULLCHECK("tries"); 1216 if (value == NULL) 1217 goto need_value; 1218 if (!state) 1219 goto invalid_option; 1220 result = parse_uint(&lookup->retries, value, 1221 MAXTRIES, "tries"); 1222 if (result != ISC_R_SUCCESS) 1223 fatal("Couldn't parse tries"); 1224 if (lookup->retries == 0) 1225 lookup->retries = 1; 1226 break; 1227 default: 1228 goto invalid_option; 1229 } 1230 break; 1231 case 't': /* ttlid */ 1232 FULLCHECK("ttlid"); 1233 nottl = ISC_TF(!state); 1234 break; 1235 default: 1236 goto invalid_option; 1237 } 1238 break; 1239 case 'v': 1240 FULLCHECK("vc"); 1241 if (!is_batchfile) { 1242 lookup->tcp_mode = state; 1243 lookup->tcp_mode_set = ISC_TRUE; 1244 } 1245 break; 1246 default: 1247 invalid_option: 1248 need_value: 1249 fprintf(stderr, "Invalid option: +%s\n", 1250 option); 1251 usage(); 1252 } 1253 return; 1254 } 1255 1256 /*% 1257 * #ISC_TRUE returned if value was used 1258 */ 1259 static const char *single_dash_opts = "46dhinuv"; 1260 static const char *dash_opts = "46bcdfhikmnptvyx"; 1261 static isc_boolean_t 1262 dash_option(char *option, char *next, dig_lookup_t **lookup, 1263 isc_boolean_t *open_type_class, isc_boolean_t *need_clone, 1264 isc_boolean_t config_only, int argc, char **argv, 1265 isc_boolean_t *firstarg) 1266 { 1267 char opt, *value, *ptr, *ptr2, *ptr3; 1268 isc_result_t result; 1269 isc_boolean_t value_from_next; 1270 isc_textregion_t tr; 1271 dns_rdatatype_t rdtype; 1272 dns_rdataclass_t rdclass; 1273 char textname[MXNAME]; 1274 struct in_addr in4; 1275 struct in6_addr in6; 1276 in_port_t srcport; 1277 char *hash, *cmd; 1278 uint32_t num; 1279 1280 while (strpbrk(option, single_dash_opts) == &option[0]) { 1281 /* 1282 * Since the -[46dhinuv] options do not take an argument, 1283 * account for them (in any number and/or combination) 1284 * if they appear as the first character(s) of a q-opt. 1285 */ 1286 opt = option[0]; 1287 switch (opt) { 1288 case '4': 1289 if (have_ipv4) { 1290 isc_net_disableipv6(); 1291 have_ipv6 = ISC_FALSE; 1292 } else { 1293 fatal("can't find IPv4 networking"); 1294 /* NOTREACHED */ 1295 return (ISC_FALSE); 1296 } 1297 break; 1298 case '6': 1299 if (have_ipv6) { 1300 isc_net_disableipv4(); 1301 have_ipv4 = ISC_FALSE; 1302 } else { 1303 fatal("can't find IPv6 networking"); 1304 /* NOTREACHED */ 1305 return (ISC_FALSE); 1306 } 1307 break; 1308 case 'd': 1309 ptr = strpbrk(&option[1], dash_opts); 1310 if (ptr != &option[1]) { 1311 cmd = option; 1312 FULLCHECK("debug"); 1313 debugging = ISC_TRUE; 1314 return (ISC_FALSE); 1315 } else 1316 debugging = ISC_TRUE; 1317 break; 1318 case 'h': 1319 help(); 1320 exit(0); 1321 break; 1322 case 'i': 1323 ip6_int = ISC_TRUE; 1324 break; 1325 case 'n': 1326 /* deprecated */ 1327 break; 1328 case 'u': 1329 use_usec = ISC_TRUE; 1330 break; 1331 case 'v': 1332 version(); 1333 exit(0); 1334 break; 1335 } 1336 if (strlen(option) > 1U) 1337 option = &option[1]; 1338 else 1339 return (ISC_FALSE); 1340 } 1341 opt = option[0]; 1342 if (strlen(option) > 1U) { 1343 value_from_next = ISC_FALSE; 1344 value = &option[1]; 1345 } else { 1346 value_from_next = ISC_TRUE; 1347 value = next; 1348 } 1349 if (value == NULL) 1350 goto invalid_option; 1351 switch (opt) { 1352 case 'b': 1353 hash = strchr(value, '#'); 1354 if (hash != NULL) { 1355 result = parse_uint(&num, hash + 1, MAXPORT, 1356 "port number"); 1357 if (result != ISC_R_SUCCESS) 1358 fatal("Couldn't parse port number"); 1359 srcport = num; 1360 *hash = '\0'; 1361 } else 1362 srcport = 0; 1363 if (have_ipv6 && inet_pton(AF_INET6, value, &in6) == 1) { 1364 isc_sockaddr_fromin6(&bind_address, &in6, srcport); 1365 isc_net_disableipv4(); 1366 } else if (have_ipv4 && inet_pton(AF_INET, value, &in4) == 1) { 1367 isc_sockaddr_fromin(&bind_address, &in4, srcport); 1368 isc_net_disableipv6(); 1369 } else { 1370 if (hash != NULL) 1371 *hash = '#'; 1372 fatal("invalid address %s", value); 1373 } 1374 if (hash != NULL) 1375 *hash = '#'; 1376 specified_source = ISC_TRUE; 1377 return (value_from_next); 1378 case 'c': 1379 if ((*lookup)->rdclassset) { 1380 fprintf(stderr, ";; Warning, extra class option\n"); 1381 } 1382 *open_type_class = ISC_FALSE; 1383 tr.base = value; 1384 tr.length = (unsigned int) strlen(value); 1385 result = dns_rdataclass_fromtext(&rdclass, 1386 (isc_textregion_t *)&tr); 1387 if (result == ISC_R_SUCCESS) { 1388 (*lookup)->rdclass = rdclass; 1389 (*lookup)->rdclassset = ISC_TRUE; 1390 } else 1391 fprintf(stderr, ";; Warning, ignoring " 1392 "invalid class %s\n", 1393 value); 1394 return (value_from_next); 1395 case 'f': 1396 batchname = value; 1397 return (value_from_next); 1398 case 'k': 1399 strlcpy(keyfile, value, sizeof(keyfile)); 1400 return (value_from_next); 1401 case 'p': 1402 result = parse_uint(&num, value, MAXPORT, "port number"); 1403 if (result != ISC_R_SUCCESS) 1404 fatal("Couldn't parse port number"); 1405 port = num; 1406 return (value_from_next); 1407 case 'q': 1408 if (!config_only) { 1409 if (*need_clone) 1410 (*lookup) = clone_lookup(default_lookup, 1411 ISC_TRUE); 1412 *need_clone = ISC_TRUE; 1413 strlcpy((*lookup)->textname, value, 1414 sizeof((*lookup)->textname)); 1415 (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1416 (*lookup)->ns_search_only); 1417 (*lookup)->new_search = ISC_TRUE; 1418 if (*firstarg) { 1419 printgreeting(argc, argv, *lookup); 1420 *firstarg = ISC_FALSE; 1421 } 1422 ISC_LIST_APPEND(lookup_list, (*lookup), link); 1423 debug("looking up %s", (*lookup)->textname); 1424 } 1425 return (value_from_next); 1426 case 't': 1427 *open_type_class = ISC_FALSE; 1428 if (strncasecmp(value, "ixfr=", 5) == 0) { 1429 rdtype = dns_rdatatype_ixfr; 1430 result = ISC_R_SUCCESS; 1431 } else { 1432 tr.base = value; 1433 tr.length = (unsigned int) strlen(value); 1434 result = dns_rdatatype_fromtext(&rdtype, 1435 (isc_textregion_t *)&tr); 1436 if (result == ISC_R_SUCCESS && 1437 rdtype == dns_rdatatype_ixfr) { 1438 result = DNS_R_UNKNOWN; 1439 } 1440 } 1441 if (result == ISC_R_SUCCESS) { 1442 if ((*lookup)->rdtypeset) { 1443 fprintf(stderr, ";; Warning, " 1444 "extra type option\n"); 1445 } 1446 if (rdtype == dns_rdatatype_ixfr) { 1447 uint32_t serial; 1448 (*lookup)->rdtype = dns_rdatatype_ixfr; 1449 (*lookup)->rdtypeset = ISC_TRUE; 1450 result = parse_uint(&serial, &value[5], 1451 MAXSERIAL, "serial number"); 1452 if (result != ISC_R_SUCCESS) 1453 fatal("Couldn't parse serial number"); 1454 (*lookup)->ixfr_serial = serial; 1455 (*lookup)->section_question = plusquest; 1456 (*lookup)->comments = pluscomm; 1457 if (!(*lookup)->tcp_mode_set) 1458 (*lookup)->tcp_mode = ISC_TRUE; 1459 } else { 1460 (*lookup)->rdtype = rdtype; 1461 if (!config_only) 1462 (*lookup)->rdtypeset = ISC_TRUE; 1463 if (rdtype == dns_rdatatype_axfr) { 1464 (*lookup)->section_question = plusquest; 1465 (*lookup)->comments = pluscomm; 1466 } 1467 (*lookup)->ixfr_serial = ISC_FALSE; 1468 } 1469 } else 1470 fprintf(stderr, ";; Warning, ignoring " 1471 "invalid type %s\n", 1472 value); 1473 return (value_from_next); 1474 case 'y': 1475 ptr = next_token(&value, ":"); /* hmac type or name */ 1476 if (ptr == NULL) { 1477 usage(); 1478 } 1479 ptr2 = next_token(&value, ":"); /* name or secret */ 1480 if (ptr2 == NULL) 1481 usage(); 1482 ptr3 = next_token(&value, ":"); /* secret or NULL */ 1483 if (ptr3 != NULL) { 1484 parse_hmac(ptr); 1485 ptr = ptr2; 1486 ptr2 = ptr3; 1487 } else { 1488 hmacname = DNS_TSIG_HMACSHA256_NAME; 1489 digestbits = 0; 1490 } 1491 strlcpy(keynametext, ptr, sizeof(keynametext)); 1492 strlcpy(keysecret, ptr2, sizeof(keysecret)); 1493 return (value_from_next); 1494 case 'x': 1495 if (*need_clone) 1496 *lookup = clone_lookup(default_lookup, ISC_TRUE); 1497 *need_clone = ISC_TRUE; 1498 if (get_reverse(textname, sizeof(textname), value, 1499 ip6_int, ISC_FALSE) == ISC_R_SUCCESS) { 1500 strlcpy((*lookup)->textname, textname, 1501 sizeof((*lookup)->textname)); 1502 debug("looking up %s", (*lookup)->textname); 1503 (*lookup)->trace_root = ISC_TF((*lookup)->trace || 1504 (*lookup)->ns_search_only); 1505 (*lookup)->ip6_int = ip6_int; 1506 if (!(*lookup)->rdtypeset) 1507 (*lookup)->rdtype = dns_rdatatype_ptr; 1508 if (!(*lookup)->rdclassset) 1509 (*lookup)->rdclass = dns_rdataclass_in; 1510 (*lookup)->new_search = ISC_TRUE; 1511 if (*firstarg) { 1512 printgreeting(argc, argv, *lookup); 1513 *firstarg = ISC_FALSE; 1514 } 1515 ISC_LIST_APPEND(lookup_list, *lookup, link); 1516 } else { 1517 fprintf(stderr, "Invalid IP address %s\n", value); 1518 exit(1); 1519 } 1520 return (value_from_next); 1521 invalid_option: 1522 default: 1523 fprintf(stderr, "Invalid option: -%s\n", option); 1524 usage(); 1525 } 1526 /* NOTREACHED */ 1527 return (ISC_FALSE); 1528 } 1529 1530 /*% 1531 * Because we may be trying to do memory allocation recording, we're going 1532 * to need to parse the arguments for the -m *before* we start the main 1533 * argument parsing routine. 1534 * 1535 * I'd prefer not to have to do this, but I am not quite sure how else to 1536 * fix the problem. Argument parsing in dig involves memory allocation 1537 * by its nature, so it can't be done in the main argument parser. 1538 */ 1539 static void 1540 preparse_args(int argc, char **argv) { 1541 int rc; 1542 char **rv; 1543 char *option; 1544 1545 rc = argc; 1546 rv = argv; 1547 for (rc--, rv++; rc > 0; rc--, rv++) { 1548 if (rv[0][0] != '-') 1549 continue; 1550 option = &rv[0][1]; 1551 while (strpbrk(option, single_dash_opts) == &option[0]) { 1552 switch (option[0]) { 1553 case '4': 1554 if (ipv6only) 1555 fatal("only one of -4 and -6 allowed"); 1556 ipv4only = ISC_TRUE; 1557 break; 1558 case '6': 1559 if (ipv4only) 1560 fatal("only one of -4 and -6 allowed"); 1561 ipv6only = ISC_TRUE; 1562 break; 1563 } 1564 option = &option[1]; 1565 } 1566 } 1567 } 1568 1569 static void 1570 parse_args(isc_boolean_t is_batchfile, isc_boolean_t config_only, 1571 int argc, char **argv) 1572 { 1573 isc_result_t result; 1574 isc_textregion_t tr; 1575 isc_boolean_t firstarg = ISC_TRUE; 1576 dig_lookup_t *lookup = NULL; 1577 dns_rdatatype_t rdtype; 1578 dns_rdataclass_t rdclass; 1579 isc_boolean_t open_type_class = ISC_TRUE; 1580 char batchline[MXNAME]; 1581 int bargc; 1582 char *bargv[64]; 1583 int rc; 1584 char **rv; 1585 char *input; 1586 int i; 1587 isc_boolean_t need_clone = ISC_TRUE; 1588 1589 /* 1590 * The semantics for parsing the args is a bit complex; if 1591 * we don't have a host yet, make the arg apply globally, 1592 * otherwise make it apply to the latest host. This is 1593 * a bit different than the previous versions, but should 1594 * form a consistent user interface. 1595 * 1596 * First, create a "default lookup" which won't actually be used 1597 * anywhere, except for cloning into new lookups 1598 */ 1599 1600 debug("parse_args()"); 1601 if (!is_batchfile) { 1602 debug("making new lookup"); 1603 default_lookup = make_empty_lookup(); 1604 default_lookup->adflag = ISC_TRUE; 1605 default_lookup->edns = 0; 1606 } 1607 1608 if (is_batchfile && !config_only) { 1609 /* Processing '-f batchfile'. */ 1610 lookup = clone_lookup(default_lookup, ISC_TRUE); 1611 need_clone = ISC_FALSE; 1612 } else 1613 lookup = default_lookup; 1614 1615 rc = argc; 1616 rv = argv; 1617 for (rc--, rv++; rc > 0; rc--, rv++) { 1618 debug("main parsing %s", rv[0]); 1619 if (strncmp(rv[0], "%", 1) == 0) 1620 break; 1621 if (rv[0][0] == '@') { 1622 1623 if (is_batchfile && !config_only) { 1624 addresscount = getaddresses(lookup, &rv[0][1], 1625 &result); 1626 if (result != ISC_R_SUCCESS) { 1627 fprintf(stderr, "couldn't get address " 1628 "for '%s': %s: skipping " 1629 "lookup\n", &rv[0][1], 1630 isc_result_totext(result)); 1631 if (ISC_LINK_LINKED(lookup, link)) 1632 ISC_LIST_DEQUEUE(lookup_list, 1633 lookup, link); 1634 destroy_lookup(lookup); 1635 return; 1636 } 1637 } else 1638 addresscount = getaddresses(lookup, &rv[0][1], 1639 NULL); 1640 } else if (rv[0][0] == '+') { 1641 plus_option(&rv[0][1], is_batchfile, 1642 lookup); 1643 } else if (rv[0][0] == '-') { 1644 if (rc <= 1) { 1645 if (dash_option(&rv[0][1], NULL, 1646 &lookup, &open_type_class, 1647 &need_clone, config_only, 1648 argc, argv, &firstarg)) { 1649 rc--; 1650 rv++; 1651 } 1652 } else { 1653 if (dash_option(&rv[0][1], rv[1], 1654 &lookup, &open_type_class, 1655 &need_clone, config_only, 1656 argc, argv, &firstarg)) { 1657 rc--; 1658 rv++; 1659 } 1660 } 1661 } else { 1662 /* 1663 * Anything which isn't an option 1664 */ 1665 if (open_type_class) { 1666 if (strncasecmp(rv[0], "ixfr=", 5) == 0) { 1667 rdtype = dns_rdatatype_ixfr; 1668 result = ISC_R_SUCCESS; 1669 } else { 1670 tr.base = rv[0]; 1671 tr.length = 1672 (unsigned int) strlen(rv[0]); 1673 result = dns_rdatatype_fromtext(&rdtype, 1674 (isc_textregion_t *)&tr); 1675 if (result == ISC_R_SUCCESS && 1676 rdtype == dns_rdatatype_ixfr) { 1677 fprintf(stderr, ";; Warning, " 1678 "ixfr requires a " 1679 "serial number\n"); 1680 continue; 1681 } 1682 } 1683 if (result == ISC_R_SUCCESS) { 1684 if (lookup->rdtypeset) { 1685 fprintf(stderr, ";; Warning, " 1686 "extra type option\n"); 1687 } 1688 if (rdtype == dns_rdatatype_ixfr) { 1689 uint32_t serial; 1690 lookup->rdtype = 1691 dns_rdatatype_ixfr; 1692 lookup->rdtypeset = ISC_TRUE; 1693 result = parse_uint(&serial, 1694 &rv[0][5], 1695 MAXSERIAL, 1696 "serial number"); 1697 if (result != ISC_R_SUCCESS) 1698 fatal("Couldn't parse " 1699 "serial number"); 1700 lookup->ixfr_serial = serial; 1701 lookup->section_question = 1702 plusquest; 1703 lookup->comments = pluscomm; 1704 if (!lookup->tcp_mode_set) 1705 lookup->tcp_mode = ISC_TRUE; 1706 } else { 1707 lookup->rdtype = rdtype; 1708 lookup->rdtypeset = ISC_TRUE; 1709 if (rdtype == 1710 dns_rdatatype_axfr) { 1711 lookup->section_question = 1712 plusquest; 1713 lookup->comments = pluscomm; 1714 } 1715 lookup->ixfr_serial = ISC_FALSE; 1716 } 1717 continue; 1718 } 1719 result = dns_rdataclass_fromtext(&rdclass, 1720 (isc_textregion_t *)&tr); 1721 if (result == ISC_R_SUCCESS) { 1722 if (lookup->rdclassset) { 1723 fprintf(stderr, ";; Warning, " 1724 "extra class option\n"); 1725 } 1726 lookup->rdclass = rdclass; 1727 lookup->rdclassset = ISC_TRUE; 1728 continue; 1729 } 1730 } 1731 1732 if (!config_only) { 1733 if (need_clone) 1734 lookup = clone_lookup(default_lookup, 1735 ISC_TRUE); 1736 need_clone = ISC_TRUE; 1737 strlcpy(lookup->textname, rv[0], 1738 sizeof(lookup->textname)); 1739 lookup->trace_root = ISC_TF(lookup->trace || 1740 lookup->ns_search_only); 1741 lookup->new_search = ISC_TRUE; 1742 if (firstarg) { 1743 printgreeting(argc, argv, lookup); 1744 firstarg = ISC_FALSE; 1745 } 1746 ISC_LIST_APPEND(lookup_list, lookup, link); 1747 debug("looking up %s", lookup->textname); 1748 } 1749 /* XXX Error message */ 1750 } 1751 } 1752 1753 /* 1754 * If we have a batchfile, seed the lookup list with the 1755 * first entry, then trust the callback in dighost_shutdown 1756 * to get the rest 1757 */ 1758 if ((batchname != NULL) && !(is_batchfile)) { 1759 if (strcmp(batchname, "-") == 0) 1760 batchfp = stdin; 1761 else 1762 batchfp = fopen(batchname, "r"); 1763 if (batchfp == NULL) { 1764 perror(batchname); 1765 if (exitcode < 8) 1766 exitcode = 8; 1767 fatal("couldn't open specified batch file"); 1768 } 1769 /* XXX Remove code dup from shutdown code */ 1770 next_line: 1771 if (fgets(batchline, sizeof(batchline), batchfp) != NULL) { 1772 bargc = 1; 1773 debug("batch line %s", batchline); 1774 if (batchline[0] == '\r' || batchline[0] == '\n' 1775 || batchline[0] == '#' || batchline[0] == ';') 1776 goto next_line; 1777 input = batchline; 1778 bargv[bargc] = next_token(&input, " \t\r\n"); 1779 while ((bargc < 14) && (bargv[bargc] != NULL)) { 1780 bargc++; 1781 bargv[bargc] = next_token(&input, " \t\r\n"); 1782 } 1783 1784 bargv[0] = argv[0]; 1785 argv0 = argv[0]; 1786 1787 for(i = 0; i < bargc; i++) 1788 debug("batch argv %d: %s", i, bargv[i]); 1789 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 1790 return; 1791 } 1792 return; 1793 } 1794 /* 1795 * If no lookup specified, search for root 1796 */ 1797 if ((lookup_list.head == NULL) && !config_only) { 1798 if (need_clone) 1799 lookup = clone_lookup(default_lookup, ISC_TRUE); 1800 need_clone = ISC_TRUE; 1801 lookup->trace_root = ISC_TF(lookup->trace || 1802 lookup->ns_search_only); 1803 lookup->new_search = ISC_TRUE; 1804 strlcpy(lookup->textname, ".", sizeof(lookup->textname)); 1805 lookup->rdtype = dns_rdatatype_ns; 1806 lookup->rdtypeset = ISC_TRUE; 1807 if (firstarg) { 1808 printgreeting(argc, argv, lookup); 1809 firstarg = ISC_FALSE; 1810 } 1811 ISC_LIST_APPEND(lookup_list, lookup, link); 1812 } 1813 if (!need_clone) 1814 destroy_lookup(lookup); 1815 } 1816 1817 /* 1818 * Callback from dighost.c to allow program-specific shutdown code. 1819 * Here, we're possibly reading from a batch file, then shutting down 1820 * for real if there's nothing in the batch file to read. 1821 */ 1822 static void 1823 query_finished(void) { 1824 char batchline[MXNAME]; 1825 int bargc; 1826 char *bargv[16]; 1827 char *input; 1828 int i; 1829 1830 if (batchname == NULL) { 1831 isc_app_shutdown(); 1832 return; 1833 } 1834 1835 fflush(stdout); 1836 if (feof(batchfp)) { 1837 batchname = NULL; 1838 isc_app_shutdown(); 1839 if (batchfp != stdin) 1840 fclose(batchfp); 1841 return; 1842 } 1843 1844 if (fgets(batchline, sizeof(batchline), batchfp) != NULL) { 1845 debug("batch line %s", batchline); 1846 bargc = 1; 1847 input = batchline; 1848 bargv[bargc] = next_token(&input, " \t\r\n"); 1849 while ((bargc < 14) && (bargv[bargc] != NULL)) { 1850 bargc++; 1851 bargv[bargc] = next_token(&input, " \t\r\n"); 1852 } 1853 1854 bargv[0] = argv0; 1855 1856 for(i = 0; i < bargc; i++) 1857 debug("batch argv %d: %s", i, bargv[i]); 1858 parse_args(ISC_TRUE, ISC_FALSE, bargc, (char **)bargv); 1859 start_lookup(); 1860 } else { 1861 batchname = NULL; 1862 if (batchfp != stdin) 1863 fclose(batchfp); 1864 isc_app_shutdown(); 1865 return; 1866 } 1867 } 1868 1869 void dig_setup(int argc, char **argv) 1870 { 1871 isc_result_t result; 1872 1873 ISC_LIST_INIT(lookup_list); 1874 ISC_LIST_INIT(server_list); 1875 ISC_LIST_INIT(root_hints_server_list); 1876 ISC_LIST_INIT(search_list); 1877 1878 if (pledge("stdio rpath inet dns", NULL) == -1) { 1879 perror("pledge"); 1880 exit(1); 1881 } 1882 1883 debug("dig_setup()"); 1884 1885 /* setup dighost callbacks */ 1886 dighost_printmessage = printmessage; 1887 dighost_received = received; 1888 dighost_trying = trying; 1889 dighost_shutdown = query_finished; 1890 1891 progname = argv[0]; 1892 preparse_args(argc, argv); 1893 1894 result = isc_app_start(); 1895 check_result(result, "isc_app_start"); 1896 1897 setup_libs(); 1898 setup_system(ipv4only, ipv6only); 1899 } 1900 1901 void dig_query_setup(isc_boolean_t is_batchfile, isc_boolean_t config_only, 1902 int argc, char **argv) 1903 { 1904 debug("dig_query_setup"); 1905 1906 parse_args(is_batchfile, config_only, argc, argv); 1907 if (keyfile[0] != 0) 1908 setup_file_key(); 1909 else if (keysecret[0] != 0) 1910 setup_text_key(); 1911 1912 if (pledge("stdio inet dns", NULL) == -1) { 1913 perror("pledge"); 1914 exit(1); 1915 } 1916 1917 if (domainopt[0] != '\0') { 1918 set_search_domain(domainopt); 1919 usesearch = ISC_TRUE; 1920 } 1921 } 1922 1923 void dig_startup() { 1924 isc_result_t result; 1925 1926 debug("dig_startup()"); 1927 1928 result = isc_app_onrun(global_task, onrun_callback, NULL); 1929 check_result(result, "isc_app_onrun"); 1930 isc_app_run(); 1931 } 1932 1933 void 1934 dig_shutdown() { 1935 destroy_lookup(default_lookup); 1936 if (batchname != NULL) { 1937 if (batchfp != stdin) 1938 fclose(batchfp); 1939 batchname = NULL; 1940 } 1941 1942 cancel_all(); 1943 destroy_libs(); 1944 } 1945 1946 /*% Main processing routine for dig */ 1947 int 1948 main(int argc, char **argv) { 1949 extern char *__progname; 1950 1951 if (strcmp("host", __progname) == 0) 1952 return host_main(argc, argv); 1953 if (strcmp("nslookup", __progname) == 0) 1954 return nslookup_main(argc, argv); 1955 1956 dig_setup(argc, argv); 1957 dig_query_setup(ISC_FALSE, ISC_FALSE, argc, argv); 1958 dig_startup(); 1959 dig_shutdown(); 1960 1961 return (exitcode); 1962 } 1963