"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/bin/delv/delv.c" (4 Sep 2020, 45970 Bytes) of package /linux/misc/dns/bind9/9.16.7/bind-9.16.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "delv.c" see the Fossies "Dox" file reference documentation.

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