]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
work on nsec3 negative cache for qtype DS .
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 8 Oct 2008 14:42:46 +0000 (14:42 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Wed, 8 Oct 2008 14:42:46 +0000 (14:42 +0000)
git-svn-id: file:///svn/unbound/trunk@1290 be551aaa-1e26-0410-a405-d3ace91eadb9

iterator/iterator.c
validator/val_neg.c
validator/val_neg.h
validator/val_nsec3.c
validator/val_nsec3.h

index 11226d2e8393c8f7ef12d5738124fb622193fb0a..94c8c848e2c066fe94fa39178c83b54e45a988c1 100644 (file)
@@ -760,7 +760,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
                 * NOERROR/NODATA or NXDOMAIN answers that need validation */
                msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
                        qstate->region, qstate->env->rrset_cache,
-                       *qstate->env->now);
+                       qstate->env->scratch_buffer, *qstate->env->now);
        }
        if(msg) {
                /* handle positive cache response */
index f2bcd61e66f5f12f146bc7cff9dca274e4ec14e8..49f96c2d2030f8a0e79db108d35cdcc91ab1bc7c 100644 (file)
@@ -44,6 +44,7 @@
 #include "config.h"
 #include "validator/val_neg.h"
 #include "validator/val_nsec.h"
+#include "validator/val_nsec3.h"
 #include "validator/val_utils.h"
 #include "util/data/dname.h"
 #include "util/data/msgreply.h"
@@ -205,6 +206,7 @@ static void neg_delete_zone(struct val_neg_cache* neg, struct val_neg_zone* z)
                np = p->parent;
                (void)rbtree_delete(&neg->tree, &p->node);
                neg->use -= p->len + sizeof(*p);
+               free(p->nsec3_salt);
                free(p->name);
                free(p);
                p = np;
@@ -295,6 +297,29 @@ static struct val_neg_zone* neg_find_zone(struct val_neg_cache* neg,
        return result;
 }
 
+/**
+ * Find the given data
+ * @param zone: negative zone
+ * @param nm: what to look for.
+ * @param len: length of nm
+ * @param labs: labels in nm
+ * @return data or NULL if not found.
+ */
+static struct val_neg_data* neg_find_data(struct val_neg_zone* zone, 
+       uint8_t* nm, size_t len, int labs)
+{
+       struct val_neg_data lookfor;
+       struct val_neg_data* result;
+       lookfor.node.key = &lookfor;
+       lookfor.name = nm;
+       lookfor.len = len;
+       lookfor.labs = labs;
+
+       result = (struct val_neg_data*)
+               rbtree_search(&zone->tree, lookfor.node.key);
+       return result;
+}
+
 /**
  * Calculate space needed for the data and all its parents
  * @param rep: NSEC entries.
@@ -660,12 +685,21 @@ static void wipeout(struct val_neg_cache* neg, struct val_neg_zone* zone,
        int end_labs, m;
        rbnode_t* walk, *next;
        struct val_neg_data* cur;
+       uint8_t buf[257];
        /* get endpoint */
        if(!d || d->count == 0 || d->rr_len[0] < 2+1)
                return;
-       end = d->rr_data[0]+2;
-       end_len = dname_valid(end, d->rr_len[0]-2);
-       end_labs = dname_count_labels(end);
+       if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC) {
+               end = d->rr_data[0]+2;
+               end_len = dname_valid(end, d->rr_len[0]-2);
+               end_labs = dname_count_labels(end);
+       } else {
+               /* NSEC3 */
+               if(!nsec3_get_nextowner_b32(nsec, 0, buf, sizeof(buf)))
+                       return;
+               end = buf;
+               end_labs = dname_count_size_labels(end, &end_len);
+       }
 
        /* sanity check, both owner and end must be below the zone apex */
        if(!dname_subdomain_c(el->name, zone->name) || 
@@ -734,10 +768,12 @@ static void neg_insert_data(struct val_neg_cache* neg,
        int labs = dname_count_labels(nsec->rk.dname);
 
        d = (struct packed_rrset_data*)nsec->entry.data;
-       if(d->security != sec_status_secure)
+       if( !(d->security == sec_status_secure ||
+               (d->security == sec_status_unchecked && d->rrsig_count > 0)))
                return;
        log_nametypeclass(VERB_ALGO, "negcache rr", 
-               nsec->rk.dname, LDNS_RR_TYPE_NSEC, ntohs(nsec->rk.rrset_class));
+               nsec->rk.dname, ntohs(nsec->rk.type), 
+               ntohs(nsec->rk.rrset_class));
 
        /* find closest enclosing parent data that (still) exists */
        parent = neg_closest_data_parent(zone, nm, nm_len, labs);
@@ -790,6 +826,26 @@ static void neg_insert_data(struct val_neg_cache* neg,
                neg_lru_touch(neg, el);
        }
 
+       /* if nsec3 store last used parameters */
+       if(ntohs(nsec->rk.type) == LDNS_RR_TYPE_NSEC3) {
+               int h;
+               uint8_t* s;
+               size_t slen, it;
+               if(nsec3_get_params(nsec, 0, &h, &it, &s, &slen) &&
+                       (h != zone->nsec3_hash || it != zone->nsec3_iter ||
+                       slen != zone->nsec3_saltlen || 
+                       memcmp(zone->nsec3_salt, s, slen) != 0)) {
+                       uint8_t* sa = memdup(s, slen);
+                       if(sa) {
+                               free(zone->nsec3_salt);
+                               zone->nsec3_salt = sa;
+                               zone->nsec3_saltlen = slen;
+                               zone->nsec3_hash = h;
+                               zone->nsec3_iter = it;
+                       }
+               }
+       }
+
        /* wipe out the cache items between NSEC start and end */
        wipeout(neg, zone, el, nsec);
 }
