dig.c revision 1.20
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.20 2023/09/06 04:57:28 jsg 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 55dig_lookup_t *default_lookup = NULL; 56 57static char *batchname = NULL; 58static FILE *batchfp = NULL; 59static char *argv0; 60static int addresscount = 0; 61 62static char domainopt[DNS_NAME_MAXTEXT]; 63static char sitvalue[256]; 64 65static 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; 70static uint32_t splitwidth = 0xffffffff; 71 72/*% rrcomments are neither explicitly enabled nor disabled by default */ 73static int rrcomments = 0; 74 75/*% opcode text */ 76static 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 */ 96static 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[] */ 117static const char * 118rcode_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 */ 132static void 133print_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 150static __dead void 151usage(void); 152 153static void 154usage(void) { 155 print_usage(stderr); 156 exit(1); 157} 158 159/*% version */ 160static void 161version(void) { 162 fputs("dig " VERSION "\n", stderr); 163} 164 165/*% help */ 166static void 167help(void) { 168 print_usage(stdout); 169} 170 171/*% 172 * Callback from dighost.c to print the received message. 173 */ 174static void 175received(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 */ 241static void 242trying(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 */ 250static isc_result_t 251say_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 */ 292static isc_result_t 293short_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 340static int 341isdotlocal(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 */ 363static isc_result_t 364printmessage(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 496repopulate_buffer: 497 498 if (query->lookup->comments && headers && !short_form) { 499 result = dns_message_pseudosectiontotext(msg, 500 DNS_PSEUDOSECTION_OPT, 501 style, flags, buf); 502 if (result == ISC_R_NOSPACE) { 503buftoosmall: 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, buf); 567 if (result == ISC_R_NOSPACE) 568 goto buftoosmall; 569 check_result(result, 570 "dns_message_pseudosectiontotext"); 571 result = dns_message_pseudosectiontotext( 572 msg, 573 DNS_PSEUDOSECTION_SIG0, 574 style, flags, buf); 575 if (result == ISC_R_NOSPACE) 576 goto buftoosmall; 577 check_result(result, 578 "dns_message_pseudosectiontotext"); 579 } 580 } 581 } 582 583 if (headers && query->lookup->comments && !short_form) 584 printf("\n"); 585 586 printf("%.*s", (int)isc_buffer_usedlength(buf), 587 (char *)isc_buffer_base(buf)); 588 isc_buffer_free(&buf); 589 590cleanup: 591 if (style != NULL) 592 dns_master_styledestroy(&style); 593 return (result); 594} 595 596/*% 597 * print the greeting message when the program first starts up. 598 */ 599static void 600printgreeting(int argc, char **argv, dig_lookup_t *lookup) { 601 int i; 602 static int first = 1; 603 char append[MXNAME]; 604 605 if (printcmd) { 606 snprintf(lookup->cmdline, sizeof(lookup->cmdline), 607 "%s; <<>> dig " VERSION " <<>>", 608 first?"\n":""); 609 i = 1; 610 while (i < argc) { 611 snprintf(append, sizeof(append), " %s", argv[i++]); 612 strlcat(lookup->cmdline, append, 613 sizeof(lookup->cmdline)); 614 } 615 strlcat(lookup->cmdline, "\n", sizeof(lookup->cmdline)); 616 if (first && addresscount != 0) { 617 snprintf(append, sizeof(append), 618 "; (%d server%s found)\n", 619 addresscount, 620 addresscount > 1 ? "s" : ""); 621 strlcat(lookup->cmdline, append, 622 sizeof(lookup->cmdline)); 623 } 624 if (first) { 625 snprintf(append, sizeof(append), 626 ";; global options:%s%s\n", 627 short_form ? " +short" : "", 628 printcmd ? " +cmd" : ""); 629 first = 0; 630 strlcat(lookup->cmdline, append, 631 sizeof(lookup->cmdline)); 632 } 633 } 634} 635 636static void 637plus_option(const char *option, int is_batchfile, 638 dig_lookup_t *lookup) 639{ 640 isc_result_t result; 641 char option_store[256]; 642 char *cmd, *value, *ptr, *code, *ep; 643 const char *errstr; 644 long lval; 645 uint32_t num; 646 int state = 1; 647 size_t n; 648 649 strlcpy(option_store, option, sizeof(option_store)); 650 ptr = option_store; 651 cmd = next_token(&ptr, "="); 652 if (cmd == NULL) { 653 printf(";; Invalid option %s\n", option_store); 654 return; 655 } 656 value = ptr; 657 if (strncasecmp(cmd, "no", 2)==0) { 658 cmd += 2; 659 state = 0; 660 } 661 662#define FULLCHECK(A) \ 663 do { \ 664 size_t _l = strlen(cmd); \ 665 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 666 goto invalid_option; \ 667 } while (0) 668#define FULLCHECK2(A, B) \ 669 do { \ 670 size_t _l = strlen(cmd); \ 671 if ((_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) && \ 672 (_l >= sizeof(B) || strncasecmp(cmd, B, _l) != 0)) \ 673 goto invalid_option; \ 674 } while (0) 675 676 switch (cmd[0]) { 677 case 'a': 678 switch (cmd[1]) { 679 case 'a': /* aaonly / aaflag */ 680 FULLCHECK2("aaonly", "aaflag"); 681 lookup->aaonly = state; 682 break; 683 case 'd': 684 switch (cmd[2]) { 685 case 'd': /* additional */ 686 FULLCHECK("additional"); 687 lookup->section_additional = state; 688 break; 689 case 'f': /* adflag */ 690 case '\0': /* +ad is a synonym for +adflag */ 691 FULLCHECK("adflag"); 692 lookup->adflag = state; 693 break; 694 default: 695 goto invalid_option; 696 } 697 break; 698 case 'l': /* all */ 699 FULLCHECK("all"); 700 lookup->section_question = state; 701 lookup->section_authority = state; 702 lookup->section_answer = state; 703 lookup->section_additional = state; 704 lookup->comments = state; 705 lookup->stats = state; 706 printcmd = state; 707 break; 708 case 'n': /* answer */ 709 FULLCHECK("answer"); 710 lookup->section_answer = state; 711 break; 712 case 'u': /* authority */ 713 FULLCHECK("authority"); 714 lookup->section_authority = state; 715 break; 716 default: 717 goto invalid_option; 718 } 719 break; 720 case 'b': 721 switch (cmd[1]) { 722 case 'e':/* besteffort */ 723 FULLCHECK("besteffort"); 724 lookup->besteffort = state; 725 break; 726 case 'u':/* bufsize */ 727 FULLCHECK("bufsize"); 728 if (value == NULL) 729 goto need_value; 730 if (!state) 731 goto invalid_option; 732 num = strtonum(value, 0, COMMSIZE, &errstr); 733 if (errstr != NULL) 734 fatal("buffer size is %s: '%s'", errstr, value); 735 lookup->udpsize = num; 736 break; 737 default: 738 goto invalid_option; 739 } 740 break; 741 case 'c': 742 switch (cmd[1]) { 743 case 'd':/* cdflag */ 744 switch (cmd[2]) { 745 case 'f': /* cdflag */ 746 case '\0': /* +cd is a synonym for +cdflag */ 747 FULLCHECK("cdflag"); 748 lookup->cdflag = state; 749 break; 750 default: 751 goto invalid_option; 752 } 753 break; 754 case 'l': /* class */ 755 /* keep +cl for backwards compatibility */ 756 FULLCHECK2("cl", "class"); 757 noclass = !state; 758 break; 759 case 'm': /* cmd */ 760 FULLCHECK("cmd"); 761 printcmd = state; 762 break; 763 case 'o': /* comments */ 764 switch (cmd[2]) { 765 case 'o': 766 FULLCHECK("cookie"); 767 goto sit; 768 case 'm': 769 FULLCHECK("comments"); 770 lookup->comments = state; 771 if (lookup == default_lookup) 772 pluscomm = state; 773 break; 774 default: 775 goto invalid_option; 776 } 777 break; 778 case 'r': 779 FULLCHECK("crypto"); 780 nocrypto = !state; 781 break; 782 default: 783 goto invalid_option; 784 } 785 break; 786 case 'd': 787 switch (cmd[1]) { 788 case 'e': /* defname */ 789 FULLCHECK("defname"); 790 if (!lookup->trace) { 791 usesearch = state; 792 } 793 break; 794 case 'n': /* dnssec */ 795 FULLCHECK("dnssec"); 796 if (state && lookup->edns == -1) 797 lookup->edns = 0; 798 lookup->dnssec = state; 799 break; 800 case 'o': /* domain */ 801 FULLCHECK("domain"); 802 if (value == NULL) 803 goto need_value; 804 if (!state) 805 goto invalid_option; 806 strlcpy(domainopt, value, sizeof(domainopt)); 807 break; 808 default: 809 goto invalid_option; 810 } 811 break; 812 case 'e': 813 switch (cmd[1]) { 814 case 'd': 815 switch(cmd[2]) { 816 case 'n': 817 switch (cmd[3]) { 818 case 's': 819 switch (cmd[4]) { 820 case 0: 821 FULLCHECK("edns"); 822 if (!state) { 823 lookup->edns = -1; 824 break; 825 } 826 if (value == NULL) { 827 lookup->edns = 0; 828 break; 829 } 830 num = strtonum(value, 0, 255, 831 &errstr); 832 if (errstr != NULL) 833 fatal("edns is %s: " 834 "'%s'", errstr, 835 value); 836 lookup->edns = num; 837 break; 838 case 'f': 839 FULLCHECK("ednsflags"); 840 if (!state) { 841 lookup->ednsflags = 0; 842 break; 843 } 844 if (value == NULL) { 845 lookup->ednsflags = 0; 846 break; 847 } 848 errno = 0; 849 lval = strtol(value, &ep, 0); 850 if (value[0] == '\0' || *ep != 851 '\0' || lval < 0 || lval > 852 0xffff || errno != 0) 853 fatal("Couldn't parse " 854 "ednsflags"); 855 lookup->ednsflags = lval; 856 break; 857 case 'n': 858 FULLCHECK("ednsnegotiation"); 859 lookup->ednsneg = state; 860 break; 861 case 'o': 862 FULLCHECK("ednsopt"); 863 if (!state) { 864 lookup->ednsoptscnt = 0; 865 break; 866 } 867 if (value == NULL) 868 fatal("ednsopt no " 869 "code point " 870 "specified"); 871 code = next_token(&value, ":"); 872 save_opt(lookup, code, value); 873 break; 874 default: 875 goto invalid_option; 876 } 877 break; 878 default: 879 goto invalid_option; 880 } 881 break; 882 default: 883 goto invalid_option; 884 } 885 break; 886 case 'x': 887 FULLCHECK("expire"); 888 lookup->expire = state; 889 break; 890 default: 891 goto invalid_option; 892 } 893 break; 894 case 'f': /* fail */ 895 FULLCHECK("fail"); 896 lookup->servfail_stops = state; 897 break; 898 case 'i': 899 switch (cmd[1]) { 900 case 'd': /* identify */ 901 switch (cmd[2]) { 902 case 'e': 903 FULLCHECK("identify"); 904 lookup->identify = state; 905 break; 906 case 'n': 907 FULLCHECK("idnout"); 908 fprintf(stderr, ";; IDN support not enabled\n"); 909 break; 910 default: 911 goto invalid_option; 912 } 913 break; 914 case 'g': /* ignore */ 915 default: /* 916 * Inherits default for compatibility (+[no]i*). 917 */ 918 FULLCHECK("ignore"); 919 lookup->ignore = state; 920 } 921 break; 922 case 'k': 923 FULLCHECK("keepopen"); 924 keep_open = state; 925 break; 926 case 'm': /* multiline */ 927 FULLCHECK("multiline"); 928 multiline = state; 929 break; 930 case 'n': 931 switch (cmd[1]) { 932 case 'd': /* ndots */ 933 FULLCHECK("ndots"); 934 if (value == NULL) 935 goto need_value; 936 if (!state) 937 goto invalid_option; 938 num = strtonum(value, 0, MAXNDOTS, &errstr); 939 if (errstr != NULL) 940 fatal("ndots is %s: '%s'", errstr, value); 941 ndots = num; 942 break; 943 case 's': 944 switch (cmd[2]) { 945 case 'i': /* nsid */ 946 FULLCHECK("nsid"); 947 if (state && lookup->edns == -1) 948 lookup->edns = 0; 949 lookup->nsid = state; 950 break; 951 case 's': /* nssearch */ 952 FULLCHECK("nssearch"); 953 lookup->ns_search_only = state; 954 if (state) { 955 lookup->trace_root = 1; 956 lookup->recurse = 1; 957 lookup->identify = 1; 958 lookup->stats = 0; 959 lookup->comments = 0; 960 lookup->section_additional = 0; 961 lookup->section_authority = 0; 962 lookup->section_question = 0; 963 lookup->rdtype = dns_rdatatype_ns; 964 lookup->rdtypeset = 1; 965 short_form = 1; 966 rrcomments = 0; 967 } 968 break; 969 default: 970 goto invalid_option; 971 } 972 break; 973 default: 974 goto invalid_option; 975 } 976 break; 977 case 'o': 978 switch (cmd[1]) { 979 case 'n': 980 FULLCHECK("onesoa"); 981 onesoa = state; 982 break; 983 case 'p': 984 FULLCHECK("opcode"); 985 if (!state) { 986 lookup->opcode = 0; /* default - query */ 987 break; 988 } 989 if (value == NULL) 990 goto need_value; 991 for (num = 0; 992 num < sizeof(opcodetext)/sizeof(opcodetext[0]); 993 num++) { 994 if (strcasecmp(opcodetext[num], value) == 0) 995 break; 996 } 997 if (num < 16) { 998 lookup->opcode = (dns_opcode_t)num; 999 break; 1000 } 1001 num = strtonum(value, 0, 15, &errstr); 1002 if (errstr != NULL) 1003 fatal("opcode is %s: '%s'", errstr, value); 1004 lookup->opcode = (dns_opcode_t)num; 1005 break; 1006 default: 1007 goto invalid_option; 1008 } 1009 break; 1010 case 'q': 1011 switch (cmd[1]) { 1012 case 'r': /* qr */ 1013 FULLCHECK("qr"); 1014 qr = state; 1015 break; 1016 case 'u': /* question */ 1017 FULLCHECK("question"); 1018 lookup->section_question = state; 1019 if (lookup == default_lookup) 1020 plusquest = state; 1021 break; 1022 default: 1023 goto invalid_option; 1024 } 1025 break; 1026 case 'r': 1027 switch (cmd[1]) { 1028 case 'd': /* rdflag */ 1029 FULLCHECK("rdflag"); 1030 lookup->recurse = state; 1031 break; 1032 case 'e': 1033 switch (cmd[2]) { 1034 case 'c': /* recurse */ 1035 FULLCHECK("recurse"); 1036 lookup->recurse = state; 1037 break; 1038 case 't': /* retry / retries */ 1039 FULLCHECK2("retry", "retries"); 1040 if (value == NULL) 1041 goto need_value; 1042 if (!state) 1043 goto invalid_option; 1044 lookup->retries = strtonum(value, 0, 1045 MAXTRIES - 1, &errstr); 1046 if (errstr != NULL) 1047 fatal("retries is %s: '%s'", errstr, 1048 value); 1049 lookup->retries++; 1050 break; 1051 default: 1052 goto invalid_option; 1053 } 1054 break; 1055 case 'r': /* rrcomments */ 1056 FULLCHECK("rrcomments"); 1057 rrcomments = state ? 1 : -1; 1058 break; 1059 default: 1060 goto invalid_option; 1061 } 1062 break; 1063 case 's': 1064 switch (cmd[1]) { 1065 case 'e': /* search */ 1066 FULLCHECK("search"); 1067 if (!lookup->trace) { 1068 usesearch = state; 1069 } 1070 break; 1071 case 'h': 1072 if (cmd[2] != 'o') 1073 goto invalid_option; 1074 switch (cmd[3]) { 1075 case 'r': /* short */ 1076 FULLCHECK("short"); 1077 short_form = state; 1078 if (state) { 1079 printcmd = 0; 1080 lookup->section_additional = 0; 1081 lookup->section_answer = 1; 1082 lookup->section_authority = 0; 1083 lookup->section_question = 0; 1084 lookup->comments = 0; 1085 lookup->stats = 0; 1086 rrcomments = -1; 1087 } 1088 break; 1089 case 'w': /* showsearch */ 1090 FULLCHECK("showsearch"); 1091 if (!lookup->trace) { 1092 showsearch = state; 1093 usesearch = state; 1094 } 1095 break; 1096 default: 1097 goto invalid_option; 1098 } 1099 break; 1100 case 'i': 1101 switch (cmd[2]) { 1102 case 't': /* sit */ 1103 FULLCHECK("sit"); 1104 sit: 1105 if (state && lookup->edns == -1) 1106 lookup->edns = 0; 1107 lookup->sit = state; 1108 if (value != NULL) { 1109 n = strlcpy(sitvalue, value, 1110 sizeof(sitvalue)); 1111 if (n >= sizeof(sitvalue)) 1112 fatal("SIT data too large"); 1113 lookup->sitvalue = sitvalue; 1114 } else 1115 lookup->sitvalue = NULL; 1116 break; 1117 default: 1118 goto invalid_option; 1119 } 1120 break; 1121 case 'p': /* split */ 1122 FULLCHECK("split"); 1123 if (value != NULL && !state) 1124 goto invalid_option; 1125 if (!state) { 1126 splitwidth = 0; 1127 break; 1128 } else if (value == NULL) 1129 break; 1130 1131 splitwidth = strtonum(value, 0, 1023, &errstr); 1132 if (errstr != NULL) 1133 fatal("split is %s: '%s'", errstr, value); 1134 if ((splitwidth % 4) != 0U) { 1135 splitwidth = ((splitwidth + 3) / 4) * 4; 1136 fprintf(stderr, ";; Warning, split must be " 1137 "a multiple of 4; adjusting " 1138 "to %u\n", splitwidth); 1139 } 1140 /* 1141 * There is an adjustment done in the 1142 * totext_<rrtype>() functions which causes 1143 * splitwidth to shrink. This is okay when we're 1144 * using the default width but incorrect in this 1145 * case, so we correct for it 1146 */ 1147 if (splitwidth) 1148 splitwidth += 3; 1149 break; 1150 case 't': /* stats */ 1151 FULLCHECK("stats"); 1152 lookup->stats = state; 1153 break; 1154 case 'u': /* subnet */ 1155 FULLCHECK("subnet"); 1156 if (state && value == NULL) 1157 goto need_value; 1158 if (!state) { 1159 if (lookup->ecs_addr != NULL) { 1160 free(lookup->ecs_addr); 1161 lookup->ecs_addr = NULL; 1162 } 1163 break; 1164 } 1165 if (lookup->edns == -1) 1166 lookup->edns = 0; 1167 if (lookup->ecs_addr != NULL) { 1168 free(lookup->ecs_addr); 1169 lookup->ecs_addr = NULL; 1170 } 1171 result = parse_netprefix(&lookup->ecs_addr, 1172 &lookup->ecs_plen, value); 1173 if (result != ISC_R_SUCCESS) 1174 fatal("Couldn't parse client"); 1175 break; 1176 default: 1177 goto invalid_option; 1178 } 1179 break; 1180 case 't': 1181 switch (cmd[1]) { 1182 case 'c': /* tcp */ 1183 FULLCHECK("tcp"); 1184 if (!is_batchfile) { 1185 lookup->tcp_mode = state; 1186 lookup->tcp_mode_set = 1; 1187 } 1188 break; 1189 case 'i': /* timeout */ 1190 FULLCHECK("timeout"); 1191 if (value == NULL) 1192 goto need_value; 1193 if (!state) 1194 goto invalid_option; 1195 timeout = strtonum(value, 0, MAXTIMEOUT, &errstr); 1196 if (errstr != NULL) 1197 fatal("timeout is %s: '%s'", errstr, value); 1198 if (timeout == 0) 1199 timeout = 1; 1200 break; 1201 case 'r': 1202 switch (cmd[2]) { 1203 case 'a': /* trace */ 1204 FULLCHECK("trace"); 1205 lookup->trace = state; 1206 lookup->trace_root = state; 1207 if (state) { 1208 lookup->recurse = 0; 1209 lookup->identify = 1; 1210 lookup->comments = 0; 1211 rrcomments = 0; 1212 lookup->stats = 0; 1213 lookup->section_additional = 0; 1214 lookup->section_authority = 1; 1215 lookup->section_question = 0; 1216 lookup->dnssec = 1; 1217 usesearch = 0; 1218 } 1219 break; 1220 case 'i': /* tries */ 1221 FULLCHECK("tries"); 1222 if (value == NULL) 1223 goto need_value; 1224 if (!state) 1225 goto invalid_option; 1226 lookup->retries = strtonum(value, 0, MAXTRIES, 1227 &errstr); 1228 if (errstr != NULL) 1229 fatal("tries is %s: '%s'", errstr, 1230 value); 1231 if (lookup->retries == 0) 1232 lookup->retries = 1; 1233 break; 1234 default: 1235 goto invalid_option; 1236 } 1237 break; 1238 case 't': /* ttlid */ 1239 FULLCHECK("ttlid"); 1240 nottl = !state; 1241 break; 1242 default: 1243 goto invalid_option; 1244 } 1245 break; 1246 case 'v': 1247 FULLCHECK("vc"); 1248 if (!is_batchfile) { 1249 lookup->tcp_mode = state; 1250 lookup->tcp_mode_set = 1; 1251 } 1252 break; 1253 default: 1254 invalid_option: 1255 need_value: 1256 fprintf(stderr, "Invalid option: +%s\n", 1257 option); 1258 usage(); 1259 } 1260 return; 1261} 1262 1263/*% 1264 * #1 returned if value was used 1265 */ 1266static const char *single_dash_opts = "46dhinuv"; 1267static const char *dash_opts = "46bcdfhikmnptvyx"; 1268static int 1269dash_option(char *option, char *next, dig_lookup_t **lookup, 1270 int *open_type_class, int *need_clone, 1271 int config_only, int argc, char **argv, 1272 int *firstarg) 1273{ 1274 char opt, *value, *ptr, *ptr2, *ptr3; 1275 isc_result_t result; 1276 int value_from_next; 1277 isc_textregion_t tr; 1278 dns_rdatatype_t rdtype; 1279 dns_rdataclass_t rdclass; 1280 char textname[MXNAME]; 1281 char *cmd; 1282 uint32_t num; 1283 const char *errstr; 1284 1285 while (strpbrk(option, single_dash_opts) == &option[0]) { 1286 /* 1287 * Since the -[46dhinuv] options do not take an argument, 1288 * account for them (in any number and/or combination) 1289 * if they appear as the first character(s) of a q-opt. 1290 */ 1291 opt = option[0]; 1292 switch (opt) { 1293 case '4': 1294 if (have_ipv4) 1295 have_ipv6 = 0; 1296 else 1297 fatal("can't find IPv4 networking"); 1298 break; 1299 case '6': 1300 if (have_ipv6) 1301 have_ipv4 = 0; 1302 else 1303 fatal("can't find IPv6 networking"); 1304 break; 1305 case 'd': 1306 ptr = strpbrk(&option[1], dash_opts); 1307 if (ptr != &option[1]) { 1308 cmd = option; 1309 FULLCHECK("debug"); 1310 debugging = 1; 1311 return (0); 1312 } else 1313 debugging = 1; 1314 break; 1315 case 'h': 1316 help(); 1317 exit(0); 1318 break; 1319 case 'i': 1320 ip6_int = 1; 1321 break; 1322 case 'n': 1323 /* deprecated */ 1324 break; 1325 case 'u': 1326 use_usec = 1; 1327 break; 1328 case 'v': 1329 version(); 1330 exit(0); 1331 break; 1332 } 1333 if (strlen(option) > 1U) 1334 option = &option[1]; 1335 else 1336 return (0); 1337 } 1338 opt = option[0]; 1339 if (strlen(option) > 1U) { 1340 value_from_next = 0; 1341 value = &option[1]; 1342 } else { 1343 value_from_next = 1; 1344 value = next; 1345 } 1346 if (value == NULL) 1347 goto invalid_option; 1348 switch (opt) { 1349 case 'b': { 1350 struct addrinfo *ai = NULL, hints; 1351 int error; 1352 char *hash; 1353 1354 memset(&hints, 0, sizeof(hints)); 1355 hints.ai_flags = AI_NUMERICHOST; 1356 hints.ai_socktype = SOCK_DGRAM; 1357 1358 hash = strchr(value, '#'); 1359 if (hash != NULL) { 1360 *hash = '\0'; 1361 error = getaddrinfo(value, hash + 1, &hints, &ai); 1362 *hash = '#'; 1363 } else 1364 error = getaddrinfo(value, NULL, &hints, &ai); 1365 1366 if (error) 1367 fatal("invalid address %s: %s", value, 1368 gai_strerror(error)); 1369 if (ai == NULL || ai->ai_addrlen > sizeof(bind_address)) 1370 fatal("invalid address %s", value); 1371 if (!have_ipv4 && ai->ai_family == AF_INET) 1372 fatal("%s: wrong address family", value); 1373 if (!have_ipv6 && ai->ai_family == AF_INET6) 1374 fatal("%s: wrong address family", value); 1375 1376 memset(&bind_address, 0, sizeof(bind_address)); 1377 memcpy(&bind_address, ai->ai_addr, ai->ai_addrlen); 1378 1379 specified_source = 1; 1380 return (value_from_next); 1381 } 1382 case 'c': 1383 if ((*lookup)->rdclassset) { 1384 fprintf(stderr, ";; Warning, extra class option\n"); 1385 } 1386 *open_type_class = 0; 1387 tr.base = value; 1388 tr.length = (unsigned int) strlen(value); 1389 result = dns_rdataclass_fromtext(&rdclass, 1390 (isc_textregion_t *)&tr); 1391 if (result == ISC_R_SUCCESS) { 1392 (*lookup)->rdclass = rdclass; 1393 (*lookup)->rdclassset = 1; 1394 } else 1395 fprintf(stderr, ";; Warning, ignoring " 1396 "invalid class %s\n", 1397 value); 1398 return (value_from_next); 1399 case 'f': 1400 batchname = value; 1401 return (value_from_next); 1402 case 'k': 1403 strlcpy(keyfile, value, sizeof(keyfile)); 1404 return (value_from_next); 1405 case 'p': 1406 num = strtonum(value, 0, MAXPORT, &errstr); 1407 if (errstr != NULL) 1408 fatal("port number is %s: '%s'", errstr, value); 1409 port = num; 1410 return (value_from_next); 1411 case 'q': 1412 if (!config_only) { 1413 if (*need_clone) 1414 (*lookup) = clone_lookup(default_lookup, 1415 1); 1416 *need_clone = 1; 1417 strlcpy((*lookup)->textname, value, 1418 sizeof((*lookup)->textname)); 1419 (*lookup)->trace_root = (*lookup)->trace || 1420 (*lookup)->ns_search_only; 1421 (*lookup)->new_search = 1; 1422 if (*firstarg) { 1423 printgreeting(argc, argv, *lookup); 1424 *firstarg = 0; 1425 } 1426 ISC_LIST_APPEND(lookup_list, (*lookup), link); 1427 debug("looking up %s", (*lookup)->textname); 1428 } 1429 return (value_from_next); 1430 case 't': 1431 *open_type_class = 0; 1432 if (strncasecmp(value, "ixfr=", 5) == 0) { 1433 rdtype = dns_rdatatype_ixfr; 1434 result = ISC_R_SUCCESS; 1435 } else { 1436 tr.base = value; 1437 tr.length = (unsigned int) strlen(value); 1438 result = dns_rdatatype_fromtext(&rdtype, 1439 (isc_textregion_t *)&tr); 1440 if (result == ISC_R_SUCCESS && 1441 rdtype == dns_rdatatype_ixfr) { 1442 result = DNS_R_UNKNOWN; 1443 } 1444 } 1445 if (result == ISC_R_SUCCESS) { 1446 if ((*lookup)->rdtypeset) { 1447 fprintf(stderr, ";; Warning, " 1448 "extra type option\n"); 1449 } 1450 if (rdtype == dns_rdatatype_ixfr) { 1451 uint32_t serial; 1452 (*lookup)->rdtype = dns_rdatatype_ixfr; 1453 (*lookup)->rdtypeset = 1; 1454 serial = strtonum(&value[5], 0, MAXSERIAL, 1455 &errstr); 1456 if (errstr != NULL) 1457 fatal("serial number is %s: '%s'", 1458 errstr, &value[5]); 1459 (*lookup)->ixfr_serial = serial; 1460 (*lookup)->section_question = plusquest; 1461 (*lookup)->comments = pluscomm; 1462 if (!(*lookup)->tcp_mode_set) 1463 (*lookup)->tcp_mode = 1; 1464 } else { 1465 (*lookup)->rdtype = rdtype; 1466 if (!config_only) 1467 (*lookup)->rdtypeset = 1; 1468 if (rdtype == dns_rdatatype_axfr) { 1469 (*lookup)->section_question = plusquest; 1470 (*lookup)->comments = pluscomm; 1471 } 1472 (*lookup)->ixfr_serial = 0; 1473 } 1474 } else 1475 fprintf(stderr, ";; Warning, ignoring " 1476 "invalid type %s\n", 1477 value); 1478 return (value_from_next); 1479 case 'y': 1480 ptr = next_token(&value, ":"); /* hmac type or name */ 1481 if (ptr == NULL) { 1482 usage(); 1483 } 1484 ptr2 = next_token(&value, ":"); /* name or secret */ 1485 if (ptr2 == NULL) 1486 usage(); 1487 ptr3 = next_token(&value, ":"); /* secret or NULL */ 1488 if (ptr3 != NULL) { 1489 parse_hmac(ptr); 1490 ptr = ptr2; 1491 ptr2 = ptr3; 1492 } else { 1493 hmacname = DNS_TSIG_HMACSHA256_NAME; 1494 digestbits = 0; 1495 } 1496 strlcpy(keynametext, ptr, sizeof(keynametext)); 1497 strlcpy(keysecret, ptr2, sizeof(keysecret)); 1498 return (value_from_next); 1499 case 'x': 1500 if (*need_clone) 1501 *lookup = clone_lookup(default_lookup, 1); 1502 *need_clone = 1; 1503 if (get_reverse(textname, sizeof(textname), value, 1504 ip6_int, 0) == ISC_R_SUCCESS) { 1505 strlcpy((*lookup)->textname, textname, 1506 sizeof((*lookup)->textname)); 1507 debug("looking up %s", (*lookup)->textname); 1508 (*lookup)->trace_root = (*lookup)->trace || 1509 (*lookup)->ns_search_only; 1510 (*lookup)->ip6_int = ip6_int; 1511 if (!(*lookup)->rdtypeset) 1512 (*lookup)->rdtype = dns_rdatatype_ptr; 1513 if (!(*lookup)->rdclassset) 1514 (*lookup)->rdclass = dns_rdataclass_in; 1515 (*lookup)->new_search = 1; 1516 if (*firstarg) { 1517 printgreeting(argc, argv, *lookup); 1518 *firstarg = 0; 1519 } 1520 ISC_LIST_APPEND(lookup_list, *lookup, link); 1521 } else { 1522 fprintf(stderr, "Invalid IP address %s\n", value); 1523 exit(1); 1524 } 1525 return (value_from_next); 1526 invalid_option: 1527 default: 1528 fprintf(stderr, "Invalid option: -%s\n", option); 1529 usage(); 1530 } 1531 /* NOTREACHED */ 1532 return (0); 1533} 1534 1535/*% 1536 * Because we may be trying to do memory allocation recording, we're going 1537 * to need to parse the arguments for the -m *before* we start the main 1538 * argument parsing routine. 1539 * 1540 * I'd prefer not to have to do this, but I am not quite sure how else to 1541 * fix the problem. Argument parsing in dig involves memory allocation 1542 * by its nature, so it can't be done in the main argument parser. 1543 */ 1544static void 1545preparse_args(int argc, char **argv) { 1546 int rc; 1547 char **rv; 1548 char *option; 1549 1550 rc = argc; 1551 rv = argv; 1552 for (rc--, rv++; rc > 0; rc--, rv++) { 1553 if (rv[0][0] != '-') 1554 continue; 1555 option = &rv[0][1]; 1556 while (strpbrk(option, single_dash_opts) == &option[0]) { 1557 switch (option[0]) { 1558 case '4': 1559 if (ipv6only) 1560 fatal("only one of -4 and -6 allowed"); 1561 ipv4only = 1; 1562 break; 1563 case '6': 1564 if (ipv4only) 1565 fatal("only one of -4 and -6 allowed"); 1566 ipv6only = 1; 1567 break; 1568 } 1569 option = &option[1]; 1570 } 1571 } 1572} 1573 1574static void 1575parse_args(int is_batchfile, int config_only, 1576 int argc, char **argv) 1577{ 1578 isc_result_t result; 1579 isc_textregion_t tr; 1580 int firstarg = 1; 1581 dig_lookup_t *lookup = NULL; 1582 dns_rdatatype_t rdtype; 1583 dns_rdataclass_t rdclass; 1584 int open_type_class = 1; 1585 char batchline[MXNAME]; 1586 int bargc; 1587 char *bargv[64]; 1588 int rc; 1589 char **rv; 1590 char *input; 1591 int i; 1592 int need_clone = 1; 1593 const char *errstr; 1594 1595 /* 1596 * The semantics for parsing the args is a bit complex; if 1597 * we don't have a host yet, make the arg apply globally, 1598 * otherwise make it apply to the latest host. This is 1599 * a bit different than the previous versions, but should 1600 * form a consistent user interface. 1601 * 1602 * First, create a "default lookup" which won't actually be used 1603 * anywhere, except for cloning into new lookups 1604 */ 1605 1606 debug("parse_args()"); 1607 if (!is_batchfile) { 1608 debug("making new lookup"); 1609 default_lookup = make_empty_lookup(); 1610 default_lookup->adflag = 1; 1611 default_lookup->edns = 0; 1612 } 1613 1614 if (is_batchfile && !config_only) { 1615 /* Processing '-f batchfile'. */ 1616 lookup = clone_lookup(default_lookup, 1); 1617 need_clone = 0; 1618 } else 1619 lookup = default_lookup; 1620 1621 rc = argc; 1622 rv = argv; 1623 for (rc--, rv++; rc > 0; rc--, rv++) { 1624 debug("main parsing %s", rv[0]); 1625 if (strncmp(rv[0], "%", 1) == 0) 1626 break; 1627 if (rv[0][0] == '@') { 1628 1629 if (is_batchfile && !config_only) { 1630 addresscount = getaddresses(lookup, &rv[0][1], 1631 &result); 1632 if (result != ISC_R_SUCCESS) { 1633 fprintf(stderr, "couldn't get address " 1634 "for '%s': %s: skipping " 1635 "lookup\n", &rv[0][1], 1636 isc_result_totext(result)); 1637 if (ISC_LINK_LINKED(lookup, link)) 1638 ISC_LIST_DEQUEUE(lookup_list, 1639 lookup, link); 1640 destroy_lookup(lookup); 1641 return; 1642 } 1643 } else 1644 addresscount = getaddresses(lookup, &rv[0][1], 1645 NULL); 1646 } else if (rv[0][0] == '+') { 1647 plus_option(&rv[0][1], is_batchfile, 1648 lookup); 1649 } else if (rv[0][0] == '-') { 1650 if (rc <= 1) { 1651 if (dash_option(&rv[0][1], NULL, 1652 &lookup, &open_type_class, 1653 &need_clone, config_only, 1654 argc, argv, &firstarg)) { 1655 rc--; 1656 rv++; 1657 } 1658 } else { 1659 if (dash_option(&rv[0][1], rv[1], 1660 &lookup, &open_type_class, 1661 &need_clone, config_only, 1662 argc, argv, &firstarg)) { 1663 rc--; 1664 rv++; 1665 } 1666 } 1667 } else { 1668 /* 1669 * Anything which isn't an option 1670 */ 1671 if (open_type_class) { 1672 if (strncasecmp(rv[0], "ixfr=", 5) == 0) { 1673 rdtype = dns_rdatatype_ixfr; 1674 result = ISC_R_SUCCESS; 1675 } else { 1676 tr.base = rv[0]; 1677 tr.length = 1678 (unsigned int) strlen(rv[0]); 1679 result = dns_rdatatype_fromtext(&rdtype, 1680 (isc_textregion_t *)&tr); 1681 if (result == ISC_R_SUCCESS && 1682 rdtype == dns_rdatatype_ixfr) { 1683 fprintf(stderr, ";; Warning, " 1684 "ixfr requires a " 1685 "serial number\n"); 1686 continue; 1687 } 1688 } 1689 if (result == ISC_R_SUCCESS) { 1690 if (lookup->rdtypeset) { 1691 fprintf(stderr, ";; Warning, " 1692 "extra type option\n"); 1693 } 1694 if (rdtype == dns_rdatatype_ixfr) { 1695 uint32_t serial; 1696 lookup->rdtype = 1697 dns_rdatatype_ixfr; 1698 lookup->rdtypeset = 1; 1699 serial = strtonum(&rv[0][5], 0, 1700 MAXSERIAL, &errstr); 1701 if (errstr != NULL) 1702 fatal("serial number " 1703 "is %s: '%s'", 1704 errstr, &rv[0][5]); 1705 lookup->ixfr_serial = serial; 1706 lookup->section_question = 1707 plusquest; 1708 lookup->comments = pluscomm; 1709 if (!lookup->tcp_mode_set) 1710 lookup->tcp_mode = 1; 1711 } else { 1712 lookup->rdtype = rdtype; 1713 lookup->rdtypeset = 1; 1714 if (rdtype == 1715 dns_rdatatype_axfr) { 1716 lookup->section_question = 1717 plusquest; 1718 lookup->comments = pluscomm; 1719 } 1720 lookup->ixfr_serial = 0; 1721 } 1722 continue; 1723 } 1724 result = dns_rdataclass_fromtext(&rdclass, 1725 (isc_textregion_t *)&tr); 1726 if (result == ISC_R_SUCCESS) { 1727 if (lookup->rdclassset) { 1728 fprintf(stderr, ";; Warning, " 1729 "extra class option\n"); 1730 } 1731 lookup->rdclass = rdclass; 1732 lookup->rdclassset = 1; 1733 continue; 1734 } 1735 } 1736 1737 if (!config_only) { 1738 if (need_clone) 1739 lookup = clone_lookup(default_lookup, 1740 1); 1741 need_clone = 1; 1742 strlcpy(lookup->textname, rv[0], 1743 sizeof(lookup->textname)); 1744 lookup->trace_root = lookup->trace || 1745 lookup->ns_search_only; 1746 lookup->new_search = 1; 1747 if (firstarg) { 1748 printgreeting(argc, argv, lookup); 1749 firstarg = 0; 1750 } 1751 ISC_LIST_APPEND(lookup_list, lookup, link); 1752 debug("looking up %s", lookup->textname); 1753 } 1754 /* XXX Error message */ 1755 } 1756 } 1757 1758 /* 1759 * If we have a batchfile, seed the lookup list with the 1760 * first entry, then trust the callback in dighost_shutdown 1761 * to get the rest 1762 */ 1763 if ((batchname != NULL) && !(is_batchfile)) { 1764 if (strcmp(batchname, "-") == 0) 1765 batchfp = stdin; 1766 else 1767 batchfp = fopen(batchname, "r"); 1768 if (batchfp == NULL) { 1769 perror(batchname); 1770 if (exitcode < 8) 1771 exitcode = 8; 1772 fatal("couldn't open specified batch file"); 1773 } 1774 /* XXX Remove code dup from shutdown code */ 1775 next_line: 1776 if (fgets(batchline, sizeof(batchline), batchfp) != NULL) { 1777 bargc = 1; 1778 debug("batch line %s", batchline); 1779 if (batchline[0] == '\r' || batchline[0] == '\n' 1780 || batchline[0] == '#' || batchline[0] == ';') 1781 goto next_line; 1782 input = batchline; 1783 bargv[bargc] = next_token(&input, " \t\r\n"); 1784 while ((bargc < 14) && (bargv[bargc] != NULL)) { 1785 bargc++; 1786 bargv[bargc] = next_token(&input, " \t\r\n"); 1787 } 1788 1789 bargv[0] = argv[0]; 1790 argv0 = argv[0]; 1791 1792 for(i = 0; i < bargc; i++) 1793 debug("batch argv %d: %s", i, bargv[i]); 1794 parse_args(1, 0, bargc, (char **)bargv); 1795 return; 1796 } 1797 return; 1798 } 1799 /* 1800 * If no lookup specified, search for root 1801 */ 1802 if ((lookup_list.head == NULL) && !config_only) { 1803 if (need_clone) 1804 lookup = clone_lookup(default_lookup, 1); 1805 need_clone = 1; 1806 lookup->trace_root = lookup->trace || lookup->ns_search_only; 1807 lookup->new_search = 1; 1808 strlcpy(lookup->textname, ".", sizeof(lookup->textname)); 1809 lookup->rdtype = dns_rdatatype_ns; 1810 lookup->rdtypeset = 1; 1811 if (firstarg) { 1812 printgreeting(argc, argv, lookup); 1813 firstarg = 0; 1814 } 1815 ISC_LIST_APPEND(lookup_list, lookup, link); 1816 } 1817 if (!need_clone) 1818 destroy_lookup(lookup); 1819} 1820 1821/* 1822 * Callback from dighost.c to allow program-specific shutdown code. 1823 * Here, we're possibly reading from a batch file, then shutting down 1824 * for real if there's nothing in the batch file to read. 1825 */ 1826static void 1827query_finished(void) { 1828 char batchline[MXNAME]; 1829 int bargc; 1830 char *bargv[16]; 1831 char *input; 1832 int i; 1833 1834 if (batchname == NULL) { 1835 isc_app_shutdown(); 1836 return; 1837 } 1838 1839 fflush(stdout); 1840 if (feof(batchfp)) { 1841 batchname = NULL; 1842 isc_app_shutdown(); 1843 if (batchfp != stdin) 1844 fclose(batchfp); 1845 return; 1846 } 1847 1848 if (fgets(batchline, sizeof(batchline), batchfp) != NULL) { 1849 debug("batch line %s", batchline); 1850 bargc = 1; 1851 input = batchline; 1852 bargv[bargc] = next_token(&input, " \t\r\n"); 1853 while ((bargc < 14) && (bargv[bargc] != NULL)) { 1854 bargc++; 1855 bargv[bargc] = next_token(&input, " \t\r\n"); 1856 } 1857 1858 bargv[0] = argv0; 1859 1860 for(i = 0; i < bargc; i++) 1861 debug("batch argv %d: %s", i, bargv[i]); 1862 parse_args(1, 0, bargc, (char **)bargv); 1863 start_lookup(); 1864 } else { 1865 batchname = NULL; 1866 if (batchfp != stdin) 1867 fclose(batchfp); 1868 isc_app_shutdown(); 1869 return; 1870 } 1871} 1872 1873void dig_setup(int argc, char **argv) 1874{ 1875 isc_result_t result; 1876 1877 ISC_LIST_INIT(lookup_list); 1878 ISC_LIST_INIT(server_list); 1879 ISC_LIST_INIT(root_hints_server_list); 1880 ISC_LIST_INIT(search_list); 1881 1882 if (pledge("stdio rpath inet dns", NULL) == -1) { 1883 perror("pledge"); 1884 exit(1); 1885 } 1886 1887 debug("dig_setup()"); 1888 1889 /* setup dighost callbacks */ 1890 dighost_printmessage = printmessage; 1891 dighost_received = received; 1892 dighost_trying = trying; 1893 dighost_shutdown = query_finished; 1894 1895 progname = argv[0]; 1896 preparse_args(argc, argv); 1897 1898 result = isc_app_start(); 1899 check_result(result, "isc_app_start"); 1900 1901 setup_libs(); 1902 setup_system(ipv4only, ipv6only); 1903} 1904 1905void dig_query_setup(int is_batchfile, int config_only, 1906 int argc, char **argv) 1907{ 1908 debug("dig_query_setup"); 1909 1910 parse_args(is_batchfile, config_only, argc, argv); 1911 if (keyfile[0] != 0) 1912 setup_file_key(); 1913 else if (keysecret[0] != 0) 1914 setup_text_key(); 1915 1916 if (pledge("stdio inet dns", NULL) == -1) { 1917 perror("pledge"); 1918 exit(1); 1919 } 1920 1921 if (domainopt[0] != '\0') { 1922 set_search_domain(domainopt); 1923 usesearch = 1; 1924 } 1925} 1926 1927void dig_startup(void) { 1928 isc_result_t result; 1929 1930 debug("dig_startup()"); 1931 1932 result = isc_app_onrun(global_task, onrun_callback, NULL); 1933 check_result(result, "isc_app_onrun"); 1934 isc_app_run(); 1935} 1936 1937void 1938dig_shutdown(void) { 1939 destroy_lookup(default_lookup); 1940 if (batchname != NULL) { 1941 if (batchfp != stdin) 1942 fclose(batchfp); 1943 batchname = NULL; 1944 } 1945 1946 cancel_all(); 1947 destroy_libs(); 1948} 1949 1950/*% Main processing routine for dig */ 1951int 1952main(int argc, char **argv) { 1953 extern char *__progname; 1954 1955 if (strcmp("host", __progname) == 0) 1956 return host_main(argc, argv); 1957 if (strcmp("nslookup", __progname) == 0) 1958 return nslookup_main(argc, argv); 1959 1960 dig_setup(argc, argv); 1961 dig_query_setup(0, 0, argc, argv); 1962 dig_startup(); 1963 dig_shutdown(); 1964 1965 return (exitcode); 1966} 1967