"Fossies" - the Fresh Open Source Software Archive

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