1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup dnsdbupdate Dynamic update functions
36 * @ingroup dnsdb
37 * @brief
38 *
39 * @{
40 */
41 /*------------------------------------------------------------------------------
42 *
43 * USE INCLUDES */
44 #include "dnsdb/dnsdb-config.h"
45 #include <stdio.h>
46 #include <stdlib.h>
47
48 #include <dnscore/rfc.h>
49 #include <dnscore/ptr_vector.h>
50 #include <dnscore/ptr_set.h>
51 #include <dnscore/u32_set.h>
52 #include <dnscore/logger.h>
53 #include <dnscore/dnsname.h>
54 #include <dnscore/digest.h>
55
56 #include <dnscore/dnskey-signature.h>
57
58 #include "dnsdb/zdb_types.h"
59 #include "dnsdb/nsec.h"
60 #include "dnsdb/nsec3.h"
61
62 #include <dnscore/base32hex.h>
63 #include <dnscore/format.h>
64 #include <dnscore/dnsformat.h>
65 #include "dnsdb/dnssec.h"
66 #include "dnsdb/zdb_zone.h"
67 #include "dnsdb/dnssec-keystore.h"
68 #include "dnsdb/zdb_utils.h"
69
70 #include "dnsdb/dynupdate-diff.h"
71
72 #define MODULE_MSG_HANDLE g_database_logger
73 extern logger_handle *g_database_logger;
74
75 #define NSC3NODE_TAG 0x45444f4e3343534e
76
77 static const u8 UNKNOWN_FQDN[] = "\007UNKNOWN";
78
79 struct dnssec_chain_node_nsec3
80 {
81 nsec3_node *prev;
82 nsec3_node *self;
83 nsec3_node *next;
84 u8 *fqdn;
85 u8 state;
86 u8 reserved[sizeof(void*)-2];
87 u8 digest[1 + SHA_DIGEST_LENGTH];
88 };
89
90 typedef struct dnssec_chain_node_nsec3 dnssec_chain_node_nsec3;
91
dnssec_chain_node_nsec3_set_fqdn(dnssec_chain_node_nsec3 * node,const u8 * fqdn)92 static void dnssec_chain_node_nsec3_set_fqdn(dnssec_chain_node_nsec3 *node, const u8 *fqdn)
93 {
94 yassert(node->fqdn == NULL);
95 node->fqdn = dnsname_zdup(fqdn);
96 }
97
dnssec_chain_node_nsec3_get_digest(const dnssec_chain_node_nsec3 * node)98 static const u8* dnssec_chain_node_nsec3_get_digest(const dnssec_chain_node_nsec3 *node)
99 {
100 return (node->self != NULL)?node->self->digest:node->digest;
101 }
102
103 static void
dnssec_chain_node_nsec3_format_handler_method(const void * val,output_stream * stream,s32 padding,char pad_char,bool left_justified,void * reserved_for_method_parameters)104 dnssec_chain_node_nsec3_format_handler_method(const void *val, output_stream *stream, s32 padding, char pad_char, bool left_justified, void *reserved_for_method_parameters)
105 {
106 (void)padding;
107 (void)pad_char;
108 (void)left_justified;
109 (void)reserved_for_method_parameters;
110 dnssec_chain_node_nsec3 *node = (dnssec_chain_node_nsec3*)val;
111 const u8* digest = dnssec_chain_node_nsec3_get_digest(node);
112 output_stream_write_base32hex(stream, &digest[1], *digest);
113 output_stream_write_u8(stream, '(');
114 if(node->fqdn != NULL)
115 {
116 dnsname_format_handler_method(node->fqdn, stream, 0, 0, FALSE, NULL);
117 }
118 else
119 {
120 output_stream_write_u8(stream, '?');
121 }
122 output_stream_write_u8(stream, ')');
123 }
124
dnssec_chain_node_nsec3_format_writer_init(dnssec_chain_node_t node_,format_writer * outfw)125 static void dnssec_chain_node_nsec3_format_writer_init(dnssec_chain_node_t node_, format_writer *outfw)
126 {
127 dnssec_chain_node_nsec3 *node = (dnssec_chain_node_nsec3*)node_;
128 outfw->callback = dnssec_chain_node_nsec3_format_handler_method;
129 outfw->value = node;
130 }
131
132 //#define NSEC3_HANDLE_SUBDELEGATION 1
133
dnssec_chain_node_nsec3_fqdn_is_covered(const zone_diff_fqdn * diff_fqdn)134 static bool dnssec_chain_node_nsec3_fqdn_is_covered(const zone_diff_fqdn *diff_fqdn)
135 {
136 return diff_fqdn->is_apex ||
137 (diff_fqdn->at_delegation && !diff_fqdn->under_delegation)|| // has NS records (but is not below NS records)
138 (!(diff_fqdn->at_delegation || diff_fqdn->under_delegation) && (diff_fqdn->will_be_non_empty || diff_fqdn->will_have_children))
139 // else it's under a delegation
140 ;
141 }
142
dnssec_chain_node_nsec3_fqdn_was_covered(const zone_diff_fqdn * diff_fqdn)143 static bool dnssec_chain_node_nsec3_fqdn_was_covered(const zone_diff_fqdn *diff_fqdn)
144 {
145 return diff_fqdn->is_apex ||
146 (diff_fqdn->was_at_delegation && !diff_fqdn->was_under_delegation) || // had NS records (but is not below NS records)
147 (!(diff_fqdn->was_at_delegation || diff_fqdn->was_under_delegation) && (diff_fqdn->was_non_empty || diff_fqdn->had_children))
148 // else it was under a delegation
149 ;
150 }
151
dnssec_chain_node_nsec3_optout_fqdn_is_covered(const zone_diff_fqdn * diff_fqdn)152 static bool dnssec_chain_node_nsec3_optout_fqdn_is_covered(const zone_diff_fqdn *diff_fqdn)
153 {
154 return diff_fqdn->is_apex ||
155 (diff_fqdn->at_delegation && !diff_fqdn->under_delegation && diff_fqdn->will_have_ds) || // has DS record(s)
156 (!(diff_fqdn->at_delegation || diff_fqdn->under_delegation) && (diff_fqdn->will_be_non_empty || diff_fqdn->will_have_children))
157 // else it's under a delegation
158 ;
159 }
160
dnssec_chain_node_nsec3_optout_fqdn_was_covered(const zone_diff_fqdn * diff_fqdn)161 static bool dnssec_chain_node_nsec3_optout_fqdn_was_covered(const zone_diff_fqdn *diff_fqdn)
162 {
163 return diff_fqdn->is_apex ||
164 (diff_fqdn->was_at_delegation && !diff_fqdn->was_under_delegation && diff_fqdn->had_ds) || // had DS record(s)
165 (!(diff_fqdn->was_at_delegation || diff_fqdn->was_under_delegation) && (diff_fqdn->was_non_empty || diff_fqdn->had_children))
166 // else it was under a delegation
167 ;
168 }
169
170 /**
171 * Creates a new entry with its pred/next from the zone nsec3 database
172 *
173 * @param digest
174 * @param chain nsec3_zone
175 * @return
176 */
177
178 static dnssec_chain_node_nsec3 *
dnssec_chain_node_nsec3_new_from_digest(const u8 * digest,const nsec3_zone * n3)179 dnssec_chain_node_nsec3_new_from_digest(const u8 *digest, const nsec3_zone *n3)
180 {
181 // compute the digest of the fqdn for the chain
182 // find if the node already exists
183 // return the appropriate node
184
185 nsec3_zone_item *self = NULL;
186 nsec3_zone_item *prev;
187 nsec3_zone_item *next;
188
189 bool empty = (n3->items == NULL);
190
191 if(!empty)
192 {
193 prev = nsec3_find_interval_prev_mod(&n3->items, (u8*)digest);
194 next = nsec3_node_mod_next(prev);
195
196 if(memcmp(&next->digest[1], &digest[1], digest[0]) == 0)
197 {
198 // exists
199 self = next;
200 next = nsec3_node_mod_next(self);
201 }
202 }
203 else
204 {
205 prev = NULL;
206 next = NULL;
207 }
208
209 dnssec_chain_node_nsec3 *node;
210
211 ZALLOC_OBJECT_OR_DIE(node, dnssec_chain_node_nsec3, NSC3NODE_TAG);
212 node->prev = prev;
213 node->self = self;
214 node->next = next;
215 node->fqdn = NULL;
216
217 if(self != NULL)
218 {
219 node->state = DNSSEC_CHAIN_EXISTS;
220 }
221 else
222 {
223 node->state = DNSSEC_CHAIN_ADD;
224 memcpy(node->digest, digest, digest[0] + 1);
225 }
226
227 return node;
228 }
229
dnssec_chain_node_nsec3_new(const u8 * fqdn,dnssec_chain_head_t chain)230 static dnssec_chain_node_t dnssec_chain_node_nsec3_new(const u8 *fqdn, dnssec_chain_head_t chain)
231 {
232 // compute the digest of the fqdn for the chain
233 // find if the node already exists
234 // return the appropriate node
235
236 const nsec3_zone* n3 = (nsec3_zone*)chain;
237 u8 digest[1 + SHA_DIGEST_LENGTH];
238
239 nsec3_compute_digest_from_fqdn_with_len(n3, fqdn, dnsname_len(fqdn), digest, FALSE);
240
241 dnssec_chain_node_nsec3 *node = dnssec_chain_node_nsec3_new_from_digest(digest, n3);
242
243 dnssec_chain_node_nsec3_set_fqdn(node, fqdn);
244
245 if(node->prev != NULL)
246 {
247 if(node->next != NULL)
248 {
249 log_debug1("update: nsec3: %{dnsname} has node %{digest32h} [ %{digest32h} ; %{digest32h} ] (%02x)", fqdn,
250 dnssec_chain_node_nsec3_get_digest(node),
251 node->prev->digest,
252 node->next->digest,
253 node->state);
254 }
255 else
256 {
257 log_debug1("update: nsec3: %{dnsname} has node %{digest32h} [ %{digest32h} ; ? [ (%02x)", fqdn,
258 dnssec_chain_node_nsec3_get_digest(node),
259 node->prev->digest,
260 node->state);
261 }
262 }
263 else
264 {
265 log_debug1("update: nsec3: %{dnsname} has node %{digest32h} [ ? ; ? [ (%02x)", fqdn,
266 dnssec_chain_node_nsec3_get_digest(node),
267 node->state);
268 }
269
270 return (dnssec_chain_node_t)node;
271 }
272
dnssec_chain_node_nsec3_delete(dnssec_chain_node_t node_)273 static void dnssec_chain_node_nsec3_delete(dnssec_chain_node_t node_)
274 {
275 dnssec_chain_node_nsec3 *nsec3_node = (dnssec_chain_node_nsec3*)node_;
276 if((nsec3_node->fqdn != NULL) && (nsec3_node->fqdn != UNKNOWN_FQDN))
277 {
278 dnsname_zfree(nsec3_node->fqdn);
279 }
280 ZFREE(nsec3_node, dnssec_chain_node_nsec3);
281 }
282
dnssec_chain_node_nsec3_has_bits_map(const dnssec_chain_node_nsec3 * node)283 static bool dnssec_chain_node_nsec3_has_bits_map(const dnssec_chain_node_nsec3 *node)
284 {
285 return node->self != NULL;
286 }
287
dnssec_chain_node_nsec3_get_bits_map(const dnssec_chain_node_nsec3 * node)288 static const u8 *dnssec_chain_node_nsec3_get_bits_map(const dnssec_chain_node_nsec3 *node)
289 {
290 return node->self->type_bit_maps;
291 }
292
dnssec_chain_node_nsec3_get_bits_map_size(const dnssec_chain_node_nsec3 * node)293 static u16 dnssec_chain_node_nsec3_get_bits_map_size(const dnssec_chain_node_nsec3 *node)
294 {
295 return node->self->type_bit_maps_size;
296 }
297
dnssec_chain_node_nsec3_compare(const void * a_,const void * b_)298 static int dnssec_chain_node_nsec3_compare(const void *a_, const void *b_)
299 {
300 const dnssec_chain_node_nsec3 *a = (const dnssec_chain_node_nsec3*)a_;
301 const dnssec_chain_node_nsec3 *b = (const dnssec_chain_node_nsec3*)b_;
302
303 const u8 *a_digest = dnssec_chain_node_nsec3_get_digest(a);
304 const u8 *b_digest = dnssec_chain_node_nsec3_get_digest(b);
305
306 yassert(a_digest[0] == SHA_DIGEST_LENGTH && b_digest[0] == SHA_DIGEST_LENGTH);
307
308 int ret = memcmp(&a_digest[1], &b_digest[1], a_digest[0]);
309
310 return ret;
311 }
312
dnssec_chain_node_nsec3_prev(const dnssec_chain_node_t node_)313 static dnssec_chain_node_t dnssec_chain_node_nsec3_prev(const dnssec_chain_node_t node_)
314 {
315 dnssec_chain_node_nsec3 *self = (dnssec_chain_node_nsec3*)node_;
316 dnssec_chain_node_nsec3 *node;
317 ZALLOC_OBJECT_OR_DIE(node, dnssec_chain_node_nsec3, NSC3NODE_TAG);
318 node->prev = NULL;
319 node->self = self->prev;
320 node->next = self->next; // ?
321 node->fqdn = (u8*)UNKNOWN_FQDN;
322 node->state = DNSSEC_CHAIN_EXISTS|DNSSEC_CHAIN_BEGIN;
323 node->digest[0] = 0;
324 log_debug1("update: prev is %{digest32h} (%02x) '%{dnsname}'", node->self->digest, node->state, node->fqdn);
325
326 return (dnssec_chain_node_t)node;
327 }
328
dnssec_chain_node_nsec3_next(const dnssec_chain_node_t node_)329 static dnssec_chain_node_t dnssec_chain_node_nsec3_next(const dnssec_chain_node_t node_)
330 {
331 dnssec_chain_node_nsec3 *self = (dnssec_chain_node_nsec3*)node_;
332 dnssec_chain_node_nsec3 *node;
333 ZALLOC_OBJECT_OR_DIE(node, dnssec_chain_node_nsec3, NSC3NODE_TAG);
334 node->prev = self->prev; // ?
335 node->self = self->next;
336 node->next = NULL;
337 node->fqdn = (u8*)UNKNOWN_FQDN;
338 node->state = DNSSEC_CHAIN_EXISTS|DNSSEC_CHAIN_END;
339 log_debug1("update: next is %{digest32h} (%02x) '%{dnsname}'", node->self->digest, node->state, node->fqdn);
340
341 return (dnssec_chain_node_t)node;
342 }
343
dnssec_chain_node_nsec3_state_get(const dnssec_chain_node_t node_)344 static u8 dnssec_chain_node_nsec3_state_get(const dnssec_chain_node_t node_)
345 {
346 const dnssec_chain_node_nsec3 *self = (const dnssec_chain_node_nsec3*)node_;
347 return self->state;
348 }
349
dnssec_chain_node_nsec3_state_set(dnssec_chain_node_t node_,u8 value)350 static void dnssec_chain_node_nsec3_state_set(dnssec_chain_node_t node_, u8 value)
351 {
352 dnssec_chain_node_nsec3 *self = (dnssec_chain_node_nsec3*)node_;
353 log_debug1("update: status %{digest32h} from %02x to %02x", dnssec_chain_node_nsec3_get_digest(self), self->state, value);
354 self->state = value;
355 }
356
dnssec_chain_node_nsec3_merge(dnssec_chain_node_t chain_node,dnssec_chain_node_t chain_with)357 static void dnssec_chain_node_nsec3_merge(dnssec_chain_node_t chain_node, dnssec_chain_node_t chain_with)
358 {
359 dnssec_chain_node_nsec3 *node = (dnssec_chain_node_nsec3*)chain_node;
360 dnssec_chain_node_nsec3 *with = (dnssec_chain_node_nsec3*)chain_with;
361
362 u8 node_state = dnssec_chain_node_nsec3_state_get(chain_node);
363 u8 with_state = dnssec_chain_node_nsec3_state_get(chain_with);
364
365 #if DEBUG
366 format_writer node_writer;
367 dnssec_chain_node_nsec3_format_writer_init(chain_node, &node_writer);
368 format_writer with_writer;
369 dnssec_chain_node_nsec3_format_writer_init(chain_with, &with_writer);
370 log_debug2("nsec3_merge: %w (%02x) with %w(%02x)", &node_writer, node_state, &with_writer, with_state);
371 #endif
372
373 if((node_state & DNSSEC_CHAIN_END) && (with_state & DNSSEC_CHAIN_BEGIN))
374 {
375 #if DEBUG
376 log_debug("dnssec_chain_node_nsec3_merge(%{digest32h},%{digest32h}) end<->begin (%08x %08x)",
377 dnssec_chain_node_nsec3_get_digest(node), dnssec_chain_node_nsec3_get_digest(with),
378 node_state, with_state);
379 #endif
380 dnssec_chain_node_nsec3_state_set(chain_node, dnssec_chain_node_nsec3_state_get(chain_node) & ~DNSSEC_CHAIN_END);
381 }
382
383 if((node_state & DNSSEC_CHAIN_BEGIN) && (with_state & DNSSEC_CHAIN_END))
384 {
385 #if DEBUG
386 log_debug("dnssec_chain_node_nsec3_merge(%{digest32h},%{digest32h}) begin<->end (%08x %08x)",
387 dnssec_chain_node_nsec3_get_digest(node), dnssec_chain_node_nsec3_get_digest(with),
388 node_state, with_state);
389 #endif
390 dnssec_chain_node_nsec3_state_set(chain_node, dnssec_chain_node_nsec3_state_get(chain_node) & ~DNSSEC_CHAIN_BEGIN);
391 }
392
393 // properly handle merging of the FQDN
394
395 if(node->fqdn == UNKNOWN_FQDN)
396 {
397 if(with->fqdn != UNKNOWN_FQDN)
398 {
399 node->fqdn = with->fqdn;
400 with->fqdn = (u8*)UNKNOWN_FQDN;
401 }
402 }
403
404 dnssec_chain_node_nsec3_delete(chain_with);
405 }
406
407 /**
408 *
409 * @param n3
410 * @param from
411 * @param to
412 * @param diff
413 * @param collection
414 * @param mask ZONE_DIFF_REMOVE: get the new state, ZONE_DIFF_ADD: get the old state
415 * @param append_existing_signatures adds the existing signature to the collection (e.g.: to remove them)
416 * @param optout
417 */
418
dnssec_chain_node_nsec3_publish_record(nsec3_zone * n3,dnssec_chain_node_nsec3 * from,dnssec_chain_node_nsec3 * to,zone_diff * diff,ptr_vector * collection,u8 mask,bool append_existing_signatures,u8 optout)419 static void dnssec_chain_node_nsec3_publish_record(nsec3_zone *n3,
420 dnssec_chain_node_nsec3 *from, dnssec_chain_node_nsec3 *to,
421 zone_diff *diff, ptr_vector *collection, u8 mask,
422 bool append_existing_signatures, u8 optout)
423 {
424
425 const u8 *digest = dnssec_chain_node_nsec3_get_digest(from);
426 const u8 *next_digest = dnssec_chain_node_nsec3_get_digest(to);
427
428 u32 b32_len;
429 u32 fqdn_len;
430 u8 hash_len;
431 u8 digest_fqdn[512];
432
433 log_debug1("update: %{dnsname}: %{digest32h}: %x: %{dnsname} -> %{digest32h}", diff->origin, digest, mask, from->fqdn, next_digest);
434 // generate the label
435
436 hash_len = digest[0];
437 b32_len = base32hex_encode(&digest[1], hash_len, (char*)&digest_fqdn[1]);
438 digest_fqdn[0] = b32_len;
439 fqdn_len = dnsname_len(diff->origin);
440 memcpy(&digest_fqdn[b32_len + 1], diff->origin, fqdn_len );
441
442 u32 nsec3param_rdata_size = NSEC3PARAM_RDATA_SIZE_FROM_RDATA(n3->rdata);
443
444 if(!dnssec_chain_node_nsec3_has_bits_map(from) || ((mask & ZONE_DIFF_RR_REMOVE) && (from->state & DNSSEC_CHAIN_REMAP))
445 /*
446 * can only modify if (mask & ZONE_DIFF_RR_REMOVE)
447 || ((from->state & (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_REMAP|DNSSEC_CHAIN_EXISTS)) == (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_REMAP|DNSSEC_CHAIN_EXISTS))
448 */
449 )
450 {
451 // generate the type map
452 #if DEBUG
453 log_debug2("update: %{dnsname}: %{digest32h}: %x: %{dnsname} -> %{digest32h} regenerating bitmap (%i || (%i && %i [%02x])",
454 diff->origin, digest, mask, from->fqdn, next_digest,
455 !dnssec_chain_node_nsec3_has_bits_map(from), (mask & ZONE_DIFF_RR_REMOVE), (from->state & DNSSEC_CHAIN_REMAP), from->state);
456 #endif
457 type_bit_maps_context bitmap;
458
459 u16 bitmap_size = zone_diff_type_bit_map_generate(diff, from->fqdn, &bitmap, mask | ZONE_DIFF_RR_REMOVE, 0, digest_fqdn, append_existing_signatures);
460
461 u16 rdata_size = nsec3param_rdata_size + 1 + next_digest[0] + bitmap_size;
462
463 #if C11_VLA_AVAILABLE
464 u8 rdata[rdata_size];
465 #else
466 u8* const rdata = (u8* const)stack_alloc(rdata_size);
467 #endif
468
469 memcpy(rdata, n3->rdata, nsec3param_rdata_size);
470 rdata[1] = optout;
471 memcpy(&rdata[nsec3param_rdata_size], next_digest, 1 + next_digest[0]);
472 type_bit_maps_write(&bitmap, &rdata[nsec3param_rdata_size + 1 + next_digest[0]]);
473 type_bit_maps_finalize(&bitmap);
474
475 // the record can be created
476
477 zone_diff_label_rr *nsec3_rr = zone_diff_label_rr_new(digest_fqdn, TYPE_NSEC3, CLASS_IN, diff->nttl, rdata, rdata_size, TRUE);
478 nsec3_rr->state |= ZONE_DIFF_RR_VOLATILE;
479 ptr_vector_append(collection, nsec3_rr);
480 }
481 else // bitmap already present
482 {
483 #if DEBUG
484 log_debug2("update: %{dnsname}: %{digest32h}: %x: %{dnsname} -> %{digest32h} keeping bitmap (%i || (%i && %i [%02x])",
485 diff->origin, digest, mask, from->fqdn, next_digest,
486 !dnssec_chain_node_nsec3_has_bits_map(from), (mask & ZONE_DIFF_RR_REMOVE), (from->state & DNSSEC_CHAIN_REMAP),
487 from->state);
488 #endif
489 u16 bitmap_size = dnssec_chain_node_nsec3_get_bits_map_size(from);
490 u16 rdata_size = nsec3param_rdata_size + 1 + next_digest[0] + bitmap_size;
491
492 #if C11_VLA_AVAILABLE
493 u8 rdata[rdata_size];
494 #else
495 u8* const rdata = (u8* const)stack_alloc(rdata_size);
496 #endif
497
498 memcpy(rdata, n3->rdata, nsec3param_rdata_size);
499 rdata[1] = optout;
500 memcpy(&rdata[nsec3param_rdata_size], next_digest, 1 + next_digest[0]);
501 memcpy(&rdata[nsec3param_rdata_size + 1 + next_digest[0]], dnssec_chain_node_nsec3_get_bits_map(from), bitmap_size);
502
503 // the record can be created
504
505 zone_diff_label_rr *nsec3_rr = zone_diff_label_rr_new(
506 digest_fqdn, TYPE_NSEC3, CLASS_IN, diff->nttl, rdata, rdata_size, TRUE);
507 nsec3_rr->state |= ZONE_DIFF_RR_VOLATILE | (from->state & DNSSEC_CHAIN_EXISTS);
508 ptr_vector_append(collection, nsec3_rr);
509 }
510
511 if(append_existing_signatures && (from->self != NULL))
512 {
513 zdb_packed_ttlrdata *rrsig = from->self->rrsig;
514 while(rrsig != NULL)
515 {
516 zone_diff_label_rr *rrsig_rr = zone_diff_label_rr_new(digest_fqdn, TYPE_RRSIG, CLASS_IN, diff->nttl,
517 ZDB_PACKEDRECORD_PTR_RDATAPTR(rrsig), ZDB_PACKEDRECORD_PTR_RDATASIZE(rrsig), TRUE);
518 rrsig_rr->state |= ZONE_DIFF_RR_VOLATILE;
519 ptr_vector_append(collection, rrsig_rr);
520 rrsig = rrsig->next;
521 }
522 }
523 }
524
dnssec_chain_node_nsec3_publish_log(dnssec_chain_node_t from_,dnssec_chain_node_t to_)525 static void dnssec_chain_node_nsec3_publish_log(dnssec_chain_node_t from_, dnssec_chain_node_t to_)
526 {
527 dnssec_chain_node_nsec3 *from = (dnssec_chain_node_nsec3*)from_;
528 dnssec_chain_node_nsec3 *to = (dnssec_chain_node_nsec3*)to_;
529
530 const u8 *digest = dnssec_chain_node_nsec3_get_digest(from);
531 if(to != NULL)
532 {
533 const u8 *next_digest = dnssec_chain_node_nsec3_get_digest(to);
534
535 log_debug1("update: %{digest32h} -> %{digest32h}", digest, next_digest);
536 }
537 else
538 {
539 log_debug1("update: %{digest32h} -> ?", digest);
540 }
541 }
542
dnssec_chain_node_nsec3_publish_add(dnssec_chain_head_t chain_,dnssec_chain_node_t from_,dnssec_chain_node_t to_,zone_diff * diff,ptr_vector * collection)543 static void dnssec_chain_node_nsec3_publish_add(dnssec_chain_head_t chain_, dnssec_chain_node_t from_, dnssec_chain_node_t to_, zone_diff *diff, ptr_vector *collection)
544 {
545 dnssec_chain_node_nsec3 *from = (dnssec_chain_node_nsec3*)from_;
546 dnssec_chain_node_nsec3 *to = (dnssec_chain_node_nsec3*)to_;
547 nsec3_zone *n3 = (nsec3_zone*)chain_;
548 dnssec_chain_node_nsec3_publish_record(n3, from, to, diff, collection, ZONE_DIFF_RR_REMOVE, FALSE, 0);
549 }
550
dnssec_chain_node_nsec3_publish_delete(dnssec_chain_head_t chain_,dnssec_chain_node_t from_,dnssec_chain_node_t to_,zone_diff * diff,ptr_vector * collection)551 static void dnssec_chain_node_nsec3_publish_delete(dnssec_chain_head_t chain_, dnssec_chain_node_t from_, dnssec_chain_node_t to_, zone_diff *diff, ptr_vector *collection)
552 {
553 dnssec_chain_node_nsec3 *from = (dnssec_chain_node_nsec3*)from_;
554 dnssec_chain_node_nsec3 *to = (dnssec_chain_node_nsec3*)to_;
555 nsec3_zone *n3 = (nsec3_zone*)chain_;
556 dnssec_chain_node_nsec3_publish_record(n3, from, to, diff, collection, ZONE_DIFF_RR_ADD, TRUE, 0);
557 }
558
dnssec_chain_node_nsec3_publish_add_optout(dnssec_chain_head_t chain_,dnssec_chain_node_t from_,dnssec_chain_node_t to_,zone_diff * diff,ptr_vector * collection)559 static void dnssec_chain_node_nsec3_publish_add_optout(dnssec_chain_head_t chain_, dnssec_chain_node_t from_, dnssec_chain_node_t to_, zone_diff *diff, ptr_vector *collection)
560 {
561 dnssec_chain_node_nsec3 *from = (dnssec_chain_node_nsec3*)from_;
562 dnssec_chain_node_nsec3 *to = (dnssec_chain_node_nsec3*)to_;
563 nsec3_zone *n3 = (nsec3_zone*)chain_;
564 dnssec_chain_node_nsec3_publish_record(n3, from, to, diff, collection, ZONE_DIFF_RR_REMOVE, FALSE, 1);
565 }
566
dnssec_chain_node_nsec3_publish_delete_optout(dnssec_chain_head_t chain_,dnssec_chain_node_t from_,dnssec_chain_node_t to_,zone_diff * diff,ptr_vector * collection)567 static void dnssec_chain_node_nsec3_publish_delete_optout(dnssec_chain_head_t chain_, dnssec_chain_node_t from_, dnssec_chain_node_t to_, zone_diff *diff, ptr_vector *collection)
568 {
569 dnssec_chain_node_nsec3 *from = (dnssec_chain_node_nsec3*)from_;
570 dnssec_chain_node_nsec3 *to = (dnssec_chain_node_nsec3*)to_;
571 nsec3_zone *n3 = (nsec3_zone*)chain_;
572 dnssec_chain_node_nsec3_publish_record(n3, from, to, diff, collection, ZONE_DIFF_RR_ADD, TRUE, 1);
573 }
574
dnssec_chain_nsec3_isempty(dnssec_chain_head_t chain_)575 static bool dnssec_chain_nsec3_isempty(dnssec_chain_head_t chain_)
576 {
577 nsec3_zone *nsec3_chain = (nsec3_zone*)chain_;
578 bool ret = (nsec3_chain != NULL)?nsec3_isempty(&nsec3_chain->items):TRUE;
579 return ret;
580 }
581
dnssec_chain_nsec3_finalize_delete_callback(ptr_node * node)582 static void dnssec_chain_nsec3_finalize_delete_callback(ptr_node *node)
583 {
584 dnssec_chain_node_nsec3_delete(node->value);
585 }
586
dnssec_chain_node_nsec3_rrset_should_be_signed(const zone_diff_fqdn * diff_fqdn,const zone_diff_fqdn_rr_set * rr_set)587 static bool dnssec_chain_node_nsec3_rrset_should_be_signed(const zone_diff_fqdn *diff_fqdn, const zone_diff_fqdn_rr_set *rr_set)
588 {
589 if(diff_fqdn->at_delegation || diff_fqdn->under_delegation)
590 {
591 return (rr_set->rtype == TYPE_NS) || (rr_set->rtype == TYPE_DS);
592 }
593 else
594 {
595 return TRUE;
596 }
597 }
598
599
dnssec_chain_node_nsec3_optout_rrset_should_be_signed(const zone_diff_fqdn * diff_fqdn,const zone_diff_fqdn_rr_set * rr_set)600 static bool dnssec_chain_node_nsec3_optout_rrset_should_be_signed(const zone_diff_fqdn *diff_fqdn, const zone_diff_fqdn_rr_set *rr_set)
601 {
602 if(diff_fqdn->at_delegation || diff_fqdn->under_delegation)
603 {
604 return (rr_set->rtype == TYPE_DS);
605 }
606 else
607 {
608 return TRUE;
609 }
610 }
611
612 static dnssec_chain_node_vtbl dnssec_chain_node_nsec3_vtbl =
613 {
614 dnssec_chain_node_nsec3_fqdn_is_covered,
615 dnssec_chain_node_nsec3_fqdn_was_covered,
616 dnssec_chain_node_nsec3_new,
617 dnssec_chain_node_nsec3_prev,
618 dnssec_chain_node_nsec3_merge,
619 dnssec_chain_node_nsec3_next,
620 dnssec_chain_node_nsec3_state_set,
621 dnssec_chain_node_nsec3_state_get,
622 dnssec_chain_node_nsec3_delete,
623 dnssec_chain_node_nsec3_publish_delete,
624 dnssec_chain_node_nsec3_publish_add,
625 dnssec_chain_node_nsec3_publish_log,
626 dnssec_chain_node_nsec3_compare,
627 dnssec_chain_nsec3_finalize_delete_callback,
628 dnssec_chain_nsec3_isempty,
629 dnssec_chain_node_nsec3_format_writer_init,
630 dnssec_chain_node_nsec3_rrset_should_be_signed,
631 "nsec3"
632 };
633
634 const dnssec_chain_node_vtbl *
dynupdate_nsec3_chain_get_vtbl()635 dynupdate_nsec3_chain_get_vtbl()
636 {
637 return &dnssec_chain_node_nsec3_vtbl;
638 }
639
640 static dnssec_chain_node_vtbl dnssec_chain_node_nsec3_optout_vtbl =
641 {
642 dnssec_chain_node_nsec3_optout_fqdn_is_covered,
643 dnssec_chain_node_nsec3_optout_fqdn_was_covered,
644 dnssec_chain_node_nsec3_new,
645 dnssec_chain_node_nsec3_prev,
646 dnssec_chain_node_nsec3_merge,
647 dnssec_chain_node_nsec3_next,
648 dnssec_chain_node_nsec3_state_set,
649 dnssec_chain_node_nsec3_state_get,
650 dnssec_chain_node_nsec3_delete,
651 dnssec_chain_node_nsec3_publish_delete_optout,
652 dnssec_chain_node_nsec3_publish_add_optout,
653 dnssec_chain_node_nsec3_publish_log,
654 dnssec_chain_node_nsec3_compare,
655 dnssec_chain_nsec3_finalize_delete_callback,
656 dnssec_chain_nsec3_isempty,
657 dnssec_chain_node_nsec3_format_writer_init,
658 dnssec_chain_node_nsec3_optout_rrset_should_be_signed,
659 "nsec3-optout"
660 };
661
662 const dnssec_chain_node_vtbl *
dynupdate_nsec3_optout_chain_get_vtbl()663 dynupdate_nsec3_optout_chain_get_vtbl()
664 {
665 return &dnssec_chain_node_nsec3_optout_vtbl;
666 }
667