/** * findCoveringNSEC3 * Given a name, find a covering NSEC3 from among a list of NSEC3s. * * @param env: module environment with temporary region and buffer. * @param flt: the NSEC3 RR filter, contains zone name and RRs. * @param ct: cached hashes table. * @param nm: name to check if covered. * @param nmlen: length of name. * @param rrset: covering NSEC3 rrset is returned here. * @param rr: rr of cover is returned here. * @return true if a covering NSEC3 is found, false if not. */ static int find_covering_nsec3(struct module_env* env, struct nsec3_filter* flt, rbtree_t* ct, uint8_t* nm, size_t nmlen, struct ub_packed_rrset_key** rrset, int* rr) { size_t i_rs; int i_rr; struct ub_packed_rrset_key* s; struct nsec3_cached_hash* hash; int r; /* this loop skips other-zone and unknown NSEC3s, also non-NSEC3 RRs */ for(s=filter_first(flt, &i_rs, &i_rr); s; s=filter_next(flt, &i_rs, &i_rr)) { /* get name hashed for this NSEC3 RR */ r = nsec3_hash_name(ct, env->scratch, env->scratch_buffer, s, i_rr, nm, nmlen, &hash); if(r == 0) { log_err("nsec3: malloc failure"); break; /* alloc failure */ } else if(r < 0) continue; /* malformed NSEC3 */ 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 */ return 1; } } *rrset = NULL; *rr = 0; return 0; }
/** 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, uint8_t* topname) { 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; /* TTL reduced in grab_nsec */ if(!dns_msg_authadd(msg, region, ce_rrset, 0)) return NULL; return msg; } /* optout is not allowed without knowing the trust-anchor in use, * otherwise the optout could spoof away that anchor */ if(!topname) return NULL; /* 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 */ /* capacity=3: ce + nc + soa(if needed) */ if(!(msg = dns_msg_create(qname, qname_len, LDNS_RR_TYPE_DS, zone->dclass, region, 3))) return NULL; /* now=0 because TTL was reduced in grab_nsec */ if(!dns_msg_authadd(msg, region, ce_rrset, 0)) return NULL; if(!dns_msg_authadd(msg, region, nc_rrset, 0)) return NULL; return msg; } return NULL; }