Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * nsec3.c -- nsec3 handling.
      3  *
      4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
      5  *
      6  * See LICENSE for the license.
      7  *
      8  */
      9 #include "config.h"
     10 #ifdef NSEC3
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 
     14 #include "nsec3.h"
     15 #include "iterated_hash.h"
     16 #include "namedb.h"
     17 #include "nsd.h"
     18 #include "answer.h"
     19 #include "options.h"
     20 
     21 #define NSEC3_RDATA_BITMAP 5
     22 
     23 /* compare nsec3 hashes in nsec3 tree */
     24 static int
     25 cmp_hash_tree(const void* x, const void* y)
     26 {
     27 	const domain_type* a = (const domain_type*)x;
     28 	const domain_type* b = (const domain_type*)y;
     29 	if(!a->nsec3) return (b->nsec3?-1:0);
     30 	if(!b->nsec3) return 1;
     31 	if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0);
     32 	if(!b->nsec3->hash_wc) return 1;
     33 	return memcmp(a->nsec3->hash_wc->hash.hash,
     34 		b->nsec3->hash_wc->hash.hash, NSEC3_HASH_LEN);
     35 }
     36 
     37 /* compare nsec3 hashes in nsec3 wc tree */
     38 static int
     39 cmp_wchash_tree(const void* x, const void* y)
     40 {
     41 	const domain_type* a = (const domain_type*)x;
     42 	const domain_type* b = (const domain_type*)y;
     43 	if(!a->nsec3) return (b->nsec3?-1:0);
     44 	if(!b->nsec3) return 1;
     45 	if(!a->nsec3->hash_wc) return (b->nsec3->hash_wc?-1:0);
     46 	if(!b->nsec3->hash_wc) return 1;
     47 	return memcmp(a->nsec3->hash_wc->wc.hash,
     48 		b->nsec3->hash_wc->wc.hash, NSEC3_HASH_LEN);
     49 }
     50 
     51 /* compare nsec3 hashes in nsec3 ds tree */
     52 static int
     53 cmp_dshash_tree(const void* x, const void* y)
     54 {
     55 	const domain_type* a = (const domain_type*)x;
     56 	const domain_type* b = (const domain_type*)y;
     57 	if(!a->nsec3) return (b->nsec3?-1:0);
     58 	if(!b->nsec3) return 1;
     59 	if(!a->nsec3->ds_parent_hash) return (b->nsec3->ds_parent_hash?-1:0);
     60 	if(!b->nsec3->ds_parent_hash) return 1;
     61 	return memcmp(a->nsec3->ds_parent_hash->hash,
     62 		b->nsec3->ds_parent_hash->hash, NSEC3_HASH_LEN);
     63 }
     64 
     65 /* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are
     66  * stored in the domain name of the node */
     67 static int
     68 cmp_nsec3_tree(const void* x, const void* y)
     69 {
     70 	const domain_type* a = (const domain_type*)x;
     71 	const domain_type* b = (const domain_type*)y;
     72 	/* labelcount + 32long label */
     73 	assert(dname_name(domain_dname_const(a))[0] == 32);
     74 	assert(dname_name(domain_dname_const(b))[0] == 32);
     75 	return memcmp(dname_name(domain_dname_const(a)), dname_name(domain_dname_const(b)), 33);
     76 }
     77 
     78 void nsec3_zone_trees_create(struct region* region, zone_type* zone)
     79 {
     80 	if(!zone->nsec3tree)
     81 		zone->nsec3tree = rbtree_create(region, cmp_nsec3_tree);
     82 	if(!zone->hashtree)
     83 		zone->hashtree = rbtree_create(region, cmp_hash_tree);
     84 	if(!zone->wchashtree)
     85 		zone->wchashtree = rbtree_create(region, cmp_wchash_tree);
     86 	if(!zone->dshashtree)
     87 		zone->dshashtree = rbtree_create(region, cmp_dshash_tree);
     88 }
     89 
     90 static void
     91 detect_nsec3_params(rr_type* nsec3_apex,
     92 	const unsigned char** salt, int* salt_len, int* iter)
     93 {
     94 	assert(salt && salt_len && iter);
     95 	assert(nsec3_apex);
     96 	if(nsec3_apex->rdlength < 5)
     97 		return;
     98 	if(nsec3_apex->rdlength < 5 + (uint16_t)(nsec3_apex->rdata[4]))
     99 		return;
    100 	*salt_len = nsec3_apex->rdata[4];
    101 	*salt = (unsigned char*)(nsec3_apex->rdata + 5);
    102 	*iter = read_uint16(nsec3_apex->rdata + 2);
    103 }
    104 
    105 const dname_type *
    106 nsec3_b32_create(region_type* region, zone_type* zone, unsigned char* hash)
    107 {
    108 	const dname_type* dname;
    109 	char b32[SHA_DIGEST_LENGTH*2+1];
    110 	b32_ntop(hash, SHA_DIGEST_LENGTH, b32, sizeof(b32));
    111 	dname=dname_parse(region, b32);
    112 	dname=dname_concatenate(region, dname, domain_dname(zone->apex));
    113 	return dname;
    114 }
    115 
    116 void
    117 nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store)
    118 {
    119 	const unsigned char* nsec3_salt = NULL;
    120 	int nsec3_saltlength = 0;
    121 	int nsec3_iterations = 0;
    122 
    123 	detect_nsec3_params(zone->nsec3_param, &nsec3_salt,
    124 		&nsec3_saltlength, &nsec3_iterations);
    125 	assert(nsec3_iterations >= 0 && nsec3_iterations <= 65536);
    126 	iterated_hash((unsigned char*)store, nsec3_salt, nsec3_saltlength,
    127 		dname_name(dname), dname->name_size, nsec3_iterations);
    128 }
    129 
    130 #define STORE_HASH(x,y) memmove(domain->nsec3->x,y,NSEC3_HASH_LEN); domain->nsec3->have_##x =1;
    131 
    132 /** find hash or create it and store it */
    133 static void
    134 nsec3_lookup_hash_and_wc(region_type* region, zone_type* zone,
    135 	const dname_type* dname, domain_type* domain, region_type* tmpregion)
    136 {
    137 	const dname_type* wcard;
    138 	if(domain->nsec3->hash_wc) {
    139 		return;
    140 	}
    141 	/* lookup failed; disk failure or so */
    142 	domain->nsec3->hash_wc = (nsec3_hash_wc_node_type *)
    143 		region_alloc(region, sizeof(nsec3_hash_wc_node_type));
    144 	domain->nsec3->hash_wc->hash.node.key = NULL;
    145 	domain->nsec3->hash_wc->wc.node.key = NULL;
    146 	nsec3_hash_and_store(zone, dname, domain->nsec3->hash_wc->hash.hash);
    147 	wcard = dname_parse(tmpregion, "*");
    148 	wcard = dname_concatenate(tmpregion, wcard, dname);
    149 	nsec3_hash_and_store(zone, wcard, domain->nsec3->hash_wc->wc.hash);
    150 }
    151 
    152 static void
    153 nsec3_lookup_hash_ds(region_type* region, zone_type* zone,
    154 	const dname_type* dname, domain_type* domain)
    155 {
    156 	if(domain->nsec3->ds_parent_hash) {
    157 		return;
    158 	}
    159 	/* lookup failed; disk failure or so */
    160 	domain->nsec3->ds_parent_hash = (nsec3_hash_node_type *)
    161 		region_alloc(region, sizeof(nsec3_hash_node_type));
    162 	domain->nsec3->ds_parent_hash->node.key = NULL;
    163 	nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash);
    164 }
    165 
    166 static int
    167 nsec3_has_soa(rr_type* rr)
    168 {
    169 	size_t offset;
    170 	/* byte + byte + short + string + string + bitmap */
    171 	if(rr->rdlength < 6)
    172 		return 0;
    173 	offset = 4;
    174 	if(rr->rdlength < offset+1 ||
    175 		rr->rdlength < offset+1+rr->rdata[offset])
    176 		return 0;
    177 	offset += 1 + rr->rdata[offset];
    178 	if(rr->rdlength < offset+1 ||
    179 		rr->rdlength < offset+1+rr->rdata[offset])
    180 		return 0;
    181 	offset += 1 + rr->rdata[offset];
    182 	if (rr->rdlength >= offset + 3 && /* has types in bitmap */
    183 			rr->rdata[offset] == 0 && /* first window = 0, */
    184 	    /* [1]: bitmap length must be >= 1 */
    185 	    /* [2]: bit[6] = SOA, thus mask first bitmap octet with 0x02 */
    186 	    (rr->rdata[offset+2] & 0x02))
    187 		return 1;
    188 	return 0;
    189 }
    190 
    191 static rr_type*
    192 check_apex_soa(namedb_type* namedb, zone_type *zone, int nolog)
    193 {
    194 	uint8_t h[NSEC3_HASH_LEN];
    195 	domain_type* domain;
    196 	const dname_type* hashed_apex, *dname = domain_dname(zone->apex);
    197 	unsigned j;
    198 	rrset_type* nsec3_rrset;
    199 	region_type* tmpregion;
    200 
    201 	nsec3_hash_and_store(zone, dname, h);
    202 	tmpregion = region_create(xalloc, free);
    203 	hashed_apex = nsec3_b32_create(tmpregion, zone, h);
    204 	domain = domain_table_find(namedb->domains, hashed_apex);
    205 	if(!domain) {
    206 		if(!nolog) {
    207 			log_msg(LOG_ERR, "%s NSEC3PARAM entry has no hash(apex).",
    208 				domain_to_string(zone->apex));
    209 			log_msg(LOG_ERR, "hash(apex)= %s",
    210 				dname_to_string(hashed_apex, NULL));
    211 		}
    212 		region_destroy(tmpregion);
    213 		return NULL;
    214 	}
    215 	nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC3);
    216 	if(!nsec3_rrset) {
    217 		if(!nolog) {
    218 			log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) has no NSEC3 RRset.",
    219 				domain_to_string(zone->apex));
    220 			log_msg(LOG_ERR, "hash(apex)= %s",
    221 				dname_to_string(hashed_apex, NULL));
    222 		}
    223 		region_destroy(tmpregion);
    224 		return NULL;
    225 	}
    226 	for(j=0; j<nsec3_rrset->rr_count; j++) {
    227 		if(nsec3_has_soa(nsec3_rrset->rrs[j])) {
    228 			region_destroy(tmpregion);
    229 			return nsec3_rrset->rrs[j];
    230 		}
    231 	}
    232 	if(!nolog) {
    233 		log_msg(LOG_ERR, "%s NSEC3PARAM entry: hash(apex) NSEC3 has no SOA flag.",
    234 			domain_to_string(zone->apex));
    235 		log_msg(LOG_ERR, "hash(apex)= %s",
    236 			dname_to_string(hashed_apex, NULL));
    237 	}
    238 	region_destroy(tmpregion);
    239 	return NULL;
    240 }
    241 
    242 static void
    243 nsec3param_to_str(struct rr* rr, char* str, size_t buflen)
    244 {
    245 	size_t len;
    246 	if(rr->rdlength < 5 || rr->rdlength < 5 + (uint16_t)rr->rdata[4]) {
    247 		str[0]=0;
    248 		return;
    249 	}
    250 	len = snprintf(str, buflen, "%u %u %u ",
    251 		(unsigned)rr->rdata[0], (unsigned)rr->rdata[1],
    252 		(unsigned)read_uint16(rr->rdata+2));
    253 	if(rr->rdata[4] == 0) {
    254 		if(buflen > len + 2)
    255 			str[len++] = '-';
    256 	} else {
    257 		len += hex_ntop(rr->rdata+5, rr->rdata[4], str+len, buflen-len-1);
    258 	}
    259 	if(buflen > len + 1) {
    260 		str[len] = 0;
    261 	} else {
    262 		assert(buflen > 0);
    263 		str[buflen-1] = 0;
    264 	}
    265 }
    266 
    267 static struct rr*
    268 db_find_nsec3param(struct namedb* db, struct zone* z, struct rr* avoid_rr,
    269 	int checkchain)
    270 {
    271 	unsigned i;
    272 	rrset_type* rrset = domain_find_rrset(z->apex, z, TYPE_NSEC3PARAM);
    273 	if(!rrset) /* no NSEC3PARAM in mem */
    274 		return NULL;
    275 	/* find first nsec3param we can support (SHA1, no flags) */
    276 	for(i=0; i<rrset->rr_count; i++) {
    277 		/* do not use the RR that is going to be deleted (in IXFR) */
    278 		if(rrset->rrs[i] == avoid_rr) continue;
    279 		if(rrset->rrs[i]->rdlength < 5) continue; /* require salt field */
    280 		if(rrset->rrs[i]->rdata[0] == NSEC3_SHA1_HASH &&
    281 			rrset->rrs[i]->rdata[1] == 0) {
    282 			if(checkchain) {
    283 				z->nsec3_param = rrset->rrs[i];
    284 				if(!check_apex_soa(db, z, 1)) {
    285 					char str[MAX_RDLENGTH*2+16];
    286 					nsec3param_to_str(z->nsec3_param,
    287 						str, sizeof(str));
    288 					VERBOSITY(1, (LOG_WARNING, "zone %s NSEC3PARAM %s has broken chain, ignoring", domain_to_string(z->apex), str));
    289 					continue; /* don't use broken chain */
    290 				}
    291 			}
    292 			if(2 <= verbosity) {
    293 				char str[MAX_RDLENGTH*2+16];
    294 				nsec3param_to_str(rrset->rrs[i], str,
    295 					sizeof(str));
    296 				VERBOSITY(2, (LOG_INFO, "rehash of zone %s with parameters %s",
    297 					domain_to_string(z->apex), str));
    298 			}
    299 			return rrset->rrs[i];
    300 		}
    301 	}
    302 	return NULL;
    303 }
    304 
    305 void
    306 nsec3_find_zone_param(struct namedb* db, struct zone* zone,
    307 	struct rr* avoid_rr, int checkchain)
    308 {
    309 	/* avoid using the rr that is going to be deleted, avoid_rr */
    310 	zone->nsec3_param = db_find_nsec3param(db, zone, avoid_rr, checkchain);
    311 }
    312 
    313 /* check params ok for one RR */
    314 static int
    315 nsec3_rdata_params_ok(const rr_type *prr, const rr_type* rr)
    316 {
    317 	if(prr->rdlength > rr->rdlength)
    318 		return 0; /* The salt has to fit */
    319 	if(prr->rdlength < 5)
    320 		return 0; /* Malformed */
    321 	return prr->rdata[0] == rr->rdata[0] &&
    322 		(memcmp(prr->rdata+2, rr->rdata+2, prr->rdlength-2) == 0);
    323 }
    324 
    325 int
    326 nsec3_rr_uses_params(rr_type* rr, zone_type* zone)
    327 {
    328 	if(!rr || rr->rdlength < 6)
    329 		return 0;
    330 	return nsec3_rdata_params_ok(zone->nsec3_param, rr);
    331 }
    332 
    333 int
    334 nsec3_in_chain_count(domain_type* domain, zone_type* zone)
    335 {
    336 	rrset_type* rrset = domain_find_rrset(domain, zone, TYPE_NSEC3);
    337 	unsigned i;
    338 	int count = 0;
    339 	if(!rrset || !zone->nsec3_param)
    340 		return 0; /* no NSEC3s, none in the chain */
    341 	for(i=0; i<rrset->rr_count; i++) {
    342 		if(nsec3_rr_uses_params(rrset->rrs[i], zone))
    343 			count++;
    344 	}
    345 	return count;
    346 }
    347 
    348 struct domain*
    349 nsec3_chain_find_prev(struct zone* zone, struct domain* domain)
    350 {
    351 	if(domain->nsec3 && domain->nsec3->nsec3_node.key) {
    352 		/* see if there is a prev */
    353 		rbnode_type* r = rbtree_previous(&domain->nsec3->nsec3_node);
    354 		if(r != RBTREE_NULL) {
    355 			/* found a previous, which is not the root-node in
    356 			 * the prehash tree (and thus points to the tree) */
    357 			return (domain_type*)r->key;
    358 		}
    359 	}
    360 	if(zone->nsec3_last && zone->nsec3_last != domain)
    361 		return zone->nsec3_last;
    362 	return NULL;
    363 }
    364 
    365 
    366 /** clear hash tree. Called from nsec3_clear_precompile() only. */
    367 static void
    368 hash_tree_clear(rbtree_type* tree)
    369 {
    370 	if(!tree) return;
    371 
    372 	/* Previously (before commit 4ca61188b3f7a0e077476875810d18a5d439871f
    373 	 * and/or svn commit 4776) prehashes and corresponding rbtree nodes
    374 	 * were part of struct nsec3_domain_data. Clearing the hash_tree would
    375 	 * then mean setting the key value of the nodes to NULL to indicate
    376 	 * absence of the prehash.
    377 	 * But since prehash structs are separatly allocated, this is no longer
    378 	 * necessary as currently the prehash structs are simply recycled and
    379 	 * NULLed.
    380 	 *
    381 	 * rbnode_type* n;
    382 	 * for(n=rbtree_first(tree); n!=RBTREE_NULL; n=rbtree_next(n)) {
    383 	 *	n->key = NULL;
    384 	 * }
    385 	 */
    386 	tree->count = 0;
    387 	tree->root = RBTREE_NULL;
    388 }
    389 
    390 void
    391 nsec3_clear_precompile(struct namedb* db, zone_type* zone)
    392 {
    393 	domain_type* walk;
    394 	/* clear prehash items (there must not be items for other zones) */
    395 	prehash_clear(db->domains);
    396 	/* clear trees */
    397 	hash_tree_clear(zone->nsec3tree);
    398 	hash_tree_clear(zone->hashtree);
    399 	hash_tree_clear(zone->wchashtree);
    400 	hash_tree_clear(zone->dshashtree);
    401 	/* wipe hashes */
    402 
    403 	/* wipe precompile */
    404 	walk = zone->apex;
    405 	while(walk && domain_is_subdomain(walk, zone->apex)) {
    406 		if(walk->nsec3) {
    407 			if(nsec3_condition_hash(walk, zone)) {
    408 				walk->nsec3->nsec3_node.key = NULL;
    409 				walk->nsec3->nsec3_cover = NULL;
    410 				walk->nsec3->nsec3_wcard_child_cover = NULL;
    411 				walk->nsec3->nsec3_is_exact = 0;
    412 				if (walk->nsec3->hash_wc) {
    413 					region_recycle(db->domains->region,
    414 						walk->nsec3->hash_wc,
    415 						sizeof(nsec3_hash_wc_node_type));
    416 					walk->nsec3->hash_wc = NULL;
    417 				}
    418 			}
    419 			if(nsec3_condition_dshash(walk, zone)) {
    420 				walk->nsec3->nsec3_ds_parent_cover = NULL;
    421 				walk->nsec3->nsec3_ds_parent_is_exact = 0;
    422 				if (walk->nsec3->ds_parent_hash) {
    423 					region_recycle(db->domains->region,
    424 						walk->nsec3->ds_parent_hash,
    425 						sizeof(nsec3_hash_node_type));
    426 					walk->nsec3->ds_parent_hash = NULL;
    427 				}
    428 			}
    429 		}
    430 		walk = domain_next(walk);
    431 	}
    432 	zone->nsec3_last = NULL;
    433 }
    434 
    435 /* see if domain name is part of (existing names in) the nsec3 zone */
    436 int
    437 nsec3_domain_part_of_zone(domain_type* d, zone_type* z)
    438 {
    439 	while(d) {
    440 		if(d->is_apex)
    441 			return (z->apex == d); /* zonecut, if right zone*/
    442 		d = d->parent;
    443 	}
    444 	return 0;
    445 }
    446 
    447 /* condition when a domain is precompiled */
    448 int
    449 nsec3_condition_hash(domain_type* d, zone_type* z)
    450 {
    451 	return d->is_existing && !domain_has_only_NSEC3(d, z) &&
    452 		nsec3_domain_part_of_zone(d, z) && !domain_is_glue(d, z);
    453 }
    454 
    455 /* condition when a domain is ds precompiled */
    456 int
    457 nsec3_condition_dshash(domain_type* d, zone_type* z)
    458 {
    459 	return d->is_existing && !domain_has_only_NSEC3(d, z) &&
    460 		(domain_find_rrset(d, z, TYPE_DS) ||
    461 		domain_find_rrset(d, z, TYPE_NS)) && d != z->apex
    462 		&& nsec3_domain_part_of_zone(d->parent, z);
    463 }
    464 
    465 zone_type*
    466 nsec3_tree_zone(namedb_type* db, domain_type* d)
    467 {
    468 	/* see nsec3_domain_part_of_zone; domains part of zone that has
    469 	 * apex above them */
    470 	/* this does not use the rrset->zone pointer because there may be
    471 	 * no rrsets left at apex (no SOA), e.g. during IXFR */
    472 	while(d) {
    473 		if(d->is_apex) {
    474 			/* we can try a SOA if its present (faster than tree)*/
    475 			/* DNSKEY and NSEC3PARAM are also good indicators */
    476 			rrset_type *rrset;
    477 			for (rrset = d->rrsets; rrset; rrset = rrset->next)
    478 				if (rrset_rrtype(rrset) == TYPE_SOA ||
    479 					rrset_rrtype(rrset) == TYPE_DNSKEY ||
    480 					rrset_rrtype(rrset) == TYPE_NSEC3PARAM)
    481 					return rrset->zone;
    482 			return namedb_find_zone(db, domain_dname(d));
    483 		}
    484 		d = d->parent;
    485 	}
    486 	return NULL;
    487 }
    488 
    489 zone_type*
    490 nsec3_tree_dszone(namedb_type* db, domain_type* d)
    491 {
    492 	/* the DStree does not contain nodes with d==z->apex */
    493 	if(d->is_apex)
    494 		d = d->parent;
    495 	while (d) {
    496 		if (d->is_apex) {
    497 			zone_type *zone = NULL;
    498 			for (rrset_type *rrset = d->rrsets; rrset; rrset = rrset->next)
    499 				if (rrset_rrtype(rrset) == TYPE_SOA ||
    500 				    rrset_rrtype(rrset) == TYPE_DNSKEY ||
    501 				    rrset_rrtype(rrset) == TYPE_NSEC3PARAM)
    502 					zone = rrset->zone;
    503 			if (!zone)
    504 				zone = namedb_find_zone(db, domain_dname(d));
    505 			if (zone && zone->dshashtree)
    506 				return zone;
    507 		}
    508 		d = d->parent;
    509 	}
    510 	return NULL;
    511 }
    512 
    513 int
    514 nsec3_find_cover(zone_type* zone, uint8_t* hash, size_t hashlen,
    515 	domain_type** result)
    516 {
    517 	rbnode_type* r = NULL;
    518 	int exact;
    519 	domain_type d;
    520 	uint8_t n[48];
    521 
    522 	/* nsec3tree is sorted by b32 encoded domain name of the NSEC3 */
    523 	b32_ntop(hash, hashlen, (char*)(n+5), sizeof(n)-5);
    524 #ifdef USE_RADIX_TREE
    525 	d.dname = (dname_type*)n;
    526 #else
    527 	d.node.key = n;
    528 #endif
    529 	n[0] = 34; /* name_size */
    530 	n[1] = 2; /* label_count */
    531 	n[2] = 0; /* label_offset[0] */
    532 	n[3] = 0; /* label_offset[1] */
    533 	n[4] = 32; /* label-size[0] */
    534 
    535 	assert(result);
    536 	assert(zone->nsec3_param && zone->nsec3tree);
    537 
    538 	exact = rbtree_find_less_equal(zone->nsec3tree, &d, &r);
    539 	if(r) {
    540 		*result = (domain_type*)r->key;
    541 	} else {
    542 		*result = zone->nsec3_last;
    543 	}
    544 	return exact;
    545 }
    546 
    547 void
    548 nsec3_precompile_domain(struct namedb* db, struct domain* domain,
    549 	struct zone* zone, region_type* tmpregion)
    550 {
    551 	domain_type* result = 0;
    552 	int exact;
    553 	allocate_domain_nsec3(db->domains, domain);
    554 
    555 	/* hash it */
    556 	nsec3_lookup_hash_and_wc(db->region,
    557 		zone, domain_dname(domain), domain, tmpregion);
    558 
    559 	/* add into tree */
    560 	zone_add_domain_in_hash_tree(db->region, &zone->hashtree,
    561 		cmp_hash_tree, domain, &domain->nsec3->hash_wc->hash.node);
    562 	zone_add_domain_in_hash_tree(db->region, &zone->wchashtree,
    563 		cmp_wchash_tree, domain, &domain->nsec3->hash_wc->wc.node);
    564 
    565 	/* lookup in tree cover ptr (or exact) */
    566 	exact = nsec3_find_cover(zone, domain->nsec3->hash_wc->hash.hash,
    567 		sizeof(domain->nsec3->hash_wc->hash.hash), &result);
    568 	domain->nsec3->nsec3_cover = result;
    569 	if(exact)
    570 		domain->nsec3->nsec3_is_exact = 1;
    571 	else	domain->nsec3->nsec3_is_exact = 0;
    572 
    573 	/* find cover for *.domain for wildcard denial */
    574 	(void)nsec3_find_cover(zone, domain->nsec3->hash_wc->wc.hash,
    575 		sizeof(domain->nsec3->hash_wc->wc.hash), &result);
    576 	domain->nsec3->nsec3_wcard_child_cover = result;
    577 }
    578 
    579 void
    580 nsec3_precompile_domain_ds(struct namedb* db, struct domain* domain,
    581 	struct zone* zone)
    582 {
    583 	domain_type* result = 0;
    584 	int exact;
    585 	allocate_domain_nsec3(db->domains, domain);
    586 
    587 	/* hash it : it could have different hash parameters then the
    588 	   other hash for this domain name */
    589 	nsec3_lookup_hash_ds(db->region, zone, domain_dname(domain), domain);
    590 	/* lookup in tree cover ptr (or exact) */
    591 	exact = nsec3_find_cover(zone, domain->nsec3->ds_parent_hash->hash,
    592 		sizeof(domain->nsec3->ds_parent_hash->hash), &result);
    593 	domain->nsec3->nsec3_ds_parent_is_exact = exact != 0;
    594 	domain->nsec3->nsec3_ds_parent_cover = result;
    595 	/* add into tree */
    596 	zone_add_domain_in_hash_tree(db->region, &zone->dshashtree,
    597 		cmp_dshash_tree, domain, &domain->nsec3->ds_parent_hash->node);
    598 }
    599 
    600 static void
    601 parse_nsec3_name(const dname_type* dname, uint8_t* hash, size_t buflen)
    602 {
    603 	/* first label must be the match, */
    604 	size_t lablen = (buflen-1) * 8 / 5;
    605 	const uint8_t* wire = dname_name(dname);
    606 	assert(lablen == 32 && buflen == NSEC3_HASH_LEN+1);
    607 	/* labels of length 32 for SHA1, and must have space+1 for convert */
    608 	if(wire[0] != lablen) {
    609 		/* not NSEC3 */
    610 		memset(hash, 0, buflen);
    611 		return;
    612 	}
    613 	(void)b32_pton((char*)wire+1, hash, buflen);
    614 }
    615 
    616 void
    617 nsec3_precompile_nsec3rr(namedb_type* db, struct domain* domain,
    618 	struct zone* zone)
    619 {
    620 	allocate_domain_nsec3(db->domains, domain);
    621 	/* add into nsec3tree */
    622 	zone_add_domain_in_hash_tree(db->region, &zone->nsec3tree,
    623 		cmp_nsec3_tree, domain, &domain->nsec3->nsec3_node);
    624 	/* fixup the last in the zone */
    625 	if(rbtree_last(zone->nsec3tree)->key == domain) {
    626 		zone->nsec3_last = domain;
    627 	}
    628 }
    629 
    630 void
    631 nsec3_precompile_newparam(namedb_type* db, zone_type* zone)
    632 {
    633 	region_type* tmpregion = region_create(xalloc, free);
    634 	domain_type* walk;
    635 	time_t s = time(NULL);
    636 	unsigned long n = 0, c = 0;
    637 
    638 	/* add nsec3s of chain to nsec3tree */
    639 	for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex);
    640 		walk = domain_next(walk)) {
    641 		n++;
    642 		if(nsec3_in_chain_count(walk, zone) != 0) {
    643 			nsec3_precompile_nsec3rr(db, walk, zone);
    644 		}
    645 	}
    646 	/* hash and precompile zone */
    647 	for(walk=zone->apex; walk && domain_is_subdomain(walk, zone->apex);
    648 		walk = domain_next(walk)) {
    649 		if(nsec3_condition_hash(walk, zone)) {
    650 			nsec3_precompile_domain(db, walk, zone, tmpregion);
    651 			region_free_all(tmpregion);
    652 		}
    653 		if(nsec3_condition_dshash(walk, zone))
    654 			nsec3_precompile_domain_ds(db, walk, zone);
    655 		if(++c % ZONEC_PCT_COUNT == 0 && time(NULL) > s + ZONEC_PCT_TIME) {
    656 			s = time(NULL);
    657 			VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%",
    658 				zone->opts->name,
    659 				(n==0)?0:(int)(c*((unsigned long)100)/n)));
    660 		}
    661 	}
    662 	region_destroy(tmpregion);
    663 }
    664 
    665 void
    666 prehash_zone_complete(struct namedb* db, struct zone* zone)
    667 {
    668 	/* robust clear it */
    669 	nsec3_clear_precompile(db, zone);
    670 	/* find zone settings */
    671 
    672 	assert(db && zone);
    673 	nsec3_find_zone_param(db, zone, NULL, 1);
    674 	if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) {
    675 		zone->nsec3_param = NULL;
    676 		zone->nsec3_last = NULL;
    677 		return;
    678 	}
    679 	nsec3_zone_trees_create(db->region, zone);
    680 	nsec3_precompile_newparam(db, zone);
    681 }
    682 
    683 static void
    684 init_lookup_key_hash_tree(domain_type* d, uint8_t* hash)
    685 { memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN); }
    686 
    687 static void
    688 init_lookup_key_wc_tree(domain_type* d, uint8_t* hash)
    689 { memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN); }
    690 
    691 static void
    692 init_lookup_key_ds_tree(domain_type* d, uint8_t* hash)
    693 { memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN); }
    694 
    695 /* find first in the tree and true if the first to process it */
    696 static int
    697 process_first(rbtree_type* tree, uint8_t* hash, rbnode_type** p,
    698 	void (*init)(domain_type*, uint8_t*))
    699 {
    700 	domain_type d;
    701 	struct nsec3_domain_data n;
    702 	nsec3_hash_wc_node_type hash_wc;
    703 	nsec3_hash_node_type ds_parent_hash;
    704 
    705 	if(!tree) {
    706 		*p = RBTREE_NULL;
    707 		return 0;
    708 	}
    709 	hash_wc.hash.node.key = NULL;
    710 	hash_wc.wc.node.key = NULL;
    711 	n.hash_wc = &hash_wc;
    712 	ds_parent_hash.node.key = NULL;
    713 	n.ds_parent_hash = &ds_parent_hash;
    714 	d.nsec3 = &n;
    715 	init(&d, hash);
    716 	if(rbtree_find_less_equal(tree, &d, p)) {
    717 		/* found an exact match */
    718 		return 1;
    719 	}
    720 	if(!*p) /* before first, go from first */
    721 		*p = rbtree_first(tree);
    722 	/* the inexact, smaller, match we found, does not itself need to
    723 	 * be edited */
    724 	else
    725 		*p = rbtree_next(*p); /* if this becomes NULL, nothing to do */
    726 	return 0;
    727 }
    728 
    729 /* set end pointer if possible */
    730 static void
    731 process_end(rbtree_type* tree, uint8_t* hash, rbnode_type** p,
    732 	void (*init)(domain_type*, uint8_t*))
    733 {
    734 	domain_type d;
    735 	struct nsec3_domain_data n;
    736 	nsec3_hash_wc_node_type hash_wc;
    737 	nsec3_hash_node_type ds_parent_hash;
    738 
    739 	if(!tree) {
    740 		*p = RBTREE_NULL;
    741 		return;
    742 	}
    743 	hash_wc.hash.node.key = NULL;
    744 	hash_wc.wc.node.key = NULL;
    745 	n.hash_wc = &hash_wc;
    746 	ds_parent_hash.node.key = NULL;
    747 	n.ds_parent_hash = &ds_parent_hash;
    748 	d.nsec3 = &n;
    749 	init(&d, hash);
    750 	if(rbtree_find_less_equal(tree, &d, p)) {
    751 		/* an exact match, fine, because this one does not get
    752 		 * processed */
    753 		return;
    754 	}
    755 	/* inexact element, but if NULL, until first element in tree */
    756 	if(!*p) {
    757 		*p = rbtree_first(tree);
    758 		return;
    759 	}
    760 	/* inexact match, use next element, if possible, the smaller
    761 	 * element is part of the range */
    762 	*p = rbtree_next(*p);
    763 	/* if next returns null, we go until the end of the tree */
    764 }
    765 
    766 /* prehash domains in hash range start to end */
    767 static void
    768 process_range(zone_type* zone, domain_type* start,
    769 	domain_type* end, domain_type* nsec3)
    770 {
    771 	/* start NULL means from first in tree */
    772 	/* end NULL means to last in tree */
    773 	rbnode_type *p = RBTREE_NULL, *pwc = RBTREE_NULL, *pds = RBTREE_NULL;
    774 	rbnode_type *p_end = RBTREE_NULL, *pwc_end = RBTREE_NULL, *pds_end = RBTREE_NULL;
    775 	/* because the nodes are on the prehashlist, the domain->nsec3 is
    776 	 * already allocated, and we need not allocate it here */
    777 	/* set start */
    778 	if(start) {
    779 		uint8_t hash[NSEC3_HASH_LEN+1];
    780 		parse_nsec3_name(domain_dname(start), hash, sizeof(hash));
    781 		/* if exact match on first, set is_exact */
    782 		if(process_first(zone->hashtree, hash, &p, init_lookup_key_hash_tree)) {
    783 			((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3;
    784 			((domain_type*)(p->key))->nsec3->nsec3_is_exact = 1;
    785 			p = rbtree_next(p);
    786 		}
    787 		(void)process_first(zone->wchashtree, hash, &pwc, init_lookup_key_wc_tree);
    788 		if(process_first(zone->dshashtree, hash, &pds, init_lookup_key_ds_tree)){
    789 			((domain_type*)(pds->key))->nsec3->
    790 				nsec3_ds_parent_cover = nsec3;
    791 			((domain_type*)(pds->key))->nsec3->
    792 				nsec3_ds_parent_is_exact = 1;
    793 			pds = rbtree_next(pds);
    794 		}
    795 	} else {
    796 		if(zone->hashtree)
    797 			p = rbtree_first(zone->hashtree);
    798 		if(zone->wchashtree)
    799 			pwc = rbtree_first(zone->wchashtree);
    800 		if(zone->dshashtree)
    801 			pds = rbtree_first(zone->dshashtree);
    802 	}
    803 	/* set end */
    804 	if(end) {
    805 		uint8_t hash[NSEC3_HASH_LEN+1];
    806 		parse_nsec3_name(domain_dname(end), hash, sizeof(hash));
    807 		process_end(zone->hashtree, hash, &p_end, init_lookup_key_hash_tree);
    808 		process_end(zone->wchashtree, hash, &pwc_end, init_lookup_key_wc_tree);
    809 		process_end(zone->dshashtree, hash, &pds_end, init_lookup_key_ds_tree);
    810 	}
    811 
    812 	/* precompile */
    813 	while(p != RBTREE_NULL && p != p_end) {
    814 		((domain_type*)(p->key))->nsec3->nsec3_cover = nsec3;
    815 		((domain_type*)(p->key))->nsec3->nsec3_is_exact = 0;
    816 		p = rbtree_next(p);
    817 	}
    818 	while(pwc != RBTREE_NULL && pwc != pwc_end) {
    819 		((domain_type*)(pwc->key))->nsec3->
    820 			nsec3_wcard_child_cover = nsec3;
    821 		pwc = rbtree_next(pwc);
    822 	}
    823 	while(pds != RBTREE_NULL && pds != pds_end) {
    824 		((domain_type*)(pds->key))->nsec3->
    825 			nsec3_ds_parent_cover = nsec3;
    826 		((domain_type*)(pds->key))->nsec3->
    827 			nsec3_ds_parent_is_exact = 0;
    828 		pds = rbtree_next(pds);
    829 	}
    830 }
    831 
    832 /* prehash a domain from the prehash list */
    833 static void
    834 process_prehash_domain(domain_type* domain, zone_type* zone)
    835 {
    836 	/* in the hashtree, wchashtree, dshashtree walk through to next NSEC3
    837 	 * and set precompile pointers to point to this domain (or is_exact),
    838 	 * the first domain can be is_exact. If it is the last NSEC3, also
    839 	 * process the initial part (before the first) */
    840 	rbnode_type* nx;
    841 
    842 	/* this domain is part of the prehash list and therefore the
    843 	 * domain->nsec3 is allocated and need not be allocated here */
    844 	assert(domain->nsec3 && domain->nsec3->nsec3_node.key);
    845 	nx = rbtree_next(&domain->nsec3->nsec3_node);
    846 	if(nx != RBTREE_NULL) {
    847 		/* process until next nsec3 */
    848 		domain_type* end = (domain_type*)nx->key;
    849 		process_range(zone, domain, end, domain);
    850 	} else {
    851 		/* first is root, but then comes the first nsec3 */
    852 		domain_type* first = (domain_type*)(rbtree_first(
    853 			zone->nsec3tree)->key);
    854 		/* last in zone */
    855 		process_range(zone, domain, NULL, domain);
    856 		/* also process before first in zone */
    857 		process_range(zone, NULL, first, domain);
    858 	}
    859 }
    860 
    861 void prehash_zone(struct namedb* db, struct zone* zone)
    862 {
    863 	domain_type* d;
    864 	if(!zone->nsec3_param) {
    865 		prehash_clear(db->domains);
    866 		return;
    867 	}
    868 	if(!check_apex_soa(db, zone, 1)) {
    869 		/* the zone fails apex soa check, prehash complete may
    870 		 * detect other valid chains */
    871 		prehash_clear(db->domains);
    872 		prehash_zone_complete(db, zone);
    873 		return;
    874 	}
    875 	/* process prehash list */
    876 	for(d = db->domains->prehash_list; d; d = d->nsec3->prehash_next) {
    877 		process_prehash_domain(d, zone);
    878 	}
    879 	/* clear prehash list */
    880 	prehash_clear(db->domains);
    881 
    882 	if(!check_apex_soa(db, zone, 0)) {
    883 		zone->nsec3_param = NULL;
    884 		zone->nsec3_last = NULL;
    885 	}
    886 }
    887 
    888 /* add the NSEC3 rrset to the query answer at the given domain */
    889 static void
    890 nsec3_add_rrset(struct query* query, struct answer* answer,
    891 	rr_section_type section, struct domain* domain)
    892 {
    893 	if(domain) {
    894 		rrset_type* rrset = domain_find_rrset(domain, query->zone, TYPE_NSEC3);
    895 		if(rrset)
    896 			answer_add_rrset(answer, section, domain, rrset);
    897 	}
    898 }
    899 
    900 /* this routine does hashing at query-time. slow. */
    901 static void
    902 nsec3_add_nonexist_proof(struct query* query, struct answer* answer,
    903         struct domain* encloser, const dname_type* qname)
    904 {
    905 	uint8_t hash[NSEC3_HASH_LEN];
    906 	const dname_type* to_prove;
    907 	domain_type* cover=0;
    908 	assert(encloser);
    909 	/* if query=a.b.c.d encloser=c.d. then proof needed for b.c.d. */
    910 	/* if query=a.b.c.d encloser=*.c.d. then proof needed for b.c.d. */
    911 	to_prove = dname_partial_copy(query->region, qname,
    912 		dname_label_match_count(qname, domain_dname(encloser))+1);
    913 	/* generate proof that one label below closest encloser does not exist */
    914 	nsec3_hash_and_store(query->zone, to_prove, hash);
    915 	if(nsec3_find_cover(query->zone, hash, sizeof(hash), &cover))
    916 	{
    917 		/* exact match, hash collision */
    918 		domain_type* walk;
    919 		char hashbuf[512];
    920 		char reversebuf[512];
    921 		(void)b32_ntop(hash, sizeof(hash), hashbuf, sizeof(hashbuf));
    922 		snprintf(reversebuf, sizeof(reversebuf), "(no name in the zone hashes to this nsec3 record)");
    923 		walk = query->zone->apex;
    924 		while(walk) {
    925 			if(walk->nsec3 && walk->nsec3->nsec3_cover == cover) {
    926 				snprintf(reversebuf, sizeof(reversebuf),
    927 					"%s %s", domain_to_string(walk),
    928 					walk->nsec3->nsec3_is_exact?"exact":"no_exact_hash_match");
    929 				if(walk->nsec3->nsec3_is_exact)
    930 					break;
    931 			}
    932 			if(walk->nsec3 && walk->nsec3->nsec3_ds_parent_cover == cover) {
    933 				snprintf(reversebuf, sizeof(reversebuf),
    934 					"%s %s", domain_to_string(walk),
    935 					walk->nsec3->nsec3_ds_parent_is_exact?"exact":"no_exact_hash_match");
    936 				if(walk->nsec3->nsec3_ds_parent_is_exact)
    937 					break;
    938 			}
    939 			walk = domain_next(walk);
    940 		}
    941 
    942 
    943 		/* the hashed name of the query corresponds to an existing name. */
    944 		VERBOSITY(3, (LOG_ERR, "nsec3 hash collision for name=%s hash=%s reverse=%s",
    945 			dname_to_string(to_prove, NULL), hashbuf, reversebuf));
    946 		RCODE_SET(query->packet, RCODE_SERVFAIL);
    947 		/* RFC 8914 - Extended DNS Errors
    948 		 * 4.21. Extended DNS Error Code 0 - Other */
    949 		ASSIGN_EDE_CODE_AND_STRING_LITERAL(query->edns.ede,
    950 			EDE_OTHER, "NSEC3 hash collision");
    951 		return;
    952 	}
    953 	else
    954 	{
    955 		/* cover proves the qname does not exist */
    956 		nsec3_add_rrset(query, answer, AUTHORITY_SECTION, cover);
    957 	}
    958 }
    959 
    960 static void
    961 nsec3_add_closest_encloser_proof(
    962 	struct query* query, struct answer* answer,
    963 	struct domain* closest_encloser, const dname_type* qname)
    964 {
    965 	if(!closest_encloser)
    966 		return;
    967 	/* prove that below closest encloser nothing exists */
    968 	nsec3_add_nonexist_proof(query, answer, closest_encloser, qname);
    969 	/* proof that closest encloser exists */
    970 	if(closest_encloser->nsec3 && closest_encloser->nsec3->nsec3_is_exact)
    971 		nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
    972 			closest_encloser->nsec3->nsec3_cover);
    973 }
    974 
    975 void
    976 nsec3_answer_wildcard(struct query *query, struct answer *answer,
    977         struct domain *wildcard, const dname_type* qname)
    978 {
    979 	if(!wildcard)
    980 		return;
    981 	if(!query->zone->nsec3_param)
    982 		return;
    983 	nsec3_add_nonexist_proof(query, answer, wildcard, qname);
    984 }
    985 
    986 static void
    987 nsec3_add_ds_proof(struct query *query, struct answer *answer,
    988 	struct domain *domain, int delegpt)
    989 {
    990 	/* assert we are above the zone cut */
    991 	assert(domain != query->zone->apex);
    992 	if(domain->nsec3 && domain->nsec3->nsec3_ds_parent_is_exact) {
    993 		/* use NSEC3 record from above the zone cut. */
    994 		nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
    995 			domain->nsec3->nsec3_ds_parent_cover);
    996 	} else if (!delegpt && domain->nsec3 && domain->nsec3->nsec3_is_exact
    997 		&& nsec3_domain_part_of_zone(domain->nsec3->nsec3_cover,
    998 		query->zone)) {
    999 		nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1000 			domain->nsec3->nsec3_cover);
   1001 	} else {
   1002 		/* prove closest provable encloser */
   1003 		domain_type* par = domain->parent;
   1004 		domain_type* prev_par = 0;
   1005 
   1006 		while(par && (!par->nsec3 || !par->nsec3->nsec3_is_exact))
   1007 		{
   1008 			prev_par = par;
   1009 			par = par->parent;
   1010 		}
   1011 		assert(par); /* parent zone apex must be provable, thus this ends */
   1012 		if(!par->nsec3) return;
   1013 		nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1014 			par->nsec3->nsec3_cover);
   1015 		/* we took several steps to go to the provable parent, so
   1016 		   the one below it has no exact nsec3, disprove it.
   1017 		   disprove is easy, it has a prehashed cover ptr. */
   1018 		if(prev_par && prev_par->nsec3) {
   1019 			assert(prev_par != domain &&
   1020 				!prev_par->nsec3->nsec3_is_exact);
   1021 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1022 				prev_par->nsec3->nsec3_cover);
   1023 		} else {
   1024 			/* the exact case was handled earlier, so this is
   1025 			 * with a closest-encloser proof, if in the part
   1026 			 * before the else the closest encloser proof is done,
   1027 			 * then we do not need to add a DS here because
   1028 			 * the optout proof is already complete. If not,
   1029 			 * we add the nsec3 here to complete the closest
   1030 			 * encloser proof with a next closer */
   1031 			/* add optout range from parent zone */
   1032 			/* note: no check of optout bit, resolver checks it */
   1033 			if(domain->nsec3) {
   1034 				nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1035 					domain->nsec3->nsec3_ds_parent_cover);
   1036 			}
   1037 		}
   1038 	}
   1039 }
   1040 
   1041 void
   1042 nsec3_answer_nodata(struct query* query, struct answer* answer,
   1043 	struct domain* original)
   1044 {
   1045 	if(!query->zone->nsec3_param)
   1046 		return;
   1047 	/* nodata when asking for secure delegation */
   1048 	if(query->qtype == TYPE_DS)
   1049 	{
   1050 		if(original == query->zone->apex) {
   1051 			/* DS at zone apex, but server not authoritative for parent zone */
   1052 			/* so answer at the child zone level */
   1053 			if(original->nsec3 && original->nsec3->nsec3_is_exact)
   1054 				nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1055 					original->nsec3->nsec3_cover);
   1056 			return;
   1057 		}
   1058 		/* query->zone must be the parent zone */
   1059 		nsec3_add_ds_proof(query, answer, original, 0);
   1060 		/* if the DS is from a wildcard match */
   1061 		if (original==original->wildcard_child_closest_match
   1062 			&& label_is_wildcard(dname_name(domain_dname(original)))) {
   1063 			/* denial for wildcard is already there */
   1064 			/* add parent proof to have a closest encloser proof for wildcard parent */
   1065 			/* in other words: nsec3 matching closest encloser */
   1066 			if(original->parent && original->parent->nsec3 &&
   1067 				original->parent->nsec3->nsec3_is_exact)
   1068 				nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1069 					original->parent->nsec3->nsec3_cover);
   1070 		}
   1071 	}
   1072 	/* the nodata is result from a wildcard match */
   1073 	else if (original==original->wildcard_child_closest_match
   1074 		&& label_is_wildcard(dname_name(domain_dname(original)))) {
   1075 		/* denial for wildcard is already there */
   1076 
   1077 		/* add parent proof to have a closest encloser proof for wildcard parent */
   1078 		/* in other words: nsec3 matching closest encloser */
   1079 		if(original->parent && original->parent->nsec3 &&
   1080 			original->parent->nsec3->nsec3_is_exact)
   1081 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1082 				original->parent->nsec3->nsec3_cover);
   1083 		/* proof for wildcard itself */
   1084 		/* in other words: nsec3 matching source of synthesis */
   1085 		if(original->nsec3)
   1086 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1087 				original->nsec3->nsec3_cover);
   1088 	}
   1089 	else {	/* add nsec3 to prove rrset does not exist */
   1090 		if(original->nsec3) {
   1091 			if(!original->nsec3->nsec3_is_exact) {
   1092 				/* go up to an existing parent */
   1093 				while(original->parent && original->parent->nsec3 && !original->parent->nsec3->nsec3_is_exact)
   1094 					original = original->parent;
   1095 			}
   1096 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1097 				original->nsec3->nsec3_cover);
   1098 			if(!original->nsec3->nsec3_is_exact) {
   1099 				if(original->parent && original->parent->nsec3 && original->parent->nsec3->nsec3_is_exact)
   1100 				    nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1101 					original->parent->nsec3->nsec3_cover);
   1102 
   1103 			}
   1104 		}
   1105 	}
   1106 }
   1107 
   1108 void
   1109 nsec3_answer_delegation(struct query *query, struct answer *answer)
   1110 {
   1111 	if(!query->zone->nsec3_param)
   1112 		return;
   1113 	nsec3_add_ds_proof(query, answer, query->delegation_domain, 1);
   1114 }
   1115 
   1116 int
   1117 domain_has_only_NSEC3(struct domain* domain, struct zone* zone)
   1118 {
   1119 	/* check for only NSEC3/RRSIG */
   1120 	rrset_type* rrset = domain->rrsets;
   1121 	int nsec3_seen = 0;
   1122 	while(rrset)
   1123 	{
   1124 		if(!zone || rrset->zone == zone)
   1125 		{
   1126 			if(rrset->rrs[0]->type == TYPE_NSEC3)
   1127 				nsec3_seen = 1;
   1128 			else if(rrset->rrs[0]->type != TYPE_RRSIG)
   1129 				return 0;
   1130 		}
   1131 		rrset = rrset->next;
   1132 	}
   1133 	return nsec3_seen;
   1134 }
   1135 
   1136 void
   1137 nsec3_answer_authoritative(struct domain** match, struct query *query,
   1138 	struct answer *answer, struct domain* closest_encloser,
   1139 	const dname_type* qname)
   1140 {
   1141 	if(!query->zone->nsec3_param)
   1142 		return;
   1143 	assert(match);
   1144 	/* there is a match, this has 1 RRset, which is NSEC3, but qtype is not. */
   1145         /* !is_existing: no RR types exist at the QNAME, nor at any descendant of QNAME */
   1146 	if(*match && !(*match)->is_existing &&
   1147 #if 0
   1148 		query->qtype != TYPE_NSEC3 &&
   1149 #endif
   1150 		domain_has_only_NSEC3(*match, query->zone))
   1151 	{
   1152 		/* act as if the NSEC3 domain did not exist, name error */
   1153 		*match = 0;
   1154 		/* all nsec3s are directly below the apex, that is closest encloser */
   1155 		if(query->zone->apex->nsec3 &&
   1156 			query->zone->apex->nsec3->nsec3_is_exact)
   1157 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1158 				query->zone->apex->nsec3->nsec3_cover);
   1159 		/* disprove the nsec3 record. */
   1160 		if(closest_encloser->nsec3)
   1161 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION, closest_encloser->nsec3->nsec3_cover);
   1162 		/* disprove a wildcard */
   1163 		if(query->zone->apex->nsec3)
   1164 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1165 				query->zone->apex->nsec3->nsec3_wcard_child_cover);
   1166 		if (domain_wildcard_child(query->zone->apex)) {
   1167 			/* wildcard exists below the domain */
   1168 			/* wildcard and nsec3 domain clash. server failure. */
   1169 			RCODE_SET(query->packet, RCODE_SERVFAIL);
   1170 			/* RFC 8914 - Extended DNS Errors
   1171 			 * 4.21. Extended DNS Error Code 0 - Other */
   1172 			ASSIGN_EDE_CODE_AND_STRING_LITERAL(query->edns.ede,
   1173 				EDE_OTHER, "Wildcard and NSEC3 domain clash");
   1174 		}
   1175 		return;
   1176 	}
   1177 	else if(*match && (*match)->is_existing &&
   1178 #if 0
   1179 		query->qtype != TYPE_NSEC3 &&
   1180 #endif
   1181 		(domain_has_only_NSEC3(*match, query->zone) ||
   1182 		!domain_find_any_rrset(*match, query->zone)))
   1183 	{
   1184 		/* this looks like a NSEC3 domain, but is actually an empty non-terminal. */
   1185 		nsec3_answer_nodata(query, answer, *match);
   1186 		return;
   1187 	}
   1188 	if(!*match) {
   1189 		/* name error, domain does not exist */
   1190 		nsec3_add_closest_encloser_proof(query, answer, closest_encloser,
   1191 			qname);
   1192 		if(closest_encloser->nsec3)
   1193 			nsec3_add_rrset(query, answer, AUTHORITY_SECTION,
   1194 				closest_encloser->nsec3->nsec3_wcard_child_cover);
   1195 	}
   1196 }
   1197 
   1198 #endif /* NSEC3 */
   1199