"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/bin/dnssec/dnssectool.c" (4 Sep 2020, 12549 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 "dnssectool.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 /*! \file */
   13 
   14 /*%
   15  * DNSSEC Support Routines.
   16  */
   17 
   18 #include <inttypes.h>
   19 #include <stdbool.h>
   20 #include <stdlib.h>
   21 
   22 #ifdef _WIN32
   23 #include <Winsock2.h>
   24 #endif /* ifdef _WIN32 */
   25 
   26 #include <isc/base32.h>
   27 #include <isc/buffer.h>
   28 #include <isc/commandline.h>
   29 #include <isc/dir.h>
   30 #include <isc/file.h>
   31 #include <isc/heap.h>
   32 #include <isc/list.h>
   33 #include <isc/mem.h>
   34 #include <isc/platform.h>
   35 #include <isc/print.h>
   36 #include <isc/string.h>
   37 #include <isc/time.h>
   38 #include <isc/util.h>
   39 
   40 #include <dns/db.h>
   41 #include <dns/dbiterator.h>
   42 #include <dns/dnssec.h>
   43 #include <dns/fixedname.h>
   44 #include <dns/keyvalues.h>
   45 #include <dns/log.h>
   46 #include <dns/name.h>
   47 #include <dns/nsec.h>
   48 #include <dns/nsec3.h>
   49 #include <dns/rdataclass.h>
   50 #include <dns/rdataset.h>
   51 #include <dns/rdatasetiter.h>
   52 #include <dns/rdatastruct.h>
   53 #include <dns/rdatatype.h>
   54 #include <dns/result.h>
   55 #include <dns/secalg.h>
   56 #include <dns/time.h>
   57 
   58 #include "dnssectool.h"
   59 
   60 #define KEYSTATES_NVALUES 4
   61 static const char *keystates[KEYSTATES_NVALUES] = {
   62     "hidden",
   63     "rumoured",
   64     "omnipresent",
   65     "unretentive",
   66 };
   67 
   68 int verbose = 0;
   69 bool quiet = false;
   70 uint8_t dtype[8];
   71 
   72 static fatalcallback_t *fatalcallback = NULL;
   73 
   74 void
   75 fatal(const char *format, ...) {
   76     va_list args;
   77 
   78     fprintf(stderr, "%s: fatal: ", program);
   79     va_start(args, format);
   80     vfprintf(stderr, format, args);
   81     va_end(args);
   82     fprintf(stderr, "\n");
   83     if (fatalcallback != NULL) {
   84         (*fatalcallback)();
   85     }
   86     exit(1);
   87 }
   88 
   89 void
   90 setfatalcallback(fatalcallback_t *callback) {
   91     fatalcallback = callback;
   92 }
   93 
   94 void
   95 check_result(isc_result_t result, const char *message) {
   96     if (result != ISC_R_SUCCESS) {
   97         fatal("%s: %s", message, isc_result_totext(result));
   98     }
   99 }
  100 
  101 void
  102 vbprintf(int level, const char *fmt, ...) {
  103     va_list ap;
  104     if (level > verbose) {
  105         return;
  106     }
  107     va_start(ap, fmt);
  108     fprintf(stderr, "%s: ", program);
  109     vfprintf(stderr, fmt, ap);
  110     va_end(ap);
  111 }
  112 
  113 void
  114 version(const char *name) {
  115     fprintf(stderr, "%s %s\n", name, VERSION);
  116     exit(0);
  117 }
  118 
  119 void
  120 sig_format(dns_rdata_rrsig_t *sig, char *cp, unsigned int size) {
  121     char namestr[DNS_NAME_FORMATSIZE];
  122     char algstr[DNS_NAME_FORMATSIZE];
  123 
  124     dns_name_format(&sig->signer, namestr, sizeof(namestr));
  125     dns_secalg_format(sig->algorithm, algstr, sizeof(algstr));
  126     snprintf(cp, size, "%s/%s/%d", namestr, algstr, sig->keyid);
  127 }
  128 
  129 void
  130 setup_logging(isc_mem_t *mctx, isc_log_t **logp) {
  131     isc_logdestination_t destination;
  132     isc_logconfig_t *logconfig = NULL;
  133     isc_log_t *log = NULL;
  134     int level;
  135 
  136     if (verbose < 0) {
  137         verbose = 0;
  138     }
  139     switch (verbose) {
  140     case 0:
  141         /*
  142          * We want to see warnings about things like out-of-zone
  143          * data in the master file even when not verbose.
  144          */
  145         level = ISC_LOG_WARNING;
  146         break;
  147     case 1:
  148         level = ISC_LOG_INFO;
  149         break;
  150     default:
  151         level = ISC_LOG_DEBUG(verbose - 2 + 1);
  152         break;
  153     }
  154 
  155     isc_log_create(mctx, &log, &logconfig);
  156     isc_log_setcontext(log);
  157     dns_log_init(log);
  158     dns_log_setcontext(log);
  159     isc_log_settag(logconfig, program);
  160 
  161     /*
  162      * Set up a channel similar to default_stderr except:
  163      *  - the logging level is passed in
  164      *  - the program name and logging level are printed
  165      *  - no time stamp is printed
  166      */
  167     destination.file.stream = stderr;
  168     destination.file.name = NULL;
  169     destination.file.versions = ISC_LOG_ROLLNEVER;
  170     destination.file.maximum_size = 0;
  171     isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, level,
  172                   &destination,
  173                   ISC_LOG_PRINTTAG | ISC_LOG_PRINTLEVEL);
  174 
  175     RUNTIME_CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL) ==
  176               ISC_R_SUCCESS);
  177 
  178     *logp = log;
  179 }
  180 
  181 void
  182 cleanup_logging(isc_log_t **logp) {
  183     isc_log_t *log;
  184 
  185     REQUIRE(logp != NULL);
  186 
  187     log = *logp;
  188     *logp = NULL;
  189 
  190     if (log == NULL) {
  191         return;
  192     }
  193 
  194     isc_log_destroy(&log);
  195     isc_log_setcontext(NULL);
  196     dns_log_setcontext(NULL);
  197 }
  198 
  199 static isc_stdtime_t
  200 time_units(isc_stdtime_t offset, char *suffix, const char *str) {
  201     switch (suffix[0]) {
  202     case 'Y':
  203     case 'y':
  204         return (offset * (365 * 24 * 3600));
  205     case 'M':
  206     case 'm':
  207         switch (suffix[1]) {
  208         case 'O':
  209         case 'o':
  210             return (offset * (30 * 24 * 3600));
  211         case 'I':
  212         case 'i':
  213             return (offset * 60);
  214         case '\0':
  215             fatal("'%s' ambiguous: use 'mi' for minutes "
  216                   "or 'mo' for months",
  217                   str);
  218         default:
  219             fatal("time value %s is invalid", str);
  220         }
  221         /* NOTREACHED */
  222         break;
  223     case 'W':
  224     case 'w':
  225         return (offset * (7 * 24 * 3600));
  226     case 'D':
  227     case 'd':
  228         return (offset * (24 * 3600));
  229     case 'H':
  230     case 'h':
  231         return (offset * 3600);
  232     case 'S':
  233     case 's':
  234     case '\0':
  235         return (offset);
  236     default:
  237         fatal("time value %s is invalid", str);
  238     }
  239     /* NOTREACHED */
  240     return (0); /* silence compiler warning */
  241 }
  242 
  243 static inline bool
  244 isnone(const char *str) {
  245     return ((strcasecmp(str, "none") == 0) ||
  246         (strcasecmp(str, "never") == 0));
  247 }
  248 
  249 dns_ttl_t
  250 strtottl(const char *str) {
  251     const char *orig = str;
  252     dns_ttl_t ttl;
  253     char *endp;
  254 
  255     if (isnone(str)) {
  256         return ((dns_ttl_t)0);
  257     }
  258 
  259     ttl = strtol(str, &endp, 0);
  260     if (ttl == 0 && endp == str) {
  261         fatal("TTL must be numeric");
  262     }
  263     ttl = time_units(ttl, endp, orig);
  264     return (ttl);
  265 }
  266 
  267 dst_key_state_t
  268 strtokeystate(const char *str) {
  269     if (isnone(str)) {
  270         return (DST_KEY_STATE_NA);
  271     }
  272 
  273     for (int i = 0; i < KEYSTATES_NVALUES; i++) {
  274         if (keystates[i] != NULL && strcasecmp(str, keystates[i]) == 0)
  275         {
  276             return ((dst_key_state_t)i);
  277         }
  278     }
  279     fatal("unknown key state");
  280 }
  281 
  282 isc_stdtime_t
  283 strtotime(const char *str, int64_t now, int64_t base, bool *setp) {
  284     int64_t val, offset;
  285     isc_result_t result;
  286     const char *orig = str;
  287     char *endp;
  288     size_t n;
  289 
  290     if (isnone(str)) {
  291         if (setp != NULL) {
  292             *setp = false;
  293         }
  294         return ((isc_stdtime_t)0);
  295     }
  296 
  297     if (setp != NULL) {
  298         *setp = true;
  299     }
  300 
  301     if ((str[0] == '0' || str[0] == '-') && str[1] == '\0') {
  302         return ((isc_stdtime_t)0);
  303     }
  304 
  305     /*
  306      * We accept times in the following formats:
  307      *   now([+-]offset)
  308      *   YYYYMMDD([+-]offset)
  309      *   YYYYMMDDhhmmss([+-]offset)
  310      *   [+-]offset
  311      */
  312     n = strspn(str, "0123456789");
  313     if ((n == 8u || n == 14u) &&
  314         (str[n] == '\0' || str[n] == '-' || str[n] == '+')) {
  315         char timestr[15];
  316 
  317         strlcpy(timestr, str, sizeof(timestr));
  318         timestr[n] = 0;
  319         if (n == 8u) {
  320             strlcat(timestr, "000000", sizeof(timestr));
  321         }
  322         result = dns_time64_fromtext(timestr, &val);
  323         if (result != ISC_R_SUCCESS) {
  324             fatal("time value %s is invalid: %s", orig,
  325                   isc_result_totext(result));
  326         }
  327         base = val;
  328         str += n;
  329     } else if (strncmp(str, "now", 3) == 0) {
  330         base = now;
  331         str += 3;
  332     }
  333 
  334     if (str[0] == '\0') {
  335         return ((isc_stdtime_t)base);
  336     } else if (str[0] == '+') {
  337         offset = strtol(str + 1, &endp, 0);
  338         offset = time_units((isc_stdtime_t)offset, endp, orig);
  339         val = base + offset;
  340     } else if (str[0] == '-') {
  341         offset = strtol(str + 1, &endp, 0);
  342         offset = time_units((isc_stdtime_t)offset, endp, orig);
  343         val = base - offset;
  344     } else {
  345         fatal("time value %s is invalid", orig);
  346     }
  347 
  348     return ((isc_stdtime_t)val);
  349 }
  350 
  351 dns_rdataclass_t
  352 strtoclass(const char *str) {
  353     isc_textregion_t r;
  354     dns_rdataclass_t rdclass;
  355     isc_result_t result;
  356 
  357     if (str == NULL) {
  358         return (dns_rdataclass_in);
  359     }
  360     DE_CONST(str, r.base);
  361     r.length = strlen(str);
  362     result = dns_rdataclass_fromtext(&rdclass, &r);
  363     if (result != ISC_R_SUCCESS) {
  364         fatal("unknown class %s", str);
  365     }
  366     return (rdclass);
  367 }
  368 
  369 unsigned int
  370 strtodsdigest(const char *str) {
  371     isc_textregion_t r;
  372     dns_dsdigest_t alg;
  373     isc_result_t result;
  374 
  375     DE_CONST(str, r.base);
  376     r.length = strlen(str);
  377     result = dns_dsdigest_fromtext(&alg, &r);
  378     if (result != ISC_R_SUCCESS) {
  379         fatal("unknown DS algorithm %s", str);
  380     }
  381     return (alg);
  382 }
  383 
  384 static int
  385 cmp_dtype(const void *ap, const void *bp) {
  386     int a = *(const uint8_t *)ap;
  387     int b = *(const uint8_t *)bp;
  388     return (a - b);
  389 }
  390 
  391 void
  392 add_dtype(unsigned int dt) {
  393     unsigned i, n;
  394 
  395     /* ensure there is space for a zero terminator */
  396     n = sizeof(dtype) / sizeof(dtype[0]) - 1;
  397     for (i = 0; i < n; i++) {
  398         if (dtype[i] == dt) {
  399             return;
  400         }
  401         if (dtype[i] == 0) {
  402             dtype[i] = dt;
  403             qsort(dtype, i + 1, 1, cmp_dtype);
  404             return;
  405         }
  406     }
  407     fatal("too many -a digest type arguments");
  408 }
  409 
  410 isc_result_t
  411 try_dir(const char *dirname) {
  412     isc_result_t result;
  413     isc_dir_t d;
  414 
  415     isc_dir_init(&d);
  416     result = isc_dir_open(&d, dirname);
  417     if (result == ISC_R_SUCCESS) {
  418         isc_dir_close(&d);
  419     }
  420     return (result);
  421 }
  422 
  423 /*
  424  * Check private key version compatibility.
  425  */
  426 void
  427 check_keyversion(dst_key_t *key, char *keystr) {
  428     int major, minor;
  429     dst_key_getprivateformat(key, &major, &minor);
  430     INSIST(major <= DST_MAJOR_VERSION); /* invalid private key */
  431 
  432     if (major < DST_MAJOR_VERSION || minor < DST_MINOR_VERSION) {
  433         fatal("Key %s has incompatible format version %d.%d, "
  434               "use -f to force upgrade to new version.",
  435               keystr, major, minor);
  436     }
  437     if (minor > DST_MINOR_VERSION) {
  438         fatal("Key %s has incompatible format version %d.%d, "
  439               "use -f to force downgrade to current version.",
  440               keystr, major, minor);
  441     }
  442 }
  443 
  444 void
  445 set_keyversion(dst_key_t *key) {
  446     int major, minor;
  447     dst_key_getprivateformat(key, &major, &minor);
  448     INSIST(major <= DST_MAJOR_VERSION);
  449 
  450     if (major != DST_MAJOR_VERSION || minor != DST_MINOR_VERSION) {
  451         dst_key_setprivateformat(key, DST_MAJOR_VERSION,
  452                      DST_MINOR_VERSION);
  453     }
  454 
  455     /*
  456      * If the key is from a version older than 1.3, set
  457      * set the creation date
  458      */
  459     if (major < 1 || (major == 1 && minor <= 2)) {
  460         isc_stdtime_t now;
  461         isc_stdtime_get(&now);
  462         dst_key_settime(key, DST_TIME_CREATED, now);
  463     }
  464 }
  465 
  466 bool
  467 key_collision(dst_key_t *dstkey, dns_name_t *name, const char *dir,
  468           isc_mem_t *mctx, bool *exact) {
  469     isc_result_t result;
  470     bool conflict = false;
  471     dns_dnsseckeylist_t matchkeys;
  472     dns_dnsseckey_t *key = NULL;
  473     uint16_t id, oldid;
  474     uint32_t rid, roldid;
  475     dns_secalg_t alg;
  476     char filename[NAME_MAX];
  477     isc_buffer_t fileb;
  478     isc_stdtime_t now;
  479 
  480     if (exact != NULL) {
  481         *exact = false;
  482     }
  483 
  484     id = dst_key_id(dstkey);
  485     rid = dst_key_rid(dstkey);
  486     alg = dst_key_alg(dstkey);
  487 
  488     /*
  489      * For Diffie Hellman just check if there is a direct collision as
  490      * they can't be revoked.  Additionally dns_dnssec_findmatchingkeys
  491      * only handles DNSKEY which is not used for HMAC.
  492      */
  493     if (alg == DST_ALG_DH) {
  494         isc_buffer_init(&fileb, filename, sizeof(filename));
  495         result = dst_key_buildfilename(dstkey, DST_TYPE_PRIVATE, dir,
  496                            &fileb);
  497         if (result != ISC_R_SUCCESS) {
  498             return (true);
  499         }
  500         return (isc_file_exists(filename));
  501     }
  502 
  503     ISC_LIST_INIT(matchkeys);
  504     isc_stdtime_get(&now);
  505     result = dns_dnssec_findmatchingkeys(name, dir, now, mctx, &matchkeys);
  506     if (result == ISC_R_NOTFOUND) {
  507         return (false);
  508     }
  509 
  510     while (!ISC_LIST_EMPTY(matchkeys) && !conflict) {
  511         key = ISC_LIST_HEAD(matchkeys);
  512         if (dst_key_alg(key->key) != alg) {
  513             goto next;
  514         }
  515 
  516         oldid = dst_key_id(key->key);
  517         roldid = dst_key_rid(key->key);
  518 
  519         if (oldid == rid || roldid == id || id == oldid) {
  520             conflict = true;
  521             if (id != oldid) {
  522                 if (verbose > 1) {
  523                     fprintf(stderr,
  524                         "Key ID %d could "
  525                         "collide with %d\n",
  526                         id, oldid);
  527                 }
  528             } else {
  529                 if (exact != NULL) {
  530                     *exact = true;
  531                 }
  532                 if (verbose > 1) {
  533                     fprintf(stderr, "Key ID %d exists\n",
  534                         id);
  535                 }
  536             }
  537         }
  538 
  539     next:
  540         ISC_LIST_UNLINK(matchkeys, key, link);
  541         dns_dnsseckey_destroy(mctx, &key);
  542     }
  543 
  544     /* Finish freeing the list */
  545     while (!ISC_LIST_EMPTY(matchkeys)) {
  546         key = ISC_LIST_HEAD(matchkeys);
  547         ISC_LIST_UNLINK(matchkeys, key, link);
  548         dns_dnsseckey_destroy(mctx, &key);
  549     }
  550 
  551     return (conflict);
  552 }
  553 
  554 bool
  555 isoptarg(const char *arg, char **argv, void (*usage)(void)) {
  556     if (!strcasecmp(isc_commandline_argument, arg)) {
  557         if (argv[isc_commandline_index] == NULL) {
  558             fprintf(stderr, "%s: missing argument -%c %s\n",
  559                 program, isc_commandline_option,
  560                 isc_commandline_argument);
  561             usage();
  562         }
  563         isc_commandline_argument = argv[isc_commandline_index];
  564         /* skip to next argument */
  565         isc_commandline_index++;
  566         return (true);
  567     }
  568     return (false);
  569 }
  570 
  571 #ifdef _WIN32
  572 void
  573 InitSockets(void) {
  574     WORD wVersionRequested;
  575     WSADATA wsaData;
  576     int err;
  577 
  578     wVersionRequested = MAKEWORD(2, 0);
  579 
  580     err = WSAStartup(wVersionRequested, &wsaData);
  581     if (err != 0) {
  582         fprintf(stderr, "WSAStartup() failed: %d\n", err);
  583         exit(1);
  584     }
  585 }
  586 
  587 void
  588 DestroySockets(void) {
  589     WSACleanup();
  590 }
  591 #endif /* ifdef _WIN32 */