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