1 /*  Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  */
16 
17 #include <assert.h>
18 
19 #include "libknot/dname.h"
20 #include "knot/dnssec/nsec-chain.h"
21 #include "knot/dnssec/nsec3-chain.h"
22 #include "knot/dnssec/zone-sign.h"
23 #include "knot/dnssec/zone-nsec.h"
24 #include "knot/zone/adjust.h"
25 #include "knot/zone/zone-diff.h"
26 #include "contrib/base32hex.h"
27 #include "contrib/wire_ctx.h"
28 
nsec3_empty(const zone_node_t * node,const dnssec_nsec3_params_t * params)29 static bool nsec3_empty(const zone_node_t *node, const dnssec_nsec3_params_t *params)
30 {
31 	bool opt_out = (params->flags & KNOT_NSEC3_FLAG_OPT_OUT);
32 	return opt_out ? !(node->flags & NODE_FLAGS_SUBTREE_AUTH) : !(node->flags & NODE_FLAGS_SUBTREE_DATA);
33 }
34 
35 /*!
36  * \brief Check whether at least one RR type in node should be signed,
37  *        used when signing with NSEC3.
38  *
39  * \param node  Node for which the check is done.
40  *
41  * \return true/false.
42  */
node_should_be_signed_nsec3(const zone_node_t * n)43 static bool node_should_be_signed_nsec3(const zone_node_t *n)
44 {
45 	for (int i = 0; i < n->rrset_count; i++) {
46 		knot_rrset_t rrset = node_rrset_at(n, i);
47 		if (rrset.type == KNOT_RRTYPE_NSEC ||
48 		    rrset.type == KNOT_RRTYPE_RRSIG) {
49 			continue;
50 		}
51 
52 		if (knot_zone_sign_rr_should_be_signed(n, &rrset)) {
53 			return true;
54 		}
55 	}
56 
57 	return false;
58 }
59 
60 /*!
61  * \brief Custom NSEC3 tree free function.
62  *
63  */
free_nsec3_tree(zone_tree_t * nodes)64 static void free_nsec3_tree(zone_tree_t *nodes)
65 {
66 	assert(nodes);
67 
68 	zone_tree_it_t it = { 0 };
69 	for ((void)zone_tree_it_begin(nodes, &it); !zone_tree_it_finished(&it); zone_tree_it_next(&it)) {
70 		zone_node_t *node = zone_tree_it_val(&it);
71 		// newly allocated NSEC3 nodes
72 		knot_rdataset_t *nsec3 = node_rdataset(node, KNOT_RRTYPE_NSEC3);
73 		knot_rdataset_t *rrsig = node_rdataset(node, KNOT_RRTYPE_RRSIG);
74 		knot_rdataset_clear(nsec3, NULL);
75 		knot_rdataset_clear(rrsig, NULL);
76 		node_free(node, NULL);
77 	}
78 
79 	zone_tree_it_free(&it);
80 	zone_tree_free(&nodes);
81 }
82 
83 /* - NSEC3 nodes construction ----------------------------------------------- */
84 
85 /*!
86  * \brief Get NSEC3 RDATA size.
87  */
nsec3_rdata_size(const dnssec_nsec3_params_t * params,const dnssec_nsec_bitmap_t * rr_types)88 static size_t nsec3_rdata_size(const dnssec_nsec3_params_t *params,
89                                const dnssec_nsec_bitmap_t *rr_types)
90 {
91 	assert(params);
92 	assert(rr_types);
93 
94 	return 6 + params->salt.size
95 	       + dnssec_nsec3_hash_length(params->algorithm)
96 	       + dnssec_nsec_bitmap_size(rr_types);
97 }
98 
99 /*!
100  * \brief Fill NSEC3 RDATA.
101  *
102  * \note Content of next hash field is not changed.
103  */
nsec3_fill_rdata(uint8_t * rdata,size_t rdata_len,const dnssec_nsec3_params_t * params,const dnssec_nsec_bitmap_t * rr_types,const uint8_t * next_hashed)104 static int nsec3_fill_rdata(uint8_t *rdata, size_t rdata_len,
105                             const dnssec_nsec3_params_t *params,
106                             const dnssec_nsec_bitmap_t *rr_types,
107                             const uint8_t *next_hashed)
108 {
109 	assert(rdata);
110 	assert(params);
111 	assert(rr_types);
112 
113 	uint8_t hash_length = dnssec_nsec3_hash_length(params->algorithm);
114 
115 	wire_ctx_t wire = wire_ctx_init(rdata, rdata_len);
116 
117 	wire_ctx_write_u8(&wire, params->algorithm);
118 	wire_ctx_write_u8(&wire, params->flags);
119 	wire_ctx_write_u16(&wire, params->iterations);
120 	wire_ctx_write_u8(&wire, params->salt.size);
121 	wire_ctx_write(&wire, params->salt.data, params->salt.size);
122 	wire_ctx_write_u8(&wire, hash_length);
123 
124 	if (next_hashed != NULL) {
125 		wire_ctx_write(&wire, next_hashed, hash_length);
126 	} else {
127 		wire_ctx_skip(&wire, hash_length);
128 	}
129 
130 	if (wire.error != KNOT_EOK) {
131 		return wire.error;
132 	}
133 
134 	dnssec_nsec_bitmap_write(rr_types, wire.position);
135 
136 	return KNOT_EOK;
137 }
138 
139 /*!
140  * \brief Creates NSEC3 RRSet.
141  *
142  * \param owner        Owner for the RRSet.
143  * \param params       Parsed NSEC3PARAM.
144  * \param rr_types     Bitmap.
145  * \param next_hashed  Next hashed.
146  * \param ttl          TTL for the RRSet.
147  *
148  * \return Pointer to created RRSet on success, NULL on errors.
149  */
create_nsec3_rrset(knot_rrset_t * rrset,const knot_dname_t * owner,const dnssec_nsec3_params_t * params,const dnssec_nsec_bitmap_t * rr_types,const uint8_t * next_hashed,uint32_t ttl)150 static int create_nsec3_rrset(knot_rrset_t *rrset,
151                               const knot_dname_t *owner,
152                               const dnssec_nsec3_params_t *params,
153                               const dnssec_nsec_bitmap_t *rr_types,
154                               const uint8_t *next_hashed,
155                               uint32_t ttl)
156 {
157 	assert(rrset);
158 	assert(owner);
159 	assert(params);
160 	assert(rr_types);
161 
162 	knot_dname_t *owner_copy = knot_dname_copy(owner, NULL);
163 	if (owner_copy == NULL) {
164 		return KNOT_ENOMEM;
165 	}
166 	knot_rrset_init(rrset, owner_copy, KNOT_RRTYPE_NSEC3, KNOT_CLASS_IN, ttl);
167 
168 	size_t rdata_size = nsec3_rdata_size(params, rr_types);
169 	uint8_t rdata[rdata_size];
170 	memset(rdata, 0, rdata_size);
171 	int ret = nsec3_fill_rdata(rdata, rdata_size, params, rr_types,
172 	                           next_hashed);
173 	if (ret != KNOT_EOK) {
174 		knot_dname_free(owner_copy, NULL);
175 		return ret;
176 	}
177 
178 	ret = knot_rrset_add_rdata(rrset, rdata, rdata_size, NULL);
179 	if (ret != KNOT_EOK) {
180 		knot_dname_free(owner_copy, NULL);
181 		return ret;
182 	}
183 
184 	return KNOT_EOK;
185 }
186 
187 /*!
188  * \brief Create NSEC3 node.
189  */
create_nsec3_node(const knot_dname_t * owner,const dnssec_nsec3_params_t * nsec3_params,zone_node_t * apex_node,const dnssec_nsec_bitmap_t * rr_types,uint32_t ttl)190 static zone_node_t *create_nsec3_node(const knot_dname_t *owner,
191                                       const dnssec_nsec3_params_t *nsec3_params,
192                                       zone_node_t *apex_node,
193                                       const dnssec_nsec_bitmap_t *rr_types,
194                                       uint32_t ttl)
195 {
196 	assert(owner);
197 	assert(nsec3_params);
198 	assert(apex_node);
199 	assert(rr_types);
200 
201 	zone_node_t *new_node = node_new(owner, false, false, NULL);
202 	if (!new_node) {
203 		return NULL;
204 	}
205 
206 	knot_rrset_t nsec3_rrset;
207 	int ret = create_nsec3_rrset(&nsec3_rrset, owner, nsec3_params,
208 	                             rr_types, NULL, ttl);
209 	if (ret != KNOT_EOK) {
210 		node_free(new_node, NULL);
211 		return NULL;
212 	}
213 
214 	ret = node_add_rrset(new_node, &nsec3_rrset, NULL);
215 	knot_rrset_clear(&nsec3_rrset, NULL);
216 	if (ret != KNOT_EOK) {
217 		node_free(new_node, NULL);
218 		return NULL;
219 	}
220 
221 	return new_node;
222 }
223 
224 /*!
225  * \brief Create new NSEC3 node for given regular node.
226  *
227  * \param node       Node for which the NSEC3 node is created.
228  * \param apex       Zone apex node.
229  * \param params     NSEC3 hash function parameters.
230  * \param ttl        TTL of the new NSEC3 node.
231  *
232  * \return Error code, KNOT_EOK if successful.
233  */
create_nsec3_node_for_node(const zone_node_t * node,zone_node_t * apex,const dnssec_nsec3_params_t * params,uint32_t ttl)234 static zone_node_t *create_nsec3_node_for_node(const zone_node_t *node,
235                                                zone_node_t *apex,
236                                                const dnssec_nsec3_params_t *params,
237                                                uint32_t ttl)
238 {
239 	assert(node);
240 	assert(apex);
241 	assert(params);
242 
243 	knot_dname_storage_t nsec3_owner;
244 	int ret = knot_create_nsec3_owner(nsec3_owner, sizeof(nsec3_owner),
245 	                                  node->owner, apex->owner, params);
246 	if (ret != KNOT_EOK) {
247 		return NULL;
248 	}
249 
250 	dnssec_nsec_bitmap_t *rr_types = dnssec_nsec_bitmap_new();
251 	if (!rr_types) {
252 		return NULL;
253 	}
254 
255 	bitmap_add_node_rrsets(rr_types, node, false);
256 	if (node->rrset_count > 0 && node_should_be_signed_nsec3(node)) {
257 		dnssec_nsec_bitmap_add(rr_types, KNOT_RRTYPE_RRSIG);
258 	}
259 	if (node == apex) {
260 		dnssec_nsec_bitmap_add(rr_types, KNOT_RRTYPE_NSEC3PARAM);
261 	}
262 
263 	zone_node_t *nsec3_node = create_nsec3_node(nsec3_owner, params, apex,
264 	                                            rr_types, ttl);
265 	dnssec_nsec_bitmap_free(rr_types);
266 
267 	return nsec3_node;
268 }
269 
270 /* - NSEC3 chain creation --------------------------------------------------- */
271 
272 // see connect_nsec3_nodes() for what this function does
connect_nsec3_base(knot_rdataset_t * a_rrs,const knot_dname_t * b_name)273 static int connect_nsec3_base(knot_rdataset_t *a_rrs, const knot_dname_t *b_name)
274 {
275 	assert(a_rrs);
276 	uint8_t algorithm = knot_nsec3_alg(a_rrs->rdata);
277 	if (algorithm == 0) {
278 		return KNOT_EINVAL;
279 	}
280 
281 	uint8_t raw_length = knot_nsec3_next_len(a_rrs->rdata);
282 	assert(raw_length == dnssec_nsec3_hash_length(algorithm));
283 	uint8_t *raw_hash = (uint8_t *)knot_nsec3_next(a_rrs->rdata);
284 	if (raw_hash == NULL) {
285 		return KNOT_EINVAL;
286 	}
287 
288 	assert(b_name);
289 	uint8_t b32_length = b_name[0];
290 	const uint8_t *b32_hash = &(b_name[1]);
291 	int32_t written = knot_base32hex_decode(b32_hash, b32_length, raw_hash, raw_length);
292 	if (written != raw_length) {
293 		return KNOT_EINVAL;
294 	}
295 
296 	return KNOT_EOK;
297 }
298 
299 /*!
300  * \brief Connect two nodes by filling 'hash' field of NSEC3 RDATA of the first node.
301  *
302  * \param a     First node. Gets modified in-place!
303  * \param b     Second node (immediate follower of a).
304  * \param data  Unused parameter.
305  *
306  * \return Error code, KNOT_EOK if successful.
307  */
connect_nsec3_nodes(zone_node_t * a,zone_node_t * b,_unused_ nsec_chain_iterate_data_t * data)308 static int connect_nsec3_nodes(zone_node_t *a, zone_node_t *b,
309                                _unused_ nsec_chain_iterate_data_t *data)
310 {
311 	assert(a);
312 	assert(b);
313 	assert(a->rrset_count == 1);
314 
315 	return connect_nsec3_base(node_rdataset(a, KNOT_RRTYPE_NSEC3), b->owner);
316 }
317 
318 /*!
319  * \brief Connect two nodes by updating the changeset.
320  *
321  * \param a     First node.
322  * \param b     Second node.
323  * \param data  Contains the changeset to be updated.
324  *
325  * \return Error code, KNOT_EOK if successful.
326  */
connect_nsec3_nodes2(zone_node_t * a,zone_node_t * b,nsec_chain_iterate_data_t * data)327 static int connect_nsec3_nodes2(zone_node_t *a, zone_node_t *b,
328                                 nsec_chain_iterate_data_t *data)
329 {
330 	assert(data);
331 
332 	knot_rrset_t aorig = node_rrset(a, KNOT_RRTYPE_NSEC3);
333 	assert(!knot_rrset_empty(&aorig));
334 
335 	// prepare a copy of NSEC3 rrsets in question
336 	knot_rrset_t *acopy = knot_rrset_copy(&aorig, NULL);
337 	if (acopy == NULL) {
338 		return KNOT_ENOMEM;
339 	}
340 
341 	// connect the copied rrset
342 	int ret = connect_nsec3_base(&acopy->rrs, b->owner);
343 	if (ret != KNOT_EOK || knot_rrset_equal(&aorig, acopy, true)) {
344 		knot_rrset_free(acopy, NULL);
345 		return ret;
346 	}
347 
348 	// add the removed original and the updated copy to changeset
349 	ret = zone_update_remove(data->update, &aorig);
350 	if (ret == KNOT_EOK) {
351 		ret = zone_update_add(data->update, acopy);
352 	}
353 	knot_rrset_free(acopy, NULL);
354 	return ret;
355 }
356 
357 /*!
358  * \brief Replace the "next hash" field in b's NSEC3 by that in a's NSEC3, by updating the changeset.
359  *
360  * \param a      A node to take the "next hash" from.
361  * \param b      A node to put the "next hash" into.
362  * \param data   Contains the changeset to be updated.
363  *
364  * \return KNOT_E*
365  */
reconnect_nsec3_nodes2(zone_node_t * a,zone_node_t * b,nsec_chain_iterate_data_t * data)366 static int reconnect_nsec3_nodes2(zone_node_t *a, zone_node_t *b,
367 				  nsec_chain_iterate_data_t *data)
368 {
369 	assert(data);
370 
371 	knot_rrset_t an = node_rrset(a, KNOT_RRTYPE_NSEC3);
372 	assert(!knot_rrset_empty(&an));
373 
374 	knot_rrset_t bnorig = node_rrset(b, KNOT_RRTYPE_NSEC3);
375 	assert(!knot_rrset_empty(&bnorig));
376 
377 	// prepare a copy of NSEC3 rrsets in question
378 	knot_rrset_t *bnnew = knot_rrset_copy(&bnorig, NULL);
379 	if (bnnew == NULL) {
380 		return KNOT_ENOMEM;
381 	}
382 
383 	uint8_t raw_length = knot_nsec3_next_len(an.rrs.rdata);
384 	uint8_t *a_hash = (uint8_t *)knot_nsec3_next(an.rrs.rdata);
385 	uint8_t *bnew_hash = (uint8_t *)knot_nsec3_next(bnnew->rrs.rdata);
386 	if (a_hash == NULL || bnew_hash == NULL ||
387 	    raw_length != knot_nsec3_next_len(bnnew->rrs.rdata)) {
388 		knot_rrset_free(bnnew, NULL);
389 		return KNOT_ERROR;
390 	}
391 	memcpy(bnew_hash, a_hash, raw_length);
392 
393 	int ret = zone_update_remove(data->update, &bnorig);
394 	if (ret == KNOT_EOK) {
395 		ret = zone_update_add(data->update, bnnew);
396 	}
397 	knot_rrset_free(bnnew, NULL);
398 	return ret;
399 }
400 
401 /*!
402  * \brief Create NSEC3 node for each regular node in the zone.
403  *
404  * \param zone         Zone.
405  * \param params       NSEC3 params.
406  * \param ttl          TTL for the created NSEC records.
407  * \param cds_in_apex  Hint to guess apex node type bitmap: false=just DNSKEY, true=DNSKEY,CDS,CDNSKEY.
408  * \param nsec3_nodes  Tree whereto new NSEC3 nodes will be added.
409  * \param update       Zone update for possible NSEC removals
410  *
411  * \return Error code, KNOT_EOK if successful.
412  */
create_nsec3_nodes(const zone_contents_t * zone,const dnssec_nsec3_params_t * params,uint32_t ttl,zone_tree_t * nsec3_nodes,zone_update_t * update)413 static int create_nsec3_nodes(const zone_contents_t *zone,
414                               const dnssec_nsec3_params_t *params,
415                               uint32_t ttl,
416                               zone_tree_t *nsec3_nodes,
417                               zone_update_t *update)
418 {
419 	assert(zone);
420 	assert(nsec3_nodes);
421 	assert(update);
422 
423 	zone_tree_delsafe_it_t it = { 0 };
424 	int result = zone_tree_delsafe_it_begin(zone->nodes, &it, false); // delsafe - removing nodes that contain only NSEC+RRSIG
425 
426 	while (!zone_tree_delsafe_it_finished(&it)) {
427 		zone_node_t *node = zone_tree_delsafe_it_val(&it);
428 
429 		/*!
430 		 * Remove possible NSEC from the node. (Do not allow both NSEC
431 		 * and NSEC3 in the zone at once.)
432 		 */
433 		result = knot_nsec_changeset_remove(node, update);
434 		if (result != KNOT_EOK) {
435 			break;
436 		}
437 		if (node->flags & NODE_FLAGS_NONAUTH || nsec3_empty(node, params) || node->flags & NODE_FLAGS_DELETED) {
438 			zone_tree_delsafe_it_next(&it);
439 			continue;
440 		}
441 
442 		zone_node_t *nsec3_node;
443 		nsec3_node = create_nsec3_node_for_node(node, zone->apex,
444 							params, ttl);
445 		if (!nsec3_node) {
446 			result = KNOT_ENOMEM;
447 			break;
448 		}
449 
450 		result = zone_tree_insert(nsec3_nodes, &nsec3_node);
451 		if (result != KNOT_EOK) {
452 			break;
453 		}
454 
455 		zone_tree_delsafe_it_next(&it);
456 	}
457 
458 	zone_tree_delsafe_it_free(&it);
459 
460 	return result;
461 }
462 
463 /*!
464  * \brief For given dname, check if anything changed in zone_update, and recreate (possibly unconnected) NSEC3 nodes appropriately.
465  *
466  * \param update    Zone update structure holding zone contents changes.
467  * \param params    NSEC3 params.
468  * \param ttl       TTL for newly created NSEC3 records.
469  * \param for_node  Domain name of the node in question.
470  *
471  * \retval KNOT_ENORECORD if the NSEC3 chain shall be rather recreated completely.
472  * \return KNOT_EOK, KNOT_E* if any error.
473  */
fix_nsec3_for_node(zone_update_t * update,const dnssec_nsec3_params_t * params,uint32_t ttl,const knot_dname_t * for_node)474 static int fix_nsec3_for_node(zone_update_t *update, const dnssec_nsec3_params_t *params,
475                               uint32_t ttl, const knot_dname_t *for_node)
476 {
477 	// check if we need to do something
478 	const zone_node_t *old_n = zone_contents_find_node(update->zone->contents, for_node);
479 	const zone_node_t *new_n = zone_contents_find_node(update->new_cont, for_node);
480 
481 	bool had_no_nsec = (old_n == NULL || old_n->nsec3_node == NULL || !(old_n->flags & NODE_FLAGS_NSEC3_NODE));
482 	bool shall_no_nsec = (new_n == NULL || new_n->flags & NODE_FLAGS_NONAUTH || nsec3_empty(new_n, params) || new_n->flags & NODE_FLAGS_DELETED);
483 
484 	if (had_no_nsec == shall_no_nsec && node_bitmap_equal(old_n, new_n)) {
485 		return KNOT_EOK;
486 	}
487 
488 	knot_dname_storage_t for_node_hashed;
489 	int ret = knot_create_nsec3_owner(for_node_hashed, sizeof(for_node_hashed),
490 	                                  for_node, update->new_cont->apex->owner, params);
491 	if (ret != KNOT_EOK) {
492 		return ret;
493 	}
494 
495 	// saved hash of next node
496 	uint8_t *next_hash = NULL;
497 	uint8_t next_length = 0;
498 
499 	// remove (all) existing NSEC3
500 	const zone_node_t *old_nsec3_n = zone_contents_find_nsec3_node(update->new_cont, for_node_hashed);
501 	assert((bool)(old_nsec3_n == NULL) == had_no_nsec);
502 	if (old_nsec3_n != NULL) {
503 		knot_rrset_t rem_nsec3 = node_rrset(old_nsec3_n, KNOT_RRTYPE_NSEC3);
504 		if (!knot_rrset_empty(&rem_nsec3)) {
505 			knot_rrset_t rem_rrsig = node_rrset(old_nsec3_n, KNOT_RRTYPE_RRSIG);
506 			ret = zone_update_remove(update, &rem_nsec3);
507 			if (ret == KNOT_EOK && !knot_rrset_empty(&rem_rrsig)) {
508 				ret = zone_update_remove(update, &rem_rrsig);
509 			}
510 			assert(update->flags & UPDATE_INCREMENTAL); // to make sure the following pointer remains valid
511 			next_hash = (uint8_t *)knot_nsec3_next(rem_nsec3.rrs.rdata);
512 			next_length = knot_nsec3_next_len(rem_nsec3.rrs.rdata);
513 		}
514 	}
515 
516 	// add NSEC3 with correct bitmap
517 	if (!shall_no_nsec && ret == KNOT_EOK) {
518 		zone_node_t *new_nsec3_n = create_nsec3_node_for_node(new_n, update->new_cont->apex, params, ttl);
519 		if (new_nsec3_n == NULL) {
520 			return KNOT_ENOMEM;
521 		}
522 		knot_rrset_t nsec3 = node_rrset(new_nsec3_n, KNOT_RRTYPE_NSEC3);
523 		assert(!knot_rrset_empty(&nsec3));
524 
525 		// copy hash of next element from removed record
526 		if (next_hash != NULL) {
527 			uint8_t *raw_hash = (uint8_t *)knot_nsec3_next(nsec3.rrs.rdata);
528 			uint8_t raw_length = knot_nsec3_next_len(nsec3.rrs.rdata);
529 			assert(raw_hash != NULL);
530 			if (raw_length != next_length) {
531 				ret = KNOT_EMALF;
532 			} else {
533 				memcpy(raw_hash, next_hash, raw_length);
534 			}
535 		}
536 		if (ret == KNOT_EOK) {
537 			ret = zone_update_add(update, &nsec3);
538 		}
539 		binode_unify(new_nsec3_n, false, NULL);
540 		node_free_rrsets(new_nsec3_n, NULL);
541 		node_free(new_nsec3_n, NULL);
542 	}
543 
544 	return ret;
545 }
546 
fix_nsec3_nodes(zone_update_t * update,const dnssec_nsec3_params_t * params,uint32_t ttl)547 static int fix_nsec3_nodes(zone_update_t *update, const dnssec_nsec3_params_t *params,
548                            uint32_t ttl)
549 {
550 	assert(update);
551 
552 	zone_tree_it_t it = { 0 };
553 	int ret = zone_tree_it_begin(update->a_ctx->node_ptrs, &it);
554 
555 	while (!zone_tree_it_finished(&it) && ret == KNOT_EOK) {
556 		zone_node_t *n = zone_tree_it_val(&it);
557 		ret = fix_nsec3_for_node(update, params, ttl, n->owner);
558 		zone_tree_it_next(&it);
559 	}
560 	zone_tree_it_free(&it);
561 
562 	return ret;
563 }
564 
zone_update_nsec3_nodes(zone_update_t * up,zone_tree_t * nsec3n)565 static int zone_update_nsec3_nodes(zone_update_t *up, zone_tree_t *nsec3n)
566 {
567 	int ret = KNOT_EOK;
568 	zone_tree_delsafe_it_t dit = { 0 };
569 	zone_tree_it_t it = { 0 };
570 	if (up->new_cont->nsec3_nodes == NULL) {
571 		goto add_nsec3n;
572 	}
573 	ret = zone_tree_delsafe_it_begin(up->new_cont->nsec3_nodes, &dit, false);
574 	while (ret == KNOT_EOK && !zone_tree_delsafe_it_finished(&dit)) {
575 		zone_node_t *nold = zone_tree_delsafe_it_val(&dit);
576 		knot_rrset_t ns3old = node_rrset(nold, KNOT_RRTYPE_NSEC3);
577 		zone_node_t *nnew = zone_tree_get(nsec3n, nold->owner);
578 		if (!knot_rrset_empty(&ns3old)) {
579 			knot_rrset_t ns3new = node_rrset(nnew, KNOT_RRTYPE_NSEC3);
580 			if (knot_rrset_equal(&ns3old, &ns3new, true)) {
581 				node_remove_rdataset(nnew, KNOT_RRTYPE_NSEC3);
582 			} else {
583 				ret = knot_nsec_changeset_remove(nold, up);
584 			}
585 		} else if (node_rrtype_exists(nold, KNOT_RRTYPE_RRSIG)) {
586 			ret = knot_nsec_changeset_remove(nold, up);
587 		}
588 		zone_tree_delsafe_it_next(&dit);
589 	}
590 	zone_tree_delsafe_it_free(&dit);
591 	if (ret != KNOT_EOK) {
592 		return ret;
593 	}
594 
595 add_nsec3n:
596 	ret = zone_tree_it_begin(nsec3n, &it);
597 	while (ret == KNOT_EOK && !zone_tree_it_finished(&it)) {
598 		zone_node_t *nnew = zone_tree_it_val(&it);
599 		knot_rrset_t ns3new = node_rrset(nnew, KNOT_RRTYPE_NSEC3);
600 		if (!knot_rrset_empty(&ns3new)) {
601 			ret = zone_update_add(up, &ns3new);
602 		}
603 		zone_tree_it_next(&it);
604 	}
605 	zone_tree_it_free(&it);
606 	return ret;
607 }
608 
609 /* - Public API ------------------------------------------------------------- */
610 
delete_nsec3_chain(zone_update_t * up)611 int delete_nsec3_chain(zone_update_t *up)
612 {
613 	zone_tree_t *empty = zone_tree_create(false);
614 	if (empty == NULL) {
615 		return KNOT_ENOMEM;
616 	}
617 	int ret = zone_update_nsec3_nodes(up, empty);
618 	zone_tree_free(&empty);
619 	return ret;
620 }
621 
622 /*!
623  * \brief Create new NSEC3 chain, add differences from current into a changeset.
624  */
knot_nsec3_create_chain(const zone_contents_t * zone,const dnssec_nsec3_params_t * params,uint32_t ttl,zone_update_t * update)625 int knot_nsec3_create_chain(const zone_contents_t *zone,
626                             const dnssec_nsec3_params_t *params,
627                             uint32_t ttl,
628                             zone_update_t *update)
629 {
630 	assert(zone);
631 	assert(params);
632 
633 	zone_tree_t *nsec3_nodes = zone_tree_create(false);
634 	if (!nsec3_nodes) {
635 		return KNOT_ENOMEM;
636 	}
637 
638 	int result = create_nsec3_nodes(zone, params, ttl, nsec3_nodes, update);
639 	if (result != KNOT_EOK) {
640 		free_nsec3_tree(nsec3_nodes);
641 		return result;
642 	}
643 
644 	result = knot_nsec_chain_iterate_create(nsec3_nodes,
645 	                                        connect_nsec3_nodes, NULL);
646 	if (result != KNOT_EOK) {
647 		free_nsec3_tree(nsec3_nodes);
648 		return result;
649 	}
650 
651 	result = zone_update_nsec3_nodes(update, nsec3_nodes);
652 
653 	free_nsec3_tree(nsec3_nodes);
654 
655 	return result;
656 }
657 
knot_nsec3_fix_chain(zone_update_t * update,const dnssec_nsec3_params_t * params,uint32_t ttl)658 int knot_nsec3_fix_chain(zone_update_t *update,
659                          const dnssec_nsec3_params_t *params,
660                          uint32_t ttl)
661 {
662 	assert(update);
663 	assert(params);
664 
665 	// ensure that the salt has not changed
666 	if (!knot_nsec3param_uptodate(update->new_cont, params)) {
667 		int ret = knot_nsec3param_update(update, params, ttl);
668 		if (ret != KNOT_EOK) {
669 			return ret;
670 		}
671 		return knot_nsec3_create_chain(update->new_cont, params, ttl, update);
672 	}
673 
674 	int ret = fix_nsec3_nodes(update, params, ttl);
675 	if (ret != KNOT_EOK) {
676 		return ret;
677 	}
678 
679 	ret = zone_adjust_contents(update->new_cont, NULL, adjust_cb_void, false, true, 1, update->a_ctx->nsec3_ptrs);
680 	if (ret != KNOT_EOK) {
681 		return ret;
682 	}
683 
684 	// ensure that nsec3 node for zone root is in list of changed nodes
685 	const zone_node_t *nsec3_for_root = NULL, *unused;
686 	ret = zone_contents_find_nsec3_for_name(update->new_cont, update->zone->name, &nsec3_for_root, &unused);
687 	if (ret >= 0) {
688 		assert(ret == ZONE_NAME_FOUND);
689 		assert(!(nsec3_for_root->flags & NODE_FLAGS_DELETED));
690 		assert(!(binode_counterpart((zone_node_t *)nsec3_for_root)->flags & NODE_FLAGS_DELETED));
691 		ret = zone_tree_insert(update->a_ctx->nsec3_ptrs, (zone_node_t **)&nsec3_for_root);
692 	}
693 	if (ret != KNOT_EOK) {
694 		return ret;
695 	}
696 
697 	nsec_chain_iterate_data_t data = { ttl, update, KNOT_RRTYPE_NSEC3 };
698 
699 	ret = knot_nsec_chain_iterate_fix(update->a_ctx->nsec3_ptrs,
700 	                                  connect_nsec3_nodes2, reconnect_nsec3_nodes2, &data);
701 
702 	return ret;
703 }
704 
knot_nsec3_check_chain(zone_update_t * update,const dnssec_nsec3_params_t * params)705 int knot_nsec3_check_chain(zone_update_t *update, const dnssec_nsec3_params_t *params)
706 {
707 	nsec_chain_iterate_data_t data = { 0, update, KNOT_RRTYPE_NSEC3, params };
708 
709 	int ret = nsec_check_bitmaps(update->new_cont->nodes, &data);
710 	if (ret != KNOT_EOK) {
711 		return ret;
712 	}
713 
714 	return knot_nsec_chain_iterate_create(update->new_cont->nsec3_nodes,
715 					      nsec_check_connect_nodes, &data);
716 }
717 
knot_nsec3_check_chain_fix(zone_update_t * update,const dnssec_nsec3_params_t * params)718 int knot_nsec3_check_chain_fix(zone_update_t *update, const dnssec_nsec3_params_t *params)
719 {
720 	nsec_chain_iterate_data_t data = { 0, update, KNOT_RRTYPE_NSEC3, params };
721 
722 	int ret = nsec_check_bitmaps(update->a_ctx->node_ptrs, &data);
723 	if (ret != KNOT_EOK) {
724 		return ret;
725 	}
726 
727 	ret = nsec_check_bitmaps(update->a_ctx->adjust_ptrs, &data); // adjust_ptrs contain also NSEC3-nodes. See check_nsec_bitmap() how this is handled.
728 	if (ret != KNOT_EOK) {
729 		return ret;
730 	}
731 
732 	return nsec_check_new_connects(update->a_ctx->nsec3_ptrs, &data);
733 }
734