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