@@ -898,6 +954,12 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
        log_nametypeclass(VERB_ALGO, "negcache zone", zone->name, 0, 
                zone->dclass);
 
+       /* DLV is defined to use NSEC only */
+       if(zone->nsec3_hash) {
+               lock_basic_unlock(&neg->lock);
+               return 0;
+       }
+
        /* lookup closest data record */
        (void)neg_closest_data(zone, qname, len, labs, &data);
        while(data && !data->in_use)
@@ -972,7 +1034,8 @@ static uint8_t* reply_nsec_signer(struct reply_info* rep, size_t* signer_len,
        struct packed_rrset_data* d;
        uint8_t* s;
        for(i=rep->an_numrrsets; i< rep->an_numrrsets+rep->ns_numrrsets; i++){
-               if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC) {
+               if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC ||
+                       ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NSEC3) {
                        d = (struct packed_rrset_data*)rep->rrsets[i]->
                                entry.data;
                        /* return first signer name of first NSEC */
@@ -1090,9 +1153,177 @@ grab_nsec(struct rrset_cache* rrset_cache, uint8_t* qname, size_t qname_len,
        return r;
 }
 
+/** find nsec3 closest encloser in neg cache */
+static struct val_neg_data*
+neg_find_nsec3_ce(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
+               int qlabs, ldns_buffer* buf, uint8_t* hashnc, size_t* nclen)
+{
+       struct val_neg_data* data;
+       uint8_t hashce[SHA_DIGEST_LENGTH];
+       uint8_t b32[257];
+       size_t celen, b32len;
+
+       *nclen = 0;
+       while(qlabs > 0) {
+               /* hash */
+               if(!(celen=nsec3_get_hashed(buf, qname, qname_len, 
+                       zone->nsec3_hash, zone->nsec3_iter, zone->nsec3_salt, 
+                       zone->nsec3_saltlen, hashce, sizeof(hashce))))
+                       return NULL;
+               if(!(b32len=nsec3_hash_to_b32(hashce, celen, zone->name,
+                       zone->len, b32, sizeof(b32))))
+                       return NULL;
+
+               /* lookup (exact match only) */
+               data = neg_find_data(zone, b32, b32len, zone->labs+1);
+               if(data && data->in_use) {
+                       /* found ce match! */
+                       return data;
+               }
+
+               *nclen = celen;
+               memmove(hashnc, hashce, celen);
+               dname_remove_label(&qname, &qname_len);
+               qlabs --;
+       }
+       return NULL;
+}
+
+/** check nsec3 parameters on nsec3 rrset with current zone values */
+static int
+neg_params_ok(struct val_neg_zone* zone, struct ub_packed_rrset_key* rrset)
+{
+       int h;
+       uint8_t* s;
+       size_t slen, it;
+       if(!nsec3_get_params(rrset, 0, &h, &it, &s, &slen))
+               return 0;
+       return (h == zone->nsec3_hash && it == zone->nsec3_iter &&
+               slen == zone->nsec3_saltlen &&
+               memcmp(zone->nsec3_salt, s, slen) == 0);
+}
+
+/** get next closer for nsec3 proof */
+static struct ub_packed_rrset_key*
+neg_nsec3_getnc(struct val_neg_zone* zone, uint8_t* hashnc, size_t nclen,
+       struct rrset_cache* rrset_cache, struct regional* region, 
+       uint32_t now, uint8_t* b32, size_t maxb32)
+{
+       struct ub_packed_rrset_key* nc_rrset;
+       struct val_neg_data* data;
+       size_t b32len;
+
+       if(!(b32len=nsec3_hash_to_b32(hashnc, nclen, zone->name,
+               zone->len, b32, maxb32)))
+               return NULL;
+       (void)neg_closest_data(zone, b32, b32len, zone->labs+1, &data);
+       if(!data && zone->tree.count != 0) {
+               /* could be before the first entry ; return the last
+                * entry (possibly the rollover nsec3 at end) */
+               data = (struct val_neg_data*)rbtree_last(&zone->tree);
+       }
+       while(data && !data->in_use)
+               data = data->parent;
+       if(!data)
+               return NULL;
+       /* got a data element in tree, grab it */
+       nc_rrset = grab_nsec(rrset_cache, data->name, data->len, 
+               LDNS_RR_TYPE_NSEC3, zone->dclass, 0, region, 0, 0, now);
+       if(!nc_rrset)
+               return NULL;
+       if(!neg_params_ok(zone, nc_rrset))
+               return NULL;
+       return nc_rrset;
+}
+
+/** neg cache nsec3 proof procedure*/
+static struct dns_msg*
+neg_nsec3_proof_ds(struct val_neg_zone* zone, uint8_t* qname, size_t qname_len,
+               int qlabs, ldns_buffer* buf, struct rrset_cache* rrset_cache,
+               struct regional* region, uint32_t now)
+{
+       struct dns_msg* msg;
+       struct val_neg_data* data;
+       uint8_t hashnc[SHA_DIGEST_LENGTH];
+       size_t nclen;
+       struct ub_packed_rrset_key* ce_rrset, *nc_rrset;
+       struct nsec3_cached_hash c;
+       uint8_t nc_b32[257];
+
+       /* for NSEC3 ; determine the closest encloser for which we
+        * can find an exact match. Remember the hashed lower name,
+        * since that is the one we need a closest match for. 
+        * If we find a match straight away, then it becomes NODATA.
+        * Otherwise, NXDOMAIN or if OPTOUT, an insecure delegation.
+        * Also check that parameters are the same on closest encloser
+        * and on closest match.
+        */
+       if(!zone->nsec3_hash) 
+               return NULL; /* not nsec3 zone */
+
+       if(!(data=neg_find_nsec3_ce(zone, qname, qname_len, qlabs, buf,
+               hashnc, &nclen))) {
+               return NULL;
+       }
+
+       /* grab the ce rrset */
+       ce_rrset = grab_nsec(rrset_cache, data->name, data->len, 
+               LDNS_RR_TYPE_NSEC3, zone->dclass, 0, region, 1, 
+               LDNS_RR_TYPE_DS, now);
+       if(!ce_rrset)
+               return NULL;
+       if(!neg_params_ok(zone, ce_rrset))
+               return NULL;
+
+       if(nclen == 0) {
+               /* exact match, just check the type bits */
+               /* need: -SOA, -DS, +NS */
+               if(nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_SOA) ||
+                       nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_DS) ||
+                       !nsec3_has_type(ce_rrset, 0, LDNS_RR_TYPE_NS))
+                       return NULL;
+               if(!(msg = dns_msg_create(qname, qname_len, 
+                       LDNS_RR_TYPE_DS, zone->dclass, region, 1))) 
+                       return NULL;
+               if(!dns_msg_authadd(msg, region, ce_rrset, now)) 
+                       return NULL;
+               return msg;
+       }
+       /* if there is no exact match, it must be in an optout span
+        * (an existing DS implies an NSEC3 must exist) */
+       nc_rrset = neg_nsec3_getnc(zone, hashnc, nclen, rrset_cache, 
+               region, now, nc_b32, sizeof(nc_b32));
+       if(!nc_rrset) 
+               return NULL;
+       if(!neg_params_ok(zone, nc_rrset))
+               return NULL;
+       if(!nsec3_has_optout(nc_rrset, 0))
+               return NULL;
+       c.hash = hashnc;
+       c.hash_len = nclen;
+       c.b32 = nc_b32+1;
+       c.b32_len = (size_t)nc_b32[0];
+       if(nsec3_covers(zone->name, &c, nc_rrset, 0, buf)) {
+               /* nc_rrset covers the next closer name.
+                * ce_rrset equals a closer encloser.
+                * nc_rrset is optout.
+                * No need to check wildcard for type DS */
+               if(!(msg = dns_msg_create(qname, qname_len, 
+                       LDNS_RR_TYPE_DS, zone->dclass, region, 2))) 
+                       return NULL;
+               if(!dns_msg_authadd(msg, region, ce_rrset, now)) 
+                       return NULL;
+               if(!dns_msg_authadd(msg, region, nc_rrset, now)) 
+                       return NULL;
+               return msg;
+       }
+       return NULL;
+}
+
 struct dns_msg* 
 val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo, 
