Bug Summary

File:src/usr.sbin/nsd/nsec3.c
Warning:line 1045, 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.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name nsec3.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -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 -fno-rounding-math -mconstructor-aliases -munwind-tables -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/lib/clang/13.0.0 -I . -I /usr/src/usr.sbin/nsd -internal-isystem /usr/local/lib/clang/13.0.0/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 -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/vmm/scan-build/2022-01-12-194120-40624-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 "udbzone.h"
20#include "options.h"
21
22#define NSEC3_RDATA_BITMAP5 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_LEN20);
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_LEN20);
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_LEN20);
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)((void)0);
75 assert(dname_name(domain_dname_const(b))[0] == 32)((void)0);
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)((void)0);
96 assert(nsec3_apex)((void)0);
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_LENGTH20*2+1];
107 b32_ntop(hash, SHA_DIGEST_LENGTH20, 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((void*)0);
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)((void)0);
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,20); domain->nsec3->have_x
=1;
memmove(domain->nsec3->x,y,NSEC3_HASH_LEN20); 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((void*)0);
142 domain->nsec3->hash_wc->wc.node.key = NULL((void*)0);
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((void*)0);
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_BITMAP5]) >= 3 && /* has types in bitmap */
167 rdata_atom_data(rr->rdatas[NSEC3_RDATA_BITMAP5])[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_BITMAP5])[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_LEN20];
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_ERR3, "%s NSEC3PARAM entry has no hash(apex).",
193 domain_to_string(zone->apex));
194 log_msg(LOG_ERR3, "hash(apex)= %s",
195 dname_to_string(hashed_apex, NULL((void*)0)));
196 }
197 region_destroy(tmpregion);
198 return NULL((void*)0);
199 }
200 nsec3_rrset = domain_find_rrset(domain, zone, TYPE_NSEC350);
201 if(!nsec3_rrset) {
202 if(!nolog) {
203 log_msg(LOG_ERR3, "%s NSEC3PARAM entry: hash(apex) has no NSEC3 RRset.",
204 domain_to_string(zone->apex));
205 log_msg(LOG_ERR3, "hash(apex)= %s",
206 dname_to_string(hashed_apex, NULL((void*)0)));
207 }
208 region_destroy(tmpregion);
209 return NULL((void*)0);
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_ERR3, "%s NSEC3PARAM entry: hash(apex) NSEC3 has no SOA flag.",
219 domain_to_string(zone->apex));
220 log_msg(LOG_ERR3, "hash(apex)= %s",
221 dname_to_string(hashed_apex, NULL((void*)0)));
222 }
223 region_destroy(tmpregion);
224 return NULL((void*)0);
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_NSEC3PARAM51);
253 if(!rrset) /* no NSEC3PARAM in mem */
254 return NULL((void*)0);
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_HASH1 &&
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_RDLENGTH65535*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))do { if ((1) <= verbosity) { log_msg (4, "zone %s NSEC3PARAM %s has broken chain, ignoring"
, domain_to_string(z->apex), str) ; } } while (0)
;
270 continue; /* don't use broken chain */
271 }
272 }
273 if(2 <= verbosity) {
274 char str[MAX_RDLENGTH65535*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",do { if ((2) <= verbosity) { log_msg (6, "rehash of zone %s with parameters %s"
, domain_to_string(z->apex), str) ; } } while (0)
278 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)
;
279 }
280 return &rrset->rrs[i];
281 }
282 }
283 return NULL((void*)0);
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_NSEC3PARAM51);
293 if(!rrset) /* no NSEC3PARAM in mem */
294 return NULL((void*)0);
295 udb_ptr_new(&urr, udb, &ZONE(uz)((struct zone_d*)(((void*)((char*)(*((uz)->base)) + ((uz)->
data)))))
->nsec3param);
296 if(!urr.data || RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->len < 5) {
297 /* no NSEC3PARAM in udb */
298 udb_ptr_unlink(&urr, udb);
299 return NULL((void*)0);
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)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->wire[0] == rdata_atom_data(rd[0])[0] && /*alg*/
307 RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->wire[1] == rdata_atom_data(rd[1])[0] && /*flg*/
308 RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->wire[2] == rdata_atom_data(rd[2])[0] && /*iter*/
309 RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->wire[3] == rdata_atom_data(rd[2])[1] &&
310 RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->wire[4] == rdata_atom_data(rd[3])[0] && /*slen*/
311 RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->len >= 5 + RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->wire[4] &&
312 memcmp(RR(&urr)((struct rr_d*)(((void*)((char*)(*((&urr)->base)) + ((
&urr)->data)))))
->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((void*)0), checkchain);
320 }
321 return &rrset->rrs[i];
322 }
323 }
324 udb_ptr_unlink(&urr, udb);
325 return NULL((void*)0);
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_NSEC350);
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&rbtree_null_node) {
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((void*)0);
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&rbtree_null_node;
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((void*)0);
443 walk->nsec3->nsec3_cover = NULL((void*)0);
444 walk->nsec3->nsec3_wcard_child_cover = NULL((void*)0);
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((void*)0);
451 }
452 }
453 if(nsec3_condition_dshash(walk, zone)) {
454 walk->nsec3->nsec3_ds_parent_cover = NULL((void*)0);
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((void*)0);
461 }
462 }
463 }
464 walk = domain_next(walk);
465 }
466 zone->nsec3_last = NULL((void*)0);
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_DS43) ||
495 domain_find_rrset(d, z, TYPE_NS2)) && 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_SOA6 ||
513 rrset_rrtype(rrset) == TYPE_DNSKEY48 ||
514 rrset_rrtype(rrset) == TYPE_NSEC3PARAM51)
515 return rrset->zone;
516 return namedb_find_zone(db, domain_dname(d));
517 }
518 d = d->parent;
519 }
520 return NULL((void*)0);
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((void*)0);
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)((void)0);
555 assert(zone->nsec3_param && zone->nsec3tree)((void)0);
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)((void)0);
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((void*)0));
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_COUNT100000 == 0 && time(NULL((void*)0)) > s + ZONEC_PCT_TIME5) {
677 s = time(NULL((void*)0));
678 VERBOSITY(1, (LOG_INFO, "nsec3 %s %d %%",do { if ((1) <= verbosity) { log_msg (6, "nsec3 %s %d %%",
zone->opts->name, (int)(c*((unsigned long)100)/n)) ; }
} while (0)
679 zone->opts->name,do { if ((1) <= verbosity) { log_msg (6, "nsec3 %s %d %%",
zone->opts->name, (int)(c*((unsigned long)100)/n)) ; }
} while (0)
680 (int)(c*((unsigned long)100)/n)))do { if ((1) <= verbosity) { log_msg (6, "nsec3 %s %d %%",
zone->opts->name, (int)(c*((unsigned long)100)/n)) ; }
} while (0)
;
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)((void)0);
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((void*)0), 1);
704 if(!zone->nsec3_param || !check_apex_soa(db, zone, 0)) {
705 zone->nsec3_param = NULL((void*)0);
706 zone->nsec3_last = NULL((void*)0);
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_LEN20); }
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_LEN20); }
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_LEN20); }
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&rbtree_null_node;
740 return 0;
741 }
742 hash_wc.hash.node.key = NULL((void*)0);
743 hash_wc.wc.node.key = NULL((void*)0);
744 n.hash_wc = &hash_wc;
745 ds_parent_hash.node.key = NULL((void*)0);
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&rbtree_null_node;
774 return;
775 }
776 hash_wc.hash.node.key = NULL((void*)0);
777 hash_wc.wc.node.key = NULL((void*)0);
778 n.hash_wc = &hash_wc;
779 ds_parent_hash.node.key = NULL((void*)0);
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&rbtree_null_node, *pwc = RBTREE_NULL&rbtree_null_node, *pds = RBTREE_NULL&rbtree_null_node;
807 rbnode_type *p_end = RBTREE_NULL&rbtree_null_node, *pwc_end = RBTREE_NULL&rbtree_null_node, *pds_end = RBTREE_NULL&rbtree_null_node;
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_LEN20+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_LEN20+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&rbtree_null_node && 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&rbtree_null_node && 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&rbtree_null_node && 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)((void)0);
878 nx = rbtree_next(&domain->nsec3->nsec3_node);
879 if(nx != RBTREE_NULL&rbtree_null_node) {
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((void*)0), domain);
889 /* also process before first in zone */
890 process_range(zone, NULL((void*)0), 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((void*)0);
917 zone->nsec3_last = NULL((void*)0);
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_NSEC350);
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_LEN20];
939 const dname_type* to_prove;
940 domain_type* cover=0;
941 assert(encloser)((void)0);
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",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)
978 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)
;
979 RCODE_SET(query->packet, RCODE_SERVFAIL)(*buffer_at((query->packet), 3) = (*buffer_at((query->packet
), 3) & ~0x0fU) | (2))
;
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,do { query->edns.ede = (0); query->edns.ede_text = ("NSEC3 hash collision"
""); query->edns.ede_text_len = sizeof("NSEC3 hash collision"
) - 1; } while (0)
983 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)
;
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)((void)0);
1025 if(domain->nsec3 && domain->nsec3->nsec3_ds_parent_is_exact) {
22
Assuming field 'nsec3' is null
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
22.1
'delegpt' is 0
&& domain->nsec3
22.2
Field 'nsec3' is null
&& 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;
23
'par' initialized here
1037 domain_type* prev_par = 0;
1038
1039 while(par && (!par->nsec3 || !par->nsec3->nsec3_is_exact))
24
Assuming 'par' is null
1040 {
1041 prev_par = par;
1042 par = par->parent;
1043 }
1044 assert(par)((void)0); /* parent zone apex must be provable, thus this ends */
1045 if(!par->nsec3) return;
25
Access to field 'nsec3' results in a dereference of a null pointer (loaded from variable 'par')
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 &&((void)0)
1053 !prev_par->nsec3->nsec3_is_exact)((void)0);
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)
15
Assuming field 'nsec3_param' is non-null
16
Taking false branch
1079 return;
1080 /* nodata when asking for secure delegation */
1081 if(query->qtype == TYPE_DS43)
17
Assuming field 'qtype' is equal to TYPE_DS
18
Taking true branch
1082 {
1083 if(original == query->zone->apex) {
19
Assuming 'original' is not equal to field 'apex'
20
Taking false branch
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);
21
Calling 'nsec3_add_ds_proof'
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)
6
Loop condition is false. Execution continues on line 1166
1156 {
1157 if(!zone || rrset->zone == zone)
1158 {
1159 if(rrset->rrs[0].type == TYPE_NSEC350)
1160 nsec3_seen = 1;
1161 else if(rrset->rrs[0].type != TYPE_RRSIG46)
1162 return 0;
1163 }
1164 rrset = rrset->next;
1165 }
1166 return nsec3_seen;
7
Returning without writing to 'zone->nsec3_param', which participates in a condition later
8
Returning without writing to 'domain->nsec3', which participates in a condition later
9
Returning without writing to 'domain->parent'
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)
1
Assuming field 'nsec3_param' is non-null
2
Taking false branch
1175 return;
1176 assert(match)((void)0);
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 &&
3
Assuming the condition is true
4
Assuming field 'is_existing' is not equal to 0
1180#if 0
1181 query->qtype != TYPE_NSEC350 &&
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)(*buffer_at((query->packet), 3) = (*buffer_at((query->packet
), 3) & ~0x0fU) | (2))
;
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,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)
1206 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)
;
1207 }
1208 return;
1209 }
1210 else if(*match && (*match)->is_existing
4.1
Field 'is_existing' is not equal to 0
&&
13
Taking true branch
1211#if 0
1212 query->qtype != TYPE_NSEC350 &&
1213#endif
1214 (domain_has_only_NSEC3(*match, query->zone) ||
5
Calling 'domain_has_only_NSEC3'
10
Returning from 'domain_has_only_NSEC3'
1215 !domain_find_any_rrset(*match, query->zone)))
11
Value assigned to field 'parent'
12
Assuming the condition is true
1216 {
1217 /* this looks like a NSEC3 domain, but is actually an empty non-terminal. */
1218 nsec3_answer_nodata(query, answer, *match);
14
Calling 'nsec3_answer_nodata'
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 */