Bug Summary

File:src/usr.sbin/nsd/nsec3.c
Warning:line 983, column 7
Access to field 'nsec3' results in a dereference of a null pointer (loaded from variable 'par')

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsec3.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/nsd/obj -resource-dir /usr/local/llvm16/lib/clang/16 -I . -I /usr/src/usr.sbin/nsd -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/nsd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/nsd/nsec3.c
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_BITMAP5 5
22
23/* compare nsec3 hashes in nsec3 tree */
24static int
25cmp_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_LEN20);
35}
36
37/* compare nsec3 hashes in nsec3 wc tree */
38static int
39cmp_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_LEN20);
49}
50
51/* compare nsec3 hashes in nsec3 ds tree */
52static int
53cmp_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_LEN20);
63}
64
65/* compare base32-encoded nsec3 hashes in nsec3 rr tree, they are
66 * stored in the domain name of the node */
67static int
68cmp_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)((void)0);
74 assert(dname_name(domain_dname_const(b))[0] == 32)((void)0);
75 return memcmp(dname_name(domain_dname_const(a)), dname_name(domain_dname_const(b)), 33);
76}
77
78void 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
90static void
91detect_nsec3_params(rr_type* nsec3_apex,
92 const unsigned char** salt, int* salt_len, int* iter)
93{
94 assert(salt && salt_len && iter)((void)0);
95 assert(nsec3_apex)((void)0);
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
101const dname_type *
102nsec3_b32_create(region_type* region, zone_type* zone, unsigned char* hash)
103{
104 const dname_type* dname;
105 char b32[SHA_DIGEST_LENGTH20*2+1];
106 b32_ntop(hash, SHA_DIGEST_LENGTH20, b32, sizeof(b32));
107 dname=dname_parse(region, b32);
108 dname=dname_concatenate(region, dname, domain_dname(zone->apex));
109 return dname;
110}
111
112void
113nsec3_hash_and_store(zone_type* zone, const dname_type* dname, uint8_t* store)
114{
115 const unsigned char* nsec3_salt = NULL((void *)0);
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)((void)0);
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,20); domain->nsec3->have_x
=1;
memmove(domain->nsec3->x,y,NSEC3_HASH_LEN20); domain->nsec3->have_##x =1;
127
128/** find hash or create it and store it */
129static void
130nsec3_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((void *)0);
141 domain->nsec3->hash_wc->wc.node.key = NULL((void *)0);
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
148static void
149nsec3_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((void *)0);
159 nsec3_hash_and_store(zone, dname, domain->nsec3->ds_parent_hash->hash);
160}
161
162static int
163nsec3_has_soa(rr_type* rr)
164{
165 if(rdata_atom_size(rr->rdatas[NSEC3_RDATA_BITMAP5]) >= 3 && /* has types in bitmap */
166 rdata_atom_data(rr->rdatas[NSEC3_RDATA_BITMAP5])[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_BITMAP5])[2]&0x02) { /* SOA bit set */
170 return 1;
171 }
172 return 0;
173}
174
175static rr_type*
176check_apex_soa(namedb_type* namedb, zone_type *zone, int nolog)
177{
178 uint8_t h[NSEC3_HASH_LEN20];
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_ERR3, "%s NSEC3PARAM entry has no hash(apex).",
192 domain_to_string(zone->apex));
193 log_msg(LOG_ERR3, "hash(apex)= %s",
194 dname_to_string(hashed_apex, NULL((void *)0)));
195 }
196 region_destroy(tmpregion);
197 return NULL((void *)0);
198 }
199 nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC350);
200 if(!nsec3_rrset) {
201 if(!nolog) {
202 log_msg(LOG_ERR3, "%s NSEC3PARAM entry: hash(apex) has no NSEC3 RRset.",
203 domain_to_string(zone->apex));
204 log_msg(LOG_ERR3, "hash(apex)= %s",
205 dname_to_string(hashed_apex, NULL((void *)0)));
206 }
207 region_destroy(tmpregion);
208 return NULL((void *)0);
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_ERR3, "%s NSEC3PARAM entry: hash(apex) NSEC3 has no SOA flag.",
218 domain_to_string(zone->apex));
219 log_msg(LOG_ERR3, "hash(apex)= %s",
220 dname_to_string(hashed_apex, NULL((void *)0)));
221 }
222 region_destroy(tmpregion);
223 return NULL((void *)0);
224}
225
226static void
227nsec3param_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
246static struct rr*
247db_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_NSEC3PARAM51);
252 if(!rrset) /* no NSEC3PARAM in mem */
253 return NULL((void *)0);
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_HASH1 &&
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_RDLENGTH65535*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))do { if ((1) <= verbosity) { log_msg (4, "zone %s NSEC3PARAM %s has broken chain, ignoring"
, domain_to_string(z->apex), str) ; } } while (0)
;
269 continue; /* don't use broken chain */
270 }
271 }
272 if(2 <= verbosity) {
273 char str[MAX_RDLENGTH65535*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",do { if ((2) <= verbosity) { log_msg (6, "rehash of zone %s with parameters %s"
, domain_to_string(z->apex), str) ; } } while (0)
277 domain_to_string(z->apex), str))do { if ((2) <= verbosity) { log_msg (6, "rehash of zone %s with parameters %s"
, domain_to_string(z->apex), str) ; } } while (0)
;
278 }
279 return &rrset->rrs[i];
280 }
281 }
282 return NULL((void *)0);
283}
284
285void
286nsec3_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 */
294static int
295nsec3_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
310int
311nsec3_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
318int
319nsec3_in_chain_count(domain_type* domain, zone_type* zone)
320{
321 rrset_type* rrset = domain_find_rrset(domain, zone, TYPE_NSEC350);
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
333struct domain*
334nsec3_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&rbtree_null_node) {
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((void *)0);
348}
349
350
351/** clear hash tree. Called from nsec3_clear_precompile() only. */
352static void
353hash_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&rbtree_null_node;
373}
374
375void
376nsec3_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((void *)0);
394 walk->nsec3->nsec3_cover = NULL((void *)0);
395 walk->nsec3->nsec3_wcard_child_cover = NULL((void *)0);
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((void *)0);
402 }
403 }
404 if(nsec3_condition_dshash(walk, zone)) {
405 walk->nsec3->nsec3_ds_parent_cover = NULL((void *)0);
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((void *)0);
412 }
413 }
414 }
415 walk = domain_next(walk);
416 }
417 zone->nsec3_last = NULL((void *)0);
418}
419
420/* see if domain name is part of (existing names in) the nsec3 zone */
421int
422nsec3_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 */
433int
434nsec3_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 */
441int
442nsec3_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_DS43) ||
446 domain_find_rrset(d, z, TYPE_NS2)) && d != z->apex
447 && nsec3_domain_part_of_zone(d->parent, z);
448}
449
450zone_type*
451nsec3_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_SOA6 ||
464 rrset_rrtype(rrset) == TYPE_DNSKEY48 ||
465 rrset_rrtype(rrset) == TYPE_NSEC3PARAM51)
466 return rrset->zone;
467 return namedb_find_zone(db, domain_dname(d));
468 }
469 d = d->parent;
470 }
471 return NULL((void *)0);
472}
473
474zone_type*
475nsec3_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
483int
484nsec3_find_cover(zone_type* zone, uint8_t* hash, size_t hashlen,
485 domain_type** result)
486{
487 rbnode_type* r = NULL((void *)0);
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)((void)0);
506 assert(zone->nsec3_param && zone->nsec3tree)((void)0);
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
517void
518nsec3_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
549void
550nsec3_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
572static void
573parse_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)((void)0);
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
588void
589nsec3_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
602void
603nsec3_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((void *)0));
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_COUNT100000 == 0 && time(NULL((void *)0)) > s + ZONEC_PCT_TIME5) {
628 s = time(NULL((void *)0));
629 VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%",do { if ((1) <= verbosity) { log_msg (6, "nsec3 %s %d %%",
zone->opts->name, (n==0)?0:(int)(c*((unsigned long)100
)/n)) ; } } while (0)
630 zone->opts->name,do { if ((1) <= verbosity) { log_msg (6, "nsec3 %s %d %%",
zone->opts->name, (n==0)?0:(int)(c*((unsigned long)100
)/n)) ; } } while (0)
631 (n==0)?0:(int)(c*((unsigned long)100)/n)))do { if ((1) <= verbosity) { log_msg (6, "nsec3 %s %d %%",
zone->opts->name, (n==0)?0:(int)(c*((unsigned long)100
)/n)) ; } } while (0)
;
632 }
633 }
634 region_destroy(tmpregion);
635}
636
637void
638prehash_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)((void)0);
645 nsec3_find_zone_param(db, zone, NULL((void *)0), 1);
646 if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) {
647 zone->nsec3_param = NULL((void *)0);
648 zone->nsec3_last = NULL((void *)0);
649 return;
650 }
651 nsec3_precompile_newparam(db, zone);
652}
653
654static void
655init_lookup_key_hash_tree(domain_type* d, uint8_t* hash)
656{ memcpy(d->nsec3->hash_wc->hash.hash, hash, NSEC3_HASH_LEN20); }
657
658static void
659init_lookup_key_wc_tree(domain_type* d, uint8_t* hash)
660{ memcpy(d->nsec3->hash_wc->wc.hash, hash, NSEC3_HASH_LEN20); }
661
662static void
663init_lookup_key_ds_tree(domain_type* d, uint8_t* hash)
664{ memcpy(d->nsec3->ds_parent_hash->hash, hash, NSEC3_HASH_LEN20); }
665
666/* find first in the tree and true if the first to process it */
667static int
668process_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&rbtree_null_node;
678 return 0;
679 }
680 hash_wc.hash.node.key = NULL((void *)0);
681 hash_wc.wc.node.key = NULL((void *)0);
682 n.hash_wc = &hash_wc;
683 ds_parent_hash.node.key = NULL((void *)0);
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 */
701static void
702process_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&rbtree_null_node;
712 return;
713 }
714 hash_wc.hash.node.key = NULL((void *)0);
715 hash_wc.wc.node.key = NULL((void *)0);
716 n.hash_wc = &hash_wc;
717 ds_parent_hash.node.key = NULL((void *)0);
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 */
738static void
739process_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&rbtree_null_node, *pwc = RBTREE_NULL&rbtree_null_node, *pds = RBTREE_NULL&rbtree_null_node;
745 rbnode_type *p_end = RBTREE_NULL&rbtree_null_node, *pwc_end = RBTREE_NULL&rbtree_null_node, *pds_end = RBTREE_NULL&rbtree_null_node;
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_LEN20+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_LEN20+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&rbtree_null_node && 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&rbtree_null_node && 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&rbtree_null_node && 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 */
804static void
805process_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)((void)0);
816 nx = rbtree_next(&domain->nsec3->nsec3_node);
817 if(nx != RBTREE_NULL&rbtree_null_node) {
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((void *)0), domain);
827 /* also process before first in zone */
828 process_range(zone, NULL((void *)0), first, domain);
829 }
830}
831
832void 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((void *)0);
855 zone->nsec3_last = NULL((void *)0);
856 }
857}
858
859/* add the NSEC3 rrset to the query answer at the given domain */
860static void
861nsec3_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_NSEC350);
866 if(rrset)
867 answer_add_rrset(answer, section, domain, rrset);
868 }
869}
870
871/* this routine does hashing at query-time. slow. */
872static void
873nsec3_add_nonexist_proof(struct query* query, struct answer* answer,
874 struct domain* encloser, const dname_type* qname)
875{
876 uint8_t hash[NSEC3_HASH_LEN20];
877 const dname_type* to_prove;
878 domain_type* cover=0;
879 assert(encloser)((void)0);
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",do { if ((3) <= verbosity) { log_msg (3, "nsec3 hash collision for name=%s hash=%s reverse=%s"
, dname_to_string(to_prove, ((void *)0)), hashbuf, reversebuf
) ; } } while (0)
916 dname_to_string(to_prove, NULL), hashbuf, reversebuf))do { if ((3) <= verbosity) { log_msg (3, "nsec3 hash collision for name=%s hash=%s reverse=%s"
, dname_to_string(to_prove, ((void *)0)), hashbuf, reversebuf
) ; } } while (0)
;
917 RCODE_SET(query->packet, RCODE_SERVFAIL)(*buffer_at((query->packet), 3) = (*buffer_at((query->packet
), 3) & ~0x0fU) | (2))
;
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,do { query->edns.ede = (0); query->edns.ede_text = ("NSEC3 hash collision"
""); query->edns.ede_text_len = sizeof("NSEC3 hash collision"
) - 1; } while (0)
921 EDE_OTHER, "NSEC3 hash collision")do { query->edns.ede = (0); query->edns.ede_text = ("NSEC3 hash collision"
""); query->edns.ede_text_len = sizeof("NSEC3 hash collision"
) - 1; } while (0)
;
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
931static void
932nsec3_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
946void
947nsec3_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
957static void
958nsec3_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)((void)0);
963 if(domain->nsec3 && domain->nsec3->nsec3_ds_parent_is_exact) {
16
Assuming field 'nsec3' is null
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
16.1
'delegpt' is 0
&& domain->nsec3
16.2
Field 'nsec3' is null
&& 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;
17
'par' initialized here
975 domain_type* prev_par = 0;
976
977 while(par && (!par->nsec3 || !par->nsec3->nsec3_is_exact))
18
Assuming 'par' is null
978 {
979 prev_par = par;
980 par = par->parent;
981 }
982 assert(par)((void)0); /* parent zone apex must be provable, thus this ends */
983 if(!par->nsec3) return;
19
Access to field 'nsec3' results in a dereference of a null pointer (loaded from variable 'par')
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 &&((void)0)
991 !prev_par->nsec3->nsec3_is_exact)((void)0);
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
1012void
1013nsec3_answer_nodata(struct query* query, struct answer* answer,
1014 struct domain* original)
1015{
1016 if(!query->zone->nsec3_param)
9
Assuming field 'nsec3_param' is non-null
10
Taking false branch
1017 return;
1018 /* nodata when asking for secure delegation */
1019 if(query->qtype == TYPE_DS43)
11
Assuming field 'qtype' is equal to TYPE_DS
12
Taking true branch
1020 {
1021 if(original == query->zone->apex) {
13
Assuming 'original' is not equal to field 'apex'
14
Taking false branch
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);
15
Calling 'nsec3_add_ds_proof'
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
1079void
1080nsec3_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
1087int
1088domain_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_NSEC350)
1098 nsec3_seen = 1;
1099 else if(rrset->rrs[0].type != TYPE_RRSIG46)
1100 return 0;
1101 }
1102 rrset = rrset->next;
1103 }
1104 return nsec3_seen;
1105}
1106
1107void
1108nsec3_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)
1
Assuming field 'nsec3_param' is non-null
2
Taking false branch
1113 return;
1114 assert(match)((void)0);
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 &&
3
Assuming the condition is true
4
Assuming field 'is_existing' is not equal to 0
1118#if 0
1119 query->qtype != TYPE_NSEC350 &&
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)(*buffer_at((query->packet), 3) = (*buffer_at((query->packet
), 3) & ~0x0fU) | (2))
;
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,do { query->edns.ede = (0); query->edns.ede_text = ("Wildcard and NSEC3 domain clash"
""); query->edns.ede_text_len = sizeof("Wildcard and NSEC3 domain clash"
) - 1; } while (0)
1144 EDE_OTHER, "Wildcard and NSEC3 domain clash")do { query->edns.ede = (0); query->edns.ede_text = ("Wildcard and NSEC3 domain clash"
""); query->edns.ede_text_len = sizeof("Wildcard and NSEC3 domain clash"
) - 1; } while (0)
;
1145 }
1146 return;
1147 }
1148 else if(*match && (*match)->is_existing
4.1
Field 'is_existing' is not equal to 0
&&
7
Taking true branch
1149#if 0
1150 query->qtype != TYPE_NSEC350 &&
1151#endif
1152 (domain_has_only_NSEC3(*match, query->zone) ||
1153 !domain_find_any_rrset(*match, query->zone)))
5
Value assigned to field 'parent'
6
Assuming the condition is true
1154 {
1155 /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */
1156 nsec3_answer_nodata(query, answer, *match);
8
Calling 'nsec3_answer_nodata'
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 */