-       struct regional* region, struct rrset_cache* rrset_cache, uint32_t now)
+       struct regional* region, struct rrset_cache* rrset_cache, 
+       ldns_buffer* buf, uint32_t now)
 {
        struct dns_msg* msg;
        struct ub_packed_rrset_key* rrset;
@@ -1100,7 +1331,7 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
        size_t zname_len;
        int zname_labs;
        struct val_neg_zone* zone;
-       struct val_neg_data* data;
+
        /* only for DS queries */
        if(qinfo->qtype != LDNS_RR_TYPE_DS)
                return NULL;
@@ -1141,17 +1372,8 @@ val_neg_getmsg(struct val_neg_cache* neg, struct query_info* qinfo,
                return NULL;
        }
 
-       /* lookup closest data record TODO hash NSEC3 */
-       (void)neg_closest_data(zone, qinfo->qname, qinfo->qname_len, 
-               zname_labs+1, &data);
-       while(data && !data->in_use)
-               data = data->parent;
-       if(!data) {
-               lock_basic_unlock(&neg->lock);
-               return 0;
-       }
-
-       /* get RR and check */
-
-       return 0;
+       msg = neg_nsec3_proof_ds(zone, qinfo->qname, qinfo->qname_len, 
+               zname_labs+1, buf, rrset_cache, region, now);
+       lock_basic_unlock(&neg->lock);
+       return msg;
 }
