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