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