index 8bb60848ee29066c21a6cd148b6aab6f97a1c1de..e1c949c0f7ea00e945bb4e35b8f6ce43979cd23e 100644 (file)
@@ -99,7 +99,14 @@ struct val_neg_zone {
         * No elements have a count of zero, those are removed. */
        int count;
 
-       /* type of zone ; NSEC */
+       /** if 0: NSEC zone, else NSEC3 hash algorithm in use */
+       int nsec3_hash;
+       /** nsec3 iteration count in use */
+       size_t nsec3_iter;
+       /** nsec3 salt in use */
+       uint8_t* nsec3_salt;
+       /** length of salt in bytes */
+       size_t nsec3_saltlen;
 
        /** tree of NSEC data for this zone, sorted canonical 
         * by NSEC owner name */
@@ -227,6 +234,7 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
  * @param qinfo: query
  * @param region: where to allocate reply.
  * @param rrset_cache: rrset cache.
+ * @param buf: temporary buffer.
  * @param now: to check TTLs against.
  * @return a reply message if something was found. 
  *     This reply may still need validation.
@@ -234,6 +242,6 @@ int val_neg_dlvlookup(struct val_neg_cache* neg, uint8_t* qname, size_t len,
  */
 struct dns_msg* val_neg_getmsg(struct val_neg_cache* neg, 
        struct query_info* qinfo, struct regional* region, 
-       struct rrset_cache* rrset_cache, uint32_t now);
+       struct rrset_cache* rrset_cache, ldns_buffer* buf, uint32_t now);
 
 #endif /* VALIDATOR_VAL_NEG_H */
index 3d73ef9c43a9155e014dea5011d25b06c1f5e305..4d5c34a8c6d55a3a69f2eaa890b1add65efceec3 100644 (file)
@@ -125,8 +125,7 @@ nsec3_unknown_flags(struct ub_packed_rrset_key* rrset, int r)
        return (int)(d->rr_data[r][2+1] & NSEC3_UNKNOWN_FLAGS);
 }
 
