"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.16.7/lib/dns/nsec.c" (4 Sep 2020, 12016 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 "nsec.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 #include <stdbool.h>
   15 
   16 #include <isc/log.h>
   17 #include <isc/string.h>
   18 #include <isc/util.h>
   19 
   20 #include <dns/db.h>
   21 #include <dns/nsec.h>
   22 #include <dns/rdata.h>
   23 #include <dns/rdatalist.h>
   24 #include <dns/rdataset.h>
   25 #include <dns/rdatasetiter.h>
   26 #include <dns/rdatastruct.h>
   27 #include <dns/result.h>
   28 
   29 #include <dst/dst.h>
   30 
   31 #define RETERR(x)                            \
   32     do {                                 \
   33         result = (x);                \
   34         if (result != ISC_R_SUCCESS) \
   35             goto failure;        \
   36     } while (0)
   37 
   38 void
   39 dns_nsec_setbit(unsigned char *array, unsigned int type, unsigned int bit) {
   40     unsigned int shift, mask;
   41 
   42     shift = 7 - (type % 8);
   43     mask = 1 << shift;
   44 
   45     if (bit != 0) {
   46         array[type / 8] |= mask;
   47     } else {
   48         array[type / 8] &= (~mask & 0xFF);
   49     }
   50 }
   51 
   52 bool
   53 dns_nsec_isset(const unsigned char *array, unsigned int type) {
   54     unsigned int byte, shift, mask;
   55 
   56     byte = array[type / 8];
   57     shift = 7 - (type % 8);
   58     mask = 1 << shift;
   59 
   60     return ((byte & mask) != 0);
   61 }
   62 
   63 unsigned int
   64 dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw,
   65             unsigned int max_type) {
   66     unsigned char *start = map;
   67     unsigned int window;
   68     int octet;
   69 
   70     if (raw == NULL) {
   71         return (0);
   72     }
   73 
   74     for (window = 0; window < 256; window++) {
   75         if (window * 256 > max_type) {
   76             break;
   77         }
   78         for (octet = 31; octet >= 0; octet--) {
   79             if (*(raw + octet) != 0) {
   80                 break;
   81             }
   82         }
   83         if (octet < 0) {
   84             raw += 32;
   85             continue;
   86         }
   87         *map++ = window;
   88         *map++ = octet + 1;
   89         /*
   90          * Note: potential overlapping move.
   91          */
   92         memmove(map, raw, octet + 1);
   93         map += octet + 1;
   94         raw += 32;
   95     }
   96     return ((unsigned int)(map - start));
   97 }
   98 
   99 isc_result_t
  100 dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
  101             const dns_name_t *target, unsigned char *buffer,
  102             dns_rdata_t *rdata) {
  103     isc_result_t result;
  104     dns_rdataset_t rdataset;
  105     isc_region_t r;
  106     unsigned int i;
  107 
  108     unsigned char *nsec_bits, *bm;
  109     unsigned int max_type;
  110     dns_rdatasetiter_t *rdsiter;
  111 
  112     REQUIRE(target != NULL);
  113 
  114     memset(buffer, 0, DNS_NSEC_BUFFERSIZE);
  115     dns_name_toregion(target, &r);
  116     memmove(buffer, r.base, r.length);
  117     r.base = buffer;
  118     /*
  119      * Use the end of the space for a raw bitmap leaving enough
  120      * space for the window identifiers and length octets.
  121      */
  122     bm = r.base + r.length + 512;
  123     nsec_bits = r.base + r.length;
  124     dns_nsec_setbit(bm, dns_rdatatype_rrsig, 1);
  125     dns_nsec_setbit(bm, dns_rdatatype_nsec, 1);
  126     max_type = dns_rdatatype_nsec;
  127     dns_rdataset_init(&rdataset);
  128     rdsiter = NULL;
  129     result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
  130     if (result != ISC_R_SUCCESS) {
  131         return (result);
  132     }
  133     for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS;
  134          result = dns_rdatasetiter_next(rdsiter))
  135     {
  136         dns_rdatasetiter_current(rdsiter, &rdataset);
  137         if (rdataset.type != dns_rdatatype_nsec &&
  138             rdataset.type != dns_rdatatype_nsec3 &&
  139             rdataset.type != dns_rdatatype_rrsig)
  140         {
  141             if (rdataset.type > max_type) {
  142                 max_type = rdataset.type;
  143             }
  144             dns_nsec_setbit(bm, rdataset.type, 1);
  145         }
  146         dns_rdataset_disassociate(&rdataset);
  147     }
  148 
  149     /*
  150      * At zone cuts, deny the existence of glue in the parent zone.
  151      */
  152     if (dns_nsec_isset(bm, dns_rdatatype_ns) &&
  153         !dns_nsec_isset(bm, dns_rdatatype_soa))
  154     {
  155         for (i = 0; i <= max_type; i++) {
  156             if (dns_nsec_isset(bm, i) &&
  157                 !dns_rdatatype_iszonecutauth((dns_rdatatype_t)i)) {
  158                 dns_nsec_setbit(bm, i, 0);
  159             }
  160         }
  161     }
  162 
  163     dns_rdatasetiter_destroy(&rdsiter);
  164     if (result != ISC_R_NOMORE) {
  165         return (result);
  166     }
  167 
  168     nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type);
  169 
  170     r.length = (unsigned int)(nsec_bits - r.base);
  171     INSIST(r.length <= DNS_NSEC_BUFFERSIZE);
  172     dns_rdata_fromregion(rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
  173 
  174     return (ISC_R_SUCCESS);
  175 }
  176 
  177 isc_result_t
  178 dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
  179            const dns_name_t *target, dns_ttl_t ttl) {
  180     isc_result_t result;
  181     dns_rdata_t rdata = DNS_RDATA_INIT;
  182     unsigned char data[DNS_NSEC_BUFFERSIZE];
  183     dns_rdatalist_t rdatalist;
  184     dns_rdataset_t rdataset;
  185 
  186     dns_rdataset_init(&rdataset);
  187     dns_rdata_init(&rdata);
  188 
  189     RETERR(dns_nsec_buildrdata(db, version, node, target, data, &rdata));
  190 
  191     dns_rdatalist_init(&rdatalist);
  192     rdatalist.rdclass = dns_db_class(db);
  193     rdatalist.type = dns_rdatatype_nsec;
  194     rdatalist.ttl = ttl;
  195     ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
  196     RETERR(dns_rdatalist_tordataset(&rdatalist, &rdataset));
  197     result = dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL);
  198     if (result == DNS_R_UNCHANGED) {
  199         result = ISC_R_SUCCESS;
  200     }
  201 
  202 failure:
  203     if (dns_rdataset_isassociated(&rdataset)) {
  204         dns_rdataset_disassociate(&rdataset);
  205     }
  206     return (result);
  207 }
  208 
  209 bool
  210 dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
  211     dns_rdata_nsec_t nsecstruct;
  212     isc_result_t result;
  213     bool present;
  214     unsigned int i, len, window;
  215 
  216     REQUIRE(nsec != NULL);
  217     REQUIRE(nsec->type == dns_rdatatype_nsec);
  218 
  219     /* This should never fail */
  220     result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
  221     INSIST(result == ISC_R_SUCCESS);
  222 
  223     present = false;
  224     for (i = 0; i < nsecstruct.len; i += len) {
  225         INSIST(i + 2 <= nsecstruct.len);
  226         window = nsecstruct.typebits[i];
  227         len = nsecstruct.typebits[i + 1];
  228         INSIST(len > 0 && len <= 32);
  229         i += 2;
  230         INSIST(i + len <= nsecstruct.len);
  231         if (window * 256 > type) {
  232             break;
  233         }
  234         if ((window + 1) * 256 <= type) {
  235             continue;
  236         }
  237         if (type < (window * 256) + len * 8) {
  238             present = dns_nsec_isset(&nsecstruct.typebits[i],
  239                          type % 256);
  240         }
  241         break;
  242     }
  243     dns_rdata_freestruct(&nsecstruct);
  244     return (present);
  245 }
  246 
  247 isc_result_t
  248 dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version, bool *answer) {
  249     dns_dbnode_t *node = NULL;
  250     dns_rdataset_t rdataset;
  251     dns_rdata_dnskey_t dnskey;
  252     isc_result_t result;
  253 
  254     REQUIRE(answer != NULL);
  255 
  256     dns_rdataset_init(&rdataset);
  257 
  258     result = dns_db_getoriginnode(db, &node);
  259     if (result != ISC_R_SUCCESS) {
  260         return (result);
  261     }
  262 
  263     result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey, 0,
  264                      0, &rdataset, NULL);
  265     dns_db_detachnode(db, &node);
  266 
  267     if (result == ISC_R_NOTFOUND) {
  268         *answer = false;
  269     }
  270     if (result != ISC_R_SUCCESS) {
  271         return (result);
  272     }
  273     for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
  274          result = dns_rdataset_next(&rdataset))
  275     {
  276         dns_rdata_t rdata = DNS_RDATA_INIT;
  277 
  278         dns_rdataset_current(&rdataset, &rdata);
  279         result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
  280         RUNTIME_CHECK(result == ISC_R_SUCCESS);
  281 
  282         if (dnskey.algorithm == DST_ALG_RSAMD5 ||
  283             dnskey.algorithm == DST_ALG_RSASHA1) {
  284             break;
  285         }
  286     }
  287     dns_rdataset_disassociate(&rdataset);
  288     if (result == ISC_R_SUCCESS) {
  289         *answer = true;
  290     }
  291     if (result == ISC_R_NOMORE) {
  292         *answer = false;
  293         result = ISC_R_SUCCESS;
  294     }
  295     return (result);
  296 }
  297 
  298 /*%
  299  * Return ISC_R_SUCCESS if we can determine that the name doesn't exist
  300  * or we can determine whether there is data or not at the name.
  301  * If the name does not exist return the wildcard name.
  302  *
  303  * Return ISC_R_IGNORE when the NSEC is not the appropriate one.
  304  */
  305 isc_result_t
  306 dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name,
  307                const dns_name_t *nsecname, dns_rdataset_t *nsecset,
  308                bool *exists, bool *data, dns_name_t *wild,
  309                dns_nseclog_t logit, void *arg) {
  310     int order;
  311     dns_rdata_t rdata = DNS_RDATA_INIT;
  312     isc_result_t result;
  313     dns_namereln_t relation;
  314     unsigned int olabels, nlabels, labels;
  315     dns_rdata_nsec_t nsec;
  316     bool atparent;
  317     bool ns;
  318     bool soa;
  319 
  320     REQUIRE(exists != NULL);
  321     REQUIRE(data != NULL);
  322     REQUIRE(nsecset != NULL && nsecset->type == dns_rdatatype_nsec);
  323 
  324     result = dns_rdataset_first(nsecset);
  325     if (result != ISC_R_SUCCESS) {
  326         (*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC set");
  327         return (result);
  328     }
  329     dns_rdataset_current(nsecset, &rdata);
  330 
  331     (*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC");
  332     relation = dns_name_fullcompare(name, nsecname, &order, &olabels);
  333 
  334     if (order < 0) {
  335         /*
  336          * The name is not within the NSEC range.
  337          */
  338         (*logit)(arg, ISC_LOG_DEBUG(3),
  339              "NSEC does not cover name, before NSEC");
  340         return (ISC_R_IGNORE);
  341     }
  342 
  343     if (order == 0) {
  344         /*
  345          * The names are the same.   If we are validating "."
  346          * then atparent should not be set as there is no parent.
  347          */
  348         atparent = (olabels != 1) && dns_rdatatype_atparent(type);
  349         ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
  350         soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa);
  351         if (ns && !soa) {
  352             if (!atparent) {
  353                 /*
  354                  * This NSEC record is from somewhere higher in
  355                  * the DNS, and at the parent of a delegation.
  356                  * It can not be legitimately used here.
  357                  */
  358                 (*logit)(arg, ISC_LOG_DEBUG(3),
  359                      "ignoring parent nsec");
  360                 return (ISC_R_IGNORE);
  361             }
  362         } else if (atparent && ns && soa) {
  363             /*
  364              * This NSEC record is from the child.
  365              * It can not be legitimately used here.
  366              */
  367             (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring child nsec");
  368             return (ISC_R_IGNORE);
  369         }
  370         if (type == dns_rdatatype_cname || type == dns_rdatatype_nxt ||
  371             type == dns_rdatatype_nsec || type == dns_rdatatype_key ||
  372             !dns_nsec_typepresent(&rdata, dns_rdatatype_cname))
  373         {
  374             *exists = true;
  375             *data = dns_nsec_typepresent(&rdata, type);
  376             (*logit)(arg, ISC_LOG_DEBUG(3),
  377                  "nsec proves name exists (owner) data=%d",
  378                  *data);
  379             return (ISC_R_SUCCESS);
  380         }
  381         (*logit)(arg, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists");
  382         return (ISC_R_IGNORE);
  383     }
  384 
  385     if (relation == dns_namereln_subdomain &&
  386         dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
  387         !dns_nsec_typepresent(&rdata, dns_rdatatype_soa))
  388     {
  389         /*
  390          * This NSEC record is from somewhere higher in
  391          * the DNS, and at the parent of a delegation or
  392          * at a DNAME.
  393          * It can not be legitimately used here.
  394          */
  395         (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec");
  396         return (ISC_R_IGNORE);
  397     }
  398 
  399     if (relation == dns_namereln_subdomain &&
  400         dns_nsec_typepresent(&rdata, dns_rdatatype_dname))
  401     {
  402         (*logit)(arg, ISC_LOG_DEBUG(3), "nsec proves covered by dname");
  403         *exists = false;
  404         return (DNS_R_DNAME);
  405     }
  406 
  407     result = dns_rdata_tostruct(&rdata, &nsec, NULL);
  408     if (result != ISC_R_SUCCESS) {
  409         return (result);
  410     }
  411     relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels);
  412     if (order == 0) {
  413         dns_rdata_freestruct(&nsec);
  414         (*logit)(arg, ISC_LOG_DEBUG(3),
  415              "ignoring nsec matches next name");
  416         return (ISC_R_IGNORE);
  417     }
  418 
  419     if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) {
  420         /*
  421          * The name is not within the NSEC range.
  422          */
  423         dns_rdata_freestruct(&nsec);
  424         (*logit)(arg, ISC_LOG_DEBUG(3),
  425              "ignoring nsec because name is past end of range");
  426         return (ISC_R_IGNORE);
  427     }
  428 
  429     if (order > 0 && relation == dns_namereln_subdomain) {
  430         (*logit)(arg, ISC_LOG_DEBUG(3),
  431              "nsec proves name exist (empty)");
  432         dns_rdata_freestruct(&nsec);
  433         *exists = true;
  434         *data = false;
  435         return (ISC_R_SUCCESS);
  436     }
  437     if (wild != NULL) {
  438         dns_name_t common;
  439         dns_name_init(&common, NULL);
  440         if (olabels > nlabels) {
  441             labels = dns_name_countlabels(nsecname);
  442             dns_name_getlabelsequence(nsecname, labels - olabels,
  443                           olabels, &common);
  444         } else {
  445             labels = dns_name_countlabels(&nsec.next);
  446             dns_name_getlabelsequence(&nsec.next, labels - nlabels,
  447                           nlabels, &common);
  448         }
  449         result = dns_name_concatenate(dns_wildcardname, &common, wild,
  450                           NULL);
  451         if (result != ISC_R_SUCCESS) {
  452             dns_rdata_freestruct(&nsec);
  453             (*logit)(arg, ISC_LOG_DEBUG(3),
  454                  "failure generating wildcard name");
  455             return (result);
  456         }
  457     }
  458     dns_rdata_freestruct(&nsec);
  459     (*logit)(arg, ISC_LOG_DEBUG(3), "nsec range ok");
  460     *exists = false;
  461     return (ISC_R_SUCCESS);
  462 }