1 /* $NetBSD: delv.c,v 1.12 2023/01/25 21:43:23 christos Exp $ */ 2 3 /* 4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 * 6 * SPDX-License-Identifier: MPL-2.0 7 * 8 * This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 * 12 * See the COPYRIGHT file distributed with this work for additional 13 * information regarding copyright ownership. 14 */ 15 16 #include <bind.keys.h> 17 18 #ifndef WIN32 19 #include <arpa/inet.h> 20 #include <netdb.h> 21 #include <netinet/in.h> 22 #include <signal.h> 23 #include <sys/socket.h> 24 #include <sys/types.h> 25 #endif /* ifndef WIN32 */ 26 27 #include <inttypes.h> 28 #include <stdbool.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <unistd.h> 33 34 #include <isc/app.h> 35 #include <isc/base64.h> 36 #include <isc/buffer.h> 37 #include <isc/hex.h> 38 #include <isc/lib.h> 39 #include <isc/log.h> 40 #include <isc/managers.h> 41 #include <isc/md.h> 42 #include <isc/mem.h> 43 #ifdef WIN32 44 #include <isc/ntpaths.h> 45 #endif /* ifdef WIN32 */ 46 #include <isc/parseint.h> 47 #include <isc/print.h> 48 #include <isc/sockaddr.h> 49 #include <isc/socket.h> 50 #include <isc/string.h> 51 #include <isc/task.h> 52 #include <isc/timer.h> 53 #include <isc/util.h> 54 55 #include <dns/byaddr.h> 56 #include <dns/client.h> 57 #include <dns/fixedname.h> 58 #include <dns/keytable.h> 59 #include <dns/keyvalues.h> 60 #include <dns/lib.h> 61 #include <dns/log.h> 62 #include <dns/masterdump.h> 63 #include <dns/name.h> 64 #include <dns/rdata.h> 65 #include <dns/rdataclass.h> 66 #include <dns/rdataset.h> 67 #include <dns/rdatastruct.h> 68 #include <dns/rdatatype.h> 69 #include <dns/result.h> 70 #include <dns/secalg.h> 71 #include <dns/view.h> 72 73 #include <dst/dst.h> 74 #include <dst/result.h> 75 76 #include <isccfg/log.h> 77 #include <isccfg/namedconf.h> 78 79 #include <irs/resconf.h> 80 81 #define CHECK(r) \ 82 do { \ 83 result = (r); \ 84 if (result != ISC_R_SUCCESS) \ 85 goto cleanup; \ 86 } while (0) 87 88 #define MAXNAME (DNS_NAME_MAXTEXT + 1) 89 90 /* Variables used internally by delv. */ 91 char *progname; 92 static isc_mem_t *mctx = NULL; 93 static isc_log_t *lctx = NULL; 94 95 /* Configurables */ 96 static char *server = NULL; 97 static const char *port = "53"; 98 static isc_sockaddr_t *srcaddr4 = NULL, *srcaddr6 = NULL; 99 static isc_sockaddr_t a4, a6; 100 static char *curqname = NULL, *qname = NULL; 101 static bool classset = false; 102 static dns_rdatatype_t qtype = dns_rdatatype_none; 103 static bool typeset = false; 104 105 static unsigned int styleflags = 0; 106 static uint32_t splitwidth = 0xffffffff; 107 static bool showcomments = true, showdnssec = true, showtrust = true, 108 rrcomments = true, noclass = false, nocrypto = false, nottl = false, 109 multiline = false, short_form = false, print_unknown_format = false, 110 yaml = false; 111 112 static bool resolve_trace = false, validator_trace = false, 113 message_trace = false; 114 115 static bool use_ipv4 = true, use_ipv6 = true; 116 117 static bool cdflag = false, no_sigs = false, root_validation = true; 118 119 static bool use_tcp = false; 120 121 static char *anchorfile = NULL; 122 static char *trust_anchor = NULL; 123 static int num_keys = 0; 124 125 static dns_fixedname_t afn; 126 static dns_name_t *anchor_name = NULL; 127 128 /* Default bind.keys contents */ 129 static char anchortext[] = TRUST_ANCHORS; 130 131 /* 132 * Static function prototypes 133 */ 134 static isc_result_t 135 get_reverse(char *reverse, size_t len, char *value, bool strict); 136 137 static isc_result_t 138 parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc); 139 140 static void 141 usage(void) { 142 fputs("Usage: delv [@server] {q-opt} {d-opt} [domain] [q-type] " 143 "[q-class]\n" 144 "Where: domain is in the Domain Name System\n" 145 " q-class is one of (in,hs,ch,...) [default: in]\n" 146 " q-type is one of (a,any,mx,ns,soa,hinfo,axfr,txt,...) " 147 "[default:a]\n" 148 " q-opt is one of:\n" 149 " -4 (use IPv4 query transport " 150 "only)\n" 151 " -6 (use IPv6 query transport " 152 "only)\n" 153 " -a anchor-file (specify root trust " 154 "anchor)\n" 155 " -b address[#port] (bind to source " 156 "address/port)\n" 157 " -c class (option included for " 158 "compatibility;\n" 159 " -d level (set debugging level)\n" 160 " -h (print help and exit)\n" 161 " -i (disable DNSSEC " 162 "validation)\n" 163 " -m (enable memory usage " 164 "debugging)\n" 165 " -p port (specify port number)\n" 166 " -q name (specify query name)\n" 167 " -t type (specify query type)\n" 168 " only IN is supported)\n" 169 " -v (print version and exit)\n" 170 " -x dot-notation (shortcut for reverse " 171 "lookups)\n" 172 " d-opt is of the form +keyword[=value], where keyword " 173 "is:\n" 174 " +[no]all (Set or clear all display " 175 "flags)\n" 176 " +[no]class (Control display of " 177 "class)\n" 178 " +[no]comments (Control display of " 179 "comment lines)\n" 180 " +[no]crypto (Control display of " 181 "cryptographic\n" 182 " fields in records)\n" 183 " +[no]dlv (Obsolete)\n" 184 " +[no]dnssec (Display DNSSEC records)\n" 185 " +[no]mtrace (Trace messages received)\n" 186 " +[no]multiline (Print records in an " 187 "expanded format)\n" 188 " +[no]root (DNSSEC validation trust " 189 "anchor)\n" 190 " +[no]rrcomments (Control display of " 191 "per-record " 192 "comments)\n" 193 " +[no]rtrace (Trace resolver fetches)\n" 194 " +[no]short (Short form answer)\n" 195 " +[no]split=## (Split hex/base64 fields " 196 "into chunks)\n" 197 " +[no]tcp (TCP mode)\n" 198 " +[no]ttl (Control display of ttls " 199 "in records)\n" 200 " +[no]trust (Control display of trust " 201 "level)\n" 202 " +[no]unknownformat (Print RDATA in RFC 3597 " 203 "\"unknown\" format)\n" 204 " +[no]vtrace (Trace validation " 205 "process)\n" 206 " +[no]yaml (Present the results as " 207 "YAML)\n", 208 stderr); 209 exit(1); 210 } 211 212 ISC_PLATFORM_NORETURN_PRE static void 213 fatal(const char *format, ...) 214 ISC_FORMAT_PRINTF(1, 2) ISC_PLATFORM_NORETURN_POST; 215 216 static void 217 fatal(const char *format, ...) { 218 va_list args; 219 220 fflush(stdout); 221 fprintf(stderr, "%s: ", progname); 222 va_start(args, format); 223 vfprintf(stderr, format, args); 224 va_end(args); 225 fprintf(stderr, "\n"); 226 exit(1); 227 } 228 229 static void 230 warn(const char *format, ...) ISC_FORMAT_PRINTF(1, 2); 231 232 static void 233 warn(const char *format, ...) { 234 va_list args; 235 236 fflush(stdout); 237 fprintf(stderr, "%s: warning: ", progname); 238 va_start(args, format); 239 vfprintf(stderr, format, args); 240 va_end(args); 241 fprintf(stderr, "\n"); 242 } 243 244 static isc_logcategory_t categories[] = { { "delv", 0 }, { NULL, 0 } }; 245 #define LOGCATEGORY_DEFAULT (&categories[0]) 246 #define LOGMODULE_DEFAULT (&modules[0]) 247 248 static isc_logmodule_t modules[] = { { "delv", 0 }, { NULL, 0 } }; 249 250 static void 251 delv_log(int level, const char *fmt, ...) ISC_FORMAT_PRINTF(2, 3); 252 253 static void 254 delv_log(int level, const char *fmt, ...) { 255 va_list ap; 256 char msgbuf[2048]; 257 258 if (!isc_log_wouldlog(lctx, level)) { 259 return; 260 } 261 262 va_start(ap, fmt); 263 264 vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap); 265 isc_log_write(lctx, LOGCATEGORY_DEFAULT, LOGMODULE_DEFAULT, level, "%s", 266 msgbuf); 267 va_end(ap); 268 } 269 270 static int loglevel = 0; 271 272 static void 273 setup_logging(FILE *errout) { 274 isc_result_t result; 275 isc_logdestination_t destination; 276 isc_logconfig_t *logconfig = NULL; 277 278 isc_log_create(mctx, &lctx, &logconfig); 279 isc_log_registercategories(lctx, categories); 280 isc_log_registermodules(lctx, modules); 281 isc_log_setcontext(lctx); 282 dns_log_init(lctx); 283 dns_log_setcontext(lctx); 284 cfg_log_init(lctx); 285 286 destination.file.stream = errout; 287 destination.file.name = NULL; 288 destination.file.versions = ISC_LOG_ROLLNEVER; 289 destination.file.maximum_size = 0; 290 isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, 291 ISC_LOG_DYNAMIC, &destination, 292 ISC_LOG_PRINTPREFIX); 293 294 isc_log_setdebuglevel(lctx, loglevel); 295 isc_log_settag(logconfig, ";; "); 296 297 result = isc_log_usechannel(logconfig, "stderr", 298 ISC_LOGCATEGORY_DEFAULT, NULL); 299 if (result != ISC_R_SUCCESS) { 300 fatal("Couldn't attach to log channel 'stderr'"); 301 } 302 303 if (resolve_trace && loglevel < 1) { 304 isc_log_createchannel(logconfig, "resolver", ISC_LOG_TOFILEDESC, 305 ISC_LOG_DEBUG(1), &destination, 306 ISC_LOG_PRINTPREFIX); 307 308 result = isc_log_usechannel(logconfig, "resolver", 309 DNS_LOGCATEGORY_RESOLVER, 310 DNS_LOGMODULE_RESOLVER); 311 if (result != ISC_R_SUCCESS) { 312 fatal("Couldn't attach to log channel 'resolver'"); 313 } 314 } 315 316 if (validator_trace && loglevel < 3) { 317 isc_log_createchannel(logconfig, "validator", 318 ISC_LOG_TOFILEDESC, ISC_LOG_DEBUG(3), 319 &destination, ISC_LOG_PRINTPREFIX); 320 321 result = isc_log_usechannel(logconfig, "validator", 322 DNS_LOGCATEGORY_DNSSEC, 323 DNS_LOGMODULE_VALIDATOR); 324 if (result != ISC_R_SUCCESS) { 325 fatal("Couldn't attach to log channel 'validator'"); 326 } 327 } 328 329 if (message_trace && loglevel < 10) { 330 isc_log_createchannel(logconfig, "messages", ISC_LOG_TOFILEDESC, 331 ISC_LOG_DEBUG(10), &destination, 332 ISC_LOG_PRINTPREFIX); 333 334 result = isc_log_usechannel(logconfig, "messages", 335 DNS_LOGCATEGORY_RESOLVER, 336 DNS_LOGMODULE_PACKETS); 337 if (result != ISC_R_SUCCESS) { 338 fatal("Couldn't attach to log channel 'messagse'"); 339 } 340 } 341 } 342 343 static void 344 print_status(dns_rdataset_t *rdataset) { 345 char buf[1024] = { 0 }; 346 347 REQUIRE(rdataset != NULL); 348 349 if (!showtrust || !dns_rdataset_isassociated(rdataset)) { 350 return; 351 } 352 353 buf[0] = '\0'; 354 355 if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) { 356 strlcat(buf, "negative response", sizeof(buf)); 357 strlcat(buf, (yaml ? "_" : ", "), sizeof(buf)); 358 } 359 360 switch (rdataset->trust) { 361 case dns_trust_none: 362 strlcat(buf, "untrusted", sizeof(buf)); 363 break; 364 case dns_trust_pending_additional: 365 strlcat(buf, "signed additional data", sizeof(buf)); 366 if (!yaml) { 367 strlcat(buf, ", ", sizeof(buf)); 368 } 369 strlcat(buf, "pending validation", sizeof(buf)); 370 break; 371 case dns_trust_pending_answer: 372 strlcat(buf, "signed answer", sizeof(buf)); 373 if (!yaml) { 374 strlcat(buf, ", ", sizeof(buf)); 375 } 376 strlcat(buf, "pending validation", sizeof(buf)); 377 break; 378 case dns_trust_additional: 379 strlcat(buf, "unsigned additional data", sizeof(buf)); 380 break; 381 case dns_trust_glue: 382 strlcat(buf, "glue data", sizeof(buf)); 383 break; 384 case dns_trust_answer: 385 if (root_validation) { 386 strlcat(buf, "unsigned answer", sizeof(buf)); 387 } else { 388 strlcat(buf, "answer not validated", sizeof(buf)); 389 } 390 break; 391 case dns_trust_authauthority: 392 strlcat(buf, "authority data", sizeof(buf)); 393 break; 394 case dns_trust_authanswer: 395 strlcat(buf, "authoritative", sizeof(buf)); 396 break; 397 case dns_trust_secure: 398 strlcat(buf, "fully validated", sizeof(buf)); 399 break; 400 case dns_trust_ultimate: 401 strlcat(buf, "ultimate trust", sizeof(buf)); 402 break; 403 } 404 405 if (yaml) { 406 char *p; 407 408 /* Convert spaces to underscores for YAML */ 409 for (p = buf; p != NULL && *p != '\0'; p++) { 410 if (*p == ' ') { 411 *p = '_'; 412 } 413 } 414 415 printf(" - %s:\n", buf); 416 } else { 417 printf("; %s\n", buf); 418 } 419 } 420 421 static isc_result_t 422 printdata(dns_rdataset_t *rdataset, dns_name_t *owner, 423 dns_master_style_t *style) { 424 isc_result_t result = ISC_R_SUCCESS; 425 static dns_trust_t trust; 426 static bool first = true; 427 isc_buffer_t target; 428 isc_region_t r; 429 char *t = NULL; 430 int len = 2048; 431 432 if (!dns_rdataset_isassociated(rdataset)) { 433 char namebuf[DNS_NAME_FORMATSIZE]; 434 dns_name_format(owner, namebuf, sizeof(namebuf)); 435 delv_log(ISC_LOG_DEBUG(4), "WARN: empty rdataset %s", namebuf); 436 return (ISC_R_SUCCESS); 437 } 438 439 if (!showdnssec && rdataset->type == dns_rdatatype_rrsig) { 440 return (ISC_R_SUCCESS); 441 } 442 443 if (first || rdataset->trust != trust) { 444 if (!first && showtrust && !short_form && !yaml) { 445 putchar('\n'); 446 } 447 print_status(rdataset); 448 trust = rdataset->trust; 449 first = false; 450 } 451 452 do { 453 t = isc_mem_get(mctx, len); 454 455 isc_buffer_init(&target, t, len); 456 if (short_form) { 457 dns_rdata_t rdata = DNS_RDATA_INIT; 458 for (result = dns_rdataset_first(rdataset); 459 result == ISC_R_SUCCESS; 460 result = dns_rdataset_next(rdataset)) 461 { 462 if ((rdataset->attributes & 463 DNS_RDATASETATTR_NEGATIVE) != 0) 464 { 465 continue; 466 } 467 468 dns_rdataset_current(rdataset, &rdata); 469 result = dns_rdata_tofmttext( 470 &rdata, dns_rootname, styleflags, 0, 471 splitwidth, " ", &target); 472 if (result != ISC_R_SUCCESS) { 473 break; 474 } 475 476 if (isc_buffer_availablelength(&target) < 1) { 477 result = ISC_R_NOSPACE; 478 break; 479 } 480 481 isc_buffer_putstr(&target, "\n"); 482 483 dns_rdata_reset(&rdata); 484 } 485 } else { 486 dns_indent_t indent = { " ", 2 }; 487 if (!yaml && (rdataset->attributes & 488 DNS_RDATASETATTR_NEGATIVE) != 0) 489 { 490 isc_buffer_putstr(&target, "; "); 491 } 492 result = dns_master_rdatasettotext( 493 owner, rdataset, style, yaml ? &indent : NULL, 494 &target); 495 } 496 497 if (result == ISC_R_NOSPACE) { 498 isc_mem_put(mctx, t, len); 499 len += 1024; 500 } else if (result == ISC_R_NOMORE) { 501 result = ISC_R_SUCCESS; 502 } else { 503 CHECK(result); 504 } 505 } while (result == ISC_R_NOSPACE); 506 507 isc_buffer_usedregion(&target, &r); 508 printf("%.*s", (int)r.length, (char *)r.base); 509 510 cleanup: 511 if (t != NULL) { 512 isc_mem_put(mctx, t, len); 513 } 514 515 return (ISC_R_SUCCESS); 516 } 517 518 static isc_result_t 519 setup_style(dns_master_style_t **stylep) { 520 isc_result_t result; 521 dns_master_style_t *style = NULL; 522 523 REQUIRE(stylep != NULL && *stylep == NULL); 524 525 styleflags |= DNS_STYLEFLAG_REL_OWNER; 526 if (yaml) { 527 styleflags |= DNS_STYLEFLAG_YAML; 528 } else { 529 if (showcomments) { 530 styleflags |= DNS_STYLEFLAG_COMMENT; 531 } 532 if (print_unknown_format) { 533 styleflags |= DNS_STYLEFLAG_UNKNOWNFORMAT; 534 } 535 if (rrcomments) { 536 styleflags |= DNS_STYLEFLAG_RRCOMMENT; 537 } 538 if (nottl) { 539 styleflags |= DNS_STYLEFLAG_NO_TTL; 540 } 541 if (noclass) { 542 styleflags |= DNS_STYLEFLAG_NO_CLASS; 543 } 544 if (nocrypto) { 545 styleflags |= DNS_STYLEFLAG_NOCRYPTO; 546 } 547 if (multiline) { 548 styleflags |= DNS_STYLEFLAG_MULTILINE; 549 styleflags |= DNS_STYLEFLAG_COMMENT; 550 } 551 } 552 553 if (multiline || (nottl && noclass)) { 554 result = dns_master_stylecreate(&style, styleflags, 24, 24, 24, 555 32, 80, 8, splitwidth, mctx); 556 } else if (nottl || noclass) { 557 result = dns_master_stylecreate(&style, styleflags, 24, 24, 32, 558 40, 80, 8, splitwidth, mctx); 559 } else { 560 result = dns_master_stylecreate(&style, styleflags, 24, 32, 40, 561 48, 80, 8, splitwidth, mctx); 562 } 563 564 if (result == ISC_R_SUCCESS) { 565 *stylep = style; 566 } 567 return (result); 568 } 569 570 static isc_result_t 571 convert_name(dns_fixedname_t *fn, dns_name_t **name, const char *text) { 572 isc_result_t result; 573 isc_buffer_t b; 574 dns_name_t *n; 575 unsigned int len; 576 577 REQUIRE(fn != NULL && name != NULL && text != NULL); 578 len = strlen(text); 579 580 isc_buffer_constinit(&b, text, len); 581 isc_buffer_add(&b, len); 582 n = dns_fixedname_initname(fn); 583 584 result = dns_name_fromtext(n, &b, dns_rootname, 0, NULL); 585 if (result != ISC_R_SUCCESS) { 586 delv_log(ISC_LOG_ERROR, "failed to convert QNAME %s: %s", text, 587 isc_result_totext(result)); 588 return (result); 589 } 590 591 *name = n; 592 return (ISC_R_SUCCESS); 593 } 594 595 static isc_result_t 596 key_fromconfig(const cfg_obj_t *key, dns_client_t *client) { 597 dns_rdata_dnskey_t dnskey; 598 dns_rdata_ds_t ds; 599 uint32_t rdata1, rdata2, rdata3; 600 const char *datastr = NULL, *keynamestr = NULL, *atstr = NULL; 601 unsigned char data[4096]; 602 isc_buffer_t databuf; 603 unsigned char rrdata[4096]; 604 isc_buffer_t rrdatabuf; 605 isc_region_t r; 606 dns_fixedname_t fkeyname; 607 dns_name_t *keyname; 608 isc_result_t result; 609 bool match_root = false; 610 enum { 611 INITIAL_KEY, 612 STATIC_KEY, 613 INITIAL_DS, 614 STATIC_DS, 615 TRUSTED 616 } anchortype; 617 const cfg_obj_t *obj; 618 619 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name")); 620 CHECK(convert_name(&fkeyname, &keyname, keynamestr)); 621 622 if (!root_validation) { 623 return (ISC_R_SUCCESS); 624 } 625 626 if (anchor_name) { 627 match_root = dns_name_equal(keyname, anchor_name); 628 } 629 630 if (!match_root) { 631 return (ISC_R_SUCCESS); 632 } 633 634 if (!root_validation) { 635 return (ISC_R_SUCCESS); 636 } 637 638 delv_log(ISC_LOG_DEBUG(3), "adding trust anchor %s", trust_anchor); 639 640 /* if DNSKEY, flags; if DS, key tag */ 641 rdata1 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata1")); 642 643 /* if DNSKEY, protocol; if DS, algorithm */ 644 rdata2 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata2")); 645 646 /* if DNSKEY, algorithm; if DS, digest type */ 647 rdata3 = cfg_obj_asuint32(cfg_tuple_get(key, "rdata3")); 648 649 /* What type of trust anchor is this? */ 650 obj = cfg_tuple_get(key, "anchortype"); 651 if (cfg_obj_isvoid(obj)) { 652 /* 653 * "anchortype" is not defined, this must be a static-key 654 * configured with trusted-keys. 655 */ 656 anchortype = STATIC_KEY; 657 } else { 658 atstr = cfg_obj_asstring(obj); 659 if (strcasecmp(atstr, "static-key") == 0) { 660 anchortype = STATIC_KEY; 661 } else if (strcasecmp(atstr, "static-ds") == 0) { 662 anchortype = STATIC_DS; 663 } else if (strcasecmp(atstr, "initial-key") == 0) { 664 anchortype = INITIAL_KEY; 665 } else if (strcasecmp(atstr, "initial-ds") == 0) { 666 anchortype = INITIAL_DS; 667 } else { 668 delv_log(ISC_LOG_ERROR, 669 "key '%s': invalid initialization method '%s'", 670 keynamestr, atstr); 671 result = ISC_R_FAILURE; 672 goto cleanup; 673 } 674 } 675 676 isc_buffer_init(&databuf, data, sizeof(data)); 677 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata)); 678 679 if (rdata1 > 0xffff) { 680 CHECK(ISC_R_RANGE); 681 } 682 if (rdata2 > 0xff) { 683 CHECK(ISC_R_RANGE); 684 } 685 if (rdata3 > 0xff) { 686 CHECK(ISC_R_RANGE); 687 } 688 689 switch (anchortype) { 690 case STATIC_KEY: 691 case INITIAL_KEY: 692 case TRUSTED: 693 dnskey.common.rdclass = dns_rdataclass_in; 694 dnskey.common.rdtype = dns_rdatatype_dnskey; 695 dnskey.mctx = NULL; 696 697 ISC_LINK_INIT(&dnskey.common, link); 698 699 dnskey.flags = (uint16_t)rdata1; 700 dnskey.protocol = (uint8_t)rdata2; 701 dnskey.algorithm = (uint8_t)rdata3; 702 703 datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); 704 CHECK(isc_base64_decodestring(datastr, &databuf)); 705 isc_buffer_usedregion(&databuf, &r); 706 dnskey.datalen = r.length; 707 dnskey.data = r.base; 708 709 CHECK(dns_rdata_fromstruct(NULL, dnskey.common.rdclass, 710 dnskey.common.rdtype, &dnskey, 711 &rrdatabuf)); 712 CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, 713 dns_rdatatype_dnskey, keyname, 714 &rrdatabuf)); 715 break; 716 case INITIAL_DS: 717 case STATIC_DS: 718 ds.common.rdclass = dns_rdataclass_in; 719 ds.common.rdtype = dns_rdatatype_ds; 720 ds.mctx = NULL; 721 722 ISC_LINK_INIT(&ds.common, link); 723 724 ds.key_tag = (uint16_t)rdata1; 725 ds.algorithm = (uint8_t)rdata2; 726 ds.digest_type = (uint8_t)rdata3; 727 728 datastr = cfg_obj_asstring(cfg_tuple_get(key, "data")); 729 CHECK(isc_hex_decodestring(datastr, &databuf)); 730 isc_buffer_usedregion(&databuf, &r); 731 732 switch (ds.digest_type) { 733 case DNS_DSDIGEST_SHA1: 734 if (r.length != ISC_SHA1_DIGESTLENGTH) { 735 CHECK(ISC_R_UNEXPECTEDEND); 736 } 737 break; 738 case DNS_DSDIGEST_SHA256: 739 if (r.length != ISC_SHA256_DIGESTLENGTH) { 740 CHECK(ISC_R_UNEXPECTEDEND); 741 } 742 break; 743 case DNS_DSDIGEST_SHA384: 744 if (r.length != ISC_SHA384_DIGESTLENGTH) { 745 CHECK(ISC_R_UNEXPECTEDEND); 746 } 747 break; 748 } 749 750 ds.length = r.length; 751 ds.digest = r.base; 752 753 CHECK(dns_rdata_fromstruct(NULL, ds.common.rdclass, 754 ds.common.rdtype, &ds, &rrdatabuf)); 755 CHECK(dns_client_addtrustedkey(client, dns_rdataclass_in, 756 dns_rdatatype_ds, keyname, 757 &rrdatabuf)); 758 } 759 760 num_keys++; 761 762 cleanup: 763 if (result == DST_R_NOCRYPTO) { 764 cfg_obj_log(key, lctx, ISC_LOG_ERROR, "no crypto support"); 765 } else if (result == DST_R_UNSUPPORTEDALG) { 766 cfg_obj_log(key, lctx, ISC_LOG_WARNING, 767 "skipping trusted key '%s': %s", keynamestr, 768 isc_result_totext(result)); 769 result = ISC_R_SUCCESS; 770 } else if (result != ISC_R_SUCCESS) { 771 cfg_obj_log(key, lctx, ISC_LOG_ERROR, 772 "failed to add trusted key '%s': %s", keynamestr, 773 isc_result_totext(result)); 774 result = ISC_R_FAILURE; 775 } 776 777 return (result); 778 } 779 780 static isc_result_t 781 load_keys(const cfg_obj_t *keys, dns_client_t *client) { 782 const cfg_listelt_t *elt, *elt2; 783 const cfg_obj_t *key, *keylist; 784 isc_result_t result = ISC_R_SUCCESS; 785 786 for (elt = cfg_list_first(keys); elt != NULL; elt = cfg_list_next(elt)) 787 { 788 keylist = cfg_listelt_value(elt); 789 790 for (elt2 = cfg_list_first(keylist); elt2 != NULL; 791 elt2 = cfg_list_next(elt2)) 792 { 793 key = cfg_listelt_value(elt2); 794 CHECK(key_fromconfig(key, client)); 795 } 796 } 797 798 cleanup: 799 if (result == DST_R_NOCRYPTO) { 800 result = ISC_R_SUCCESS; 801 } 802 return (result); 803 } 804 805 static isc_result_t 806 setup_dnsseckeys(dns_client_t *client) { 807 isc_result_t result; 808 cfg_parser_t *parser = NULL; 809 const cfg_obj_t *trusted_keys = NULL; 810 const cfg_obj_t *managed_keys = NULL; 811 const cfg_obj_t *trust_anchors = NULL; 812 cfg_obj_t *bindkeys = NULL; 813 const char *filename = anchorfile; 814 815 if (!root_validation) { 816 return (ISC_R_SUCCESS); 817 } 818 819 if (filename == NULL) { 820 #ifndef WIN32 821 filename = NS_SYSCONFDIR "/bind.keys"; 822 #else /* ifndef WIN32 */ 823 static char buf[MAX_PATH]; 824 strlcpy(buf, isc_ntpaths_get(SYS_CONF_DIR), sizeof(buf)); 825 strlcat(buf, "\\bind.keys", sizeof(buf)); 826 filename = buf; 827 #endif /* ifndef WIN32 */ 828 } 829 830 if (trust_anchor == NULL) { 831 trust_anchor = isc_mem_strdup(mctx, "."); 832 } 833 834 if (trust_anchor != NULL) { 835 CHECK(convert_name(&afn, &anchor_name, trust_anchor)); 836 } 837 838 CHECK(cfg_parser_create(mctx, dns_lctx, &parser)); 839 840 if (access(filename, R_OK) != 0) { 841 if (anchorfile != NULL) { 842 fatal("Unable to read key file '%s'", anchorfile); 843 } 844 } else { 845 result = cfg_parse_file(parser, filename, &cfg_type_bindkeys, 846 &bindkeys); 847 if (result != ISC_R_SUCCESS) { 848 if (anchorfile != NULL) { 849 fatal("Unable to load keys from '%s'", 850 anchorfile); 851 } 852 } 853 } 854 855 if (bindkeys == NULL) { 856 isc_buffer_t b; 857 858 isc_buffer_init(&b, anchortext, sizeof(anchortext) - 1); 859 isc_buffer_add(&b, sizeof(anchortext) - 1); 860 cfg_parser_reset(parser); 861 result = cfg_parse_buffer(parser, &b, NULL, 0, 862 &cfg_type_bindkeys, 0, &bindkeys); 863 if (result != ISC_R_SUCCESS) { 864 fatal("Unable to parse built-in keys"); 865 } 866 } 867 868 INSIST(bindkeys != NULL); 869 cfg_map_get(bindkeys, "trusted-keys", &trusted_keys); 870 cfg_map_get(bindkeys, "managed-keys", &managed_keys); 871 cfg_map_get(bindkeys, "trust-anchors", &trust_anchors); 872 873 if (trusted_keys != NULL) { 874 CHECK(load_keys(trusted_keys, client)); 875 } 876 if (managed_keys != NULL) { 877 CHECK(load_keys(managed_keys, client)); 878 } 879 if (trust_anchors != NULL) { 880 CHECK(load_keys(trust_anchors, client)); 881 } 882 result = ISC_R_SUCCESS; 883 884 if (num_keys == 0) { 885 fatal("No trusted keys were loaded"); 886 } 887 888 cleanup: 889 if (bindkeys != NULL) { 890 cfg_obj_destroy(parser, &bindkeys); 891 } 892 if (parser != NULL) { 893 cfg_parser_destroy(&parser); 894 } 895 if (result != ISC_R_SUCCESS) { 896 delv_log(ISC_LOG_ERROR, "setup_dnsseckeys: %s", 897 isc_result_totext(result)); 898 } 899 return (result); 900 } 901 902 static isc_result_t 903 addserver(dns_client_t *client) { 904 struct addrinfo hints, *res, *cur; 905 int gaierror; 906 struct in_addr in4; 907 struct in6_addr in6; 908 isc_sockaddr_t *sa; 909 isc_sockaddrlist_t servers; 910 uint32_t destport; 911 isc_result_t result; 912 dns_name_t *name = NULL; 913 914 result = parse_uint(&destport, port, 0xffff, "port"); 915 if (result != ISC_R_SUCCESS) { 916 fatal("Couldn't parse port number"); 917 } 918 919 ISC_LIST_INIT(servers); 920 921 if (inet_pton(AF_INET, server, &in4) == 1) { 922 if (!use_ipv4) { 923 fatal("Use of IPv4 disabled by -6"); 924 } 925 sa = isc_mem_get(mctx, sizeof(*sa)); 926 ISC_LINK_INIT(sa, link); 927 isc_sockaddr_fromin(sa, &in4, destport); 928 ISC_LIST_APPEND(servers, sa, link); 929 } else if (inet_pton(AF_INET6, server, &in6) == 1) { 930 if (!use_ipv6) { 931 fatal("Use of IPv6 disabled by -4"); 932 } 933 sa = isc_mem_get(mctx, sizeof(*sa)); 934 ISC_LINK_INIT(sa, link); 935 isc_sockaddr_fromin6(sa, &in6, destport); 936 ISC_LIST_APPEND(servers, sa, link); 937 } else { 938 memset(&hints, 0, sizeof(hints)); 939 if (!use_ipv6) { 940 hints.ai_family = AF_INET; 941 } else if (!use_ipv4) { 942 hints.ai_family = AF_INET6; 943 } else { 944 hints.ai_family = AF_UNSPEC; 945 } 946 hints.ai_socktype = SOCK_DGRAM; 947 hints.ai_protocol = IPPROTO_UDP; 948 gaierror = getaddrinfo(server, port, &hints, &res); 949 if (gaierror != 0) { 950 delv_log(ISC_LOG_ERROR, "getaddrinfo failed: %s", 951 gai_strerror(gaierror)); 952 return (ISC_R_FAILURE); 953 } 954 955 result = ISC_R_SUCCESS; 956 for (cur = res; cur != NULL; cur = cur->ai_next) { 957 if (cur->ai_family != AF_INET && 958 cur->ai_family != AF_INET6) 959 { 960 continue; 961 } 962 sa = isc_mem_get(mctx, sizeof(*sa)); 963 memset(sa, 0, sizeof(*sa)); 964 ISC_LINK_INIT(sa, link); 965 memmove(&sa->type, cur->ai_addr, cur->ai_addrlen); 966 sa->length = (unsigned int)cur->ai_addrlen; 967 ISC_LIST_APPEND(servers, sa, link); 968 } 969 freeaddrinfo(res); 970 CHECK(result); 971 } 972 973 CHECK(dns_client_setservers(client, dns_rdataclass_in, name, &servers)); 974 975 cleanup: 976 while (!ISC_LIST_EMPTY(servers)) { 977 sa = ISC_LIST_HEAD(servers); 978 ISC_LIST_UNLINK(servers, sa, link); 979 isc_mem_put(mctx, sa, sizeof(*sa)); 980 } 981 982 if (result != ISC_R_SUCCESS) { 983 delv_log(ISC_LOG_ERROR, "addserver: %s", 984 isc_result_totext(result)); 985 } 986 987 return (result); 988 } 989 990 static isc_result_t 991 findserver(dns_client_t *client) { 992 isc_result_t result; 993 irs_resconf_t *resconf = NULL; 994 isc_sockaddrlist_t *nameservers; 995 isc_sockaddr_t *sa, *next; 996 uint32_t destport; 997 998 result = parse_uint(&destport, port, 0xffff, "port"); 999 if (result != ISC_R_SUCCESS) { 1000 fatal("Couldn't parse port number"); 1001 } 1002 1003 result = irs_resconf_load(mctx, "/etc/resolv.conf", &resconf); 1004 if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) { 1005 delv_log(ISC_LOG_ERROR, "irs_resconf_load: %s", 1006 isc_result_totext(result)); 1007 goto cleanup; 1008 } 1009 1010 /* Get nameservers from resolv.conf */ 1011 nameservers = irs_resconf_getnameservers(resconf); 1012 for (sa = ISC_LIST_HEAD(*nameservers); sa != NULL; sa = next) { 1013 next = ISC_LIST_NEXT(sa, link); 1014 1015 /* Set destination port */ 1016 if (sa->type.sa.sa_family == AF_INET && use_ipv4) { 1017 sa->type.sin.sin_port = htons(destport); 1018 continue; 1019 } 1020 if (sa->type.sa.sa_family == AF_INET6 && use_ipv6) { 1021 sa->type.sin6.sin6_port = htons(destport); 1022 continue; 1023 } 1024 1025 /* Incompatible protocol family */ 1026 ISC_LIST_UNLINK(*nameservers, sa, link); 1027 isc_mem_put(mctx, sa, sizeof(*sa)); 1028 } 1029 1030 /* None found, use localhost */ 1031 if (ISC_LIST_EMPTY(*nameservers)) { 1032 if (use_ipv4) { 1033 struct in_addr localhost; 1034 localhost.s_addr = htonl(INADDR_LOOPBACK); 1035 sa = isc_mem_get(mctx, sizeof(*sa)); 1036 isc_sockaddr_fromin(sa, &localhost, destport); 1037 1038 ISC_LINK_INIT(sa, link); 1039 ISC_LIST_APPEND(*nameservers, sa, link); 1040 } 1041 1042 if (use_ipv6) { 1043 sa = isc_mem_get(mctx, sizeof(*sa)); 1044 isc_sockaddr_fromin6(sa, &in6addr_loopback, destport); 1045 1046 ISC_LINK_INIT(sa, link); 1047 ISC_LIST_APPEND(*nameservers, sa, link); 1048 } 1049 } 1050 1051 result = dns_client_setservers(client, dns_rdataclass_in, NULL, 1052 nameservers); 1053 if (result != ISC_R_SUCCESS) { 1054 delv_log(ISC_LOG_ERROR, "dns_client_setservers: %s", 1055 isc_result_totext(result)); 1056 } 1057 1058 cleanup: 1059 if (resconf != NULL) { 1060 irs_resconf_destroy(&resconf); 1061 } 1062 return (result); 1063 } 1064 1065 static isc_result_t 1066 parse_uint(uint32_t *uip, const char *value, uint32_t max, const char *desc) { 1067 uint32_t n; 1068 isc_result_t result = isc_parse_uint32(&n, value, 10); 1069 if (result == ISC_R_SUCCESS && n > max) { 1070 result = ISC_R_RANGE; 1071 } 1072 if (result != ISC_R_SUCCESS) { 1073 printf("invalid %s '%s': %s\n", desc, value, 1074 isc_result_totext(result)); 1075 return (result); 1076 } 1077 *uip = n; 1078 return (ISC_R_SUCCESS); 1079 } 1080 1081 static void 1082 plus_option(char *option) { 1083 isc_result_t result; 1084 char *cmd, *value, *last = NULL; 1085 bool state = true; 1086 1087 INSIST(option != NULL); 1088 1089 cmd = strtok_r(option, "=", &last); 1090 if (cmd == NULL) { 1091 printf(";; Invalid option %s\n", option); 1092 return; 1093 } 1094 if (strncasecmp(cmd, "no", 2) == 0) { 1095 cmd += 2; 1096 state = false; 1097 } 1098 1099 value = strtok_r(NULL, "\0", &last); 1100 1101 #define FULLCHECK(A) \ 1102 do { \ 1103 size_t _l = strlen(cmd); \ 1104 if (_l >= sizeof(A) || strncasecmp(cmd, A, _l) != 0) \ 1105 goto invalid_option; \ 1106 } while (0) 1107 1108 switch (cmd[0]) { 1109 case 'a': /* all */ 1110 FULLCHECK("all"); 1111 showcomments = state; 1112 rrcomments = state; 1113 showtrust = state; 1114 break; 1115 case 'c': 1116 switch (cmd[1]) { 1117 case 'd': /* cdflag */ 1118 FULLCHECK("cdflag"); 1119 cdflag = state; 1120 break; 1121 case 'l': /* class */ 1122 FULLCHECK("class"); 1123 noclass = !state; 1124 break; 1125 case 'o': /* comments */ 1126 FULLCHECK("comments"); 1127 showcomments = state; 1128 break; 1129 case 'r': /* crypto */ 1130 FULLCHECK("crypto"); 1131 nocrypto = !state; 1132 break; 1133 default: 1134 goto invalid_option; 1135 } 1136 break; 1137 case 'd': 1138 switch (cmd[1]) { 1139 case 'l': /* dlv */ 1140 FULLCHECK("dlv"); 1141 if (state) { 1142 fprintf(stderr, "Invalid option: " 1143 "+dlv is obsolete\n"); 1144 exit(1); 1145 } 1146 break; 1147 case 'n': /* dnssec */ 1148 FULLCHECK("dnssec"); 1149 showdnssec = state; 1150 break; 1151 default: 1152 goto invalid_option; 1153 } 1154 break; 1155 case 'm': 1156 switch (cmd[1]) { 1157 case 't': /* mtrace */ 1158 message_trace = state; 1159 if (state) { 1160 resolve_trace = state; 1161 } 1162 break; 1163 case 'u': /* multiline */ 1164 FULLCHECK("multiline"); 1165 multiline = state; 1166 break; 1167 default: 1168 goto invalid_option; 1169 } 1170 break; 1171 case 'r': 1172 switch (cmd[1]) { 1173 case 'o': /* root */ 1174 FULLCHECK("root"); 1175 if (state && no_sigs) { 1176 break; 1177 } 1178 root_validation = state; 1179 if (value != NULL) { 1180 trust_anchor = isc_mem_strdup(mctx, value); 1181 } 1182 break; 1183 case 'r': /* rrcomments */ 1184 FULLCHECK("rrcomments"); 1185 rrcomments = state; 1186 break; 1187 case 't': /* rtrace */ 1188 FULLCHECK("rtrace"); 1189 resolve_trace = state; 1190 break; 1191 default: 1192 goto invalid_option; 1193 } 1194 break; 1195 case 's': 1196 switch (cmd[1]) { 1197 case 'h': /* short */ 1198 FULLCHECK("short"); 1199 short_form = state; 1200 if (short_form) { 1201 multiline = false; 1202 showcomments = false; 1203 showtrust = false; 1204 showdnssec = false; 1205 } 1206 break; 1207 case 'p': /* split */ 1208 FULLCHECK("split"); 1209 if (value != NULL && !state) { 1210 goto invalid_option; 1211 } 1212 if (!state) { 1213 splitwidth = 0; 1214 break; 1215 } else if (value == NULL) { 1216 break; 1217 } 1218 1219 result = parse_uint(&splitwidth, value, 1023, "split"); 1220 if (splitwidth % 4 != 0) { 1221 splitwidth = ((splitwidth + 3) / 4) * 4; 1222 warn("split must be a multiple of 4; " 1223 "adjusting to %d", 1224 splitwidth); 1225 } 1226 /* 1227 * There is an adjustment done in the 1228 * totext_<rrtype>() functions which causes 1229 * splitwidth to shrink. This is okay when we're 1230 * using the default width but incorrect in this 1231 * case, so we correct for it 1232 */ 1233 if (splitwidth) { 1234 splitwidth += 3; 1235 } 1236 if (result != ISC_R_SUCCESS) { 1237 fatal("Couldn't parse split"); 1238 } 1239 break; 1240 default: 1241 goto invalid_option; 1242 } 1243 break; 1244 case 'u': 1245 FULLCHECK("unknownformat"); 1246 print_unknown_format = state; 1247 break; 1248 case 't': 1249 switch (cmd[1]) { 1250 case 'c': /* tcp */ 1251 FULLCHECK("tcp"); 1252 use_tcp = state; 1253 break; 1254 case 'r': /* trust */ 1255 FULLCHECK("trust"); 1256 showtrust = state; 1257 break; 1258 case 't': /* ttl */ 1259 FULLCHECK("ttl"); 1260 nottl = !state; 1261 break; 1262 default: 1263 goto invalid_option; 1264 } 1265 break; 1266 case 'v': /* vtrace */ 1267 FULLCHECK("vtrace"); 1268 validator_trace = state; 1269 if (state) { 1270 resolve_trace = state; 1271 } 1272 break; 1273 case 'y': /* yaml */ 1274 FULLCHECK("yaml"); 1275 yaml = state; 1276 if (state) { 1277 rrcomments = false; 1278 } 1279 break; 1280 default: 1281 invalid_option: 1282 /* 1283 * We can also add a "need_value:" case here if we ever 1284 * add a plus-option that requires a specified value 1285 */ 1286 fprintf(stderr, "Invalid option: +%s\n", option); 1287 usage(); 1288 } 1289 return; 1290 } 1291 1292 /* 1293 * options: "46a:b:c:d:himp:q:t:vx:"; 1294 */ 1295 static const char *single_dash_opts = "46himv"; 1296 static const char *dash_opts = "46abcdhimpqtvx"; 1297 1298 static bool 1299 dash_option(char *option, char *next, bool *open_type_class) { 1300 char opt, *value; 1301 isc_result_t result; 1302 bool value_from_next; 1303 isc_textregion_t tr; 1304 dns_rdatatype_t rdtype; 1305 dns_rdataclass_t rdclass; 1306 char textname[MAXNAME]; 1307 struct in_addr in4; 1308 struct in6_addr in6; 1309 in_port_t srcport; 1310 uint32_t num; 1311 char *hash; 1312 1313 while (strpbrk(option, single_dash_opts) == &option[0]) { 1314 /* 1315 * Since the -[46himv] options do not take an argument, 1316 * account for them (in any number and/or combination) 1317 * if they appear as the first character(s) of a q-opt. 1318 */ 1319 opt = option[0]; 1320 switch (opt) { 1321 case '4': 1322 if (isc_net_probeipv4() != ISC_R_SUCCESS) { 1323 fatal("IPv4 networking not available"); 1324 } 1325 if (use_ipv6) { 1326 isc_net_disableipv6(); 1327 use_ipv6 = false; 1328 } 1329 break; 1330 case '6': 1331 if (isc_net_probeipv6() != ISC_R_SUCCESS) { 1332 fatal("IPv6 networking not available"); 1333 } 1334 if (use_ipv4) { 1335 isc_net_disableipv4(); 1336 use_ipv4 = false; 1337 } 1338 break; 1339 case 'h': 1340 usage(); 1341 exit(0); 1342 case 'i': 1343 no_sigs = true; 1344 root_validation = false; 1345 break; 1346 case 'm': 1347 /* handled in preparse_args() */ 1348 break; 1349 case 'v': 1350 fputs("delv " VERSION "\n", stderr); 1351 exit(0); 1352 default: 1353 UNREACHABLE(); 1354 } 1355 if (strlen(option) > 1U) { 1356 option = &option[1]; 1357 } else { 1358 return (false); 1359 } 1360 } 1361 opt = option[0]; 1362 if (strlen(option) > 1U) { 1363 value_from_next = false; 1364 value = &option[1]; 1365 } else { 1366 value_from_next = true; 1367 value = next; 1368 } 1369 if (value == NULL) { 1370 goto invalid_option; 1371 } 1372 switch (opt) { 1373 case 'a': 1374 anchorfile = isc_mem_strdup(mctx, value); 1375 return (value_from_next); 1376 case 'b': 1377 hash = strchr(value, '#'); 1378 if (hash != NULL) { 1379 result = parse_uint(&num, hash + 1, 0xffff, "port"); 1380 if (result != ISC_R_SUCCESS) { 1381 fatal("Couldn't parse port number"); 1382 } 1383 srcport = num; 1384 *hash = '\0'; 1385 } else { 1386 srcport = 0; 1387 } 1388 1389 if (inet_pton(AF_INET, value, &in4) == 1) { 1390 if (srcaddr4 != NULL) { 1391 fatal("Only one local address per family " 1392 "can be specified\n"); 1393 } 1394 isc_sockaddr_fromin(&a4, &in4, srcport); 1395 srcaddr4 = &a4; 1396 } else if (inet_pton(AF_INET6, value, &in6) == 1) { 1397 if (srcaddr6 != NULL) { 1398 fatal("Only one local address per family " 1399 "can be specified\n"); 1400 } 1401 isc_sockaddr_fromin6(&a6, &in6, srcport); 1402 srcaddr6 = &a6; 1403 } else { 1404 if (hash != NULL) { 1405 *hash = '#'; 1406 } 1407 fatal("Invalid address %s", value); 1408 } 1409 if (hash != NULL) { 1410 *hash = '#'; 1411 } 1412 return (value_from_next); 1413 case 'c': 1414 if (classset) { 1415 warn("extra query class"); 1416 } 1417 1418 *open_type_class = false; 1419 tr.base = value; 1420 tr.length = strlen(value); 1421 result = dns_rdataclass_fromtext(&rdclass, 1422 (isc_textregion_t *)&tr); 1423 if (result == ISC_R_SUCCESS) { 1424 classset = true; 1425 } else if (rdclass != dns_rdataclass_in) { 1426 warn("ignoring non-IN query class"); 1427 } else { 1428 warn("ignoring invalid class"); 1429 } 1430 return (value_from_next); 1431 case 'd': 1432 result = parse_uint(&num, value, 99, "debug level"); 1433 if (result != ISC_R_SUCCESS) { 1434 fatal("Couldn't parse debug level"); 1435 } 1436 loglevel = num; 1437 return (value_from_next); 1438 case 'p': 1439 port = value; 1440 return (value_from_next); 1441 case 'q': 1442 if (curqname != NULL) { 1443 warn("extra query name"); 1444 isc_mem_free(mctx, curqname); 1445 } 1446 curqname = isc_mem_strdup(mctx, value); 1447 return (value_from_next); 1448 case 't': 1449 *open_type_class = false; 1450 tr.base = value; 1451 tr.length = strlen(value); 1452 result = dns_rdatatype_fromtext(&rdtype, 1453 (isc_textregion_t *)&tr); 1454 if (result == ISC_R_SUCCESS) { 1455 if (typeset) { 1456 warn("extra query type"); 1457 } 1458 if (rdtype == dns_rdatatype_ixfr || 1459 rdtype == dns_rdatatype_axfr) 1460 { 1461 fatal("Transfer not supported"); 1462 } 1463 qtype = rdtype; 1464 typeset = true; 1465 } else { 1466 warn("ignoring invalid type"); 1467 } 1468 return (value_from_next); 1469 case 'x': 1470 result = get_reverse(textname, sizeof(textname), value, false); 1471 if (result == ISC_R_SUCCESS) { 1472 if (curqname != NULL) { 1473 isc_mem_free(mctx, curqname); 1474 warn("extra query name"); 1475 } 1476 curqname = isc_mem_strdup(mctx, textname); 1477 if (typeset) { 1478 warn("extra query type"); 1479 } 1480 qtype = dns_rdatatype_ptr; 1481 typeset = true; 1482 } else { 1483 fprintf(stderr, "Invalid IP address %s\n", value); 1484 exit(1); 1485 } 1486 return (value_from_next); 1487 invalid_option: 1488 default: 1489 fprintf(stderr, "Invalid option: -%s\n", option); 1490 usage(); 1491 } 1492 UNREACHABLE(); 1493 return (false); 1494 } 1495 1496 /* 1497 * Check for -m first to determine whether to enable 1498 * memory debugging when setting up the memory context. 1499 */ 1500 static void 1501 preparse_args(int argc, char **argv) { 1502 bool ipv4only = false, ipv6only = false; 1503 char *option; 1504 1505 for (argc--, argv++; argc > 0; argc--, argv++) { 1506 if (argv[0][0] != '-') { 1507 continue; 1508 } 1509 1510 option = &argv[0][1]; 1511 while (strpbrk(option, single_dash_opts) == &option[0]) { 1512 switch (option[0]) { 1513 case 'm': 1514 isc_mem_debugging = ISC_MEM_DEBUGTRACE | 1515 ISC_MEM_DEBUGRECORD; 1516 break; 1517 case '4': 1518 if (ipv6only) { 1519 fatal("only one of -4 and -6 allowed"); 1520 } 1521 ipv4only = true; 1522 break; 1523 case '6': 1524 if (ipv4only) { 1525 fatal("only one of -4 and -6 allowed"); 1526 } 1527 ipv6only = true; 1528 break; 1529 } 1530 option = &option[1]; 1531 } 1532 1533 if (strlen(option) == 0U) { 1534 continue; 1535 } 1536 1537 /* Look for dash value option. */ 1538 if (strpbrk(option, dash_opts) != &option[0] || 1539 strlen(option) > 1U) 1540 { 1541 /* Error or value in option. */ 1542 continue; 1543 } 1544 1545 /* Dash value is next argument so we need to skip it. */ 1546 argc--; 1547 argv++; 1548 1549 /* Handle missing argument */ 1550 if (argc == 0) { 1551 break; 1552 } 1553 } 1554 } 1555 1556 /* 1557 * Argument parsing is based on dig, but simplified: only one 1558 * QNAME/QCLASS/QTYPE tuple can be specified, and options have 1559 * been removed that aren't applicable to delv. The interface 1560 * should be familiar to dig users, however. 1561 */ 1562 static void 1563 parse_args(int argc, char **argv) { 1564 isc_result_t result; 1565 isc_textregion_t tr; 1566 dns_rdatatype_t rdtype; 1567 dns_rdataclass_t rdclass; 1568 bool open_type_class = true; 1569 1570 for (; argc > 0; argc--, argv++) { 1571 if (argv[0][0] == '@') { 1572 server = &argv[0][1]; 1573 } else if (argv[0][0] == '+') { 1574 plus_option(&argv[0][1]); 1575 } else if (argv[0][0] == '-') { 1576 if (argc <= 1) { 1577 if (dash_option(&argv[0][1], NULL, 1578 &open_type_class)) 1579 { 1580 argc--; 1581 argv++; 1582 } 1583 } else { 1584 if (dash_option(&argv[0][1], argv[1], 1585 &open_type_class)) 1586 { 1587 argc--; 1588 argv++; 1589 } 1590 } 1591 } else { 1592 /* 1593 * Anything which isn't an option 1594 */ 1595 if (open_type_class) { 1596 tr.base = argv[0]; 1597 tr.length = strlen(argv[0]); 1598 result = dns_rdatatype_fromtext( 1599 &rdtype, (isc_textregion_t *)&tr); 1600 if (result == ISC_R_SUCCESS) { 1601 if (typeset) { 1602 warn("extra query type"); 1603 } 1604 if (rdtype == dns_rdatatype_ixfr || 1605 rdtype == dns_rdatatype_axfr) 1606 { 1607 fatal("Transfer not supported"); 1608 } 1609 qtype = rdtype; 1610 typeset = true; 1611 continue; 1612 } 1613 result = dns_rdataclass_fromtext( 1614 &rdclass, (isc_textregion_t *)&tr); 1615 if (result == ISC_R_SUCCESS) { 1616 if (classset) { 1617 warn("extra query class"); 1618 } else if (rdclass != dns_rdataclass_in) 1619 { 1620 warn("ignoring non-IN " 1621 "query class"); 1622 } 1623 continue; 1624 } 1625 } 1626 1627 if (curqname == NULL) { 1628 curqname = isc_mem_strdup(mctx, argv[0]); 1629 } 1630 } 1631 } 1632 1633 /* 1634 * If no qname or qtype specified, search for root/NS 1635 * If no qtype specified, use A 1636 */ 1637 if (!typeset) { 1638 qtype = dns_rdatatype_a; 1639 } 1640 1641 if (curqname == NULL) { 1642 qname = isc_mem_strdup(mctx, "."); 1643 1644 if (!typeset) { 1645 qtype = dns_rdatatype_ns; 1646 } 1647 } else { 1648 qname = curqname; 1649 } 1650 } 1651 1652 static isc_result_t 1653 append_str(const char *text, int len, char **p, char *end) { 1654 if (len > end - *p) { 1655 return (ISC_R_NOSPACE); 1656 } 1657 memmove(*p, text, len); 1658 *p += len; 1659 return (ISC_R_SUCCESS); 1660 } 1661 1662 static isc_result_t 1663 reverse_octets(const char *in, char **p, char *end) { 1664 char *dot = strchr(in, '.'); 1665 int len; 1666 if (dot != NULL) { 1667 isc_result_t result; 1668 result = reverse_octets(dot + 1, p, end); 1669 if (result != ISC_R_SUCCESS) { 1670 return (result); 1671 } 1672 result = append_str(".", 1, p, end); 1673 if (result != ISC_R_SUCCESS) { 1674 return (result); 1675 } 1676 len = (int)(dot - in); 1677 } else { 1678 len = strlen(in); 1679 } 1680 return (append_str(in, len, p, end)); 1681 } 1682 1683 static isc_result_t 1684 get_reverse(char *reverse, size_t len, char *value, bool strict) { 1685 int r; 1686 isc_result_t result; 1687 isc_netaddr_t addr; 1688 1689 addr.family = AF_INET6; 1690 r = inet_pton(AF_INET6, value, &addr.type.in6); 1691 if (r > 0) { 1692 /* This is a valid IPv6 address. */ 1693 dns_fixedname_t fname; 1694 dns_name_t *name; 1695 unsigned int options = 0; 1696 1697 name = dns_fixedname_initname(&fname); 1698 result = dns_byaddr_createptrname(&addr, options, name); 1699 if (result != ISC_R_SUCCESS) { 1700 return (result); 1701 } 1702 dns_name_format(name, reverse, (unsigned int)len); 1703 return (ISC_R_SUCCESS); 1704 } else { 1705 /* 1706 * Not a valid IPv6 address. Assume IPv4. 1707 * If 'strict' is not set, construct the 1708 * in-addr.arpa name by blindly reversing 1709 * octets whether or not they look like integers, 1710 * so that this can be used for RFC2317 names 1711 * and such. 1712 */ 1713 char *p = reverse; 1714 char *end = reverse + len; 1715 if (strict && inet_pton(AF_INET, value, &addr.type.in) != 1) { 1716 return (DNS_R_BADDOTTEDQUAD); 1717 } 1718 result = reverse_octets(value, &p, end); 1719 if (result != ISC_R_SUCCESS) { 1720 return (result); 1721 } 1722 result = append_str(".in-addr.arpa.", 15, &p, end); 1723 if (result != ISC_R_SUCCESS) { 1724 return (result); 1725 } 1726 return (ISC_R_SUCCESS); 1727 } 1728 } 1729 1730 int 1731 main(int argc, char *argv[]) { 1732 dns_client_t *client = NULL; 1733 isc_result_t result; 1734 dns_fixedname_t qfn; 1735 dns_name_t *query_name, *response_name; 1736 char namestr[DNS_NAME_FORMATSIZE]; 1737 dns_rdataset_t *rdataset; 1738 dns_namelist_t namelist; 1739 unsigned int resopt, clopt; 1740 isc_appctx_t *actx = NULL; 1741 isc_nm_t *netmgr = NULL; 1742 isc_taskmgr_t *taskmgr = NULL; 1743 isc_socketmgr_t *socketmgr = NULL; 1744 isc_timermgr_t *timermgr = NULL; 1745 dns_master_style_t *style = NULL; 1746 #ifndef WIN32 1747 struct sigaction sa; 1748 #endif /* ifndef WIN32 */ 1749 1750 progname = argv[0]; 1751 preparse_args(argc, argv); 1752 1753 argc--; 1754 argv++; 1755 1756 isc_lib_register(); 1757 result = dns_lib_init(); 1758 if (result != ISC_R_SUCCESS) { 1759 fatal("dns_lib_init failed: %d", result); 1760 } 1761 1762 isc_mem_create(&mctx); 1763 1764 CHECK(isc_appctx_create(mctx, &actx)); 1765 CHECK(isc_managers_create(mctx, 1, 0, &netmgr, &taskmgr)); 1766 CHECK(isc_socketmgr_create(mctx, &socketmgr)); 1767 CHECK(isc_timermgr_create(mctx, &timermgr)); 1768 1769 parse_args(argc, argv); 1770 1771 CHECK(setup_style(&style)); 1772 1773 setup_logging(stderr); 1774 1775 CHECK(isc_app_ctxstart(actx)); 1776 1777 #ifndef WIN32 1778 /* Unblock SIGINT if it's been blocked by isc_app_ctxstart() */ 1779 memset(&sa, 0, sizeof(sa)); 1780 sa.sa_handler = SIG_DFL; 1781 if (sigfillset(&sa.sa_mask) != 0 || sigaction(SIGINT, &sa, NULL) < 0) { 1782 fatal("Couldn't set up signal handler"); 1783 } 1784 #endif /* ifndef WIN32 */ 1785 1786 /* Create client */ 1787 clopt = DNS_CLIENTCREATEOPT_USECACHE; 1788 result = dns_client_create(mctx, actx, taskmgr, socketmgr, timermgr, 1789 clopt, &client, srcaddr4, srcaddr6); 1790 if (result != ISC_R_SUCCESS) { 1791 delv_log(ISC_LOG_ERROR, "dns_client_create: %s", 1792 isc_result_totext(result)); 1793 goto cleanup; 1794 } 1795 1796 /* Set the nameserver */ 1797 if (server != NULL) { 1798 addserver(client); 1799 } else { 1800 findserver(client); 1801 } 1802 1803 CHECK(setup_dnsseckeys(client)); 1804 1805 /* Construct QNAME */ 1806 CHECK(convert_name(&qfn, &query_name, qname)); 1807 1808 /* Set up resolution options */ 1809 resopt = DNS_CLIENTRESOPT_NOCDFLAG; 1810 if (no_sigs) { 1811 resopt |= DNS_CLIENTRESOPT_NODNSSEC; 1812 } 1813 if (!root_validation) { 1814 resopt |= DNS_CLIENTRESOPT_NOVALIDATE; 1815 } 1816 if (cdflag) { 1817 resopt &= ~DNS_CLIENTRESOPT_NOCDFLAG; 1818 } 1819 if (use_tcp) { 1820 resopt |= DNS_CLIENTRESOPT_TCP; 1821 } 1822 1823 /* Perform resolution */ 1824 ISC_LIST_INIT(namelist); 1825 result = dns_client_resolve(client, query_name, dns_rdataclass_in, 1826 qtype, resopt, &namelist); 1827 if (result != ISC_R_SUCCESS && !yaml) { 1828 delv_log(ISC_LOG_ERROR, "resolution failed: %s", 1829 isc_result_totext(result)); 1830 } 1831 1832 if (yaml) { 1833 printf("type: DELV_RESULT\n"); 1834 dns_name_format(query_name, namestr, sizeof(namestr)); 1835 printf("query_name: %s\n", namestr); 1836 printf("status: %s\n", isc_result_totext(result)); 1837 printf("records:\n"); 1838 } 1839 1840 for (response_name = ISC_LIST_HEAD(namelist); response_name != NULL; 1841 response_name = ISC_LIST_NEXT(response_name, link)) 1842 { 1843 for (rdataset = ISC_LIST_HEAD(response_name->list); 1844 rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) 1845 { 1846 result = printdata(rdataset, response_name, style); 1847 if (result != ISC_R_SUCCESS) { 1848 delv_log(ISC_LOG_ERROR, "print data failed"); 1849 } 1850 } 1851 } 1852 1853 dns_client_freeresanswer(client, &namelist); 1854 1855 cleanup: 1856 if (trust_anchor != NULL) { 1857 isc_mem_free(mctx, trust_anchor); 1858 } 1859 if (anchorfile != NULL) { 1860 isc_mem_free(mctx, anchorfile); 1861 } 1862 if (qname != NULL) { 1863 isc_mem_free(mctx, qname); 1864 } 1865 if (style != NULL) { 1866 dns_master_styledestroy(&style, mctx); 1867 } 1868 if (client != NULL) { 1869 dns_client_destroy(&client); 1870 } 1871 if (taskmgr != NULL) { 1872 isc_managers_destroy(&netmgr, &taskmgr); 1873 } 1874 if (timermgr != NULL) { 1875 isc_timermgr_destroy(&timermgr); 1876 } 1877 if (socketmgr != NULL) { 1878 isc_socketmgr_destroy(&socketmgr); 1879 } 1880 if (actx != NULL) { 1881 isc_appctx_destroy(&actx); 1882 } 1883 if (lctx != NULL) { 1884 isc_log_destroy(&lctx); 1885 } 1886 isc_mem_detach(&mctx); 1887 1888 dns_lib_shutdown(); 1889 1890 return (0); 1891 } 1892