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