nsec.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001, 2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <isc/log.h>
00025 #include <isc/string.h>
00026 #include <isc/util.h>
00027 
00028 #include <dns/db.h>
00029 #include <dns/nsec.h>
00030 #include <dns/rdata.h>
00031 #include <dns/rdatalist.h>
00032 #include <dns/rdataset.h>
00033 #include <dns/rdatasetiter.h>
00034 #include <dns/rdatastruct.h>
00035 #include <dns/result.h>
00036 
00037 #include <dst/dst.h>
00038 
00039 #define RETERR(x) do { \
00040         result = (x); \
00041         if (result != ISC_R_SUCCESS) \
00042                 goto failure; \
00043         } while (0)
00044 
00045 void
00046 dns_nsec_setbit(unsigned char *array, unsigned int type, unsigned int bit) {
00047         unsigned int shift, mask;
00048 
00049         shift = 7 - (type % 8);
00050         mask = 1 << shift;
00051 
00052         if (bit != 0)
00053                 array[type / 8] |= mask;
00054         else
00055                 array[type / 8] &= (~mask & 0xFF);
00056 }
00057 
00058 isc_boolean_t
00059 dns_nsec_isset(const unsigned char *array, unsigned int type) {
00060         unsigned int byte, shift, mask;
00061 
00062         byte = array[type / 8];
00063         shift = 7 - (type % 8);
00064         mask = 1 << shift;
00065 
00066         return (ISC_TF(byte & mask));
00067 }
00068 
00069 unsigned int
00070 dns_nsec_compressbitmap(unsigned char *map, const unsigned char *raw,
00071                         unsigned int max_type)
00072 {
00073         unsigned char *start = map;
00074         unsigned int window;
00075         int octet;
00076 
00077         if (raw == NULL)
00078                 return (0);
00079 
00080         for (window = 0; window < 256; window++) {
00081                 if (window * 256 > max_type)
00082                         break;
00083                 for (octet = 31; octet >= 0; octet--)
00084                         if (*(raw + octet) != 0)
00085                                 break;
00086                 if (octet < 0) {
00087                         raw += 32;
00088                         continue;
00089                 }
00090                 *map++ = window;
00091                 *map++ = octet + 1;
00092                 /*
00093                  * Note: potential overlapping move.
00094                  */
00095                 memmove(map, raw, octet + 1);
00096                 map += octet + 1;
00097                 raw += 32;
00098         }
00099         return (unsigned int)(map - start);
00100 }
00101 
00102 isc_result_t
00103 dns_nsec_buildrdata(dns_db_t *db, dns_dbversion_t *version,
00104                     dns_dbnode_t *node, dns_name_t *target,
00105                     unsigned char *buffer, dns_rdata_t *rdata)
00106 {
00107         isc_result_t result;
00108         dns_rdataset_t rdataset;
00109         isc_region_t r;
00110         unsigned int i;
00111 
00112         unsigned char *nsec_bits, *bm;
00113         unsigned int max_type;
00114         dns_rdatasetiter_t *rdsiter;
00115 
00116         memset(buffer, 0, DNS_NSEC_BUFFERSIZE);
00117         dns_name_toregion(target, &r);
00118         memmove(buffer, r.base, r.length);
00119         r.base = buffer;
00120         /*
00121          * Use the end of the space for a raw bitmap leaving enough
00122          * space for the window identifiers and length octets.
00123          */
00124         bm = r.base + r.length + 512;
00125         nsec_bits = r.base + r.length;
00126         dns_nsec_setbit(bm, dns_rdatatype_rrsig, 1);
00127         dns_nsec_setbit(bm, dns_rdatatype_nsec, 1);
00128         max_type = dns_rdatatype_nsec;
00129         dns_rdataset_init(&rdataset);
00130         rdsiter = NULL;
00131         result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
00132         if (result != ISC_R_SUCCESS)
00133                 return (result);
00134         for (result = dns_rdatasetiter_first(rdsiter);
00135              result == ISC_R_SUCCESS;
00136              result = dns_rdatasetiter_next(rdsiter))
00137         {
00138                 dns_rdatasetiter_current(rdsiter, &rdataset);
00139                 if (rdataset.type != dns_rdatatype_nsec &&
00140                     rdataset.type != dns_rdatatype_nsec3 &&
00141                     rdataset.type != dns_rdatatype_rrsig) {
00142                         if (rdataset.type > max_type)
00143                                 max_type = rdataset.type;
00144                         dns_nsec_setbit(bm, rdataset.type, 1);
00145                 }
00146                 dns_rdataset_disassociate(&rdataset);
00147         }
00148 
00149         /*
00150          * At zone cuts, deny the existence of glue in the parent zone.
00151          */
00152         if (dns_nsec_isset(bm, dns_rdatatype_ns) &&
00153             ! dns_nsec_isset(bm, dns_rdatatype_soa)) {
00154                 for (i = 0; i <= max_type; i++) {
00155                         if (dns_nsec_isset(bm, i) &&
00156                             ! dns_rdatatype_iszonecutauth((dns_rdatatype_t)i))
00157                                 dns_nsec_setbit(bm, i, 0);
00158                 }
00159         }
00160 
00161         dns_rdatasetiter_destroy(&rdsiter);
00162         if (result != ISC_R_NOMORE)
00163                 return (result);
00164 
00165         nsec_bits += dns_nsec_compressbitmap(nsec_bits, bm, max_type);
00166 
00167         r.length = (unsigned int)(nsec_bits - r.base);
00168         INSIST(r.length <= DNS_NSEC_BUFFERSIZE);
00169         dns_rdata_fromregion(rdata,
00170                              dns_db_class(db),
00171                              dns_rdatatype_nsec,
00172                              &r);
00173 
00174         return (ISC_R_SUCCESS);
00175 }
00176 
00177 isc_result_t
00178 dns_nsec_build(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
00179                dns_name_t *target, dns_ttl_t ttl)
00180 {
00181         isc_result_t result;
00182         dns_rdata_t rdata = DNS_RDATA_INIT;
00183         unsigned char data[DNS_NSEC_BUFFERSIZE];
00184         dns_rdatalist_t rdatalist;
00185         dns_rdataset_t rdataset;
00186 
00187         dns_rdataset_init(&rdataset);
00188         dns_rdata_init(&rdata);
00189 
00190         RETERR(dns_nsec_buildrdata(db, version, node, target, data, &rdata));
00191 
00192         dns_rdatalist_init(&rdatalist);
00193         rdatalist.rdclass = dns_db_class(db);
00194         rdatalist.type = dns_rdatatype_nsec;
00195         rdatalist.ttl = ttl;
00196         ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
00197         RETERR(dns_rdatalist_tordataset(&rdatalist, &rdataset));
00198         result = dns_db_addrdataset(db, node, version, 0, &rdataset,
00199                                     0, NULL);
00200         if (result == DNS_R_UNCHANGED)
00201                 result = ISC_R_SUCCESS;
00202 
00203  failure:
00204         if (dns_rdataset_isassociated(&rdataset))
00205                 dns_rdataset_disassociate(&rdataset);
00206         return (result);
00207 }
00208 
00209 isc_boolean_t
00210 dns_nsec_typepresent(dns_rdata_t *nsec, dns_rdatatype_t type) {
00211         dns_rdata_nsec_t nsecstruct;
00212         isc_result_t result;
00213         isc_boolean_t present;
00214         unsigned int i, len, window;
00215 
00216         REQUIRE(nsec != NULL);
00217         REQUIRE(nsec->type == dns_rdatatype_nsec);
00218 
00219         /* This should never fail */
00220         result = dns_rdata_tostruct(nsec, &nsecstruct, NULL);
00221         INSIST(result == ISC_R_SUCCESS);
00222 
00223         present = ISC_FALSE;
00224         for (i = 0; i < nsecstruct.len; i += len) {
00225                 INSIST(i + 2 <= nsecstruct.len);
00226                 window = nsecstruct.typebits[i];
00227                 len = nsecstruct.typebits[i + 1];
00228                 INSIST(len > 0 && len <= 32);
00229                 i += 2;
00230                 INSIST(i + len <= nsecstruct.len);
00231                 if (window * 256 > type)
00232                         break;
00233                 if ((window + 1) * 256 <= type)
00234                         continue;
00235                 if (type < (window * 256) + len * 8)
00236                         present = ISC_TF(dns_nsec_isset(&nsecstruct.typebits[i],
00237                                                         type % 256));
00238                 break;
00239         }
00240         dns_rdata_freestruct(&nsecstruct);
00241         return (present);
00242 }
00243 
00244 isc_result_t
00245 dns_nsec_nseconly(dns_db_t *db, dns_dbversion_t *version,
00246                   isc_boolean_t *answer)
00247 {
00248         dns_dbnode_t *node = NULL;
00249         dns_rdataset_t rdataset;
00250         dns_rdata_dnskey_t dnskey;
00251         isc_result_t result;
00252 
00253         REQUIRE(answer != NULL);
00254 
00255         dns_rdataset_init(&rdataset);
00256 
00257         result = dns_db_getoriginnode(db, &node);
00258         if (result != ISC_R_SUCCESS)
00259                 return (result);
00260 
00261         result = dns_db_findrdataset(db, node, version, dns_rdatatype_dnskey,
00262                                      0, 0, &rdataset, NULL);
00263         dns_db_detachnode(db, &node);
00264 
00265         if (result == ISC_R_NOTFOUND)
00266                 *answer = ISC_FALSE;
00267         if (result != ISC_R_SUCCESS)
00268                 return (result);
00269         for (result = dns_rdataset_first(&rdataset);
00270              result == ISC_R_SUCCESS;
00271              result = dns_rdataset_next(&rdataset)) {
00272                 dns_rdata_t rdata = DNS_RDATA_INIT;
00273 
00274                 dns_rdataset_current(&rdataset, &rdata);
00275                 result = dns_rdata_tostruct(&rdata, &dnskey, NULL);
00276                 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00277 
00278                 if (dnskey.algorithm == DST_ALG_RSAMD5 ||
00279                     dnskey.algorithm == DST_ALG_RSASHA1 ||
00280                     dnskey.algorithm == DST_ALG_DSA ||
00281                     dnskey.algorithm == DST_ALG_ECC)
00282                         break;
00283         }
00284         dns_rdataset_disassociate(&rdataset);
00285         if (result == ISC_R_SUCCESS)
00286                 *answer = ISC_TRUE;
00287         if (result == ISC_R_NOMORE) {
00288                 *answer = ISC_FALSE;
00289                 result = ISC_R_SUCCESS;
00290         }
00291         return (result);
00292 }
00293 
00294 /*%
00295  * Return ISC_R_SUCCESS if we can determine that the name doesn't exist
00296  * or we can determine whether there is data or not at the name.
00297  * If the name does not exist return the wildcard name.
00298  *
00299  * Return ISC_R_IGNORE when the NSEC is not the appropriate one.
00300  */
00301 isc_result_t
00302 dns_nsec_noexistnodata(dns_rdatatype_t type, dns_name_t *name,
00303                        dns_name_t *nsecname, dns_rdataset_t *nsecset,
00304                        isc_boolean_t *exists, isc_boolean_t *data,
00305                        dns_name_t *wild, dns_nseclog_t logit, void *arg)
00306 {
00307         int order;
00308         dns_rdata_t rdata = DNS_RDATA_INIT;
00309         isc_result_t result;
00310         dns_namereln_t relation;
00311         unsigned int olabels, nlabels, labels;
00312         dns_rdata_nsec_t nsec;
00313         isc_boolean_t atparent;
00314         isc_boolean_t ns;
00315         isc_boolean_t soa;
00316 
00317         REQUIRE(exists != NULL);
00318         REQUIRE(data != NULL);
00319         REQUIRE(nsecset != NULL &&
00320                 nsecset->type == dns_rdatatype_nsec);
00321 
00322         result = dns_rdataset_first(nsecset);
00323         if (result != ISC_R_SUCCESS) {
00324                 (*logit)(arg, ISC_LOG_DEBUG(3), "failure processing NSEC set");
00325                 return (result);
00326         }
00327         dns_rdataset_current(nsecset, &rdata);
00328 
00329         (*logit)(arg, ISC_LOG_DEBUG(3), "looking for relevant NSEC");
00330         relation = dns_name_fullcompare(name, nsecname, &order, &olabels);
00331 
00332         if (order < 0) {
00333                 /*
00334                  * The name is not within the NSEC range.
00335                  */
00336                 (*logit)(arg, ISC_LOG_DEBUG(3),
00337                               "NSEC does not cover name, before NSEC");
00338                 return (ISC_R_IGNORE);
00339         }
00340 
00341         if (order == 0) {
00342                 /*
00343                  * The names are the same.   If we are validating "."
00344                  * then atparent should not be set as there is no parent.
00345                  */
00346                 atparent = (olabels != 1) && dns_rdatatype_atparent(type);
00347                 ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns);
00348                 soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa);
00349                 if (ns && !soa) {
00350                         if (!atparent) {
00351                                 /*
00352                                  * This NSEC record is from somewhere higher in
00353                                  * the DNS, and at the parent of a delegation.
00354                                  * It can not be legitimately used here.
00355                                  */
00356                                 (*logit)(arg, ISC_LOG_DEBUG(3),
00357                                               "ignoring parent nsec");
00358                                 return (ISC_R_IGNORE);
00359                         }
00360                 } else if (atparent && ns && soa) {
00361                         /*
00362                          * This NSEC record is from the child.
00363                          * It can not be legitimately used here.
00364                          */
00365                         (*logit)(arg, ISC_LOG_DEBUG(3),
00366                                       "ignoring child nsec");
00367                         return (ISC_R_IGNORE);
00368                 }
00369                 if (type == dns_rdatatype_cname || type == dns_rdatatype_nxt ||
00370                     type == dns_rdatatype_nsec || type == dns_rdatatype_key ||
00371                     !dns_nsec_typepresent(&rdata, dns_rdatatype_cname)) {
00372                         *exists = ISC_TRUE;
00373                         *data = dns_nsec_typepresent(&rdata, type);
00374                         (*logit)(arg, ISC_LOG_DEBUG(3),
00375                                       "nsec proves name exists (owner) data=%d",
00376                                       *data);
00377                         return (ISC_R_SUCCESS);
00378                 }
00379                 (*logit)(arg, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists");
00380                 return (ISC_R_IGNORE);
00381         }
00382 
00383         if (relation == dns_namereln_subdomain &&
00384             dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
00385             !dns_nsec_typepresent(&rdata, dns_rdatatype_soa))
00386         {
00387                 /*
00388                  * This NSEC record is from somewhere higher in
00389                  * the DNS, and at the parent of a delegation.
00390                  * It can not be legitimately used here.
00391                  */
00392                 (*logit)(arg, ISC_LOG_DEBUG(3), "ignoring parent nsec");
00393                 return (ISC_R_IGNORE);
00394         }
00395 
00396         result = dns_rdata_tostruct(&rdata, &nsec, NULL);
00397         if (result != ISC_R_SUCCESS)
00398                 return (result);
00399         relation = dns_name_fullcompare(&nsec.next, name, &order, &nlabels);
00400         if (order == 0) {
00401                 dns_rdata_freestruct(&nsec);
00402                 (*logit)(arg, ISC_LOG_DEBUG(3),
00403                               "ignoring nsec matches next name");
00404                 return (ISC_R_IGNORE);
00405         }
00406 
00407         if (order < 0 && !dns_name_issubdomain(nsecname, &nsec.next)) {
00408                 /*
00409                  * The name is not within the NSEC range.
00410                  */
00411                 dns_rdata_freestruct(&nsec);
00412                 (*logit)(arg, ISC_LOG_DEBUG(3),
00413                             "ignoring nsec because name is past end of range");
00414                 return (ISC_R_IGNORE);
00415         }
00416 
00417         if (order > 0 && relation == dns_namereln_subdomain) {
00418                 (*logit)(arg, ISC_LOG_DEBUG(3),
00419                               "nsec proves name exist (empty)");
00420                 dns_rdata_freestruct(&nsec);
00421                 *exists = ISC_TRUE;
00422                 *data = ISC_FALSE;
00423                 return (ISC_R_SUCCESS);
00424         }
00425         if (wild != NULL) {
00426                 dns_name_t common;
00427                 dns_name_init(&common, NULL);
00428                 if (olabels > nlabels) {
00429                         labels = dns_name_countlabels(nsecname);
00430                         dns_name_getlabelsequence(nsecname, labels - olabels,
00431                                                   olabels, &common);
00432                 } else {
00433                         labels = dns_name_countlabels(&nsec.next);
00434                         dns_name_getlabelsequence(&nsec.next, labels - nlabels,
00435                                                   nlabels, &common);
00436                 }
00437                 result = dns_name_concatenate(dns_wildcardname, &common,
00438                                               wild, NULL);
00439                 if (result != ISC_R_SUCCESS) {
00440                         dns_rdata_freestruct(&nsec);
00441                         (*logit)(arg, ISC_LOG_DEBUG(3),
00442                                     "failure generating wildcard name");
00443                         return (result);
00444                 }
00445         }
00446         dns_rdata_freestruct(&nsec);
00447         (*logit)(arg, ISC_LOG_DEBUG(3), "nsec range ok");
00448         *exists = ISC_FALSE;
00449         return (ISC_R_SUCCESS);
00450 }

Generated on Tue Apr 28 17:40:58 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha