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