-/** return if nsec3 RR has the optout flag */
-static int
+int
 nsec3_has_optout(struct ub_packed_rrset_key* rrset, int r)
 {
         struct packed_rrset_data* d = (struct packed_rrset_data*)
@@ -203,8 +202,19 @@ nsec3_get_salt(struct ub_packed_rrset_key* rrset, int r,
        return 1;
 }
 
-/** return nsec3 RR next hashed owner name */
-static int
+int nsec3_get_params(struct ub_packed_rrset_key* rrset, int r,
+       int* algo, size_t* iter, uint8_t** salt, size_t* saltlen)
+{
+       if(!nsec3_known_algo(rrset, r) || nsec3_unknown_flags(rrset, r))
+               return 0;
+       if(!nsec3_get_salt(rrset, r, salt, saltlen))
+               return 0;
+       *algo = nsec3_get_algo(rrset, r);
+       *iter = nsec3_get_iter(rrset, r);
+       return 1;
+}
+
+int
 nsec3_get_nextowner(struct ub_packed_rrset_key* rrset, int r,
        uint8_t** next, size_t* nextlen)
 {
@@ -233,8 +243,39 @@ nsec3_get_nextowner(struct ub_packed_rrset_key* rrset, int r,
        return 1;
 }
 
-/** see if NSEC3 RR contains given type */
-static int
+size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone,
+       size_t zonelen, uint8_t* buf, size_t max)
+{
+       /* write b32 of name, leave one for length */
+       int ret;
+       if(max < hashlen*2+1) /* quick approx of b32, as if hexb16 */
+               return 0;
+       ret = b32_ntop_extended_hex(hash, hashlen, (char*)buf+1, max-1);
+       if(ret < 1) 
+               return 0;
+       buf[0] = (uint8_t)ret; /* length of b32 label */
+       ret++;
+       if(max - ret < zonelen)
+               return 0;
+       memmove(buf+ret, zone, zonelen);
+       return zonelen+(size_t)ret;
+}
+
+size_t nsec3_get_nextowner_b32(struct ub_packed_rrset_key* rrset, int r,
+       uint8_t* buf, size_t max)
+{
+       uint8_t* nm, *zone;
+       size_t nmlen, zonelen;
+       if(!nsec3_get_nextowner(rrset, r, &nm, &nmlen))
+               return 0;
+       /* append zone name; the owner name must be <b32>.zone */
+       zone = rrset->rk.dname;
+       zonelen = rrset->rk.dname_len;
+       dname_remove_label(&zone, &zonelen);
+       return nsec3_hash_to_b32(nm, nmlen, zone, zonelen, buf, max);
+}
+
+int
 nsec3_has_type(struct ub_packed_rrset_key* rrset, int r, uint16_t type)
 {
        uint8_t* bitmap;
@@ -482,6 +523,45 @@ nsec3_hash_cmp(const void* c1, const void* c2)
        return memcmp(s1, s2, s1len);
 }
 
+size_t
+nsec3_get_hashed(ldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
+       size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max)
+{
+       size_t i, hash_len;
+       /* prepare buffer for first iteration */
+       ldns_buffer_clear(buf);
+       ldns_buffer_write(buf, nm, nmlen);
+       query_dname_tolower(ldns_buffer_begin(buf));
+       ldns_buffer_write(buf, salt, saltlen);
+       ldns_buffer_flip(buf);
+       switch(algo) {
+#ifdef SHA_DIGEST_LENGTH
+               case NSEC3_HASH_SHA1:
+                       hash_len = SHA_DIGEST_LENGTH;
+                       if(hash_len > max)
+                               return 0;
+                       (void)SHA1((unsigned char*)ldns_buffer_begin(buf),
+                               (unsigned long)ldns_buffer_limit(buf),
+                               (unsigned char*)res);
+                       for(i=0; i<iter; i++) {
+                               ldns_buffer_clear(buf);
+                               ldns_buffer_write(buf, res, hash_len);
+                               ldns_buffer_write(buf, salt, saltlen);
+                               ldns_buffer_flip(buf);
+                               (void)SHA1(
+                                       (unsigned char*)ldns_buffer_begin(buf),
+                                       (unsigned long)ldns_buffer_limit(buf),
+                                       (unsigned char*)res);
+                       }
+                       break;
+#endif /* SHA_DIGEST_LENGTH */
+               default:
+                       log_err("nsec3 hash of unknown algo %d", algo);
+                       return 0;
+       }
+       return hash_len;
+}
+
 /** perform hash of name */
 static int
 nsec3_calc_hash(struct regional* region, ldns_buffer* buf, 
@@ -682,21 +762,8 @@ find_matching_nsec3(struct module_env* env, struct nsec3_filter* flt,
        return 0;
 }
 
-/**
- * nsec3Covers
- * Given a hash and a candidate NSEC3Record, determine if that NSEC3Record
- * covers the hash. Covers specifically means that the hash is in between
- * the owner and next hashes and does not equal either.
- *
- * @param flt: the NSEC3 RR filter, contains zone name.
- * @param hash: the hash of the name
- * @param rrset: the rrset of the NSEC3.
- * @param rr: which rr in the rrset.
- * @param buf: temporary buffer.
- * @return true if covers, false if not.
- */
-static int
-nsec3_covers(struct nsec3_filter* flt, struct nsec3_cached_hash* hash,
+int
+nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
        struct ub_packed_rrset_key* rrset, int rr, ldns_buffer* buf)
 {
        uint8_t* next, *owner;
@@ -711,7 +778,7 @@ nsec3_covers(struct nsec3_filter* flt, struct nsec3_cached_hash* hash,
        if(nextlen != hash->hash_len || hash->hash_len==0||hash->b32_len==0|| 
                (size_t)*rrset->rk.dname != hash->b32_len ||
                query_dname_compare(rrset->rk.dname+1+
-                       (size_t)*rrset->rk.dname, flt->zone) != 0)
+                       (size_t)*rrset->rk.dname, zone) != 0)
                return 0; /* bad lengths or owner name */
 
        /* This is the "normal case: owner < next and owner < hash < next */
@@ -777,7 +844,7 @@ find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt,
                        break; /* alloc failure */
                } else if(r < 0)
                        continue; /* malformed NSEC3 */
-               else if(nsec3_covers(flt, hash, s, i_rr, 
+               else if(nsec3_covers(flt->zone, hash, s, i_rr, 
                        env->scratch_buffer)) {
                        *rrset = s; /* rrset with this name */
                        *rr = i_rr; /* covers hash with these parameters */
index f0188d2def4f30f4380d0082cdd98ad84d1594e1..fc6792cb882a66a5956f77214f2538fa7e07ac5a 100644 (file)
@@ -273,4 +273,105 @@ int nsec3_hash_name(rbtree_t* table, struct regional* region, ldns_buffer* buf,
        struct ub_packed_rrset_key* nsec3, int rr, uint8_t* dname, 
        size_t dname_len, struct nsec3_cached_hash** hash);
 
+/**
+ * Get next owner name, converted to base32 encoding and with the
+ * zone name (taken from the nsec3 owner name) appended.
+ * @param rrset: the NSEC3 rrset.
+ * @param r: the rr num of the nsec3 in the rrset.
+ * @param buf: buffer to store name in
+ * @param max: size of buffer.
+ * @return length of name on success. 0 on failure (buffer too short or
+ *     bad format nsec3 record).
+ */
+size_t nsec3_get_nextowner_b32(struct ub_packed_rrset_key* rrset, int r,
+       uint8_t* buf, size_t max);
+
+/**
+ * Convert hash into base32 encoding and with the
+ * zone name appended.
+ * @param hash: hashed buffer
+ * @param hashlen: length of hash
+ * @param zone: name of zone
+ * @param zonelen: length of zonename.
+ * @param buf: buffer to store name in
+ * @param max: size of buffer.
+ * @return length of name on success. 0 on failure (buffer too short or
+ *     bad format nsec3 record).
+ */
+size_t nsec3_hash_to_b32(uint8_t* hash, size_t hashlen, uint8_t* zone,
+       size_t zonelen, uint8_t* buf, size_t max);
+
+/** 
+ * Get NSEC3 parameters out of rr.
+ * @param rrset: the NSEC3 rrset.
+ * @param r: the rr num of the nsec3 in the rrset.
+ * @param algo: nsec3 hash algo.
+ * @param iter: iteration count.
+ * @param salt: ptr to salt inside rdata.
+ * @param saltlen: length of salt.
+ * @return 0 if bad formatted, unknown nsec3 hash algo, or unknown flags set.
+ */
+int nsec3_get_params(struct ub_packed_rrset_key* rrset, int r,
+       int* algo, size_t* iter, uint8_t** salt, size_t* saltlen);
+
+/**
+ * Get NSEC3 hashed in a buffer
+ * @param buf: buffer for temp use.
+ * @param nm: name to hash
+ * @param nmlen: length of nm.
+ * @param algo: algo to use, must be known.
+ * @param iter: iterations
+ * @param salt: salt for nsec3
+ * @param saltlen: length of salt.
+ * @param res: result of hash stored here.
+ * @param max: maximum space for result.
+ * @return 0 on failure, otherwise bytelength stored.
+ */
+size_t nsec3_get_hashed(ldns_buffer* buf, uint8_t* nm, size_t nmlen, int algo, 
+       size_t iter, uint8_t* salt, size_t saltlen, uint8_t* res, size_t max);
+
+/** 
+ * see if NSEC3 RR contains given type
+ * @param rrset: NSEC3 rrset
+ * @param r: RR in rrset
+ * @param type: in host order to check bit for.
+ * @return true if bit set, false if not or error.
+ */
+int nsec3_has_type(struct ub_packed_rrset_key* rrset, int r, uint16_t type);
+
+/** 
+ * return if nsec3 RR has the optout flag 
+ * @param rrset: NSEC3 rrset
+ * @param r: RR in rrset
+ * @return true if optout, false on error or not optout
+ */
+int nsec3_has_optout(struct ub_packed_rrset_key* rrset, int r);
+
+/** 
+ * Return nsec3 RR next hashed owner name 
+ * @param rrset: NSEC3 rrset
+ * @param r: RR in rrset
+ * @param next: ptr into rdata to next owner hash
+ * @param nextlen: length of hash.
+ * @return false on malformed
+ */
+int nsec3_get_nextowner(struct ub_packed_rrset_key* rrset, int r,
+       uint8_t** next, size_t* nextlen);
+
+/**
+ * nsec3Covers
+ * Given a hash and a candidate NSEC3Record, determine if that NSEC3Record
+ * covers the hash. Covers specifically means that the hash is in between
+ * the owner and next hashes and does not equal either.
+ *
+ * @param zone: the zone name.
+ * @param hash: the hash of the name
+ * @param rrset: the rrset of the NSEC3.
+ * @param rr: which rr in the rrset.
+ * @param buf: temporary buffer.
+ * @return true if covers, false if not.
+ */
+int nsec3_covers(uint8_t* zone, struct nsec3_cached_hash* hash,
+       struct ub_packed_rrset_key* rrset, int rr, ldns_buffer* buf);
+
 #endif /* VALIDATOR_VAL_NSEC3_H */