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/logger.h>
50 #include <dnscore/dnsname.h>
51 #include <dnscore/digest.h>
52
53 #include <dnscore/dnskey-signature.h>
54
55 #include "dnsdb/zdb_types.h"
56 #include "dnsdb/nsec.h"
57 #include "dnsdb/nsec3.h"
58
59 #include <dnscore/base32hex.h>
60 #include <dnscore/format.h>
61 #include <dnscore/bytearray_output_stream.h>
62 #include <dnscore/bytearray_input_stream.h>
63 #include <dnsdb/zdb-zone-maintenance.h>
64
65 #include "dnsdb/dnssec.h"
66 #include "dnsdb/zdb_zone.h"
67 #include "dnsdb/dnssec-keystore.h"
68 #include "dnsdb/zdb_utils.h"
69 #include "dnsdb/dynupdate-diff.h"
70 #include "dnsdb/zdb-zone-path-provider.h"
71 #include "dnsdb/zdb_icmtl.h"
72 #if HAS_NSEC3_SUPPORT
73 #include "dnsdb/nsec3.h"
74 #endif
75
76 #define ZDB_JOURNAL_CODE 1
77 #include "dnsdb/journal.h"
78
79 #define MODULE_MSG_HANDLE g_database_logger
80 extern logger_handle *g_database_logger;
81
82 // Disable detailed diff log even in debug builds
83
84 #define DYNUPDATE_DIFF_DETAILED_LOG 0
85
86 #ifndef DYNUPDATE_DIFF_DETAILED_LOG
87 #if DEBUG
88 #define DYNUPDATE_DIFF_DETAILED_LOG 1
89 #else
90 #define DYNUPDATE_DIFF_DETAILED_LOG 0
91 #endif
92 #endif
93
94 #if DYNUPDATE_DIFF_DETAILED_LOG
95 #pragma message("WARNING: DYNUPDATE_DIFF_DETAILED_LOG is not set to 0")
96 #endif
97
98 #define DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG 0
99
100 #ifndef DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
101 #if DEBUG
102 #define DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG 1
103 #else
104 #define DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG 0
105 #endif
106 #endif
107
108 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
109 #pragma message("WARNING: DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG is not set to 0")
110 #endif
111
112 ///////////////////////////////////////////////////////////////////////////////
113
114 static char zone_diff_record_state_format_letters[6] = {'+','-','O','V','E','A'};
115
116 void
zone_diff_record_state_format(const void * data,output_stream * os,s32 a,char b,bool c,void * reserved_for_method_parameters)117 zone_diff_record_state_format(const void* data, output_stream* os, s32 a, char b , bool c, void* reserved_for_method_parameters)
118 {
119 (void)a;
120 (void)b;
121 (void)c;
122 (void)reserved_for_method_parameters;
123
124 u8 state = *((u8*)data);
125 for(u32 i = 0; i < sizeof(zone_diff_record_state_format_letters); ++i)
126 {
127 char c = ((state & (1 << i)) != 0)?zone_diff_record_state_format_letters[i]:'_';
128 output_stream_write(os, &c, 1);
129 }
130 }
131
132 #if DEBUG
133 static char zone_diff_chain_state_format_letters[8] = {'+','-',' ','r','E','{','}','!'};
134
135 static void
zone_diff_chain_state_format(const void * data,output_stream * os,s32 a,char b,bool c,void * reserved_for_method_parameters)136 zone_diff_chain_state_format(const void* data, output_stream* os, s32 a, char b , bool c, void* reserved_for_method_parameters)
137 {
138 (void)a;
139 (void)b;
140 (void)c;
141 (void)reserved_for_method_parameters;
142
143 u8 state = *((u8*)data);
144 for(u32 i = 0; i < sizeof(zone_diff_chain_state_format_letters); ++i)
145 {
146 char c = ((state & (1 << i)) != 0)?zone_diff_chain_state_format_letters[i]:'_';
147 output_stream_write(os, &c, 1);
148 }
149 }
150 #endif
151
152 static void
zone_diff_fqdn_changes_format(const void * data,output_stream * os,s32 a,char b,bool c,void * reserved_for_method_parameters)153 zone_diff_fqdn_changes_format(const void* data, output_stream* os, s32 a, char b , bool c, void* reserved_for_method_parameters)
154 {
155 (void)a;
156 (void)b;
157 (void)c;
158 (void)reserved_for_method_parameters;
159
160 zone_diff_fqdn *diff = (zone_diff_fqdn*)data;
161
162 if(diff->type_map_changed) output_stream_write(os, "MAP ", 4);
163 if(diff->all_rrset_added) output_stream_write(os, "+ALL ", 5);
164 if(diff->all_rrset_removed) output_stream_write(os, "-ALL ", 5);
165 if(diff->is_apex) output_stream_write(os, "APEX ", 5);
166
167 output_stream_write(os, "AT(", 3);
168 output_stream_write_u8(os, diff->was_at_delegation?'1':'0');
169 output_stream_write(os, "->", 2);
170 output_stream_write_u8(os, diff->at_delegation?'1':'0');
171 output_stream_write(os, ") ", 2);
172
173 output_stream_write(os, "UNDER(", 6);
174 output_stream_write_u8(os, diff->was_under_delegation?'1':'0');
175 output_stream_write(os, "->", 2);
176 output_stream_write_u8(os, diff->under_delegation?'1':'0');
177 output_stream_write(os, ") ", 2);
178
179 output_stream_write(os, "DS(", 3);
180 output_stream_write_u8(os, diff->had_ds?'1':'0');
181 output_stream_write(os, "->", 2);
182 output_stream_write_u8(os, diff->will_have_ds?'1':'0');
183 output_stream_write(os, ") ", 2);
184
185 output_stream_write(os, "CHILDREN(", 9);
186 output_stream_write_u8(os, diff->had_children?'1':'0');
187 output_stream_write(os, "->", 2);
188 output_stream_write_u8(os, diff->will_have_children?'1':'0');
189 output_stream_write(os, ") ", 2);
190
191 output_stream_write(os, "RECORDS(", 8);
192 output_stream_write_u8(os, diff->was_non_empty?'1':'0');
193 output_stream_write(os, "->", 2);
194 output_stream_write_u8(os, diff->will_be_non_empty?'1':'0');
195 output_stream_write(os, ") ", 2);
196 }
197
198 static const u8 *
zone_diff_label_rr_rrv_get_fqdn(void * data,const void * p)199 zone_diff_label_rr_rrv_get_fqdn(void *data, const void* p)
200 {
201 (void)data;
202 zone_diff_label_rr *rr = (zone_diff_label_rr*)p;
203 return rr->fqdn;
204 }
205
206 static u16
zone_diff_label_rr_rrv_get_type(void * data,const void * p)207 zone_diff_label_rr_rrv_get_type(void *data, const void* p)
208 {
209 /*
210 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)data;
211 (void)p;
212 return rrset->rtype;
213 */
214 (void)data;
215 zone_diff_label_rr *rr = (zone_diff_label_rr*)p;
216 return rr->rtype;
217 }
218
219 static u16
zone_diff_label_rr_rrv_get_class(void * data,const void * p)220 zone_diff_label_rr_rrv_get_class(void *data, const void* p)
221 {
222 /*
223 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)data;
224 (void)p;
225 return rrset->rclass;
226 */
227 (void)data;
228 zone_diff_label_rr *rr = (zone_diff_label_rr*)p;
229 return rr->rclass;
230 }
231
232 static s32
zone_diff_label_rr_rrv_get_ttl(void * data,const void * p)233 zone_diff_label_rr_rrv_get_ttl(void *data, const void* p)
234 {
235 /*
236 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)data;
237 (void)p;
238 return rrset->new_ttl;
239 */
240 (void)data;
241 zone_diff_label_rr *rr = (zone_diff_label_rr*)p;
242 return rr->ttl;
243 }
244
245 static u16
zone_diff_label_rr_rrv_get_rdata_size(void * data,const void * p)246 zone_diff_label_rr_rrv_get_rdata_size(void *data, const void* p)
247 {
248 (void)data;
249 zone_diff_label_rr *rr = (zone_diff_label_rr*)p;
250 return rr->rdata_size;
251 }
252
253 static const u8 *
zone_diff_label_rr_rrv_get_rdata(void * data,const void * p)254 zone_diff_label_rr_rrv_get_rdata(void *data, const void* p)
255 {
256 (void)data;
257 zone_diff_label_rr *rr = (zone_diff_label_rr*)p;
258 return (const u8*)rr->rdata;
259 }
260
261 static void *
zone_diff_label_rr_rrv_new_instance(void * data,const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,u16 rdata_size,const u8 * rdata)262 zone_diff_label_rr_rrv_new_instance(void *data, const u8 *fqdn, u16 rtype, u16 rclass, s32 ttl, u16 rdata_size, const u8 *rdata)
263 {
264 (void)data;
265 zone_diff_label_rr *rr = zone_diff_label_rr_new(fqdn, rtype, rclass, ttl, (void*)rdata, rdata_size, TRUE);
266 return rr;
267 }
268
269 static const struct resource_record_view_vtbl zone_diff_label_rr_rrv_vtbl =
270 {
271 zone_diff_label_rr_rrv_get_fqdn,
272 zone_diff_label_rr_rrv_get_type,
273 zone_diff_label_rr_rrv_get_class,
274 zone_diff_label_rr_rrv_get_ttl,
275 zone_diff_label_rr_rrv_get_rdata_size,
276 zone_diff_label_rr_rrv_get_rdata,
277 zone_diff_label_rr_rrv_new_instance
278 };
279
280 ///////////////////////////////////////////////////////////////////////////////
281
282 /**
283 * Initialises a dnssec chain (editor).
284 * NSEC and NSEC3 chains cannot be mixed.
285 * The actual chain must be set using dnssec_chain_add_chain
286 *
287 * @param dc
288 * @param chain_functions
289 */
290
dnssec_chain_init(dnssec_chain * dc,const dnssec_chain_node_vtbl * chain_functions,zone_diff * diff)291 void dnssec_chain_init(dnssec_chain *dc, const dnssec_chain_node_vtbl *chain_functions, zone_diff *diff)
292 {
293 dc->diff = diff;
294 ptr_set_init(&dc->chain_diff);
295 dc->chain_diff.compare = chain_functions->compare;
296 dc->chain = chain_functions;
297 dc->chains_count = 0;
298 }
299
300 /**
301 * Adds a chain to the chain editor.
302 *
303 * NSEC3: every nsec3_zone* of the zone (one at a time).
304 * NSEC: the nsec_zone of the zone.
305 *
306 * @param dc
307 * @param chain
308 */
309
dnssec_chain_add_chain(dnssec_chain * dc,dnssec_chain_head_t chain,bool being_deleted)310 void dnssec_chain_add_chain(dnssec_chain *dc, dnssec_chain_head_t chain, bool being_deleted)
311 {
312 if(dc->chains_count < DNSSEC_CHAIN_SUPPORTED_MAX)
313 {
314 dc->chains[dc->chains_count] = chain;
315 dc->chain_being_deleted[dc->chains_count] = being_deleted;
316 ++dc->chains_count;
317 }
318 }
319
dnssec_chain_add_node(dnssec_chain * dc,const u8 * fqdn,u16 rtype,u8 asked_or_mask)320 static void dnssec_chain_add_node(dnssec_chain *dc, const u8 *fqdn, u16 rtype, u8 asked_or_mask)
321 {
322 // compute the hash
323 // find the prev & next in the current set
324 // store a node with "prev new next"
325 // store a node with "prev" marked as begin (if !E)
326 // store a node with "next" marked as end (if !E)
327
328 (void)rtype;
329
330 for(int chain_index = 0; chain_index < dc->chains_count; ++chain_index)
331 {
332 void *chain = dc->chains[chain_index];
333
334 // need to know if it's under delegation
335
336 //
337 #if DEBUG
338 log_debug("NEW NODE %{dnsname} (0)", fqdn);
339 #endif
340 void *chain_node = dc->chain->node_new(fqdn, chain);
341
342 ptr_node *node = ptr_set_insert(&dc->chain_diff, chain_node);
343
344 // if chain is not empty, edit it, else create it with one node
345
346 if(!dc->chain->isempty(chain))
347 {
348 u8 or_mask = (!dc->chain_being_deleted[chain_index])?asked_or_mask:DNSSEC_CHAIN_DELETE;
349
350 if(node->value == NULL)
351 {
352 node->value = chain_node;
353
354 // create a node for the prev & next
355
356 void *chain_begin = dc->chain->node_prev(chain_node);
357
358 // zone_diff_add_fqdn(dc->diff, node->fqdn, rr_label);
359
360 yassert(chain_begin != NULL);
361 ptr_node *node_prev = ptr_set_insert(&dc->chain_diff, chain_begin);
362 if(node_prev->value == NULL)
363 {
364 node_prev->value = chain_begin;
365 }
366 else
367 {
368 dc->chain->node_merge(node_prev->value, chain_begin);
369 }
370
371 void *chain_end = dc->chain->node_next(chain_node);
372 yassert(chain_end != NULL);
373 ptr_node *node_next = ptr_set_insert(&dc->chain_diff, chain_end);
374 if(node_next->value == NULL)
375 {
376 node_next->value = chain_end;
377 }
378 else
379 {
380 dc->chain->node_merge(node_next->value, chain_end);
381 }
382 }
383 else
384 {
385 // node exists already ...
386
387 dc->chain->state_set(node->value, dc->chain->state_get(node->value) & ~(DNSSEC_CHAIN_BEGIN|DNSSEC_CHAIN_END));
388
389 dc->chain->node_delete(chain_node);
390 }
391
392 if(or_mask != 0)
393 {
394 dc->chain->state_set(node->value, dc->chain->state_get(node->value) | or_mask);
395 }
396 }
397 else
398 {
399 // instead of the doing diff computations the chain will be fully created
400 node->value = chain_node;
401 }
402 }
403 }
404
dnssec_chain_add_node_neighbours(dnssec_chain * dc,const zone_diff_fqdn * diff_fqdn,void * chain_node,int chain_index)405 static void dnssec_chain_add_node_neighbours(dnssec_chain *dc, const zone_diff_fqdn *diff_fqdn, void *chain_node, int chain_index)
406 {
407
408
409 (void)diff_fqdn;
410 (void)chain_index;
411
412 void *chain_begin = dc->chain->node_prev(chain_node);
413 yassert(chain_begin != NULL);
414 #if DEBUG
415 format_writer chain_node_prev_fw;
416 dc->chain->format_writer_init(chain_begin, &chain_node_prev_fw);
417 #endif
418 ptr_node *node_prev = ptr_set_insert(&dc->chain_diff, chain_begin);
419 if(node_prev->value == NULL)
420 {
421 node_prev->value = chain_begin;
422 #if DEBUG
423 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: previous node is %w", diff_fqdn->fqdn, chain_index, &chain_node_prev_fw);
424 #endif
425 }
426 else
427 {
428 #if DEBUG
429 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: previous node %w already in chain, merging", diff_fqdn->fqdn, chain_index, &chain_node_prev_fw);
430 #endif
431 dc->chain->node_merge(node_prev->value, chain_begin);
432 #if DEBUG
433 dc->chain->format_writer_init(node_prev->value, &chain_node_prev_fw);
434 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: previous node %w merged", diff_fqdn->fqdn, chain_index, &chain_node_prev_fw);
435 #endif
436 }
437
438 void *chain_end = dc->chain->node_next(chain_node);
439 yassert(chain_end != NULL);
440 #if DEBUG
441 format_writer chain_node_next_fw;
442 dc->chain->format_writer_init(chain_end, &chain_node_next_fw);
443 #endif
444 ptr_node *node_next = ptr_set_insert(&dc->chain_diff, chain_end);
445 if(node_next->value == NULL)
446 {
447 #if DEBUG
448 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: next node is %w", diff_fqdn->fqdn, chain_index, &chain_node_next_fw);
449 #endif
450 node_next->value = chain_end;
451 }
452 else
453 {
454 #if DEBUG
455 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: next node %w already in chain, merging", diff_fqdn->fqdn, chain_index, &chain_node_next_fw);
456 #endif
457 dc->chain->node_merge(node_next->value, chain_end);
458 #if DEBUG
459 dc->chain->format_writer_init(node_next->value, &chain_node_next_fw);
460 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: next node %w merged", diff_fqdn->fqdn, chain_index, &chain_node_next_fw);
461 #endif
462 }
463 }
464
465 static int
dnssec_chain_add_node_from_diff_fqdn(dnssec_chain * dc,const zone_diff_fqdn * diff_fqdn,u16 rtype,u8 asked_or_mask)466 dnssec_chain_add_node_from_diff_fqdn(dnssec_chain *dc, const zone_diff_fqdn *diff_fqdn, u16 rtype, u8 asked_or_mask)
467 {
468 int ret = 0;
469 // compute the hash
470 // find the prev & next in the current set
471 // store a node with "prev new next"
472 // store a node with "prev" marked as begin (if !E)
473 // store a node with "next" marked as end (if !E)
474
475 (void)rtype;
476
477 for(int chain_index = 0; chain_index < dc->chains_count; ++chain_index)
478 {
479 void *chain = dc->chains[chain_index];
480
481 // need to know if it's under delegation
482
483 if(asked_or_mask & DNSSEC_CHAIN_DELETE)
484 {
485 // IT HAD TO EXIST FIRST!
486 if(!dc->chain->fqdn_was_covered(diff_fqdn))
487 {
488 #if DEBUG
489 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: did not cover", diff_fqdn->fqdn, chain_index);
490 #endif
491 continue;
492 }
493
494 }
495 else
496 {
497 if(!dc->chain->fqdn_is_covered(diff_fqdn))
498 {
499 #if DEBUG
500 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: does not covers", diff_fqdn->fqdn, chain_index);
501 #endif
502 continue;
503 }
504 }
505
506 #if DEBUG
507 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: covers", diff_fqdn->fqdn, chain_index);
508 #endif
509
510 //
511
512 #if DEBUG
513 log_debug3("NEW NODE %{dnsname} (1)", diff_fqdn->fqdn);
514 #endif
515
516 void *chain_node = dc->chain->node_new(diff_fqdn->fqdn, chain);
517
518 #if DEBUG
519 format_writer chain_node_fw;
520 dc->chain->format_writer_init(chain_node, &chain_node_fw);
521 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: node is %w", diff_fqdn->fqdn, chain_index, &chain_node_fw);
522 #endif
523
524 ptr_node *node = ptr_set_insert(&dc->chain_diff, chain_node);
525
526 if(!dc->chain->isempty(chain))
527 {
528 u8 or_mask = (!dc->chain_being_deleted[chain_index])?asked_or_mask:DNSSEC_CHAIN_DELETE;
529
530 if(node->value == NULL)
531 {
532 #if DEBUG
533 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: node %w is new, getting both neighbours", diff_fqdn->fqdn, chain_index, &chain_node_fw);
534 #endif
535 node->value = chain_node;
536
537 // create a node for the prev & next
538
539 dnssec_chain_add_node_neighbours(dc, diff_fqdn, chain_node, chain_index);
540 }
541 else
542 {
543 #if DEBUG
544 log_debug2("dnssec-chain: %{dnsname}: chain[%i]: node %w already exists", diff_fqdn->fqdn, chain_index, &chain_node_fw);
545 #endif
546 // node exists already ...
547 dnssec_chain_add_node_neighbours(dc, diff_fqdn, chain_node, chain_index);
548 dc->chain->node_merge(node->value, chain_node);
549 dc->chain->state_set(node->value, dc->chain->state_get(node->value) & ~(DNSSEC_CHAIN_BEGIN|DNSSEC_CHAIN_END));
550 }
551
552 // check if any of the RRSET of the label have been added or removed
553
554 //
555 u8 prev_state = dc->chain->state_get(node->value);
556
557 if(prev_state & DNSSEC_CHAIN_EXISTS)
558 {
559 bool type_map_changed = zone_diff_fqdn_type_map_changed(diff_fqdn);
560
561 if(type_map_changed)
562 {
563 or_mask |= DNSSEC_CHAIN_REMAP;
564 }
565 }
566
567 if(or_mask != 0)
568 {
569 dc->chain->state_set(node->value, prev_state | or_mask);
570 }
571 if(((prev_state & DNSSEC_CHAIN_EXISTS) == 0) || ((or_mask & (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_REMAP)) != 0))
572 {
573 ++ret;
574 }
575 }
576 else
577 {
578 #if DEBUG
579 log_debug("dnssec-chain: %{dnsname}: chain[%i] was empty", diff_fqdn->fqdn, chain_index);
580 #endif
581 // instead of the doing diff computations the chain will be fully created
582
583 if(node->value != NULL)
584 {
585 #if DEBUG
586 log_debug("dnssec-chain: %{dnsname}: chain[%i]: node %w already exists", diff_fqdn->fqdn, chain_index, &chain_node_fw);
587 #endif
588 // node exists already ...
589 assert(dc->chain->compare(node->value, chain_node) == 0);
590
591 dc->chain->node_merge(node->value, chain_node);
592 dc->chain->state_set(node->value, dc->chain->state_get(node->value) & ~(DNSSEC_CHAIN_BEGIN|DNSSEC_CHAIN_END));
593 }
594 else
595 {
596 node->value = chain_node;
597 }
598
599 ++ret;
600 }
601 }
602
603 return ret;
604 }
605
606 /**
607 * Adds a node to the chain.
608 *
609 * @param dc
610 * @param fqdn
611 * @param rtype
612 */
613
dnssec_chain_add(dnssec_chain * dc,const u8 * fqdn,u16 rtype)614 void dnssec_chain_add(dnssec_chain *dc, const u8 *fqdn, u16 rtype)
615 {
616 dnssec_chain_add_node(dc, fqdn, rtype, DNSSEC_CHAIN_ADD);
617 // It used to be :
618 // dnssec_chain_add_node(dc, fqdn, rtype, 0);
619 }
620
dnssec_chain_add_from_diff_fqdn(dnssec_chain * dc,const zone_diff_fqdn * diff_fqdn,u16 rtype)621 int dnssec_chain_add_from_diff_fqdn(dnssec_chain *dc, const zone_diff_fqdn* diff_fqdn, u16 rtype)
622 {
623 int ret = dnssec_chain_add_node_from_diff_fqdn(dc, diff_fqdn, rtype, DNSSEC_CHAIN_ADD);
624 return ret;
625 }
626
627 /**
628 * Removes a node from the chain.
629 *
630 * @param dc
631 * @param fqdn
632 * @param rtype
633 */
634
dnssec_chain_del(dnssec_chain * dc,const u8 * fqdn,u16 rtype)635 void dnssec_chain_del(dnssec_chain *dc, const u8 *fqdn, u16 rtype)
636 {
637 dnssec_chain_add_node(dc, fqdn, rtype, DNSSEC_CHAIN_DELETE);
638 }
639
dnssec_chain_del_from_diff_fqdn(dnssec_chain * dc,const zone_diff_fqdn * diff_fqdn,u16 rtype)640 int dnssec_chain_del_from_diff_fqdn(dnssec_chain *dc, const zone_diff_fqdn* diff_fqdn, u16 rtype)
641 {
642 int ret = dnssec_chain_add_node_from_diff_fqdn(dc, diff_fqdn, rtype, DNSSEC_CHAIN_DELETE);
643 return ret;
644 }
645
dnssec_chain_store_diff_publish_chain_node(dnssec_chain * dc,zone_diff * diff,ptr_vector * keys,void * chain,void * prev,void * prev_next,ptr_vector * add)646 static void dnssec_chain_store_diff_publish_chain_node(dnssec_chain *dc, zone_diff *diff, ptr_vector *keys,
647 void *chain, void *prev, void *prev_next, ptr_vector *add)
648 {
649 ya_result ret;
650 s32 from_offset = ptr_vector_size(add);
651
652 dc->chain->publish_add(chain, prev, prev_next, diff, add);
653
654 // and its signature(s)
655
656 s32 to_offset = ptr_vector_size(add);
657 // make a ptr_vector that's a view of the last added records
658 ptr_vector rrset = {&add->data[from_offset], 0, to_offset - from_offset};
659
660 struct resource_record_view rrv = {NULL, &zone_diff_label_rr_rrv_vtbl};
661 u16 rrset_type = TYPE_NONE;
662 for(int i = 0; i <= ptr_vector_last_index(&rrset); ++i)
663 {
664 void* data = ptr_vector_get(&rrset, i);
665 const void *fqdn = rrv.vtbl->get_fqdn(rrv.data, data);
666 u16 rtype = rrv.vtbl->get_type(rrv.data, data);
667 u16 rclass = rrv.vtbl->get_class(rrv.data, data);
668 s32 ttl = rrv.vtbl->get_ttl(rrv.data, data);
669 u16 rdata_size = rrv.vtbl->get_rdata_size(rrv.data, data);
670 const void *rdata = rrv.vtbl->get_rdata(rrv.data, data);
671
672 rrset_type = rtype;
673
674 rdata_desc rdt = {rtype, rdata_size, rdata};
675 log_debug("update: %{dnsname}: will sign chain record #%i: %{dnsname} %i %{dnsclass} %{typerdatadesc}",
676 diff->origin, i, fqdn, ttl, &rclass, &rdt);
677 }
678
679 bool canonize = TRUE;
680
681 for(int j = 0; j <= ptr_vector_last_index(keys); ++j)
682 {
683 const dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, j);
684
685 zone_diff_label_rr *rrsig_rr = NULL;
686
687 s32 maxinterval = diff_generate_signature_interval(diff);
688
689 // rrset_to_sign;
690 if(ISOK(ret = dnskey_sign_rrset_with_maxinterval(key, &rrset, canonize, &rrv, maxinterval, (void **) &rrsig_rr)))
691 {
692 canonize = FALSE;
693
694 // add the key to the add set
695
696 rdata_desc rdt = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
697 log_debug("update: %{dnsname}: signed chain rrset %{dnstype} with key %03d %05d: %{dnsname} %i %{dnsclass} %{typerdatadesc}",
698 diff->origin, &rrset_type, dnskey_get_algorithm(key), dnskey_get_tag_const(key),
699 rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_rr->rclass, &rdt
700 );
701
702 rrsig_rr->state |= ZONE_DIFF_RR_VOLATILE;
703 ptr_vector_append(add, rrsig_rr);
704
705 // since we are mapping inside the array and the array could have been replaced by a bigger one ...
706 rrset.data = &add->data[from_offset];
707 }
708 #if DEBUG
709 else
710 {
711 log_debug("update: %{dnsname}: did not sign rrset %{dnstype} with key %03d %05d: %r",
712 diff->origin, &rrset_type, dnskey_get_algorithm(key), dnskey_get_tag_const(key), ret);
713 }
714 #endif
715 }
716 }
717
718 /**
719 * Computes the changes of the chain into a del and an add records vector.
720 *
721 * @param diff
722 * @param origin
723 * @param nttl
724 */
725
dnssec_chain_store_diff(dnssec_chain * dc,zone_diff * diff,ptr_vector * keys,ptr_vector * del,ptr_vector * add)726 void dnssec_chain_store_diff(dnssec_chain *dc, zone_diff *diff, ptr_vector *keys, ptr_vector *del, ptr_vector *add)
727 {
728 // simplify then apply the changes
729
730 // put all the nodes in an array
731
732 ptr_vector nodes;
733
734 ptr_vector_init(&nodes);
735
736 // for every chain
737
738 for(int chain_index = 0; chain_index < dc->chains_count; ++chain_index)
739 {
740 void *chain = dc->chains[chain_index];
741
742 ptr_vector_clear(&nodes);
743
744 // gather all the nodes in the chain in an array
745 // they are inserted in sorted order (ptr_set_iterator does this)
746
747 ptr_set_iterator iter;
748 ptr_set_iterator_init(&dc->chain_diff, &iter);
749 while(ptr_set_iterator_hasnext(&iter))
750 {
751 ptr_node *node = ptr_set_iterator_next_node(&iter);
752 yassert(node->value != NULL);
753 ptr_vector_append(&nodes, node->value);
754 }
755
756 // look in a circular pattern for all the nodes that have the "delete" status
757
758 log_debug("update: %{dnsname}: %i nodes in dnssec chain #%i", diff->origin, ptr_vector_size(&nodes), chain_index);
759
760 if(ptr_vector_size(&nodes) == 0)
761 {
762 continue;
763 }
764
765 #if DEBUG
766 for(int i = 0; i <= ptr_vector_last_index(&nodes); ++i)
767 {
768 void *node = ptr_vector_get_mod(&nodes, i);
769 void *next = (i < ptr_vector_last_index(&nodes))?ptr_vector_get_mod(&nodes, i + 1) : NULL;
770 u8 state = dc->chain->state_get(node);
771
772 format_writer temp_fw_0 = {zone_diff_chain_state_format, &state};
773 log_debug1("update: %{dnsname}: %3i: %02x %w", diff->origin, i, state, &temp_fw_0);
774 dc->chain->publish_log(node, next);
775 }
776 #endif
777
778 int first_begin = -1; // the first chain node at the begin of a change
779 int last_end;
780
781 bool whole_chain = FALSE; // does the operation covers the whole chain
782
783 if(!dc->chain->isempty(chain))
784 {
785 // chain is not empty but may be too small (1 item)
786
787 if(ptr_vector_last_index(&nodes) > 0) // if true, then it has more than one item
788 {
789 int exists = 0;
790 int begin = 0;
791 int end = 0;
792 int both = 0;
793
794 bool prev_does_not_alter_the_chain = FALSE;
795
796 {
797 void *node = ptr_vector_last(&nodes);
798 u8 state = dc->chain->state_get(node);
799
800 if(state & DNSSEC_CHAIN_EXISTS)
801 {
802 ++exists;
803 // if the node exists and is not deleted
804 prev_does_not_alter_the_chain = ((state & (DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_DELETE)) != DNSSEC_CHAIN_DELETE);
805 }
806 else // the node did not exist (and thus will be added, as there is no other reason being here)
807 {
808 prev_does_not_alter_the_chain = FALSE;
809 }
810 }
811
812 // this loop marks nodes with the next field changed
813
814 for(int i = 0; i <= ptr_vector_last_index(&nodes); ++i)
815 {
816 void *node = ptr_vector_get(&nodes, i);
817 u8 state = dc->chain->state_get(node);
818
819 if(state & DNSSEC_CHAIN_BEGIN) // the node exists already in the chain and is the start of an update
820 {
821 first_begin = i;
822 ++begin;
823 }
824
825 if(state & DNSSEC_CHAIN_END) // the node exists already in the chain and is the end of an update
826 {
827 ++end;
828 if(state & DNSSEC_CHAIN_BEGIN) // if it's also the start of an update, some merging will happen
829 {
830 ++both;
831 }
832 }
833
834 bool does_not_alter_the_chain; // as in : the label is not new and is not deleted
835
836 if(state & DNSSEC_CHAIN_EXISTS)
837 {
838 ++exists;
839 // if the node exists and is not deleted
840 does_not_alter_the_chain = ((state & (DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_DELETE)) != DNSSEC_CHAIN_DELETE);
841 }
842 else // the node did not exist (and thus will be added, as there is no other reason being here)
843 {
844 does_not_alter_the_chain = FALSE;
845 }
846
847 if(!does_not_alter_the_chain && prev_does_not_alter_the_chain) // since this one is added and not the previous one, the previous one has to be
848 { // updated
849 void *prev_node = ptr_vector_get_mod(&nodes, i - 1);
850 u8 prev_state = dc->chain->state_get(prev_node);
851 dc->chain->state_set(prev_node, prev_state | (DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_DELETE));
852 }
853
854 prev_does_not_alter_the_chain = does_not_alter_the_chain;
855 }
856
857 int chain_loops = 0;
858
859 if(begin + end == 0)
860 {
861 // the chain is looping on itself, take the first exist and mark it as begin & end
862
863 for(int i = 0; i <= ptr_vector_last_index(&nodes); ++i)
864 {
865 void *node = ptr_vector_get(&nodes, i);
866 u8 state = dc->chain->state_get(node);
867 u8 masked_state = state & (DNSSEC_CHAIN_EXISTS|DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_DELETE);
868 if((masked_state == DNSSEC_CHAIN_EXISTS) ||
869 (masked_state == (DNSSEC_CHAIN_EXISTS | DNSSEC_CHAIN_ADD)) ||
870 (masked_state == (DNSSEC_CHAIN_EXISTS | DNSSEC_CHAIN_ADD | DNSSEC_CHAIN_DELETE)))
871 {
872 dc->chain->state_set(node, state | (DNSSEC_CHAIN_BEGIN|DNSSEC_CHAIN_END));
873 first_begin = i;
874 chain_loops = 1;
875 break;
876 }
877 }
878 }
879 else if((begin == 1) && (end == 1) && (both == 1))
880 {
881 whole_chain = TRUE;
882 }
883
884 yassert(first_begin >= 0);
885
886 last_end = first_begin + ptr_vector_last_index(&nodes) + chain_loops;
887 }
888 else // there is only one item in the chain update
889 {
890 log_debug("update: %{dnsname}: chain #%i update has only one item", diff->origin, chain_index);
891
892 first_begin = 0;
893 last_end = ptr_vector_last_index(&nodes);
894 }
895 }
896 else // chain is empty, we add everything
897 {
898 log_debug("update: %{dnsname}: chain #%i is empty", diff->origin, chain_index);
899
900 first_begin = 0;
901 last_end = ptr_vector_last_index(&nodes);
902 }
903
904 //yassert(dc->chain->isempty(chain) || (first_begin >= 0) || ((first_begin == 0) && (last_end == 0)));
905
906 #if DEBUG
907 for(int i = first_begin; i <= last_end; ++i)
908 {
909 void *node = ptr_vector_get_mod(&nodes, i);
910 u8 state = dc->chain->state_get(node);
911 void *next = ((state & (DNSSEC_CHAIN_BEGIN|DNSSEC_CHAIN_END)) != DNSSEC_CHAIN_END) ? ptr_vector_get_mod(&nodes, i + 1) : NULL;
912
913 format_writer temp_fw_0 = {zone_diff_chain_state_format, &state};
914 log_debug1("update: %{dnsname}: %3i: %02x %w: %p -> %p", diff->origin, i, state, &temp_fw_0, node, next);
915 dc->chain->publish_log(node, next);
916 }
917 #endif
918
919 if(dc->chain->isempty(chain) || whole_chain || ((first_begin == 0) && (last_end == 0)))
920 {
921 // we are processing a new/whole chain, or the chain chain is made of one record
922
923 for(int i = first_begin; i <= last_end; ++i)
924 {
925 int j = i + 1;
926 void *node = ptr_vector_get_mod(&nodes, i);
927 void *node_next = ptr_vector_get_mod(&nodes, j);
928 u8 state = dc->chain->state_get(node);
929
930 if(state & DNSSEC_CHAIN_EXISTS)
931 {
932 if((state & DNSSEC_CHAIN_REMAP) || ((state & (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_ADD)) == (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_ADD)))
933 {
934 #if DEBUG
935 log_debug3("update: %{dnsname}: chain %i state (%02x) del/add", diff->origin, chain_index, state);
936 #endif
937 dc->chain->publish_delete(chain, node, node_next, diff, del);
938 dnssec_chain_store_diff_publish_chain_node(dc, diff, keys, chain, node, node_next, add);
939 }
940 else if(state & DNSSEC_CHAIN_DELETE)
941 {
942 #if DEBUG
943 log_debug3("update: %{dnsname}: chain %i state (%02x) del", diff->origin, chain_index, state);
944 #endif
945 dc->chain->publish_delete(chain, node, node_next, diff, del);
946 }
947 }
948 else
949 {
950 if((state & DNSSEC_CHAIN_EXISTS) == 0)
951 {
952 state &= ~DNSSEC_CHAIN_DELETE; // cannot delete what does not exists
953 if(state & DNSSEC_CHAIN_REMAP)
954 {
955 state &= ~DNSSEC_CHAIN_REMAP; // do not remap, create
956 state |= DNSSEC_CHAIN_ADD;
957 }
958
959 dc->chain->state_set(node, state);
960 }
961
962 if(state & DNSSEC_CHAIN_ADD)
963 {
964 #if DEBUG
965 log_debug3("update: %{dnsname}: chain %i state (%02x) add", diff->origin, chain_index, state);
966 #endif
967 dnssec_chain_store_diff_publish_chain_node(dc, diff, keys, chain, node, node_next, add);
968 }
969 }
970 }
971
972 continue;
973 }
974
975 yassert(first_begin != last_end);
976
977 void *next_did_exist_node = NULL;
978 void *next_will_exist_node = NULL;
979 int next_did_exist_index = -1;
980 int next_will_exist_index = -1;
981
982 for(int i = first_begin; i < last_end; ++i)
983 {
984 void *node = ptr_vector_get_mod(&nodes, i);
985 u8 state = dc->chain->state_get(node);
986
987 if((state & DNSSEC_CHAIN_EXISTS) == 0)
988 {
989 state &= ~DNSSEC_CHAIN_DELETE; // cannot delete what does not exists
990 if(state & DNSSEC_CHAIN_REMAP)
991 {
992 state &= ~DNSSEC_CHAIN_REMAP; // do not remap, create
993 state |= DNSSEC_CHAIN_ADD;
994 }
995
996 dc->chain->state_set(node, state);
997 }
998
999 if(state & (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_REMAP))
1000 {
1001 #if DEBUG
1002 if((state & DNSSEC_CHAIN_EXISTS) == 0)
1003 {
1004 format_writer chain_node_fw;
1005 dc->chain->format_writer_init(node, &chain_node_fw);
1006 format_writer temp_fw_0 = {zone_diff_chain_state_format, &state};
1007 log_err("dnssec-chain: %{dnsname}: chain %i node %w with state %w should be remapped or deleted but does not exist ?",
1008 diff->origin, chain_index, &chain_node_fw, &temp_fw_0);
1009 logger_flush();
1010 }
1011 #endif
1012 yassert(state & DNSSEC_CHAIN_EXISTS); // trips on an empty terminal : the node to delete does not exists.
1013
1014 if(next_did_exist_index <= i)
1015 {
1016 for(int j = i + 1; j <= last_end; ++j)
1017 {
1018 void *next_node = ptr_vector_get_mod(&nodes, j);
1019 u8 next_state = dc->chain->state_get(next_node);
1020 if(next_state & DNSSEC_CHAIN_EXISTS)
1021 {
1022 next_did_exist_node = next_node;
1023 next_did_exist_index = j;
1024 break;
1025 }
1026 }
1027 }
1028
1029 yassert(next_did_exist_index > i);
1030
1031 dc->chain->publish_delete(chain, node, next_did_exist_node, diff, del);
1032 }
1033
1034 switch(state & (DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_EXISTS|DNSSEC_CHAIN_REMAP))
1035 {
1036 case DNSSEC_CHAIN_ADD:
1037 case DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_REMAP:
1038 case DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_EXISTS:
1039 case DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_EXISTS|DNSSEC_CHAIN_REMAP:
1040 case DNSSEC_CHAIN_DELETE|DNSSEC_CHAIN_ADD|DNSSEC_CHAIN_EXISTS|DNSSEC_CHAIN_REMAP:
1041 {
1042 if(next_will_exist_index <= i)
1043 {
1044 for(int j = i + 1; j <= last_end; ++j)
1045 {
1046 void *next_node = ptr_vector_get_mod(&nodes, j);
1047 u8 next_state = dc->chain->state_get(next_node);
1048 if((next_state & DNSSEC_CHAIN_ADD) || ((next_state & (DNSSEC_CHAIN_DELETE | DNSSEC_CHAIN_EXISTS)) == DNSSEC_CHAIN_EXISTS))
1049 {
1050 next_will_exist_node = next_node;
1051 next_will_exist_index = j;
1052 break;
1053 }
1054 }
1055 }
1056
1057 yassert(next_will_exist_index > i);
1058
1059 #if DEBUG
1060 log_debug3("update: %{dnsname}: chain %i state (%02x) publish chain node", diff->origin, chain_index, state);
1061 #endif
1062
1063 dnssec_chain_store_diff_publish_chain_node(dc, diff, keys, chain, node, next_will_exist_node, add);
1064
1065 break;
1066 }
1067 default:
1068 {
1069 break;
1070 }
1071 }
1072 } // for all items in [begin;end[
1073 }
1074
1075 ptr_vector_destroy(&nodes);
1076 }
1077
1078 /**
1079 * Releases the memory used by a chain
1080 */
1081
dnssec_chain_finalize(dnssec_chain * dc)1082 void dnssec_chain_finalize(dnssec_chain *dc)
1083 {
1084 ptr_set_callback_and_destroy(&dc->chain_diff, dc->chain->ptr_set_node_delete_callback);
1085 }
1086
zone_diff_label_rr_compare(const void * node_a,const void * node_b)1087 static int zone_diff_label_rr_compare(const void *node_a, const void *node_b)
1088 {
1089 const zone_diff_label_rr *a = (const zone_diff_label_rr*)node_a;
1090 const zone_diff_label_rr *b = (const zone_diff_label_rr*)node_b;
1091
1092 int d;
1093
1094 d = a->rclass;
1095 d -= b->rclass;
1096
1097 if(d == 0)
1098 {
1099 d = a->rtype;
1100 d -= b->rtype;
1101
1102 if(d == 0)
1103 {
1104 d = dnsname_getdepth(a->fqdn);
1105 d -= dnsname_getdepth(b->fqdn);
1106
1107 if(d == 0)
1108 {
1109 d = dnsname_compare(a->fqdn, b->fqdn);
1110
1111 if(d == 0)
1112 {
1113 u16 len = MIN(a->rdata_size, b->rdata_size);
1114 d = memcmp(a->rdata, b->rdata, len);
1115
1116 if(d == 0)
1117 {
1118 d = a->rdata_size;
1119 d -= b->rdata_size;
1120 }
1121 }
1122 }
1123 }
1124 else
1125 {
1126 // SOA have to be first
1127
1128 if(a->rtype == TYPE_SOA)
1129 {
1130 d = -1;
1131 }
1132 else
1133 {
1134 d = 1;
1135 }
1136 }
1137 }
1138
1139 return d;
1140 }
1141
1142 zone_diff_label_rr *
zone_diff_label_rr_new(const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,void * rdata,u16 rdata_size,bool copy)1143 zone_diff_label_rr_new(const u8 *fqdn, u16 rtype, u16 rclass, s32 ttl, void *rdata, u16 rdata_size, bool copy)
1144 {
1145 zone_diff_label_rr *rr;
1146 ZALLOC_OBJECT_OR_DIE(rr, zone_diff_label_rr, ZDFFLABL_TAG);
1147 rr->fqdn = dnsname_zdup(fqdn);
1148 rr->ttl = ttl;
1149 rr->rtype = rtype;
1150 rr->rclass = rclass;
1151 rr->rdata_size = rdata_size;
1152 if(copy)
1153 {
1154 ZALLOC_ARRAY_OR_DIE(u8*, rr->rdata, rdata_size, ZDFFLBRR_TAG);
1155 memcpy(rr->rdata, rdata, rdata_size);
1156 rr->state = ZONE_DIFF_RR_RDATA_OWNED;
1157 }
1158 else
1159 {
1160 rr->rdata = rdata;
1161 rr->state = 0;
1162 }
1163 return rr;
1164 }
1165
1166 void
zone_diff_label_rr_init_tmp(zone_diff_label_rr * rr,const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,void * rdata,u16 rdata_size)1167 zone_diff_label_rr_init_tmp(zone_diff_label_rr *rr, const u8 *fqdn, u16 rtype, u16 rclass, s32 ttl, void *rdata, u16 rdata_size)
1168 {
1169 rr->fqdn = (u8*)fqdn;
1170 rr->ttl = ttl;
1171 rr->rtype = rtype;
1172 rr->rclass = rclass;
1173 rr->rdata_size = rdata_size;
1174 rr->rdata = rdata;
1175 rr->state = 0;
1176 }
1177
1178 zone_diff_label_rr *
zone_diff_label_rr_new_nordata(const u8 * fqdn,u16 rtype,u16 rclass,s32 ttl,u16 rdata_size)1179 zone_diff_label_rr_new_nordata(const u8 *fqdn, u16 rtype, u16 rclass, s32 ttl, u16 rdata_size)
1180 {
1181 zone_diff_label_rr *rr;
1182 ZALLOC_OBJECT_OR_DIE(rr, zone_diff_label_rr, ZDFFLABL_TAG);
1183 rr->fqdn = dnsname_zdup(fqdn);
1184 rr->ttl = ttl;
1185 rr->rtype = rtype;
1186 rr->rclass = rclass;
1187 rr->rdata_size = rdata_size;
1188 ZALLOC_ARRAY_OR_DIE(u8*, rr->rdata, rdata_size, ZDFFLBRR_TAG);
1189 rr->state = ZONE_DIFF_RR_RDATA_OWNED;
1190
1191 return rr;
1192 }
1193
zone_diff_label_rr_delete(zone_diff_label_rr * rr)1194 static void zone_diff_label_rr_delete(zone_diff_label_rr *rr)
1195 {
1196 dnsname_zfree(rr->fqdn);
1197
1198 if(rr->state & ZONE_DIFF_RR_RDATA_OWNED)
1199 {
1200 #if DEBUG
1201 memset(rr->rdata, 0xff, rr->rdata_size);
1202 #endif
1203 ZFREE_ARRAY(rr->rdata, rr->rdata_size);
1204 }
1205 #if DEBUG
1206 memset(rr, 0xff, sizeof(zone_diff_label_rr));
1207 #endif
1208 ZFREE_OBJECT(rr);
1209 }
1210
zone_diff_label_rr_vector_clear(ptr_vector * records)1211 static void zone_diff_label_rr_vector_clear(ptr_vector *records)
1212 {
1213 for(int i = 0; i <= ptr_vector_last_index(records); ++i)
1214 {
1215 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(records, i);
1216 if((rr->state & ZONE_DIFF_RR_VOLATILE) != 0)
1217 {
1218 zone_diff_label_rr_delete(rr);
1219 }
1220 }
1221 ptr_vector_clear(records);
1222 }
1223
zone_diff_fqdn_rr_set_new(u16 rtype)1224 zone_diff_fqdn_rr_set *zone_diff_fqdn_rr_set_new(u16 rtype)
1225 {
1226 zone_diff_fqdn_rr_set *rr_set;
1227 ZALLOC_OBJECT_OR_DIE(rr_set, zone_diff_fqdn_rr_set, ZDFFRRST_TAG);
1228 ptr_set_init(&rr_set->rr);
1229 rr_set->rr.compare = zone_diff_label_rr_compare;
1230 rr_set->key_mask = 0;
1231 rr_set->org_ttl = -1;
1232 rr_set->new_ttl = -1;
1233 rr_set->rtype = rtype;
1234 rr_set->rclass = CLASS_IN;
1235 return rr_set;
1236 }
1237
zone_diff_fqdn_rr_set_delete_cb(ptr_node * node)1238 static void zone_diff_fqdn_rr_set_delete_cb(ptr_node *node)
1239 {
1240 zone_diff_label_rr *rr = (zone_diff_label_rr*)node->value;
1241 #if DEBUG
1242 log_debug7("update: %{dnsname}: deleting %{dnstype} structure", rr->fqdn, &rr->rtype);
1243 #endif
1244 zone_diff_label_rr_delete(rr);
1245 }
1246
zone_diff_fqdn_rr_set_delete(zone_diff_fqdn_rr_set * rr_set)1247 static void zone_diff_fqdn_rr_set_delete(zone_diff_fqdn_rr_set *rr_set)
1248 {
1249 if(rr_set != NULL)
1250 {
1251 ptr_set_callback_and_destroy(&rr_set->rr, zone_diff_fqdn_rr_set_delete_cb);
1252 ZFREE_OBJECT(rr_set);
1253 }
1254 }
1255
zone_diff_fqdn_rr_set_rr_add_replace(zone_diff_fqdn_rr_set * rr_set,zone_diff_label_rr * rr)1256 void zone_diff_fqdn_rr_set_rr_add_replace(zone_diff_fqdn_rr_set *rr_set, zone_diff_label_rr *rr)
1257 {
1258 ptr_node *node = ptr_set_insert(&rr_set->rr, rr);
1259
1260 if(node->value == NULL)
1261 {
1262 node->value = rr;
1263 }
1264 else
1265 {
1266 zone_diff_label_rr_delete((zone_diff_label_rr*)node->value);
1267 node->key = rr;
1268 node->value = rr;
1269 }
1270 }
1271
1272 zone_diff_label_rr*
zone_diff_fqdn_rr_set_rr_add_get(zone_diff_fqdn_rr_set * rr_set,zone_diff_label_rr * rr)1273 zone_diff_fqdn_rr_set_rr_add_get(zone_diff_fqdn_rr_set *rr_set, zone_diff_label_rr *rr)
1274 {
1275 ptr_node *node = ptr_set_insert(&rr_set->rr, rr);
1276
1277 if(node->value == NULL)
1278 {
1279 node->value = rr;
1280 }
1281 else
1282 {
1283 zone_diff_label_rr_delete(rr);
1284 rr = (zone_diff_label_rr*)node->value;
1285 }
1286 return rr;
1287 }
1288
1289 static zone_diff_label_rr *
zone_diff_fqdn_rr_set_get_existing_rr(zone_diff_fqdn_rr_set * rr_set,const zone_diff_label_rr * rr)1290 zone_diff_fqdn_rr_set_get_existing_rr(zone_diff_fqdn_rr_set *rr_set, const zone_diff_label_rr *rr)
1291 {
1292 ptr_node *node = ptr_set_find(&rr_set->rr, rr);
1293
1294 if(node != NULL)
1295 {
1296 return (zone_diff_label_rr*)node->value;
1297 }
1298
1299 return NULL;
1300 }
1301
1302 //
1303
zone_diff_fqdn_new(const u8 * fqdn)1304 static zone_diff_fqdn *zone_diff_fqdn_new(const u8 *fqdn)
1305 {
1306 zone_diff_fqdn *diff_fqdn;
1307 ZALLOC_OBJECT_OR_DIE(diff_fqdn, zone_diff_fqdn, ZDFFFQDN_TAG);
1308 memset(diff_fqdn, 0, sizeof(zone_diff_fqdn));
1309 u32_set_init(&diff_fqdn->rrset);
1310 diff_fqdn->fqdn = dnsname_zdup(fqdn);
1311 //diff_fqdn->type_map_changed = FALSE;
1312 return diff_fqdn;
1313 }
1314
zone_diff_fqdn_delete_cb(u32_node * node)1315 static void zone_diff_fqdn_delete_cb(u32_node *node)
1316 {
1317 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)node->value;
1318 #if DEBUG
1319 if(rrset == NULL)
1320 {
1321 u16 rtype = (u16)node->key;
1322 log_debug1("zone_diff_fqdn_delete_cb empty set for type %{dnstype}", &rtype);
1323 }
1324 #endif
1325 zone_diff_fqdn_rr_set_delete(rrset);
1326 }
1327
zone_diff_fqdn_delete(zone_diff_fqdn * diff_fqdn)1328 static void zone_diff_fqdn_delete(zone_diff_fqdn *diff_fqdn)
1329 {
1330 u32_set_callback_and_destroy(&diff_fqdn->rrset, zone_diff_fqdn_delete_cb);
1331
1332 #if DEBUG
1333 log_debug1("update: %{dnsname}: deleting diff fqdn", diff_fqdn->fqdn);
1334 #endif
1335 dnsname_zfree(diff_fqdn->fqdn);
1336 ZFREE_OBJECT(diff_fqdn);
1337 }
1338
1339 zone_diff_fqdn_rr_set*
zone_diff_fqdn_rr_set_add(zone_diff_fqdn * diff_fqdn,u16 rtype)1340 zone_diff_fqdn_rr_set_add(zone_diff_fqdn *diff_fqdn, u16 rtype)
1341 {
1342 u32_node *node = u32_set_insert(&diff_fqdn->rrset, rtype);
1343 if(node->value == NULL)
1344 {
1345 node->value = zone_diff_fqdn_rr_set_new(rtype);
1346 }
1347 return (zone_diff_fqdn_rr_set*)node->value;
1348 }
1349
1350 /**
1351 * Returns the local copy of the specified RRSET
1352 * Creates an emtpy set if it does not exist.
1353 *
1354 * @param diff_fqdn
1355 * @param rtype
1356 * @return
1357 */
1358
1359 zone_diff_fqdn_rr_set *
zone_diff_fqdn_rr_set_get(const zone_diff_fqdn * diff_fqdn,u16 rtype)1360 zone_diff_fqdn_rr_set_get(const zone_diff_fqdn *diff_fqdn, u16 rtype)
1361 {
1362 #if 0 /* fix */
1363 #else
1364 u32_node *node = u32_set_find(&diff_fqdn->rrset, rtype);
1365 if(node != NULL)
1366 {
1367 return (zone_diff_fqdn_rr_set*)node->value;
1368 }
1369 return NULL;
1370 #endif
1371 }
1372
1373 /**
1374 * Returns the local copy of the specified RRSET
1375 *
1376 * @param diff_fqdn
1377 * @param rtype
1378 * @return
1379 */
1380
zone_diff_fqdn_rr_get_const(const zone_diff_fqdn * diff_fqdn,u16 rtype)1381 const zone_diff_fqdn_rr_set *zone_diff_fqdn_rr_get_const(const zone_diff_fqdn *diff_fqdn, u16 rtype)
1382 {
1383 u32_node *node = u32_set_find(&diff_fqdn->rrset, rtype);
1384
1385 if(node != NULL)
1386 {
1387 return (zone_diff_fqdn_rr_set*)node->value;
1388 }
1389
1390 return NULL;
1391 }
1392
1393 s32
zone_diff_fqdn_rr_set_get_ttl(zone_diff_fqdn_rr_set * rrset)1394 zone_diff_fqdn_rr_set_get_ttl(zone_diff_fqdn_rr_set *rrset)
1395 {
1396 // @note 20170228 edf -- issue detection
1397 // If this aborts, it's likely somebody called zone_diff_fqdn_rr_get without
1398 // the intent of putting records in it.
1399 // Find it and call zone_diff_will_have_rrset_type instead.
1400 yassert(rrset != NULL);
1401
1402 ptr_set_iterator rr_iter;
1403 ptr_set_iterator_init(&rrset->rr, &rr_iter);
1404 while(ptr_set_iterator_hasnext(&rr_iter))
1405 {
1406 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
1407 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
1408
1409 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0)
1410 {
1411 // this record was present or is being added
1412 return rr->ttl;
1413 }
1414 }
1415
1416 return -1;
1417 }
1418
1419 s32
zone_diff_fqdn_rr_get_ttl(const zone_diff_fqdn * diff_fqdn,u16 rtype)1420 zone_diff_fqdn_rr_get_ttl(const zone_diff_fqdn *diff_fqdn, u16 rtype)
1421 {
1422 s32 ttl = -1;
1423 u32_node *rrset_node = u32_set_find(&diff_fqdn->rrset, rtype);
1424 if(rrset_node != NULL)
1425 {
1426 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)rrset_node->value;
1427 ttl = zone_diff_fqdn_rr_set_get_ttl(rrset);
1428 }
1429 return ttl; // TTL is signed, 32 bits and >= 0
1430 }
1431
1432 /**
1433 * Deletes an RRSET if it's empty.
1434 *
1435 * @param diff_fqdn
1436 * @param rtype
1437 */
1438
1439 void
zone_diff_fqdn_rr_clear(zone_diff_fqdn * diff_fqdn,u16 rtype)1440 zone_diff_fqdn_rr_clear(zone_diff_fqdn *diff_fqdn, u16 rtype)
1441 {
1442 u32_node *node = u32_set_insert(&diff_fqdn->rrset, rtype);
1443 if(node != NULL)
1444 {
1445 if(node->value == NULL)
1446 {
1447 u32_set_delete(&diff_fqdn->rrset, rtype);
1448 }
1449 }
1450 }
1451
1452 /**
1453 * Returns TRUE iff an rrset as been added or removed from the label.
1454 * Stressing out this concerns RRSET as a whole.
1455 *
1456 * @param diff_fqdn
1457 * @return
1458 */
1459
zone_diff_fqdn_type_map_changed(const zone_diff_fqdn * diff_fqdn)1460 bool zone_diff_fqdn_type_map_changed(const zone_diff_fqdn *diff_fqdn)
1461 {
1462 if(diff_fqdn->rrsig_kept == 0)
1463 {
1464 if(diff_fqdn->rrsig_added || diff_fqdn->rrsig_removed)
1465 {
1466 return TRUE; // RRSIG type bitmap has changed;
1467 }
1468 }
1469
1470 u32_set_iterator iter;
1471 ptr_set_iterator rr_iter;
1472
1473 u32_set_iterator_init(&diff_fqdn->rrset, &iter);
1474 while(u32_set_iterator_hasnext(&iter))
1475 {
1476 u32_node *node = u32_set_iterator_next_node(&iter);
1477 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)node->value;
1478 if(rrset != NULL)
1479 {
1480 ptr_set_iterator_init(&rrset->rr, &rr_iter);
1481 u8 rr_state = 0;
1482 while(ptr_set_iterator_hasnext(&rr_iter))
1483 {
1484 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
1485 zone_diff_label_rr *rr = (zone_diff_label_rr *)rr_node->key;
1486
1487 if(rr->state == 0)
1488 {
1489 // previously existing record : no change on this set
1490 rr_state = 0;
1491 break;
1492 }
1493
1494 rr_state |= rr->state & (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD);
1495 }
1496
1497 if((rr_state != 0) && ((rr_state & (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD)) != (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD)))
1498 {
1499 // this set is completely added or completely removed
1500
1501 if(rrset->rtype != TYPE_RRSIG) // exceptional test
1502 {
1503 return TRUE;
1504 }
1505 else
1506 {
1507 if(!diff_fqdn->is_apex)
1508 {
1509 if(diff_fqdn->has_active_zsk)
1510 {
1511 rr_state |= ZONE_DIFF_RR_ADD;
1512
1513 if((rr_state != 0) && ((rr_state & (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD)) != (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD)))
1514 {
1515 return TRUE;
1516 }
1517 }
1518 }
1519 else
1520 {
1521 if(diff_fqdn->has_active_zsk||diff_fqdn->has_active_ksk)
1522 {
1523 rr_state |= ZONE_DIFF_RR_ADD;
1524
1525 if((rr_state != 0) && ((rr_state & (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD)) != (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADD)))
1526 {
1527 return TRUE;
1528 }
1529 }
1530 }
1531 }
1532 }
1533 }
1534 }
1535
1536 return FALSE;
1537 }
1538
1539 /**
1540 * Initialises a zone diff
1541 *
1542 * @param diff
1543 * @param origin
1544 * @param nttl
1545 */
1546
zone_diff_init(zone_diff * diff,zdb_zone * zone,bool rrsig_update_allowed)1547 void zone_diff_init(zone_diff *diff, zdb_zone *zone, bool rrsig_update_allowed)
1548 {
1549 log_debug1("update: %{dnsname}: initialising diff @%p", zone->origin, diff);
1550
1551 ptr_set_init(&diff->fqdn);
1552 ptr_set_init(&diff->root.sub);
1553 diff->root.sub.compare = ptr_set_dnslabel_node_compare;
1554 diff->fqdn.compare = ptr_set_fqdn_node_compare;
1555 diff->origin = zone->origin;
1556
1557 diff->rrsig_validity_interval = MAX(zone->sig_validity_interval_seconds, 0);
1558 diff->rrsig_validity_regeneration = MAX(zone->sig_validity_regeneration_seconds, 0);
1559 diff->rrsig_validity_jitter = MAX( zone->sig_validity_jitter_seconds, 0);
1560 diff->nttl = zone->min_ttl;
1561 diff->rrsig_update_allowed = rrsig_update_allowed;
1562 diff->has_active_zsk = FALSE;
1563 diff->has_active_ksk = FALSE;
1564
1565 u8 maintain_mode = zone_get_maintain_mode(zone);
1566
1567 switch(maintain_mode)
1568 {
1569 case ZDB_ZONE_MAINTAIN_NSEC3:
1570 case ZDB_ZONE_MAINTAIN_NSEC3_OPTOUT:
1571 {
1572 diff->maintain_nsec = FALSE;
1573 diff->maintain_nsec3 = TRUE;
1574 break;
1575 }
1576 case ZDB_ZONE_MAINTAIN_NSEC:
1577 {
1578 diff->maintain_nsec = TRUE;
1579 diff->maintain_nsec3 = FALSE;
1580 break;
1581 }
1582 default:
1583 {
1584 diff->maintain_nsec = FALSE;
1585 diff->maintain_nsec3 = FALSE;
1586 break;
1587 }
1588 }
1589
1590 // NOTE: set the apex at the end of the function
1591
1592 diff->apex = zone_diff_fqdn_add(diff, zone->origin, zone->apex);
1593 }
1594
1595 static zone_diff_label_tree*
zone_diff_label_tree_add_fqdn(zone_diff * diff,const u8 * fqdn)1596 zone_diff_label_tree_add_fqdn(zone_diff *diff, const u8 *fqdn)
1597 {
1598 #if DEBUG
1599 log_debug2("zone-diff: %{dnsname}: label tree add %{dnsname}", diff->origin, fqdn);
1600 #endif
1601
1602 if(fqdn[0] != 0)
1603 {
1604 zone_diff_label_tree *label_node;
1605 ptr_node *label_tree_node;
1606 const u8 *parent_fqdn = fqdn + fqdn[0] + 1;
1607 zone_diff_label_tree *parent = zone_diff_label_tree_add_fqdn(diff, parent_fqdn);
1608
1609 label_tree_node = ptr_set_insert(&parent->sub, (u8*)fqdn);
1610
1611 if(label_tree_node->value != NULL)
1612 {
1613 label_node = (zone_diff_label_tree*)label_tree_node->value;
1614 }
1615 else
1616 {
1617 ZALLOC_OBJECT_OR_DIE(label_node, zone_diff_label_tree, ZDLABELT_TAG);
1618 label_node->label = fqdn;
1619 label_node->diff_fqdn = zone_diff_fqdn_get(diff, fqdn);
1620 ptr_set_init(&label_node->sub);
1621 label_node->sub.compare = ptr_set_dnslabel_node_compare;
1622 label_tree_node->value = label_node;
1623 }
1624
1625 return label_node;
1626 }
1627 else
1628 {
1629 return &diff->root;
1630 }
1631 }
1632
zone_diff_label_tree_destroy_cb(ptr_node * node)1633 static void zone_diff_label_tree_destroy_cb(ptr_node* node)
1634 {
1635 zone_diff_label_tree* dlt = (zone_diff_label_tree*)node->value;
1636 if(dlt != NULL)
1637 {
1638 if(!ptr_set_isempty(&dlt->sub))
1639 {
1640 ptr_set_callback_and_destroy(&dlt->sub, zone_diff_label_tree_destroy_cb);
1641 }
1642 ZFREE_OBJECT(dlt);
1643 }
1644 }
1645
zone_diff_label_tree_destroy(zone_diff * diff)1646 static void zone_diff_label_tree_destroy(zone_diff *diff)
1647 {
1648 ptr_set_callback_and_destroy(&diff->root.sub, zone_diff_label_tree_destroy_cb);
1649 }
1650
1651 static zone_diff_label_tree*
zone_diff_fqdn_label_find(zone_diff_label_tree * parent,const u8 * fqdn)1652 zone_diff_fqdn_label_find(zone_diff_label_tree* parent, const u8 *fqdn)
1653 {
1654 if(fqdn[0] != 0)
1655 {
1656 parent = zone_diff_fqdn_label_find(parent, fqdn + fqdn[0] + 1);
1657 if(parent != NULL)
1658 {
1659 ptr_node *node = ptr_set_find(&parent->sub, fqdn);
1660 parent = (zone_diff_label_tree*)node->value;
1661 }
1662 }
1663 return parent;
1664 }
1665
1666 bool
zone_diff_fqdn_has_children(zone_diff * diff,const u8 * fqdn)1667 zone_diff_fqdn_has_children(zone_diff *diff, const u8 *fqdn)
1668 {
1669 zone_diff_label_tree* parent = &diff->root;
1670 parent = zone_diff_fqdn_label_find(parent, fqdn);
1671 return parent != NULL;
1672 }
1673
1674 //#define ZONE_DIFF_FQDN_LABEL_STATE_RECORDS_EXISTED 1
1675 //#define ZONE_DIFF_FQDN_LABEL_STATE_RECORDS_ADDED 2
1676 //#define ZONE_DIFF_FQDN_LABEL_STATE_RECORDS_EXISTS 3
1677 #define ZONE_DIFF_FQDN_LABEL_STATE_NONEMPTY 2
1678 #define ZONE_DIFF_FQDN_LABEL_STATE_CHILDREN 1
1679
1680 static u8
zone_diff_fqdn_children_state_find(zone_diff_label_tree * parent)1681 zone_diff_fqdn_children_state_find(zone_diff_label_tree* parent)
1682 {
1683 u8 ret;
1684
1685 if(parent->diff_fqdn != NULL)
1686 {
1687 ret = parent->diff_fqdn->is_apex;
1688
1689 if(parent->diff_fqdn->children_flags_set)
1690 {
1691 ret |= parent->diff_fqdn->will_be_non_empty | parent->diff_fqdn->will_have_children;
1692 #if DYNUPDATE_DIFF_DETAILED_LOG
1693 log_debug3("zone_diff_fqdn_children_state_find(%{dnsname}) = %x (already known)", parent->diff_fqdn->fqdn, ret);
1694 #endif
1695 return ret;
1696 }
1697 }
1698 else
1699 {
1700 ret = 0;
1701 }
1702
1703 ptr_set_iterator iter;
1704 ptr_set_iterator_init(&parent->sub, &iter);
1705 while(ptr_set_iterator_hasnext(&iter))
1706 {
1707 ptr_node* node = ptr_set_iterator_next_node(&iter);
1708
1709 zone_diff_label_tree* fqdn_node = (zone_diff_label_tree*)node->value;
1710
1711 if(fqdn_node->diff_fqdn != NULL)
1712 {
1713 if(!fqdn_node->diff_fqdn->children_flags_set)
1714 {
1715 if(!ptr_set_isempty(&fqdn_node->sub))
1716 {
1717 if(zone_diff_fqdn_children_state_find(fqdn_node) != 0)
1718 {
1719 // ret |= ZONE_DIFF_FQDN_LABEL_STATE_CHILDREN;
1720
1721 fqdn_node->diff_fqdn->will_have_children = 1;
1722 }
1723 }
1724
1725 fqdn_node->diff_fqdn->children_flags_set = 1;
1726 }
1727
1728 ret |= fqdn_node->diff_fqdn->will_be_non_empty | fqdn_node->diff_fqdn->will_have_children;
1729 }
1730 else
1731 {
1732 if(!ptr_set_isempty(&fqdn_node->sub))
1733 {
1734 if(zone_diff_fqdn_children_state_find(fqdn_node) != 0)
1735 {
1736 ret |= ZONE_DIFF_FQDN_LABEL_STATE_CHILDREN;
1737 }
1738 }
1739 }
1740 }
1741
1742 #if DYNUPDATE_DIFF_DETAILED_LOG
1743 log_debug3("zone_diff_fqdn_children_state_find(%{dnsname}) = %x", parent->diff_fqdn->fqdn, ret);
1744 #endif
1745
1746 return ret;
1747 }
1748
1749 u8
zone_diff_fqdn_children_state(zone_diff * diff,const u8 * fqdn)1750 zone_diff_fqdn_children_state(zone_diff *diff, const u8 *fqdn)
1751 {
1752 zone_diff_label_tree* fqdn_node = zone_diff_fqdn_label_find(&diff->root, fqdn);
1753
1754 if(fqdn_node != NULL)
1755 {
1756 /*
1757 zone_diff_fqdn_children_state_parm parms;
1758 int fqdn_len = dnsname_len(fqdn);
1759 parms.fqdn = &parms.fqdn_storage[256 - fqdn_len];
1760 memcpy(parms.fqdn, fqdn, fqdn_len);
1761 */
1762 // if node has sub, set it
1763 // for all sub
1764 // if sub has all records removed, set it
1765 // if sub has records added, set it
1766 // if +- are both set, stop seeking (all needed answers are ready)
1767 // if sub has sub, go deeper
1768
1769 zone_diff_fqdn_children_state_find(fqdn_node);
1770 }
1771
1772 return 0;
1773 }
1774
1775 /**
1776 * Finalises a zone diff
1777 *
1778 * @param diff
1779 */
1780
zone_diff_finalize_cb(ptr_node * node)1781 static void zone_diff_finalize_cb(ptr_node *node)
1782 {
1783 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)node->value;
1784 zone_diff_fqdn_delete(diff_fqdn);
1785 }
1786
zone_diff_finalize(zone_diff * diff)1787 void zone_diff_finalize(zone_diff *diff)
1788 {
1789 log_debug1("update: %{dnsname}: deleting diff @%p", diff->origin, diff);
1790 zone_diff_label_tree_destroy(diff);
1791 ptr_set_callback_and_destroy(&diff->fqdn, zone_diff_finalize_cb);
1792 }
1793
1794 zone_diff_fqdn*
zone_diff_fqdn_add_empty(zone_diff * diff,const u8 * fqdn)1795 zone_diff_fqdn_add_empty(zone_diff *diff, const u8 *fqdn)
1796 {
1797 ptr_node *node = ptr_set_insert(&diff->fqdn, (u8*)fqdn);
1798
1799 if(node->value == NULL)
1800 {
1801 #if DEBUG
1802 log_debug2("update: %{dnsname} ...", fqdn);
1803 #endif
1804
1805 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_new(fqdn);
1806 node->key = diff_fqdn->fqdn; // to guarantee the const
1807 node->value = diff_fqdn;
1808 }
1809
1810 return (zone_diff_fqdn*)node->value;
1811 }
1812
1813 /**
1814 * label will be replaced ...
1815 *
1816 * @param diff
1817 * @param fqdn
1818 * @param label
1819 * @return
1820 */
1821
1822 zone_diff_fqdn*
zone_diff_fqdn_add(zone_diff * diff,const u8 * fqdn,zdb_rr_label * label)1823 zone_diff_fqdn_add(zone_diff *diff, const u8 *fqdn, zdb_rr_label *label)
1824 {
1825 ptr_node *node = ptr_set_insert(&diff->fqdn, (u8*)fqdn);
1826
1827 if(node->value == NULL)
1828 {
1829 #if DEBUG
1830 log_debug2("update: %{dnsname} (%p) ...", fqdn, label);
1831 #endif
1832
1833 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_new(fqdn);
1834 node->key = diff_fqdn->fqdn; // to guarantee the const
1835 node->value = diff_fqdn;
1836
1837 zone_diff_label_tree *diff_fqdn_label = zone_diff_label_tree_add_fqdn(diff, diff_fqdn->fqdn);
1838 diff_fqdn_label->diff_fqdn = diff_fqdn;
1839
1840 // copy all records
1841 if(label != NULL)
1842 {
1843 diff_fqdn->is_apex = zdb_rr_label_is_apex(label);
1844 diff_fqdn->at_delegation = ZDB_LABEL_ATDELEGATION(label);
1845 diff_fqdn->under_delegation = ZDB_LABEL_UNDERDELEGATION(label);
1846 diff_fqdn->had_ds = zdb_rr_label_has_rrset(label, TYPE_DS);
1847 diff_fqdn->was_at_delegation = diff_fqdn->at_delegation;
1848 diff_fqdn->was_under_delegation = diff_fqdn->under_delegation;
1849 diff_fqdn->was_non_empty = btree_notempty(label->resource_record_set);
1850 diff_fqdn->had_children = dictionary_notempty(&label->sub);
1851 //diff_fqdn->will_be_non_empty = diff_fqdn->was_non_empty;
1852 diff_fqdn->will_have_children = diff_fqdn->is_apex;
1853 diff_fqdn->will_have_ds = diff_fqdn->had_ds;
1854 diff_fqdn->children_added = 0;
1855
1856 diff_fqdn->has_active_zsk = diff->has_active_zsk;
1857 diff_fqdn->has_active_ksk = diff->has_active_ksk;
1858
1859 diff_fqdn->is_in_database = 1;
1860
1861 btree_iterator iter;
1862 btree_iterator_init(label->resource_record_set, &iter);
1863
1864 while(btree_iterator_hasnext(&iter))
1865 {
1866 btree_node *rr_node = btree_iterator_next_node(&iter);
1867 u16 type = (u16)rr_node->hash;
1868
1869 #if DEBUG
1870 log_debug2("update: %{dnsname} (%p) copying %{dnstype} RRSET", fqdn, label, &type);
1871 #endif
1872
1873 zone_diff_fqdn_rr_set *rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, type);
1874
1875 zdb_packed_ttlrdata *rr_sll = (zdb_packed_ttlrdata*)rr_node->data;
1876 yassert(rr_sll != NULL);
1877
1878 if(rr_set->org_ttl == -1)
1879 {
1880 rr_set->org_ttl = rr_sll->ttl;
1881 }
1882
1883 rr_set->new_ttl = rr_sll->ttl;
1884
1885 do
1886 {
1887 zone_diff_label_rr *rr = zone_diff_label_rr_new(fqdn, type, CLASS_IN, rr_sll->ttl, ZDB_PACKEDRECORD_PTR_RDATAPTR(rr_sll), ZDB_PACKEDRECORD_PTR_RDATASIZE(rr_sll), FALSE);
1888 rr->state |= ZONE_DIFF_RR_IN_ZONE;
1889 /** rr = */ zone_diff_fqdn_rr_set_rr_add_replace(rr_set, rr); /// NOTE: there should not be any collision here
1890 rr_sll = rr_sll->next;
1891 }
1892 while(rr_sll != NULL);
1893 }
1894 }
1895 else
1896 {
1897 #if DEBUG
1898 log_debug2("update: %{dnsname} (%p) label is not in the zone", fqdn, label);
1899 #endif
1900 /*
1901 diff_fqdn->is_apex = FALSE;
1902 diff_fqdn->at_delegation = FALSE;
1903 diff_fqdn->under_delegation = FALSE;
1904 diff_fqdn->will_have_ds = FALSE;
1905 diff_fqdn->was_at_delegation = FALSE;
1906 diff_fqdn->was_under_delegation = FALSE;
1907 diff_fqdn->had_ds = FALSE;
1908 diff_fqdn->was_non_empty = FALSE;
1909 */
1910 }
1911 }
1912 #if DEBUG
1913 else
1914 {
1915 log_debug2("update: %{dnsname} (%p) already known (add)", fqdn, label);
1916 }
1917 #endif
1918
1919 return (zone_diff_fqdn*)node->value;
1920 }
1921
1922 #if ZDB_HAS_NSEC3_SUPPORT
1923 zone_diff_fqdn*
zone_diff_add_nsec3(zone_diff * diff,const nsec3_zone * n3,const nsec3_node * item,s32 ttl,zone_diff_fqdn_rr_set ** out_nsec3_rrset)1924 zone_diff_add_nsec3(zone_diff *diff, const nsec3_zone* n3, const nsec3_node *item, s32 ttl, zone_diff_fqdn_rr_set **out_nsec3_rrset)
1925 {
1926 u8 digest_len = NSEC3_NODE_DIGEST_SIZE(item);
1927 u8 fqdn[MAX_DOMAIN_LENGTH];
1928
1929 fqdn[0] = base32hex_encode(NSEC3_NODE_DIGEST_PTR(item), digest_len, (char*)&fqdn[1]);
1930 dnsname_copy(&fqdn[fqdn[0] + 1], diff->origin);
1931
1932 ptr_node *node = ptr_set_insert(&diff->fqdn, fqdn);
1933
1934 if(node->value == NULL)
1935 {
1936 #if DEBUG
1937 log_debug2("update: %{dnsname} (%p) ...", fqdn, item);
1938 #endif
1939
1940 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_new(fqdn);
1941 node->key = diff_fqdn->fqdn; // to guarantee the const
1942 node->value = diff_fqdn;
1943
1944 zone_diff_label_tree *diff_fqdn_label = zone_diff_label_tree_add_fqdn(diff, diff_fqdn->fqdn);
1945 diff_fqdn_label->diff_fqdn = diff_fqdn;
1946
1947 // copy all records
1948 //diff_fqdn->is_apex = 0;
1949 //diff_fqdn->at_delegation = 0;
1950 //diff_fqdn->under_delegation = 0;
1951 //diff_fqdn->will_have_ds = 0;
1952 //diff_fqdn->was_at_delegation = 0;
1953 //diff_fqdn->was_under_delegation = 0;
1954 //diff_fqdn->had_ds = 0;
1955 diff_fqdn->was_non_empty = 1;
1956 //diff_fqdn->had_children = 0;
1957 //diff_fqdn->will_have_children = 0;
1958 //diff_fqdn->children_added = 0;
1959 diff_fqdn->is_nsec3 = 1;
1960
1961 diff_fqdn->has_active_zsk = diff->has_active_zsk;
1962 diff_fqdn->has_active_ksk = diff->has_active_ksk;
1963
1964 #if DEBUG
1965 log_debug2("update: %{dnsname} (%p) copying NSEC3 record", fqdn, item);
1966 #endif
1967 u32 param_rdata_size = NSEC3_ZONE_RDATA_SIZE(n3);
1968 u8 hash_len = NSEC3_NODE_DIGEST_SIZE(item);
1969 u32 type_bit_maps_size = item->type_bit_maps_size;
1970
1971 /* Whatever the editor says: rdata_size is used. */
1972 u32 rdata_size = param_rdata_size + 1 + hash_len + type_bit_maps_size;
1973
1974 zone_diff_fqdn_rr_set *nsec3_rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, TYPE_NSEC3);
1975 zone_diff_label_rr *rr = zone_diff_label_rr_new_nordata(fqdn, TYPE_NSEC3, CLASS_IN, ttl, rdata_size);
1976 nsec3_zone_item_to_rdata(n3, item, rr->rdata, rdata_size);
1977
1978 rr->state |= ZONE_DIFF_RR_IN_ZONE;
1979 zone_diff_fqdn_rr_set_rr_add_replace(nsec3_rr_set, rr); /// NOTE: there should not be any collision here
1980 if(out_nsec3_rrset != NULL)
1981 {
1982 *out_nsec3_rrset = nsec3_rr_set;
1983 }
1984
1985 zdb_packed_ttlrdata *nsec3_rrsig_rr_sll = (zdb_packed_ttlrdata*)item->rrsig;
1986
1987 if(nsec3_rrsig_rr_sll != NULL)
1988 {
1989 zone_diff_fqdn_rr_set *nsec3_rrsig_rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, TYPE_RRSIG);
1990
1991 nsec3_rrsig_rr_set->org_ttl = ttl;
1992 nsec3_rrsig_rr_set->new_ttl = ttl;
1993
1994 while(nsec3_rrsig_rr_sll != NULL)
1995 {
1996 zone_diff_label_rr *new_rr = zone_diff_label_rr_new(fqdn, TYPE_RRSIG, CLASS_IN, ttl, ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec3_rrsig_rr_sll), ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec3_rrsig_rr_sll), FALSE);
1997 new_rr->state |= ZONE_DIFF_RR_IN_ZONE;
1998 /** rr = */ zone_diff_fqdn_rr_set_rr_add_replace(nsec3_rrsig_rr_set, new_rr); /// NOTE: there should not be any collision here
1999 nsec3_rrsig_rr_sll = nsec3_rrsig_rr_sll->next;
2000 }
2001 }
2002 }
2003 #if DEBUG
2004 else
2005 {
2006 log_debug2("update: %{dnsname} (%p) already known (add nsec3)", fqdn, item);
2007 }
2008 #endif
2009
2010 return (zone_diff_fqdn*)node->value;
2011 }
2012
2013 zone_diff_fqdn*
zone_diff_add_nsec3_ex(zone_diff * diff,const ptr_vector * zsk_keys,const nsec3_zone * n3,const nsec3_node * item,s32 ttl,zone_diff_fqdn_rr_set ** out_nsec3_rrset,s32 now,s32 regeneration)2014 zone_diff_add_nsec3_ex(zone_diff *diff, const ptr_vector *zsk_keys, const nsec3_zone* n3, const nsec3_node *item, s32 ttl, zone_diff_fqdn_rr_set **out_nsec3_rrset, s32 now, s32 regeneration)
2015 {
2016 u8 digest_len = NSEC3_NODE_DIGEST_SIZE(item);
2017 u8 fqdn[MAX_DOMAIN_LENGTH];
2018
2019 fqdn[0] = base32hex_encode(NSEC3_NODE_DIGEST_PTR(item), digest_len, (char*)&fqdn[1]);
2020 dnsname_copy(&fqdn[fqdn[0] + 1], diff->origin);
2021
2022 ptr_node *node = ptr_set_insert(&diff->fqdn, fqdn);
2023
2024 if(node->value == NULL)
2025 {
2026 #if DEBUG
2027 log_debug2("update: %{dnsname} (%p) ...", fqdn, item);
2028 #endif
2029
2030 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_new(fqdn);
2031 node->key = diff_fqdn->fqdn; // to guarantee the const
2032 node->value = diff_fqdn;
2033
2034 zone_diff_label_tree *diff_fqdn_label = zone_diff_label_tree_add_fqdn(diff, diff_fqdn->fqdn);
2035 diff_fqdn_label->diff_fqdn = diff_fqdn;
2036
2037 // copy all records
2038 //diff_fqdn->is_apex = 0;
2039 //diff_fqdn->at_delegation = 0;
2040 //diff_fqdn->under_delegation = 0;
2041 //diff_fqdn->will_have_ds = 0;
2042 //diff_fqdn->was_at_delegation = 0;
2043 //diff_fqdn->was_under_delegation = 0;
2044 //diff_fqdn->had_ds = 0;
2045 diff_fqdn->was_non_empty = 1;
2046 //diff_fqdn->had_children = 0;
2047 //diff_fqdn->will_have_children = 0;
2048 //diff_fqdn->children_added = 0;
2049 diff_fqdn->is_nsec3 = 1;
2050
2051 diff_fqdn->has_active_zsk = diff->has_active_zsk;
2052 diff_fqdn->has_active_ksk = diff->has_active_ksk;
2053
2054 #if DEBUG
2055 log_debug2("update: %{dnsname} (%p) copying NSEC3 record", fqdn, item);
2056 #endif
2057 u32 param_rdata_size = NSEC3_ZONE_RDATA_SIZE(n3);
2058 u8 hash_len = NSEC3_NODE_DIGEST_SIZE(item);
2059 u32 type_bit_maps_size = item->type_bit_maps_size;
2060
2061 /* Whatever the editor says: rdata_size is used. */
2062 u32 rdata_size = param_rdata_size + 1 + hash_len + type_bit_maps_size;
2063
2064 zone_diff_fqdn_rr_set *nsec3_rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, TYPE_NSEC3);
2065 zone_diff_label_rr *rr = zone_diff_label_rr_new_nordata(fqdn, TYPE_NSEC3, CLASS_IN, ttl, rdata_size);
2066 nsec3_zone_item_to_rdata(n3, item, rr->rdata, rdata_size);
2067
2068 rr->state |= ZONE_DIFF_RR_IN_ZONE;
2069 zone_diff_fqdn_rr_set_rr_add_replace(nsec3_rr_set, rr); /// NOTE: there should not be any collision here
2070 if(out_nsec3_rrset != NULL)
2071 {
2072 *out_nsec3_rrset = nsec3_rr_set;
2073 }
2074
2075 zdb_packed_ttlrdata *nsec3_rrsig_rr_sll = (zdb_packed_ttlrdata*)item->rrsig;
2076
2077 if(nsec3_rrsig_rr_sll != NULL)
2078 {
2079 zone_diff_fqdn_rr_set *nsec3_rrsig_rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, TYPE_RRSIG);
2080
2081 nsec3_rrsig_rr_set->org_ttl = ttl;
2082 nsec3_rrsig_rr_set->new_ttl = ttl;
2083
2084 while(nsec3_rrsig_rr_sll != NULL)
2085 {
2086 zone_diff_label_rr *new_rr = zone_diff_label_rr_new(fqdn, TYPE_RRSIG, CLASS_IN, ttl, ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec3_rrsig_rr_sll), ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec3_rrsig_rr_sll), FALSE);
2087 new_rr->state |= ZONE_DIFF_RR_IN_ZONE;
2088 s32 matching_key_index = -2;
2089 if(rrsig_should_remove_signature_from_rdata(
2090 ZDB_PACKEDRECORD_PTR_RDATAPTR(nsec3_rrsig_rr_sll), ZDB_PACKEDRECORD_PTR_RDATASIZE(nsec3_rrsig_rr_sll),
2091 zsk_keys, now, regeneration, &matching_key_index) /* unnecessary: || (matching_key_index == -1)*/)
2092 {
2093 new_rr->state |= ZONE_DIFF_RR_REMOVE;
2094 }
2095
2096 /** rr = */ zone_diff_fqdn_rr_set_rr_add_replace(nsec3_rrsig_rr_set, new_rr); /// NOTE: there should not be any collision here
2097 nsec3_rrsig_rr_sll = nsec3_rrsig_rr_sll->next;
2098 }
2099 }
2100 }
2101 #if DEBUG
2102 else
2103 {
2104 log_debug2("update: %{dnsname} (%p) already known (add nsec3 ex)", fqdn, item);
2105 }
2106 #endif
2107
2108 return (zone_diff_fqdn*)node->value;
2109 }
2110
2111 #endif // HAS_NSEC3_SUPPORT
2112
2113 zone_diff_fqdn*
zone_diff_add_static_fqdn(zone_diff * diff,const u8 * fqdn,zdb_rr_label * label)2114 zone_diff_add_static_fqdn(zone_diff *diff, const u8 *fqdn, zdb_rr_label *label)
2115 {
2116 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, label);
2117 diff_fqdn->will_be_non_empty = diff_fqdn->was_non_empty;
2118 diff_fqdn->will_have_children = diff_fqdn->had_children;
2119 diff_fqdn->will_have_ds = diff_fqdn->had_ds && diff_fqdn->at_delegation;
2120 if(diff_fqdn->will_have_ds != diff_fqdn->had_ds)
2121 {
2122 // may be looking at a broken zone
2123 // it it only contains DS records (and RRSIG records) then it should be marked empty
2124
2125 btree_iterator iter;
2126 btree_iterator_init(label->resource_record_set, &iter);
2127
2128 while(btree_iterator_hasnext(&iter))
2129 {
2130 btree_node *rr_node = btree_iterator_next_node(&iter);
2131 u16 type = (u16)rr_node->hash;
2132 if((type != TYPE_RRSIG) && (type != TYPE_DS))
2133 {
2134 return diff_fqdn;
2135 }
2136 }
2137
2138 // the label will be emptied by validation later, the the NSEC3 chain doesn't know that yet.
2139
2140 log_warn("update: %{dnsname}: %{dnsname} label only contained DS and RRSIG resource record sets: they will be removed", diff->origin, fqdn);
2141
2142 diff_fqdn->will_be_non_empty = 0;
2143 }
2144 return diff_fqdn;
2145 }
2146
2147 void
zone_diff_add_fqdn_children(zone_diff * diff,const u8 * fqdn,zdb_rr_label * label)2148 zone_diff_add_fqdn_children(zone_diff *diff, const u8 *fqdn, zdb_rr_label *label)
2149 {
2150 dictionary_iterator iter;
2151 u8 sub_fqdn[MAX_DOMAIN_LENGTH];
2152 dictionary_iterator_init(&label->sub, &iter);
2153
2154 while(dictionary_iterator_hasnext(&iter))
2155 {
2156 zdb_rr_label *sub_label = *(zdb_rr_label**)dictionary_iterator_next(&iter);
2157 dnsname_copy(&sub_fqdn[dnslabel_copy(sub_fqdn, sub_label->name)], fqdn);
2158 zone_diff_fqdn *parent = zone_diff_fqdn_add(diff, sub_fqdn, sub_label);
2159 parent->children_added = 1;
2160
2161 if(dictionary_notempty(&sub_label->sub))
2162 {
2163 zone_diff_add_fqdn_children(diff, sub_fqdn, sub_label);
2164 }
2165 }
2166 }
2167
2168 void
zone_diff_add_fqdn_parents_up_to_below_apex(zone_diff * diff,const u8 * fqdn,zdb_zone * zone)2169 zone_diff_add_fqdn_parents_up_to_below_apex(zone_diff *diff, const u8 *fqdn, zdb_zone *zone)
2170 {
2171 size_t origin_len = dnsname_len(diff->origin);
2172 fqdn += fqdn[0] + 1;
2173 while(dnsname_len(fqdn) > origin_len)
2174 {
2175 zdb_rr_label *fqdn_label = zdb_rr_label_find_from_name(zone, fqdn);
2176 zone_diff_fqdn *parent = zone_diff_fqdn_add(diff, fqdn, fqdn_label);
2177 parent->children_added = 1;
2178 fqdn += fqdn[0] + 1;
2179 }
2180 }
2181
2182 /**
2183 * Enables the or_state flags in every record of the set.
2184 *
2185 * @param rrset
2186 * @param or_state
2187 */
2188
2189 void
zone_diff_fqdn_rr_set_set_state(zone_diff_fqdn_rr_set * rrset,u8 or_state)2190 zone_diff_fqdn_rr_set_set_state(zone_diff_fqdn_rr_set *rrset, u8 or_state)
2191 {
2192 ptr_set_iterator rr_iter;
2193 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2194 while(ptr_set_iterator_hasnext(&rr_iter))
2195 {
2196 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2197 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2198 rr->state |= or_state;
2199 }
2200 }
2201
2202 /**
2203 * Returns true iff an rrset of the given type will be present after applying
2204 * the diff.
2205 *
2206 * @param diff_fqdn
2207 * @param rtype
2208 * @return
2209 */
2210
2211 bool
zone_diff_will_have_rrset_type(const zone_diff_fqdn * diff_fqdn,u16 rtype)2212 zone_diff_will_have_rrset_type(const zone_diff_fqdn *diff_fqdn, u16 rtype)
2213 {
2214 u32_node *rrset_node = u32_set_find(&diff_fqdn->rrset, rtype);
2215 if(rrset_node != NULL)
2216 {
2217 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)rrset_node->value;
2218
2219 // @note 20170228 edf -- issue detection
2220 // If this aborts, it's likely somebody called zone_diff_fqdn_rr_get without
2221 // the intent of putting records in it.
2222 // Find it and call zone_diff_will_have_rrset_type instead.
2223 yassert(rrset != NULL);
2224
2225 ptr_set_iterator rr_iter;
2226 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2227 while(ptr_set_iterator_hasnext(&rr_iter))
2228 {
2229 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2230 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2231
2232 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0)
2233 {
2234 // this record was present or is being added
2235 return TRUE;
2236 }
2237 }
2238 }
2239 return FALSE;
2240 }
2241
2242 bool
zone_diff_remove_rrsig_covering_type(zone_diff_fqdn * diff_fqdn,u16 rtype)2243 zone_diff_remove_rrsig_covering_type(zone_diff_fqdn *diff_fqdn, u16 rtype)
2244 {
2245 u32_node *rrsig_rrset_node = u32_set_find(&diff_fqdn->rrset, TYPE_RRSIG);
2246 if(rrsig_rrset_node != NULL)
2247 {
2248 zone_diff_fqdn_rr_set *rrsig_rrset = (zone_diff_fqdn_rr_set*)rrsig_rrset_node->value;
2249
2250 // @note 20170228 edf -- issue detection
2251 // If this aborts, it's likely somebody called zone_diff_fqdn_rr_get without
2252 // the intent of putting records in it.
2253 // Find it and call zone_diff_will_have_rrset_type instead.
2254 yassert(rrsig_rrset != NULL);
2255
2256 ptr_vector to_remove = PTR_VECTOR_EMPTY;
2257
2258 ptr_set_iterator rr_iter;
2259 ptr_set_iterator_init(&rrsig_rrset->rr, &rr_iter);
2260 while(ptr_set_iterator_hasnext(&rr_iter))
2261 {
2262 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2263 zone_diff_label_rr *rr = (zone_diff_label_rr*)node->key;
2264
2265 if(rrsig_get_type_covered_from_rdata(rr->rdata, rr->rdata_size) == rtype)
2266 {
2267 if((rr->state & ZONE_DIFF_RR_IN_ZONE) != 0) // did exist ?
2268 {
2269 // remove
2270 rr->state |= ZONE_DIFF_RR_REMOVE;
2271
2272 log_debug2("update: %{dnsname} RRSIG covering %{dnstype} record will be removed from zone", rr->fqdn, &rtype);
2273 }
2274 else if((rr->state & ZONE_DIFF_RR_ADD) != 0) // was being added ?
2275 {
2276 // remove the entry instead (postponed)
2277 ptr_vector_append(&to_remove, rr);
2278
2279 log_debug2("update: %{dnsname} RRSIG covering %{dnstype} record will not be added to zone", rr->fqdn, &rtype);
2280 }
2281 else
2282 {
2283 //
2284
2285 log_warn("update: %{dnsname} RRSIG covering %{dnstype} record has state %02x, which is not expected", rr->fqdn, &rtype, rr->state);
2286 }
2287 }
2288 }
2289
2290 for(int i = 0; i <= ptr_vector_last_index(&to_remove); ++i)
2291 {
2292 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&to_remove, i);
2293 ptr_set_delete(&rrsig_rrset->rr, rr);
2294 zone_diff_label_rr_delete(rr);
2295 }
2296
2297 if(ptr_set_isempty(&rrsig_rrset->rr))
2298 {
2299 u32_set_delete(&diff_fqdn->rrset, TYPE_RRSIG);
2300 }
2301
2302 ptr_vector_destroy(&to_remove);
2303 }
2304 return FALSE;
2305 }
2306
2307 /**
2308 *
2309 * Removes existing records as well as cancels additions of new ones.
2310 *
2311 * This is called by zone_diff_validate.
2312 * This means there is no rrset_to_sign collection yet.
2313 *
2314 */
2315
2316 bool
zone_diff_remove_rrset_type(zone_diff_fqdn * diff_fqdn,u16 rtype)2317 zone_diff_remove_rrset_type(zone_diff_fqdn *diff_fqdn, u16 rtype)
2318 {
2319 u32_node *rrset_node = u32_set_find(&diff_fqdn->rrset, rtype);
2320 if(rrset_node != NULL)
2321 {
2322 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)rrset_node->value;
2323
2324 // @note 20170228 edf -- issue detection
2325 // If this aborts, it's likely somebody called zone_diff_fqdn_rr_get without
2326 // the intent of putting records in it.
2327 // Find it and call zone_diff_will_have_rrset_type instead.
2328 yassert(rrset != NULL);
2329
2330 ptr_vector to_remove = PTR_VECTOR_EMPTY;
2331
2332 ptr_set_iterator rr_iter;
2333 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2334 while(ptr_set_iterator_hasnext(&rr_iter))
2335 {
2336 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2337 zone_diff_label_rr *rr = (zone_diff_label_rr*)node->key;
2338
2339 if((rr->state & ZONE_DIFF_RR_IN_ZONE) != 0) // did exist ?
2340 {
2341 // remove
2342 rr->state |= ZONE_DIFF_RR_REMOVE;
2343
2344 log_debug2("update: %{dnsname} %{dnstype} record will be removed from zone", rr->fqdn, &rtype);
2345 }
2346 else if((rr->state & ZONE_DIFF_RR_ADD) != 0) // was being added ?
2347 {
2348 // remove the entry instead (postponed)
2349 ptr_vector_append(&to_remove, rr);
2350
2351 log_debug2("update: %{dnsname} %{dnstype} record will not be added to zone", rr->fqdn, &rtype);
2352 }
2353 else
2354 {
2355 //
2356
2357 log_warn("update: %{dnsname} %{dnstype} record has state %02x, which is not expected", rr->fqdn, &rtype, rr->state);
2358 }
2359 }
2360
2361 for(int i = 0; i <= ptr_vector_last_index(&to_remove); ++i)
2362 {
2363 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&to_remove, i);
2364 ptr_set_delete(&rrset->rr, rr);
2365 zone_diff_label_rr_delete(rr);
2366 }
2367
2368 if(ptr_vector_last_index(&to_remove) >= 0)
2369 {
2370 if(ptr_set_isempty(&rrset->rr))
2371 {
2372 u32_set_delete(&diff_fqdn->rrset, rtype);
2373 }
2374
2375 zone_diff_remove_rrsig_covering_type(diff_fqdn, rtype);
2376 }
2377
2378 ptr_vector_destroy(&to_remove);
2379 }
2380 return FALSE;
2381 }
2382
2383 /**
2384 * Returns true iff a DNSKEY with these exact parameters will be present in the zone after the diff.
2385 *
2386 * @param diff_fqdn
2387 * @param algorithm
2388 * @param flags
2389 * @param tag
2390 * @return
2391 */
2392
2393 bool
zone_diff_will_have_dnskey_with_algorithm_flags_tag(const zone_diff_fqdn * diff_fqdn,u8 algorithm,u16 flags,u16 tag)2394 zone_diff_will_have_dnskey_with_algorithm_flags_tag(const zone_diff_fqdn *diff_fqdn, u8 algorithm, u16 flags, u16 tag)
2395 {
2396 u32_node *rrset_node = u32_set_find(&diff_fqdn->rrset, TYPE_DNSKEY);
2397 if(rrset_node != NULL)
2398 {
2399 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)rrset_node->value;
2400
2401 // @note 20170228 edf -- issue detection
2402 // If this aborts, it's likely somebody called zone_diff_fqdn_rr_get without
2403 // the intent of putting records in it.
2404 // Find it and call zone_diff_will_have_rrset_type instead.
2405 yassert(rrset != NULL);
2406
2407 ptr_set_iterator rr_iter;
2408 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2409 while(ptr_set_iterator_hasnext(&rr_iter))
2410 {
2411 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2412 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2413
2414 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0)
2415 {
2416 // this record was present or is being added
2417 if(rr->rdata_size > 3)
2418 {
2419 if(dnskey_get_algorithm_from_rdata(rr->rdata) == algorithm)
2420 {
2421 if(dnskey_get_flags_from_rdata(rr->rdata) == flags)
2422 {
2423 if(dnskey_get_tag_from_rdata(rr->rdata, rr->rdata_size) == tag)
2424 {
2425 return TRUE;
2426 }
2427 }
2428 }
2429 }
2430 }
2431 }
2432 }
2433 return FALSE;
2434 }
2435
2436 /**
2437 * Returns true iff a DNSKEY with these exact parameters will be present in the zone after the diff.
2438 *
2439 * @param diff_fqdn
2440 * @param algorithm
2441 * @param flags
2442 * @param tag
2443 * @return
2444 */
2445
2446 bool
zone_diff_will_have_dnskey_with_algorithm_tag(const zone_diff_fqdn * diff_fqdn,u8 algorithm,u16 tag)2447 zone_diff_will_have_dnskey_with_algorithm_tag(const zone_diff_fqdn *diff_fqdn, u8 algorithm, u16 tag)
2448 {
2449 u32_node *rrset_node = u32_set_find(&diff_fqdn->rrset, TYPE_DNSKEY);
2450 if(rrset_node != NULL)
2451 {
2452 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)rrset_node->value;
2453
2454 // @note 20170228 edf -- issue detection
2455 // If this aborts, it's likely somebody called zone_diff_fqdn_rr_get without
2456 // the intent of putting records in it.
2457 // Find it and call zone_diff_will_have_rrset_type instead.
2458 yassert(rrset != NULL);
2459
2460 ptr_set_iterator rr_iter;
2461 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2462 while(ptr_set_iterator_hasnext(&rr_iter))
2463 {
2464 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2465 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2466
2467 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0)
2468 {
2469 // this record was present or is being added
2470 if(rr->rdata_size > 3)
2471 {
2472 if(dnskey_get_algorithm_from_rdata(rr->rdata) == algorithm)
2473 {
2474 if(dnskey_get_tag_from_rdata(rr->rdata, rr->rdata_size) == tag)
2475 {
2476 return TRUE;
2477 }
2478 }
2479 }
2480 }
2481 }
2482 }
2483 return FALSE;
2484 }
2485
2486 /**
2487 * Releases keys that will not be in the apex after the diff is applied.
2488 *
2489 * @param diff
2490 * @param keys
2491 */
2492
2493 void
zone_diff_filter_out_keys(const zone_diff * diff,ptr_vector * keys)2494 zone_diff_filter_out_keys(const zone_diff *diff, ptr_vector *keys)
2495 {
2496 const zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_get_const(diff, diff->origin);
2497 if(diff_fqdn != NULL)
2498 {
2499 for(int i = 0; i <= ptr_vector_last_index(keys); ++i)
2500 {
2501 dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, i);
2502
2503 #if !DEBUG
2504 if(!dnskey_is_private(key) || !zone_diff_will_have_dnskey_with_algorithm_flags_tag(diff_fqdn,
2505 dnskey_get_algorithm(
2506 key),
2507 dnskey_get_flags(key),
2508 dnskey_get_tag(key)))
2509 {
2510 ptr_vector_end_swap(keys, i);
2511 ptr_vector_pop(keys);
2512 dnskey_release(key);
2513 }
2514 #else
2515 /*if(!dnskey_is_private(key))
2516 {
2517 log_debug3("zone_diff_filter_out_keys: 'K%{dnsname}+%03d+%05hd' is not private", diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
2518
2519 ptr_vector_end_swap(keys, i);
2520 ptr_vector_pop(keys);
2521 dnskey_release(key);
2522 }
2523 else*/ if(!zone_diff_will_have_dnskey_with_algorithm_flags_tag(diff_fqdn, dnskey_get_algorithm(key), dnskey_get_flags(key), dnskey_get_tag(key)))
2524 {
2525 log_debug3("zone_diff_filter_out_keys: 'K%{dnsname}+%03d+%05hd' will not be in the zone", diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
2526
2527 ptr_vector_end_swap(keys, i);
2528 ptr_vector_pop(keys);
2529 dnskey_release(key);
2530 }
2531 #endif
2532 }
2533 }
2534 }
2535
2536 /**
2537 * find label for fqdn ...
2538 *
2539 * @param diff
2540 * @param fqdn
2541 * @param label
2542 * @return
2543 */
2544
2545 const zone_diff_fqdn*
zone_diff_fqdn_get_const(const zone_diff * diff,const u8 * fqdn)2546 zone_diff_fqdn_get_const(const zone_diff *diff, const u8 *fqdn)
2547 {
2548 zone_diff_fqdn *ret = NULL;
2549 ptr_node *node = ptr_set_find(&diff->fqdn, (u8*)fqdn);
2550 if(node != NULL)
2551 {
2552 ret = (zone_diff_fqdn*)node->value;
2553 }
2554 return ret;
2555 }
2556
2557 zone_diff_fqdn*
zone_diff_fqdn_get(const zone_diff * diff,const u8 * fqdn)2558 zone_diff_fqdn_get(const zone_diff *diff, const u8 *fqdn)
2559 {
2560 zone_diff_fqdn *ret = NULL;
2561 ptr_node *node = ptr_set_find(&diff->fqdn, (u8*)fqdn);
2562 if(node != NULL)
2563 {
2564 ret = (zone_diff_fqdn*)node->value;
2565 }
2566 return ret;
2567 }
2568
2569 /**
2570 * Generates a type bit map based on the diff including records matching:
2571 *
2572 * (status & mask) == masked
2573 *
2574 * mask,masked
2575 * all pre records : ZONE_DIFF_REMOVE|ZONE_DIFF_ADD == 0
2576 * all post records: ZONE_DIFF_REMOVE = 0
2577 *
2578 * Note: it ignores A and AAAA records at or under a delegation
2579 *
2580 * @param diff
2581 * @param fqdn
2582 * @param bitmap
2583 * @param mask
2584 * @param masked
2585 * @return
2586 */
2587
2588 u16
zone_diff_type_bit_map_generate(const zone_diff * diff,const u8 * fqdn,type_bit_maps_context * bitmap,u8 mask,u8 masked,const u8 * chain_node_fqdn,bool append_existing_signatures)2589 zone_diff_type_bit_map_generate(const zone_diff *diff, const u8 *fqdn, type_bit_maps_context *bitmap, u8 mask,
2590 u8 masked, const u8 *chain_node_fqdn, bool append_existing_signatures)
2591 {
2592 type_bit_maps_init(bitmap);
2593
2594 const zone_diff_fqdn* zdf = zone_diff_fqdn_get_const(diff, fqdn);
2595
2596 if(zdf != NULL)
2597 {
2598 if(zdf->at_delegation || zdf->under_delegation)
2599 {
2600 ptr_set_iterator rr_iter;
2601 u32_set_iterator iter;
2602 u32_set_iterator_init(&zdf->rrset, &iter);
2603 while(u32_set_iterator_hasnext(&iter))
2604 {
2605 u32_node *node = u32_set_iterator_next_node(&iter);
2606 u16 rtype = (u16)node->key;
2607
2608 if((rtype == TYPE_A) || (rtype == TYPE_AAAA))
2609 {
2610 continue;
2611 }
2612
2613 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)node->value;
2614
2615 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2616 while(ptr_set_iterator_hasnext(&rr_iter))
2617 {
2618 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2619 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2620
2621 if((rr->state & mask) == masked)
2622 {
2623 log_debug1("update: %{dnsname}: %{dnsname}: %x: %{dnstype}", diff->origin, chain_node_fqdn, mask, &rtype);
2624
2625 type_bit_maps_set_type(bitmap, rtype);
2626 break;
2627 }
2628 }
2629 }
2630 }
2631 else
2632 {
2633 ptr_set_iterator rr_iter;
2634 u32_set_iterator iter;
2635 u32_set_iterator_init(&zdf->rrset, &iter);
2636 while(u32_set_iterator_hasnext(&iter))
2637 {
2638 u32_node *node = u32_set_iterator_next_node(&iter);
2639 u16 rtype = (u16)node->key;
2640
2641 zone_diff_fqdn_rr_set *rrset = (zone_diff_fqdn_rr_set*)node->value;
2642
2643 ptr_set_iterator_init(&rrset->rr, &rr_iter);
2644 while(ptr_set_iterator_hasnext(&rr_iter))
2645 {
2646 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2647 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2648
2649 if((rr->state & mask) == masked)
2650 {
2651 log_debug1("update: %{dnsname}: %{dnsname}: %x: %{dnstype}", diff->origin, chain_node_fqdn, mask, &rtype);
2652
2653 type_bit_maps_set_type(bitmap, rtype);
2654 break;
2655 }
2656 }
2657 }
2658 }
2659
2660 if(append_existing_signatures)
2661 {
2662 if((zdf->rrsig_kept == 0) && zdf->rrsig_added)
2663 {
2664 type_bit_maps_set_type(bitmap, TYPE_RRSIG);
2665 }
2666 }
2667 }
2668 else
2669 {
2670 log_debug1("update: %{dnsname}: %{dnsname}: %x: no matching fqdn in the diff", diff->origin, chain_node_fqdn, mask);
2671 }
2672
2673 u16 bitmap_size = type_bit_maps_update_size(bitmap);
2674
2675 return bitmap_size;
2676 }
2677
2678 /**
2679 * Adds a record on a diff
2680 *
2681 *
2682 * @param diff
2683 * @param rr_label
2684 * @param fqdn
2685 * @param rtype
2686 * @param rttl
2687 * @param rdata_size
2688 * @param rdata
2689 */
2690
2691 zone_diff_label_rr*
zone_diff_record_add(zone_diff * diff,zdb_rr_label * rr_label,const u8 * fqdn,u16 rtype,s32 rttl,u16 rdata_size,void * rdata)2692 zone_diff_record_add(zone_diff *diff, zdb_rr_label *rr_label, const u8 *fqdn, u16 rtype, s32 rttl, u16 rdata_size, void *rdata)
2693 {
2694 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, rr_label);
2695 zone_diff_fqdn_rr_set *rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, rtype);
2696 zone_diff_label_rr *rr = zone_diff_label_rr_new(fqdn, rtype, CLASS_IN, rttl, rdata, rdata_size, TRUE);
2697 rr = zone_diff_fqdn_rr_set_rr_add_get(rr_set, rr);
2698
2699 #if DEBUG
2700 rdata_desc rd = {rtype, rdata_size, rdata};
2701 log_debug2("update: %{dnsname}: will add [%02x] %{dnsname} %5i %{typerdatadesc}", diff->origin, rr->state, fqdn, rttl, &rd);
2702 #endif
2703
2704 if( ((rr->state & ZONE_DIFF_RR_IN_ZONE) != 0) && ((rr->state & ZONE_DIFF_RR_REMOVE) != 0) )
2705 {
2706 //rr->state |= ZONE_DIFF_RR_ADD;
2707 rr->state &= ~ZONE_DIFF_RR_REMOVE;
2708 #if DEBUG
2709 log_debug2("update: %{dnsname}: will add [%02x] %{dnsname} %5i %{typerdatadesc} (no add needed, cleared del)", diff->origin, rr->state, fqdn, rttl, &rd);
2710 #endif
2711 }
2712 else if( ((rr->state & ZONE_DIFF_RR_IN_ZONE) == 0) || ((rr->state & ZONE_DIFF_RR_REMOVE) != 0) )
2713 {
2714 rr->state |= ZONE_DIFF_RR_ADD;
2715 #if DEBUG
2716 log_debug2("update: %{dnsname}: will add [%02x] %{dnsname} %5i %{typerdatadesc} (set add)", diff->origin, rr->state, fqdn, rttl, &rd);
2717 #endif
2718 }
2719
2720 return rr;
2721 }
2722
2723 /**
2724 *
2725 * Adds the removal of a specific record on a diff
2726 *
2727 * @param diff
2728 * @param rr_label
2729 * @param fqdn
2730 * @param rtype
2731 * @param rttl
2732 * @param rdata_size
2733 * @param rdata
2734 */
2735
2736 void
zone_diff_record_remove(zone_diff * diff,zdb_rr_label * rr_label,const u8 * fqdn,u16 rtype,s32 rttl,u16 rdata_size,void * rdata)2737 zone_diff_record_remove(zone_diff *diff, zdb_rr_label *rr_label, const u8 *fqdn, u16 rtype, s32 rttl, u16 rdata_size, void *rdata)
2738 {
2739 #if DEBUG
2740 rdata_desc rd = {rtype, rdata_size, rdata};
2741 log_debug2("update: %{dnsname}: will del %{dnsname} %5i %{typerdatadesc}", diff->origin, fqdn, rttl, &rd);
2742 #endif
2743 (void)rttl;
2744 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, rr_label);
2745 zone_diff_fqdn_rr_set *rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, rtype);
2746 zone_diff_label_rr *rr = zone_diff_label_rr_new(fqdn, rtype, CLASS_IN, 0, rdata, rdata_size, TRUE);
2747 rr = zone_diff_fqdn_rr_set_rr_add_get(rr_set, rr);
2748 rr->state |= ZONE_DIFF_RR_REMOVE;
2749 }
2750
2751 bool
zone_diff_record_remove_existing(zone_diff * diff,zdb_rr_label * rr_label,const u8 * fqdn,u16 rtype,s32 rttl,u16 rdata_size,void * rdata)2752 zone_diff_record_remove_existing(zone_diff *diff, zdb_rr_label *rr_label, const u8 *fqdn, u16 rtype, s32 rttl, u16 rdata_size, void *rdata)
2753 {
2754 #if DEBUG
2755 rdata_desc rd = {rtype, rdata_size, rdata};
2756 log_debug2("update: %{dnsname}: will del %{dnsname} %5i %{typerdatadesc}", diff->origin, fqdn, rttl, &rd);
2757 #endif
2758 (void)rttl;
2759 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, rr_label);
2760 zone_diff_fqdn_rr_set *rr_set = zone_diff_fqdn_rr_set_get(diff_fqdn, rtype);
2761 if(rr_set != NULL)
2762 {
2763 zone_diff_label_rr tmp_rr;
2764 zone_diff_label_rr_init_tmp(&tmp_rr, fqdn, rtype, CLASS_IN, 0, rdata, rdata_size);
2765 zone_diff_label_rr *rr = zone_diff_fqdn_rr_set_get_existing_rr(rr_set, &tmp_rr);
2766 if(rr != NULL)
2767 {
2768 rr->state |= ZONE_DIFF_RR_REMOVE;
2769 return TRUE;
2770 }
2771 }
2772
2773 return FALSE;
2774 }
2775
2776 void
zone_diff_record_remove_automated(zone_diff * diff,zdb_rr_label * rr_label,const u8 * fqdn,u16 rtype,s32 rttl,u16 rdata_size,void * rdata)2777 zone_diff_record_remove_automated(zone_diff *diff, zdb_rr_label *rr_label, const u8 *fqdn, u16 rtype, s32 rttl, u16 rdata_size, void *rdata)
2778 {
2779 #if DEBUG
2780 rdata_desc rd = {rtype, rdata_size, rdata};
2781 log_debug2("update: %{dnsname}: will del %{dnsname} %5i %{typerdatadesc}", diff->origin, fqdn, rttl, &rd);
2782 #endif
2783 (void)rttl;
2784 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, rr_label);
2785 zone_diff_fqdn_rr_set *rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, rtype);
2786 zone_diff_label_rr *rr = zone_diff_label_rr_new(fqdn, rtype, CLASS_IN, 0, rdata, rdata_size, TRUE);
2787 rr = zone_diff_fqdn_rr_set_rr_add_get(rr_set, rr);
2788 rr->state |= ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_AUTOMATED;
2789 }
2790
2791 /**
2792 * Adds the removal of a record set on a diff
2793 *
2794 * @param diff
2795 * @param rr_label
2796 * @param fqdn
2797 * @param rtype
2798 */
2799
zone_diff_record_remove_all(zone_diff * diff,zdb_rr_label * rr_label,const u8 * fqdn,u16 rtype)2800 void zone_diff_record_remove_all(zone_diff *diff, zdb_rr_label *rr_label, const u8 *fqdn, u16 rtype)
2801 {
2802 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, rr_label);
2803 zone_diff_fqdn_rr_set *rr_set = zone_diff_fqdn_rr_set_add(diff_fqdn, rtype);
2804
2805 ptr_set_iterator iter;
2806 ptr_set_iterator_init(&rr_set->rr, &iter);
2807 while(ptr_set_iterator_hasnext(&iter))
2808 {
2809 ptr_node *node = ptr_set_iterator_next_node(&iter);
2810 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2811 rr->state |= ZONE_DIFF_RR_REMOVE;
2812 }
2813 }
2814
2815 /**
2816 * Adds the removal all record sets on a diff
2817 *
2818 * @param diff
2819 * @param rr_label
2820 * @param fqdn
2821 * @param rtype
2822 */
2823
2824 void
zone_diff_record_remove_all_sets(zone_diff * diff,zdb_rr_label * rr_label,const u8 * fqdn)2825 zone_diff_record_remove_all_sets(zone_diff *diff, zdb_rr_label *rr_label, const u8 *fqdn)
2826 {
2827 zone_diff_fqdn *diff_fqdn = zone_diff_fqdn_add(diff, fqdn, rr_label);
2828
2829 u32_set_iterator typeiter;
2830 u32_set_iterator_init(&diff_fqdn->rrset, &typeiter);
2831 while(u32_set_iterator_hasnext(&typeiter))
2832 {
2833 u32_node* node = u32_set_iterator_next_node(&typeiter);
2834
2835 yassert((node != NULL) && (node->value != NULL));
2836
2837 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)node->value;
2838
2839 ptr_set_iterator iter;
2840 ptr_set_iterator_init(&rr_set->rr, &iter);
2841 while(ptr_set_iterator_hasnext(&iter))
2842 {
2843 ptr_node *node = ptr_set_iterator_next_node(&iter);
2844 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2845 rr->state |= ZONE_DIFF_RR_REMOVE;
2846 }
2847 }
2848 }
2849
2850 /**
2851 * Adds the SOA records for the incremental update.
2852 *
2853 * @param diff
2854 * @return
2855 */
2856
2857 ya_result
zone_diff_set_soa(zone_diff * diff,zdb_rr_label * label)2858 zone_diff_set_soa(zone_diff *diff, zdb_rr_label *label)
2859 {
2860 /**************************************************************************
2861 * SOA HANDLING
2862 **************************************************************************/
2863
2864 // check the SOA
2865 // expects 1 record, "removed", then add 1 added with incremented serial
2866 // else one and only one should be seen as "added" (and not removed), then do nothing
2867 // else still add 1 added incremented serial
2868
2869 // if one (and only one, more being an error) SOA is marked as added, then do nothing
2870 // else add one with incremented serial based on the highest found serial
2871
2872 zone_diff_fqdn *apex = zone_diff_fqdn_add(diff, diff->origin, label);
2873 zone_diff_fqdn_rr_set *soa_rrset = zone_diff_fqdn_rr_set_add(apex, TYPE_SOA);
2874
2875 //ptr_set_iterator fqdn_iter;
2876 ptr_set_iterator rr_iter;
2877
2878 zone_diff_label_rr *rr_soa_removed = NULL;
2879 zone_diff_label_rr *rr_soa_added = NULL;
2880 u32 soa_latest_serial;
2881 ya_result ret;
2882
2883 ptr_set_iterator_init(&soa_rrset->rr, &rr_iter);
2884 while(ptr_set_iterator_hasnext(&rr_iter))
2885 {
2886 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
2887 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
2888
2889 #if DEBUG
2890 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
2891 log_debug1("update: %{dnsname}: SOA[%x] %{dnsname} %9i %{typerdatadesc}", diff->origin, rr->state, rr->fqdn, rr->ttl, &rd);
2892 #endif
2893
2894 if(rr->state & ZONE_DIFF_RR_REMOVE)
2895 {
2896 u32 soa_serial;
2897
2898 if(FAIL(ret = rr_soa_get_serial(rr->rdata, rr->rdata_size, &soa_serial)))
2899 {
2900 // error
2901 return ret;
2902 }
2903
2904 if(rr_soa_removed == NULL)
2905 {
2906 soa_latest_serial = soa_serial;
2907 rr_soa_removed = rr;
2908 }
2909 else
2910 {
2911 soa_latest_serial = serial_max(soa_latest_serial, soa_serial); // soa_latest_serial is initialized
2912 if(serial_lt(soa_latest_serial, soa_serial))
2913 {
2914 rr_soa_removed = rr;
2915 }
2916 }
2917 }
2918
2919 if((rr->state & (ZONE_DIFF_RR_ADD | ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_ADD) // VS false positive: rr is a key and can't be NULL
2920 {
2921 if(rr_soa_added != NULL)
2922 {
2923 return INVALID_STATE_ERROR; // two SOA added ...
2924 }
2925
2926 rr_soa_added = rr;
2927 }
2928 }
2929
2930 if(rr_soa_removed == NULL)
2931 {
2932 return INVALID_STATE_ERROR;
2933 }
2934
2935 if(rr_soa_added != NULL)
2936 {
2937 u32 soa_serial;
2938
2939 if(FAIL(ret = rr_soa_get_serial(rr_soa_added->rdata, rr_soa_added->rdata_size, &soa_serial)))
2940 {
2941 // error
2942
2943 return ret;
2944 }
2945
2946 if(serial_le(soa_serial, soa_latest_serial)) // soa_latest_serial is initialized
2947 {
2948 // error
2949
2950 return INVALID_STATE_ERROR;
2951 }
2952 }
2953 else
2954 {
2955 // add the SOA add record
2956
2957 #if C11_VLA_AVAILABLE
2958 u8 tmp_rdata[rr_soa_removed->rdata_size];
2959 #else
2960 u8* const tmp_rdata = (u8* const)stack_alloc(rr_soa_removed->rdata_size);
2961 #endif
2962
2963 memcpy(tmp_rdata, rr_soa_removed->rdata, rr_soa_removed->rdata_size);
2964 rr_soa_increase_serial(tmp_rdata, rr_soa_removed->rdata_size, 1);
2965 rr_soa_added = zone_diff_label_rr_new(rr_soa_removed->fqdn, TYPE_SOA, CLASS_IN, rr_soa_removed->ttl, tmp_rdata, rr_soa_removed->rdata_size, TRUE);
2966 rr_soa_added = zone_diff_fqdn_rr_set_rr_add_get(soa_rrset, rr_soa_added); // add_get
2967 rr_soa_added->state |= ZONE_DIFF_RR_ADD | ZONE_DIFF_RR_AUTOMATED;
2968 }
2969
2970 return SUCCESS;
2971 }
2972
2973 /**
2974 * Updates status and validates a diff.
2975 *
2976 * @param diff
2977 * @return
2978 */
2979
2980 ya_result
zone_diff_validate(zone_diff * diff)2981 zone_diff_validate(zone_diff *diff)
2982 {
2983 ptr_set_iterator fqdn_iter;
2984
2985 ptr_vector diff_fqdn_to_remove = EMPTY_PTR_VECTOR;
2986
2987 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
2988 while(ptr_set_iterator_hasnext(&fqdn_iter))
2989 {
2990 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
2991
2992 const u8 *diff_fqdn_name = (const u8*)diff_fqdn_node->key;
2993 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
2994
2995 // update status flags
2996 // do validation tests
2997
2998 log_debug2("update: %{dnsname}: validating %{dnsname}", diff->origin, diff_fqdn_name);
2999
3000 if(diff_fqdn->is_apex)
3001 {
3002 // only check for CNAME
3003
3004 if(zone_diff_will_have_rrset_type(diff_fqdn, TYPE_CNAME))
3005 {
3006 log_err("update: %{dnsname}: update would add CNAME on apex", diff->origin);
3007
3008 //dnssec_chain_finalize(&dc);
3009
3010 return INVALID_STATE_ERROR;
3011 }
3012 }
3013 else
3014 {
3015 // check for CNAME
3016
3017 // update under-delegation
3018 //
3019 // for all labels above, look in the diff if they are present and if their delegation status will be changed
3020
3021 bool under_delegation = FALSE;
3022
3023 const u8 *above_fqdn = diff_fqdn->fqdn;
3024 bool is_right_above = TRUE;
3025 while(*above_fqdn != 0)
3026 {
3027 above_fqdn += *above_fqdn + 1;
3028
3029 const zone_diff_fqdn *parent = zone_diff_fqdn_get_const(diff, above_fqdn);
3030
3031 if(parent != NULL)
3032 {
3033 if(parent->is_apex)
3034 {
3035 break;
3036 }
3037
3038 if(is_right_above)
3039 {
3040 if((parent->was_at_delegation || parent->was_under_delegation) && !diff_fqdn->was_under_delegation)
3041 {
3042 // then we are at delegation
3043 #if DEBUG
3044 if(diff_fqdn->is_in_database)
3045 {
3046 log_warn("update: %{dnsname}: %{dnsname} expected to be marked as being under delegation in the database as %{dnsname} at=%i under=%i (fixing)", diff->origin,
3047 diff_fqdn->fqdn, parent->fqdn, parent->was_at_delegation, parent->was_under_delegation);
3048 }
3049 #endif
3050 diff_fqdn->was_under_delegation = TRUE;
3051 }
3052 else if(!((parent->was_at_delegation || parent->was_under_delegation)) && diff_fqdn->was_under_delegation)
3053 {
3054 // then we are at delegation
3055 #if DEBUG
3056 if(diff_fqdn->is_in_database)
3057 {
3058 log_warn("update: %{dnsname}: %{dnsname} not expected to be marked as being under delegation in the database as %{dnsname} at=%i under=%i (fixing)", diff->origin,
3059 diff_fqdn->fqdn, parent->fqdn, parent->was_at_delegation, parent->was_under_delegation);
3060 }
3061 #endif
3062 diff_fqdn->was_under_delegation = FALSE;
3063 }
3064
3065 is_right_above = FALSE;
3066 }
3067
3068 if(parent->under_delegation)
3069 {
3070 if(!diff_fqdn->under_delegation)
3071 {
3072 log_debug("update: %{dnsname}: %{dnsname} under under delegation %{dnsname}", diff->origin,
3073 diff_fqdn->fqdn, parent->fqdn);
3074 }
3075 under_delegation = TRUE;
3076 break;
3077 }
3078
3079 if(parent->at_delegation)
3080 {
3081 if(!diff_fqdn->under_delegation)
3082 {
3083 log_debug1("update: %{dnsname}: %{dnsname} under delegation %{dnsname}", diff->origin,
3084 diff_fqdn->fqdn, parent->fqdn);
3085 }
3086 under_delegation = TRUE;
3087 break;
3088 }
3089 }
3090 /*else
3091 {
3092 under_delegation = diff_fqdn->under_delegation;
3093 }*/
3094 }
3095
3096 if(diff_fqdn->under_delegation && !under_delegation)
3097 {
3098 log_debug1("update: %{dnsname}: %{dnsname} not under delegation anymore", diff->origin, diff_fqdn->fqdn);
3099 }
3100
3101 diff_fqdn->under_delegation = under_delegation;
3102
3103 // update delegation
3104 //
3105 //
3106
3107 if(zone_diff_will_have_rrset_type(diff_fqdn, TYPE_NS))
3108 {
3109 diff_fqdn->at_delegation = TRUE;
3110
3111 // check there will be only glue records under this level
3112 }
3113 else
3114 {
3115 diff_fqdn->at_delegation = FALSE;
3116 }
3117
3118 diff_fqdn->will_have_ds = zone_diff_will_have_rrset_type(diff_fqdn, TYPE_DS);
3119
3120 if(diff_fqdn->will_have_ds && !diff_fqdn->at_delegation)
3121 {
3122 log_debug1("update: %{dnsname}: %{dnsname} will have a DS but no NS : removing all DS", diff->origin, diff_fqdn->fqdn);
3123
3124 zone_diff_remove_rrset_type(diff_fqdn, TYPE_DS);
3125 diff_fqdn->will_have_ds = 0;
3126
3127 if(u32_set_isempty(&diff_fqdn->rrset))
3128 {
3129 ptr_vector_append(&diff_fqdn_to_remove, diff_fqdn_node);
3130 }
3131
3132 // TODO: remove NSEC3 record
3133 }
3134 }
3135
3136 log_debug2("update: %{dnsname}: validating %{dnsname}: apex=%i at=%i under=%i ds=%i was-at=%i was-under=%i had-ds=%i",
3137 diff->origin, diff_fqdn_name,
3138 diff_fqdn->is_apex, diff_fqdn->at_delegation, diff_fqdn->under_delegation, diff_fqdn->will_have_ds,
3139 diff_fqdn->was_at_delegation, diff_fqdn->was_under_delegation, diff_fqdn->had_ds
3140 );
3141 }
3142
3143 for(int i = 0; i <= ptr_vector_last_index(&diff_fqdn_to_remove); ++i)
3144 {
3145 ptr_node *diff_fqdn_node = (ptr_node*)ptr_vector_get(&diff_fqdn_to_remove, i);
3146 //const u8 *diff_fqdn_name = (const u8*)diff_fqdn_node->key;
3147 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
3148 ptr_set_delete(&diff->fqdn, diff_fqdn->fqdn); // remove the node
3149
3150 // if diff_fqdn is not in the database
3151 // from diff->root, remove the fqdn with attention to empty terminal not in the database
3152 // and
3153
3154 // zone_diff_fqdn_delete(diff_fqdn); // delete the data
3155 }
3156 ptr_vector_destroy(&diff_fqdn_to_remove);
3157
3158 return SUCCESS;
3159 }
3160
3161 struct zone_diff_get_changes_update_rr_parm
3162 {
3163 u8 changes;
3164 bool rrset_removed;
3165 bool rrset_new;
3166 bool all_rrset_added;
3167 bool all_rrset_removed;
3168 bool non_empty;
3169 };
3170
3171 static void
zone_diff_get_changes_update_rrsig_rr(zone_diff_fqdn_rr_set * rr_set,struct zone_diff_get_changes_update_rr_parm * parm,ptr_vector * remove,ptr_vector * add)3172 zone_diff_get_changes_update_rrsig_rr(zone_diff_fqdn_rr_set *rr_set, struct zone_diff_get_changes_update_rr_parm *parm, ptr_vector *remove, ptr_vector *add)
3173 {
3174 u8 changes = parm->changes;
3175 bool rrset_removed = parm->rrset_removed;
3176 bool all_rrset_added = parm->all_rrset_added;
3177 bool all_rrset_removed = parm->all_rrset_removed;
3178 bool rrset_new = TRUE;
3179
3180 ptr_set_iterator rr_iter;
3181
3182 // for all marked rr
3183
3184 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
3185 while(ptr_set_iterator_hasnext(&rr_iter))
3186 {
3187 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3188 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
3189
3190 yassert(rr->rtype == TYPE_RRSIG);
3191
3192 if((rr->state & (ZONE_DIFF_RR_IN_ZONE|ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADDED)) == ZONE_DIFF_RR_ADD)
3193 {
3194 // add
3195 #if DEBUG
3196 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3197 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3198 log_debug1("update: add %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rrsig_rr %p)",
3199 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3200 #endif
3201
3202 ptr_vector_append(add, rr);
3203 rr->state |= ZONE_DIFF_RR_ADDED;
3204
3205 // proceed with the chain if needed
3206
3207 changes |= ZONE_DIFF_CHANGES_ADD;
3208 rrset_removed = FALSE;
3209 all_rrset_removed = FALSE;
3210 }
3211 else if((rr->state & (ZONE_DIFF_RR_IN_ZONE|ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_REMOVED)) == (ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_IN_ZONE))
3212 {
3213 // remove
3214
3215 #if DEBUG
3216 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3217 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3218 log_debug1("update: del %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rrsig_rr %p)",
3219 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3220 #endif
3221
3222 ptr_vector_append(remove, rr);
3223 rr->state |= ZONE_DIFF_RR_REMOVED;
3224
3225 // proceed with the chain if needed
3226
3227 changes |= ZONE_DIFF_CHANGES_REMOVE;
3228 all_rrset_added = FALSE;
3229 }
3230 else if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == 0)
3231 {
3232 // stays
3233
3234 #if DEBUG
3235 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3236 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3237 log_debug1("update: nop %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rrsig_rr %p)",
3238 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3239 #endif
3240
3241 changes |= ZONE_DIFF_CHANGES_KEPT;
3242 rrset_removed = FALSE;
3243 all_rrset_removed = FALSE;
3244 all_rrset_added = FALSE;
3245
3246 rrset_new = TRUE;
3247 }
3248 else
3249 {
3250 #if DEBUG
3251 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3252 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3253 log_debug1("update: ign %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rrsig_rr %p)",
3254 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3255 #endif
3256 }
3257 }
3258
3259 parm->changes = changes;
3260 parm->rrset_removed = rrset_removed;
3261 parm->rrset_new = rrset_new;
3262 parm->all_rrset_added = all_rrset_added;
3263 parm->all_rrset_removed = all_rrset_removed;
3264 }
3265
3266 static void
zone_diff_get_changes_update_rr(zone_diff_fqdn_rr_set * rr_set,struct zone_diff_get_changes_update_rr_parm * parm,ptr_vector * remove,ptr_vector * add)3267 zone_diff_get_changes_update_rr(zone_diff_fqdn_rr_set *rr_set, struct zone_diff_get_changes_update_rr_parm *parm, ptr_vector *remove, ptr_vector *add)
3268 {
3269
3270 u8 changes = parm->changes;
3271 bool rrset_removed = parm->rrset_removed;
3272 bool all_rrset_added = parm->all_rrset_added;
3273 bool all_rrset_removed = parm->all_rrset_removed;
3274 bool non_empty = parm->non_empty;
3275
3276 ptr_set_iterator rr_iter;
3277
3278 // for all marked rr
3279
3280 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
3281 while(ptr_set_iterator_hasnext(&rr_iter))
3282 {
3283 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3284 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
3285
3286 if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_ADDED)) == ZONE_DIFF_RR_ADD)
3287 {
3288 // add
3289
3290 #if DEBUG
3291 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3292 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3293 log_debug1("update: add %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rr %p)",
3294 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3295 #endif
3296 ptr_vector_append(add, rr);
3297 rr->state |= ZONE_DIFF_RR_ADDED;
3298
3299 if(rr->rtype == TYPE_SOA)
3300 {
3301 ptr_vector_end_swap(add, 0);
3302 }
3303
3304 // proceed with the chain if needed
3305
3306 changes |= ZONE_DIFF_CHANGES_ADD;
3307 rrset_removed = FALSE;
3308 all_rrset_removed = FALSE;
3309 non_empty = TRUE;
3310 }
3311 else if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_REMOVED)) == ZONE_DIFF_RR_REMOVE)
3312 {
3313 // remove
3314
3315 #if DEBUG
3316 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3317 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3318 log_debug1("update: del %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rr %p)",
3319 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3320 #endif
3321
3322 ptr_vector_append(remove, rr);
3323 rr->state |= ZONE_DIFF_RR_REMOVED;
3324
3325 if(rr->rtype == TYPE_SOA)
3326 {
3327 ptr_vector_end_swap(remove, 0);
3328 }
3329
3330 // proceed with the chain if needed
3331
3332 changes |= ZONE_DIFF_CHANGES_REMOVE;
3333 all_rrset_added = FALSE;
3334 }
3335 else if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == 0)
3336 {
3337
3338 #if DEBUG
3339 rdata_desc rrsig_rr_rd = {rr->rtype, rr->rdata_size, rr->rdata};
3340 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
3341 log_debug1("update: nop %w %{dnsname} %9i %{typerdatadesc} (zone_diff_get_changes_update_rr %p)",
3342 &temp_fw_0, rr->fqdn, rr->ttl, &rrsig_rr_rd, rr);
3343 #endif
3344 // stays
3345 changes |= ZONE_DIFF_CHANGES_KEPT;
3346 rrset_removed = FALSE;
3347 all_rrset_removed = FALSE;
3348 all_rrset_added = FALSE;
3349 non_empty = TRUE;
3350 }
3351 }
3352
3353 parm->changes = changes;
3354 parm->rrset_removed = rrset_removed;
3355 parm->all_rrset_added = all_rrset_added;
3356 parm->all_rrset_removed = all_rrset_removed;
3357 parm->non_empty = non_empty;
3358 }
3359
3360 u64
zone_diff_key_vector_get_mask(ptr_vector * keys,time_t now)3361 zone_diff_key_vector_get_mask(ptr_vector *keys, time_t now)
3362 {
3363 u64 mask = 0;
3364 for(int i = 0; i <= ptr_vector_last_index(keys); ++i)
3365 {
3366 dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, i);
3367
3368 bool is_private = dnskey_is_private(key);
3369
3370 if((is_private && dnskey_is_activated(key, now)) || !is_private)
3371 {
3372 mask |= 1ULL << i;
3373 }
3374 }
3375
3376 return mask;
3377 }
3378
3379 /**
3380 * Stores changes of a diff into two vectors.
3381 * Optionally keep track of record sets that need to be signed.
3382 * Optionally notify a chain about changes.
3383 *
3384 * @param diff
3385 * @param dc can be NULL
3386 * @param rrset_to_sign_vector can be NULL
3387 * @param remove
3388 * @param add
3389 * @return TRUE iff there is a DNSKEY rrset in the diff
3390 */
3391
3392 s32
zone_diff_get_changes(zone_diff * diff,ptr_vector * rrset_to_sign_vector,ptr_vector * ksks,ptr_vector * zsks,ptr_vector * remove,ptr_vector * add)3393 zone_diff_get_changes(zone_diff *diff, ptr_vector *rrset_to_sign_vector, ptr_vector *ksks, ptr_vector *zsks, ptr_vector *remove, ptr_vector *add)
3394 {
3395 s32 mandatory_changes = 0;
3396 ya_result err = SUCCESS;
3397
3398 // first fill the arrays with the relevant keys
3399
3400 zone_diff_store_diff_dnskey_get_keys(diff, ksks, zsks);
3401
3402 ptr_set_iterator fqdn_iter;
3403 ptr_set_iterator rr_iter;
3404
3405 time_t now = time(NULL);
3406
3407 u64 ksks_mask = zone_diff_key_vector_get_mask(ksks, now);
3408 u64 zsks_mask = zone_diff_key_vector_get_mask(zsks, now);
3409
3410 //bool may_have_empty_terminals = FALSE;
3411
3412 // for all fqdn
3413
3414 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
3415 while(ptr_set_iterator_hasnext(&fqdn_iter))
3416 {
3417 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
3418 #if DYNUPDATE_DIFF_DETAILED_LOG
3419 const u8 *diff_fqdn_name = (const u8*)diff_fqdn_node->key;
3420 #endif
3421 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
3422
3423 // for all rrset
3424
3425 bool type_map_changed = FALSE;
3426 bool all_rrset_added = TRUE;
3427 bool all_rrset_removed = TRUE;
3428 bool non_empty = FALSE;
3429
3430 zone_diff_fqdn_rr_set *rrsig_rr_set = NULL;
3431
3432 u32_node *rrset_node = u32_set_find(&diff_fqdn->rrset, TYPE_RRSIG);
3433 if(rrset_node != NULL)
3434 {
3435 rrsig_rr_set = (zone_diff_fqdn_rr_set*)rrset_node->value;
3436 }
3437
3438 type_map_changed = (rrsig_rr_set == NULL);
3439
3440 // for all records
3441
3442 if(!u32_set_isempty(&diff_fqdn->rrset))
3443 {
3444 u32_set_iterator rrset_iter;
3445 u32_set_iterator_init(&diff_fqdn->rrset, &rrset_iter);
3446 while(u32_set_iterator_hasnext(&rrset_iter))
3447 {
3448 u32_node *rrset_node = u32_set_iterator_next_node(&rrset_iter);
3449
3450 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)rrset_node->value;
3451
3452 if(rr_set == NULL)
3453 {
3454 continue;
3455 }
3456
3457 #if DYNUPDATE_DIFF_DETAILED_LOG
3458 {
3459 // enumerate records
3460
3461 ptr_set_iterator rr_iter;
3462 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
3463 rdata_desc rdatadesc = {rr_set->rtype, 0, NULL};
3464 while(ptr_set_iterator_hasnext(&rr_iter))
3465 {
3466 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3467 zone_diff_label_rr *rr = (zone_diff_label_rr *)rr_node->key;
3468 rdatadesc.len = rr->rdata_size;
3469 rdatadesc.rdata = rr->rdata;
3470 log_debug("update: %02x [%llx] %{dnsname} %i %{typerdatadesc}", rr->state, rr_set->key_mask, rr->fqdn, rr->ttl, &rdatadesc);
3471 }
3472 }
3473 #endif
3474 if(rr_set->rtype == TYPE_RRSIG)
3475 {
3476 // if allowed ...
3477
3478 if(diff->rrsig_update_allowed)
3479 {
3480 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
3481 bool rrsig_added = FALSE;
3482 bool rrsig_kept = FALSE;
3483 bool rrsig_removed = FALSE;
3484 bool key_will_be_present = FALSE;
3485 bool key_will_be_present_DNSKEY = FALSE;
3486 bool key_will_be_present_not_DNSKEY = FALSE;
3487
3488 while(ptr_set_iterator_hasnext(&rr_iter))
3489 {
3490 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3491 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
3492 if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_ADD)
3493 {
3494 rdata_desc rdt = {rr->rtype, rr->rdata_size, rr->rdata};
3495
3496 log_debug("update: %{dnsname}: checking for signing key of RRSIG record %{dnsname} %i %{dnsclass} %{typerdatadesc}",
3497 diff->origin, rr->fqdn, rr->ttl, &rr->rclass, &rdt);
3498
3499 u8 algorithm = rrsig_get_algorithm_from_rdata(rr->rdata, rr->rdata_size);
3500 u16 tag = rrsig_get_key_tag_from_rdata(rr->rdata, rr->rdata_size);
3501
3502 rrsig_added = TRUE;
3503
3504 if(zone_diff_will_have_dnskey_with_algorithm_tag(diff_fqdn, algorithm, tag))
3505 {
3506 key_will_be_present = TRUE;
3507 if(rrsig_get_type_covered_from_rdata(rr->rdata, rr->rdata_size) == TYPE_DNSKEY)
3508 {
3509 key_will_be_present_DNSKEY = TRUE;
3510 }
3511 else
3512 {
3513 key_will_be_present_not_DNSKEY = TRUE;
3514 }
3515 break;
3516 }
3517 }
3518 else if((rr->state & (ZONE_DIFF_RR_IN_ZONE|ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_REMOVE)
3519 {
3520 rrsig_removed = TRUE;
3521 }
3522 else if((rr->state & (ZONE_DIFF_RR_IN_ZONE/*|ZONE_DIFF_RR_ADD*/|ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_IN_ZONE)
3523 {
3524 rrsig_kept = TRUE; // if it's added but already in zone, it does not count does it ...
3525 }
3526 }
3527
3528 diff_fqdn->rrsig_added = rrsig_added;
3529 diff_fqdn->rrsig_kept = rrsig_kept;
3530 diff_fqdn->rrsig_removed = rrsig_removed;
3531
3532 if(!rrsig_added || (rrsig_added && key_will_be_present))
3533 {
3534 u8 changes = ZONE_DIFF_CHANGES_NONE;
3535 bool rrset_removed = TRUE;
3536
3537 struct zone_diff_get_changes_update_rr_parm parms = {changes, rrset_removed, FALSE, all_rrset_added, all_rrset_removed, non_empty};
3538 zone_diff_get_changes_update_rrsig_rr(rr_set, &parms, remove, add);
3539
3540 diff_fqdn->rrsig_kept = !parms.rrset_new;
3541 }
3542 else
3543 {
3544 if(!key_will_be_present_DNSKEY)
3545 {
3546 log_info("update: %{dnsname}: DNSKEY RRSIG without signing DNSKEY present (probably on purpose)", diff_fqdn->fqdn);
3547 }
3548 if(!key_will_be_present_not_DNSKEY)
3549 {
3550 log_err("update: %{dnsname}: RRSIG without signing DNSKEY present (probably bad)", diff_fqdn->fqdn);
3551 }
3552
3553 err = INVALID_STATE_ERROR;
3554 }
3555 }
3556 #if DEBUG
3557 else
3558 {
3559 log_debug1("update: %{dnsname}: not updating RRSIG rr_set at this point (rrsig_update_allowed is false)", diff_fqdn->fqdn);
3560 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
3561 while(ptr_set_iterator_hasnext(&rr_iter))
3562 {
3563 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3564 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
3565 if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_ADD)
3566 {
3567 rdata_desc rdt = {rr->rtype, rr->rdata_size, rr->rdata};
3568
3569 log_debug("update: %{dnsname}: (ignoring) [%02x] %{dnsname} %i %{dnsclass} %{typerdatadesc}",
3570 diff->origin, rr->state, rr->fqdn, rr->ttl, &rr->rclass, &rdt);
3571 }
3572 }
3573 }
3574 #endif
3575
3576 continue;
3577 }
3578 u8 changes = ZONE_DIFF_CHANGES_NONE;
3579 bool rrset_removed = TRUE;
3580
3581 struct zone_diff_get_changes_update_rr_parm parms = {changes, FALSE, rrset_removed, all_rrset_added, all_rrset_removed, non_empty};
3582 zone_diff_get_changes_update_rr(rr_set, &parms, remove, add);
3583
3584 changes = parms.changes;
3585 rrset_removed = parms.rrset_removed;
3586 if(rr_set->rtype != TYPE_NSEC)
3587 {
3588 all_rrset_added = parms.all_rrset_added;
3589 all_rrset_removed = parms.all_rrset_removed;
3590 non_empty = parms.non_empty;
3591 }
3592
3593 /*
3594 * If the status is 0, then all the added records that have been added have also been removed => no map change, and no signature change
3595 * If the status is 1, then the rrset has completely been removed => map change and remove all signatures
3596 * If the status is 2, then the rrset has completely been added => map change, and add (new) signatures
3597 * If the status is 4, then the rrset existed and still exists => no map change, and no signature change
3598 *
3599 * Any other combination having 1 or 2 on will make no map change but update the signature
3600 *
3601 */
3602
3603 if((changes == ZONE_DIFF_CHANGES_ADD) || (changes == ZONE_DIFF_CHANGES_REMOVE))
3604 {
3605 type_map_changed = TRUE;
3606 }
3607
3608 ptr_vector *keys = zsks;
3609 u64 keys_mask = zsks_mask;
3610
3611 if(rr_set->rtype == TYPE_DNSKEY)
3612 {
3613 keys = ksks;
3614 keys_mask = ksks_mask;
3615 }
3616
3617 if(rrset_node->key == TYPE_RRSIG)
3618 {
3619 continue;
3620 }
3621
3622 bool rrset_updated = (changes & (ZONE_DIFF_CHANGES_ADD|ZONE_DIFF_CHANGES_REMOVE)); // || type_map_changed ?
3623
3624 if((rr_set->rtype != TYPE_SOA) && rrset_updated)
3625 {
3626 ++mandatory_changes;
3627 }
3628
3629 #if 0 /* fix */
3630 #else
3631 bool rrset_expected_to_be_covered =
3632 !(diff_fqdn->at_delegation || diff_fqdn->under_delegation) ||
3633 (!diff_fqdn->under_delegation &&
3634 (diff_fqdn->at_delegation && ((rr_set->rtype == TYPE_DS) || (rr_set->rtype == TYPE_NSEC)))
3635 );
3636
3637 bool rrset_rrsig_covered_with_chain_rules = (!rrset_removed && rrset_expected_to_be_covered);
3638 #endif
3639 bool came_under_delegation = (!diff_fqdn->was_under_delegation && diff_fqdn->under_delegation);
3640 //bool came_out_of_delegation = (diff_fqdn->was_under_delegation && !diff_fqdn->under_delegation);
3641
3642 // blanket bombing
3643
3644 if((rrsig_rr_set != NULL) &&
3645 (rrset_updated ||
3646 all_rrset_removed ||
3647 came_under_delegation ||
3648 #if 0 /* fix */
3649 #else
3650 !rrset_rrsig_covered_with_chain_rules
3651 #endif
3652 )
3653 )
3654 {
3655 ptr_set_iterator_init(&rrsig_rr_set->rr, &rr_iter);
3656 while(ptr_set_iterator_hasnext(&rr_iter))
3657 {
3658 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3659 zone_diff_label_rr *rrsig_rr = (zone_diff_label_rr *)rr_node->key;
3660
3661 if(rrsig_get_type_covered_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size) != rr_set->rtype)
3662 {
3663 continue;
3664 }
3665
3666 if(rrsig_rr->state & ZONE_DIFF_RR_ADD)
3667 {
3668 // manually added
3669 continue;
3670 }
3671
3672 if((rrsig_rr->state & ZONE_DIFF_RR_REMOVED) == 0) // the signature is not marked for removal (e.g.: expired)
3673 {
3674 rrsig_rr->state |= ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_AUTOMATED;
3675 #if DEBUG
3676 {
3677 rdata_desc rrsig_rr_rd = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
3678 format_writer temp_fw_0 = {zone_diff_record_state_format, &rrsig_rr->state};
3679 log_debug1("update: del %w %{dnsname} %9i %{typerdatadesc} (rrsig A zone_diff_get_changes %p)",
3680 &temp_fw_0, rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_rr_rd, rrsig_rr);
3681 }
3682 #endif
3683 ptr_vector_append(remove, rrsig_rr);
3684 rrsig_rr->state |= ZONE_DIFF_RR_REMOVED;
3685 }
3686 }
3687 }
3688
3689 // for all rrsig, enumerate properly covered types
3690
3691 //bool rrset_already_covered = FALSE;
3692
3693 if(!all_rrset_removed &&
3694 #if 0 /* fix */
3695 #else
3696 rrset_rrsig_covered_with_chain_rules
3697 #endif
3698 ) // else this would be pointless
3699 {
3700 if(rrsig_rr_set != NULL)
3701 {
3702 u64 coverage = 0;
3703
3704 ptr_set_iterator_init(&rrsig_rr_set->rr, &rr_iter);
3705 while(ptr_set_iterator_hasnext(&rr_iter))
3706 {
3707 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3708 zone_diff_label_rr *rrsig_rr = (zone_diff_label_rr *)rr_node->key;
3709
3710 if(rrsig_get_type_covered_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size) != rr_set->rtype)
3711 {
3712 continue;
3713 }
3714
3715 if((rrsig_rr->state & (ZONE_DIFF_RR_ADDED|ZONE_DIFF_RR_RDATA_OWNED)) == (ZONE_DIFF_RR_ADDED|ZONE_DIFF_RR_RDATA_OWNED))
3716 {
3717 continue;
3718 }
3719
3720 if((rrsig_rr->state & ZONE_DIFF_RR_REMOVED) != 0) // the signature is not marked for removal (e.g.: expired)
3721 {
3722 continue;
3723 }
3724
3725 // check if the signature is with a valid key and is in its validity period
3726 // if it's not valid yet, keep it
3727 // if its expired, remove it
3728 // if no valid signatures are available, may mark the record for signing
3729
3730 s32 key_index = -2;
3731
3732 if(rrsig_should_remove_signature_from_rdata(
3733 rrsig_rr->rdata, rrsig_rr->rdata_size,
3734 keys, now, diff->rrsig_validity_regeneration, &key_index) || (key_index == -1))
3735 {
3736 rrsig_rr->state |= ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_AUTOMATED;
3737
3738 #if DEBUG
3739 {
3740 rdata_desc rrsig_rr_rd = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
3741 format_writer temp_fw_0 = {zone_diff_record_state_format, &rrsig_rr->state};
3742 log_debug1("update: del %w %{dnsname} %9i %{typerdatadesc} (rrsig B zone_diff_get_changes %p)",
3743 &temp_fw_0, rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_rr_rd, rrsig_rr);
3744 }
3745 #endif
3746
3747 ptr_vector_append(remove, rrsig_rr);
3748 rrsig_rr->state |= ZONE_DIFF_RR_REMOVED;
3749 ++mandatory_changes;
3750 continue;
3751 }
3752
3753 // the signature will be kept
3754
3755 coverage |= (1ULL << key_index);
3756 }
3757
3758 rr_set->key_mask = keys_mask ^ coverage;
3759 }
3760 else
3761 {
3762 rr_set->key_mask = keys_mask;
3763 }
3764 }
3765
3766 // If the chain believes it has to handle the fqdn, add the rrset to the "to sign"
3767 // This does not work with mixed chains (NSEC & NSEC3)
3768
3769 if((rr_set->key_mask != 0) && (rrset_to_sign_vector != NULL))
3770 {
3771 if(rr_set->rtype != TYPE_SOA)
3772 {
3773 ++mandatory_changes;
3774 }
3775
3776 // will generate new signatures for the rrset (postponed)
3777
3778 // verify that signatures are not already present
3779
3780
3781 #if DYNUPDATE_DIFF_DETAILED_LOG
3782 log_debug("update: %{dnsname}: dnssec: %{dnsname} %{dnstype} rrset @%p should be signed (%08llx/%08llx)", diff->origin,
3783 diff_fqdn_name, &rr_set->rtype, rr_set, rr_set->key_mask, keys_mask);
3784 #endif
3785 ptr_vector_append(rrset_to_sign_vector, rr_set);
3786
3787 }
3788 }
3789 }
3790 else
3791 {
3792 #if DYNUPDATE_DIFF_DETAILED_LOG
3793 {
3794 // empty
3795 log_debug("update: ?? [?] %{dnsname} has no records", diff_fqdn->fqdn);
3796 }
3797 #endif
3798 type_map_changed = FALSE;
3799 all_rrset_added = FALSE;
3800 all_rrset_removed = FALSE;
3801 non_empty = FALSE;
3802
3803 //may_have_empty_terminals = TRUE;
3804 }
3805
3806 // if type_map_changes, the type map has to be updated and the signature too, obviously
3807
3808 diff_fqdn->type_map_changed = type_map_changed || (!diff_fqdn->rrsig_kept && (diff_fqdn->rrsig_added != diff_fqdn->rrsig_removed));
3809 diff_fqdn->all_rrset_added = all_rrset_added;
3810 diff_fqdn->all_rrset_removed = all_rrset_removed;
3811 diff_fqdn->will_be_non_empty = non_empty;
3812
3813 /**/
3814 diff_fqdn->type_map_changed &= non_empty;
3815 diff_fqdn->all_rrset_added &= non_empty;
3816
3817 /**/
3818
3819 diff_fqdn->records_flags_set = 1;
3820
3821 #if DYNUPDATE_DIFF_DETAILED_LOG
3822 {
3823 // empty
3824 log_debug("update: -- --- %{dnsname} remap=%i +all=%i -all=%i !empty=%i", diff_fqdn->fqdn, type_map_changed, all_rrset_added, all_rrset_removed, non_empty);
3825 }
3826 #endif
3827 }
3828
3829 if(ISOK(err))
3830 {
3831 return mandatory_changes;
3832 }
3833 else
3834 {
3835 return err;
3836 }
3837 }
3838
3839 #if 0 && DYNUPDATE_DIFF_DETAILED_LOG
3840 if(may_have_empty_terminals)
3841 {
3842 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
3843 while(ptr_set_iterator_hasnext(&fqdn_iter))
3844 {
3845 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
3846 const u8 *diff_fqdn_name = (const u8*)diff_fqdn_node->key;
3847
3848 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
3849 }
3850 }
3851 #endif
3852
3853 void
zone_diff_get_chain_changes(zone_diff * diff,dnssec_chain * dc)3854 zone_diff_get_chain_changes(zone_diff *diff, dnssec_chain* dc/*, ptr_vector *rrset_to_sign_vector, ptr_vector *ksks, ptr_vector *zsks, ptr_vector *remove, ptr_vector *add*/)
3855 {
3856 ptr_set_iterator fqdn_iter;
3857
3858 if(dc != NULL)
3859 {
3860 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
3861 while(ptr_set_iterator_hasnext(&fqdn_iter))
3862 {
3863 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
3864 const u8 *diff_fqdn_name = (const u8*)diff_fqdn_node->key;
3865
3866 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
3867
3868 zone_diff_fqdn_children_state(diff, diff_fqdn->fqdn);
3869
3870 // calling dnssec_chain_del_from_diff_fqdn and dnssec_chain_add_from_diff_fqdn respectively
3871 // tell to remove or to add a chain node (NSEC/NSEC3) for the given fqdn in the zone.
3872
3873 // Note the "was" or "is" covered means "IF the fqdn existed, was the past state covering it, is the new state covering it."
3874
3875 // This table gives the del/add for a node given the various states
3876 // (+-R => sumrises to "has changed")
3877 // Was covered | Is covered | +ALL | -ALL | REMAP | NODE
3878 // -----------------------------------------------+------
3879 // 0 0 1 0 ? |
3880 // 0 0 0 1 ? |
3881 // 0 0 0 0 0 |
3882 // 0 0 0 0 1 |
3883 // -----------------------------------------------+------
3884 // 0 1 1 0 ? | +
3885 // 0 1 0 1 ? | There is nothing anymore (empty non-terminal ? => +)
3886 // 0 1 0 0 0 | +
3887 // 0 1 0 0 1 | +
3888 // -----------------------------------------------+------
3889 // 1 0 1 0 ? | There was nothing before
3890 // 1 0 0 1 ? | -
3891 // 1 0 0 0 0 | -
3892 // 1 0 0 0 1 | -
3893 // -----------------------------------------------+------
3894 // 1 1 1 0 ? | + There was nothing before
3895 // 1 1 0 1 ? | - (empty non-terminal ? => -+)
3896 // 1 1 0 0 0 | There is no changed of state on this regard
3897 // 1 1 0 0 1 | -+
3898 // -----------------------------------------------+------
3899
3900 #define CHAIN_NODE_NOP 0
3901 #define CHAIN_NODE_DEL 1
3902 #define CHAIN_NODE_ADD 2
3903
3904 bool is_covered = dc->chain->fqdn_is_covered(diff_fqdn);
3905 bool was_covered = dc->chain->fqdn_was_covered(diff_fqdn);
3906
3907 #if DYNUPDATE_DIFF_DETAILED_LOG
3908 log_debug("update: %{dnsname}: dnssec: %{dnsname}: +ALL(%i) -ALL(%i) RECORDS(%i->%i) COVERED(%i->%i) CHILDREN(%i->%i) AT(%i->%i) UNDER(%i->%i) MAP(%i)",
3909 diff->origin,
3910 diff_fqdn_name,
3911 diff_fqdn->all_rrset_added,
3912 diff_fqdn->all_rrset_removed,
3913 diff_fqdn->was_non_empty, diff_fqdn->will_be_non_empty,
3914 was_covered, is_covered,
3915 diff_fqdn->had_children, diff_fqdn->will_have_children,
3916 diff_fqdn->was_at_delegation, diff_fqdn->at_delegation,
3917 diff_fqdn->was_under_delegation, diff_fqdn->under_delegation,
3918 diff_fqdn->type_map_changed);
3919 #endif
3920 if(was_covered || is_covered) // quickly cull the first 4 states of the table
3921 {
3922 bool did_exist = diff_fqdn->had_children || diff_fqdn->was_non_empty;
3923 bool will_exist = diff_fqdn->will_have_children || diff_fqdn->will_be_non_empty;
3924
3925 u8 ops = 0;
3926
3927 if( (diff_fqdn->had_children != diff_fqdn->will_have_children) ||
3928 (diff_fqdn->all_rrset_added) ||
3929 (diff_fqdn->all_rrset_removed) ||
3930 (diff_fqdn->type_map_changed) ||
3931 (is_covered != was_covered)
3932 )
3933 {
3934 //ops_index = 3; // means change
3935
3936 if(was_covered && did_exist)
3937 {
3938 //ops_index |= 8;
3939 ops |= CHAIN_NODE_DEL;
3940 }
3941
3942 if(is_covered && will_exist)
3943 {
3944 //ops_index |= 4;
3945 ops |= CHAIN_NODE_ADD;
3946 }
3947 }
3948
3949 #if DEBUG
3950 log_debug2("update: %{dnsname}: dnssec: %{dnsname}: operation %x", diff->origin, diff_fqdn_name, ops);
3951 #endif
3952 if(ops & CHAIN_NODE_DEL)
3953 {
3954 log_debug2("update: %{dnsname}: dnssec: %{dnsname}: removing chain node", diff->origin, diff_fqdn_name);
3955 dnssec_chain_del_from_diff_fqdn(dc, diff_fqdn, 0);
3956 }
3957
3958 if(ops & CHAIN_NODE_ADD)
3959 {
3960 log_debug2("update: %{dnsname}: dnssec: %{dnsname}: adding chain node", diff->origin, diff_fqdn_name);
3961 dnssec_chain_add_from_diff_fqdn(dc, diff_fqdn, 0);
3962 }
3963 }
3964 } // while fqdn names
3965 }
3966 }
3967
3968 /**
3969 * Returns TRUE iff there are changes in the diff
3970 *
3971 * @param diff
3972 * @param dc can be NULL
3973 * @param rrset_to_sign_vector can be NULL
3974 *
3975 * @return TRUE iff there are changes in the diff
3976 */
3977
3978 bool
zone_diff_has_changes(zone_diff * diff,ptr_vector * rrset_to_sign_vector)3979 zone_diff_has_changes(zone_diff *diff, ptr_vector *rrset_to_sign_vector)
3980 {
3981 if(ptr_vector_last_index(rrset_to_sign_vector) >= 0)
3982 {
3983 #if DEBUG
3984 for(s32 i = 0; i <= ptr_vector_last_index(rrset_to_sign_vector); ++i)
3985 {
3986 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)ptr_vector_get(rrset_to_sign_vector, i);
3987
3988 ptr_set_iterator rr_iter;
3989
3990 // for all marked rr
3991
3992 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
3993 while(ptr_set_iterator_hasnext(&rr_iter))
3994 {
3995 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
3996 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
3997
3998 rdata_desc rdatadesc = {rr->rtype, rr->rdata_size, rr->rdata};
3999
4000
4001 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
4002
4003 log_debug1("zone-diff: changes: %{dnsname}: %02x: %w: %{dnsname} %i %{typerdatadesc}", diff->origin, rr->state, &temp_fw_0, rr->fqdn, rr->ttl, &rdatadesc);
4004 }
4005 }
4006 #endif
4007
4008 return TRUE;
4009 }
4010
4011 ptr_set_iterator fqdn_iter;
4012 ptr_set_iterator rr_iter;
4013
4014 // for all fqdn
4015
4016 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
4017 while(ptr_set_iterator_hasnext(&fqdn_iter))
4018 {
4019 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
4020 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
4021
4022 // for all records
4023
4024 u32_set_iterator rrset_iter;
4025 u32_set_iterator_init(&diff_fqdn->rrset, &rrset_iter);
4026 while(u32_set_iterator_hasnext(&rrset_iter))
4027 {
4028 u32_node *rrset_node = u32_set_iterator_next_node(&rrset_iter);
4029
4030 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)rrset_node->value;
4031
4032 // for all marked rr
4033
4034 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
4035 while(ptr_set_iterator_hasnext(&rr_iter))
4036 {
4037 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
4038 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
4039 #if DEBUG
4040 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
4041 log_debug1("update: %{dnsname}: has-changes: state %02x: %{dnsname} %9i %{typerdatadesc}", diff->origin, rr->state, rr->fqdn, rr->ttl, &rd);
4042 #endif
4043 if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_ADD)
4044 {
4045 // add
4046 return TRUE;
4047 }
4048 else if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) == ZONE_DIFF_RR_REMOVE)
4049 {
4050 // remove
4051 return TRUE;
4052 }
4053 }
4054 }
4055 }
4056
4057 return FALSE;
4058 }
4059
4060 void
zone_diff_fqdn_rr_set_log(const zone_diff_fqdn_rr_set * rr_set,const u8 * origin,logger_handle * handle,int level)4061 zone_diff_fqdn_rr_set_log(const zone_diff_fqdn_rr_set *rr_set, const u8* origin, logger_handle *handle, int level)
4062 {
4063 ptr_set_iterator rr_iter;
4064
4065 // for all marked rr
4066
4067 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
4068 while(ptr_set_iterator_hasnext(&rr_iter))
4069 {
4070 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
4071 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
4072
4073 rdata_desc rdatadesc = {rr->rtype, rr->rdata_size, rr->rdata};
4074
4075 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
4076
4077 logger_handle_msg_nocull(handle, level, LOG_TEXT_PREFIX "zone-diff: %{dnsname}: %{dnsname}: %02x: %w: %{dnsname} %i %{typerdatadesc}",
4078 origin, rr->fqdn,
4079 rr->state, &temp_fw_0, rr->fqdn, rr->ttl, &rdatadesc);
4080 }
4081 }
4082
4083 void
zone_diff_fqdn_log(const zone_diff_fqdn * diff_fqdn,const u8 * origin,logger_handle * handle,int level)4084 zone_diff_fqdn_log(const zone_diff_fqdn* diff_fqdn, const u8 *origin, logger_handle *handle, int level)
4085 {
4086 if(!log_is_set(handle, level))
4087 {
4088 return;
4089 }
4090
4091 // for all rrset
4092
4093 const u8 *diff_fqdn_name = diff_fqdn->fqdn;
4094
4095 if(origin == NULL)
4096 {
4097 origin = (const u8 *)"\004NULL";
4098 }
4099
4100 format_writer temp_fw_1 = {zone_diff_fqdn_changes_format, diff_fqdn};
4101
4102 logger_handle_msg_nocull(handle, level, LOG_TEXT_PREFIX "zone-diff: %{dnsname}: %{dnsname}: %w", origin, diff_fqdn_name, &temp_fw_1);
4103
4104 // for all records
4105
4106 u32_set_iterator rrset_iter;
4107 u32_set_iterator_init(&diff_fqdn->rrset, &rrset_iter);
4108 while(u32_set_iterator_hasnext(&rrset_iter))
4109 {
4110 u32_node *rrset_node = u32_set_iterator_next_node(&rrset_iter);
4111
4112 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)rrset_node->value;
4113
4114 if(rr_set == NULL)
4115 {
4116 log_debug("zone-diff: %{dnsname}: %{dnsname} has no record set", origin, diff_fqdn_name);
4117 continue;
4118 }
4119
4120 format_writer temp_fw_1 = {zone_diff_fqdn_changes_format, diff_fqdn};
4121 logger_handle_msg_nocull(handle, level, LOG_TEXT_PREFIX "zone-diff: %{dnsname}: %{dnsname}: %w", origin, diff_fqdn_name, &temp_fw_1);
4122
4123 zone_diff_fqdn_rr_set_log(rr_set, origin, handle, level);
4124 }
4125 }
4126
4127 void
zone_diff_log(const zone_diff * diff,logger_handle * handle,int level)4128 zone_diff_log(const zone_diff *diff, logger_handle *handle, int level)
4129 {
4130 if(!log_is_set(handle, level))
4131 {
4132 return;
4133 }
4134
4135 ptr_set_iterator fqdn_iter;
4136
4137 // for all fqdn
4138
4139 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
4140 while(ptr_set_iterator_hasnext(&fqdn_iter))
4141 {
4142 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
4143 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
4144 zone_diff_fqdn_log(diff_fqdn, diff->origin, handle, level);
4145 }
4146 }
4147
4148 int
zone_diff_check_changes(const zone_diff * diff,logger_handle * handle,int level)4149 zone_diff_check_changes(const zone_diff *diff, logger_handle *handle, int level)
4150 {
4151 ptr_set_iterator fqdn_iter;
4152
4153 int changes = 0;
4154
4155 ptr_set_iterator_init(&diff->fqdn, &fqdn_iter);
4156 while(ptr_set_iterator_hasnext(&fqdn_iter))
4157 {
4158 ptr_node *diff_fqdn_node = ptr_set_iterator_next_node(&fqdn_iter);
4159 zone_diff_fqdn *diff_fqdn = (zone_diff_fqdn*)diff_fqdn_node->value;
4160
4161 u32_set_iterator rrset_iter;
4162 u32_set_iterator_init(&diff_fqdn->rrset, &rrset_iter);
4163 while(u32_set_iterator_hasnext(&rrset_iter))
4164 {
4165 u32_node *rrset_node = u32_set_iterator_next_node(&rrset_iter);
4166
4167 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)rrset_node->value;
4168
4169 ptr_set_iterator rr_iter;
4170
4171 ptr_set_iterator_init(&rr_set->rr, &rr_iter);
4172 while(ptr_set_iterator_hasnext(&rr_iter))
4173 {
4174 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
4175 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
4176
4177 if(!(rr->state & ZONE_DIFF_RR_AUTOMATED))
4178 {
4179 if(rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE))
4180 {
4181 ++changes;
4182 }
4183 }
4184 }
4185 }
4186 }
4187
4188
4189 if(changes == 0)
4190 {
4191 zone_diff_log(diff, handle, level);
4192 }
4193
4194 return changes;
4195 }
4196
4197 /**
4198 * Signs RRSET with all active keys found in keys.
4199 * Doesn't do any pertinence tests.
4200 * It's only use now is to add RRSIG records to NSEC3 rrsets that have no valid signatures
4201 *
4202 */
4203
4204 void
zone_diff_sign_rrset(zone_diff * diff,zdb_zone * zone,ptr_vector * keys,ptr_vector * add,zone_diff_fqdn_rr_set * rr_set,zone_diff_fqdn_rr_set * rrsig_rr_set)4205 zone_diff_sign_rrset(zone_diff *diff, zdb_zone *zone, ptr_vector *keys, ptr_vector *add, zone_diff_fqdn_rr_set *rr_set, zone_diff_fqdn_rr_set *rrsig_rr_set)
4206 {
4207 ptr_vector rrset = PTR_VECTOR_EMPTY;
4208 dnskey_signature ds;
4209 dnskey_signature_init(&ds);
4210
4211 // setup the view for the RRSET (RRSET abstraction for the part that generates signatures)
4212
4213 struct resource_record_view rrv = {NULL, &zone_diff_label_rr_rrv_vtbl};
4214 rrv.data = rr_set;
4215
4216 ptr_vector_clear(&rrset);
4217
4218 //const u8* rr_fqdn = NULL;
4219
4220 u8 rrsig_state_mask = ZONE_DIFF_RR_AUTOMATED;
4221
4222 // accumulate records
4223
4224 FOREACH_PTR_SET(void*,value, &rr_set->rr)
4225 {
4226 zone_diff_label_rr* rr = (zone_diff_label_rr*)value;
4227 //rr_fqdn = rr->fqdn;
4228
4229 // if the RR will exist in the zone (A.K.A: not removed), add it to the collection to sign
4230 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0)
4231 {
4232 #if DEBUG
4233 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
4234 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
4235 log_debug2("update: %{dnsname}: covers %w %{dnsname} %9i %{typerdatadesc}%s", diff->origin, &temp_fw_0, rr->fqdn, rr->ttl, &rd,
4236 ((rr->state & ZONE_DIFF_RR_AUTOMATED)!=0)?"<AUTOMATED>":"");
4237 #endif
4238 rrsig_state_mask &= rr->state;
4239
4240 ptr_vector_append(&rrset, value);
4241 }
4242 else
4243 {
4244 #if DEBUG
4245 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
4246 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
4247 log_debug2("update: %{dnsname}: ignore %w %{dnsname} %9i %{typerdatadesc}", diff->origin, &temp_fw_0, rr->fqdn, rr->ttl, &rd);
4248 #endif
4249 }
4250 }
4251
4252 for(int j = 0; j <= ptr_vector_last_index(keys); ++j)
4253 {
4254 const dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, j);
4255
4256 // check if the key has private components
4257
4258 if(!dnskey_is_private(key))
4259 {
4260 log_debug("update: %{dnsname}: key K%{dnsname}+%03d+%05d is not private", diff->origin,
4261 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4262 continue;
4263 }
4264
4265 zone_diff_label_rr *rrsig_rr = NULL;
4266
4267 ya_result ret;
4268
4269 s32 maxinterval = diff_generate_signature_interval(diff);
4270
4271 // rrset_to_sign;
4272 if(ISOK(ret = dnskey_sign_rrset_with_maxinterval(key, &rrset, TRUE, &rrv, maxinterval, (void **) &rrsig_rr)))
4273 {
4274 // add the key to the add set
4275
4276 log_debug2("update: %{dnsname}: signed %{dnsname} %{dnstype} rrset with key %03d %05d",diff->origin,
4277 rrsig_rr->fqdn, &rr_set->rtype,
4278 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4279
4280 s32 signature_valid_until = rrsig_get_valid_until_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size);
4281
4282 // if the signature expires in this time
4283
4284 if(signature_valid_until > 0)
4285 {
4286 if(signature_valid_until < dnskey_get_inactive_epoch(key))
4287 {
4288 s32 signature_regeneration_time = signature_valid_until - diff->rrsig_validity_regeneration;
4289
4290 if(zone->progressive_signature_update.earliest_signature_expiration > signature_regeneration_time)
4291 {
4292 zone->progressive_signature_update.earliest_signature_expiration = signature_regeneration_time;
4293 }
4294 }
4295 else
4296 {
4297 if(zone->progressive_signature_update.earliest_signature_expiration > signature_valid_until)
4298 {
4299 zone->progressive_signature_update.earliest_signature_expiration = signature_valid_until;
4300 }
4301 }
4302 }
4303
4304 rrsig_rr->state |= rrsig_state_mask;
4305 #if 0 /* fix */
4306 #else
4307 zone_diff_label_rr *final_rrsig_rr = zone_diff_fqdn_rr_set_rr_add_get(rrsig_rr_set, rrsig_rr);
4308 if((final_rrsig_rr->state & ZONE_DIFF_RR_IN_ZONE) == 0)
4309 {
4310 ptr_vector_append(add, final_rrsig_rr);
4311 }
4312 #endif
4313 }
4314 else
4315 {
4316 log_warn("update: %{dnsname}: failed to sign with key %03d %05d: %r",
4317 diff->origin,
4318 dnskey_get_algorithm(key), dnskey_get_tag_const(key), ret);
4319 // ...
4320 }
4321 } // for each key
4322 }
4323
4324 /**
4325 * Appends RRSIGs to remove/add vector, following the the need-to-be-signed RR set, using keys from KSK and ZSK vectors.
4326 *
4327 * @param diff
4328 * @param rrset_to_sign_vector
4329 * @param ksks
4330 * @param zsks
4331 * @param remove
4332 * @param add
4333 */
4334
4335 ya_result
zone_diff_sign(zone_diff * diff,zdb_zone * zone,ptr_vector * rrset_to_sign_vector,ptr_vector * ksks,ptr_vector * zsks,ptr_vector * remove,ptr_vector * add)4336 zone_diff_sign(zone_diff *diff, zdb_zone *zone, ptr_vector* rrset_to_sign_vector, ptr_vector *ksks, ptr_vector *zsks, ptr_vector *remove, ptr_vector* add)
4337 {
4338 /**************************************************************************
4339 * SIGNATURES HANDLING
4340 **************************************************************************/
4341
4342 (void)remove;
4343
4344 // if there are no rrset to be signed, don't bother going further
4345
4346 if(ptr_vector_last_index(rrset_to_sign_vector) < 0)
4347 {
4348 return SUCCESS;
4349 }
4350
4351 // eliminate potential duplicates (rare case)
4352
4353 {
4354 ptr_vector_qsort(rrset_to_sign_vector, ptr_vector_compare_pointers_callback);
4355
4356 void *prev = ptr_vector_get(rrset_to_sign_vector, 0);
4357 for(s32 i = 1; i <= ptr_vector_last_index(rrset_to_sign_vector);)
4358 {
4359 void *item = ptr_vector_get(rrset_to_sign_vector, i);
4360 if(item == prev)
4361 {
4362 ptr_vector_remove_at(rrset_to_sign_vector, i);
4363 continue;
4364 }
4365
4366 prev = item;
4367
4368 ++i;
4369 }
4370 }
4371
4372 /*
4373 * for each rrset in rrset_to_sign
4374 * for each valid zsk in the keyring
4375 * start new signature
4376 * add each record
4377 * generate signature
4378 */
4379
4380 log_debug("update: %{dnsname}: signing differences", diff->origin);
4381
4382 #if DEBUG
4383 zone_diff_log(diff, MODULE_MSG_HANDLE, MSG_DEBUG2);
4384 #endif
4385
4386 // if there is a chain, proceed with the changes
4387
4388 ptr_vector rrset = PTR_VECTOR_EMPTY;
4389 dnskey_signature ds;
4390 dnskey_signature_init(&ds);
4391
4392 // setup the view for the RRSET (RRSET abstraction for the part that generates signatures)
4393
4394 struct resource_record_view rrv = {NULL, &zone_diff_label_rr_rrv_vtbl};
4395
4396 // for each RRSET
4397
4398 for(int i = 0; i <= ptr_vector_last_index(rrset_to_sign_vector); ++i)
4399 {
4400 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)ptr_vector_get(rrset_to_sign_vector, i);
4401
4402 log_debug1("update: %{dnsname}: signing (trying) %{dnstype} rrset @%p", diff->origin, &rr_set->rtype, rr_set);
4403
4404 rrv.data = rr_set;
4405
4406 ptr_vector_clear(&rrset);
4407
4408 u8 rrsig_state_mask = ZONE_DIFF_RR_AUTOMATED;
4409
4410 // for each record in the RRSET
4411
4412 const u8* rr_fqdn = NULL;
4413
4414 // accumulate records
4415
4416 FOREACH_PTR_SET(void*,value, &rr_set->rr)
4417 {
4418 zone_diff_label_rr* rr = (zone_diff_label_rr*)value;
4419 rr_fqdn = rr->fqdn; // keep the fqdn from the first match
4420
4421 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4422 if(rr_set->rtype == TYPE_DNSKEY)
4423 {
4424 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
4425 log_info("update: %{dnsname}: [%02x] %{dnsname} %9i %{typerdatadesc}", diff->origin, rr->state, rr->fqdn, rr->ttl, &rd);
4426 }
4427 #endif
4428
4429 // if the RR will exist in the zone (A.K.A: not removed), add it to the collection to sign
4430 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0)
4431 {
4432 #if DEBUG
4433 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
4434 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
4435 log_debug2("update: %{dnsname}: covers %w %{dnsname} %9i %{typerdatadesc}%s", diff->origin, &temp_fw_0, rr->fqdn, rr->ttl, &rd,
4436 ((rr->state & ZONE_DIFF_RR_AUTOMATED)!=0)?"<AUTOMATED>":"");
4437 #endif
4438 rrsig_state_mask &= rr->state;
4439
4440 ptr_vector_append(&rrset, value);
4441 }
4442 else
4443 {
4444 #if DEBUG
4445 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
4446 format_writer temp_fw_0 = {zone_diff_record_state_format, &rr->state};
4447 log_debug2("update: %{dnsname}: ignore %w %{dnsname} %9i %{typerdatadesc}", diff->origin, &temp_fw_0, rr->fqdn, rr->ttl, &rd);
4448 #endif
4449 }
4450 }
4451
4452 if(rr_fqdn == NULL)
4453 {
4454 continue;
4455 }
4456
4457 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4458 if(rr_set->rtype == TYPE_DNSKEY)
4459 {
4460 log_info("update: %{dnsname}: DNSKEY records may be updated", diff->origin);
4461 }
4462 #endif
4463
4464 // if the collection is empty, nothing more to do for this RRSET
4465
4466 zone_diff_fqdn *rrsig_label = zone_diff_fqdn_add(diff, rr_fqdn, NULL);
4467
4468 if(ptr_vector_last_index(&rrset) < 0)
4469 {
4470 // except removing all signatures associated with it ...
4471
4472 if(rrsig_label != NULL)
4473 {
4474
4475 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4476 if(rr_set->rtype == TYPE_DNSKEY)
4477 {
4478 log_info("update: %{dnsname}: DNSKEY rrset empty, all its signatures will be removed", diff->origin);
4479 }
4480 #endif
4481
4482 zone_diff_fqdn_rr_set *rrsig_label_rrset = zone_diff_fqdn_rr_set_add(rrsig_label, TYPE_RRSIG);
4483
4484 FOREACH_PTR_SET(void*,value, &rrsig_label_rrset->rr)
4485 {
4486 zone_diff_label_rr* rrsig_rr = (zone_diff_label_rr*)value;
4487
4488 if(rrsig_get_type_covered_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size) == rr_set->rtype)
4489 {
4490 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4491 if(rr_set->rtype == TYPE_DNSKEY)
4492 {
4493 rdata_desc rd = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
4494 log_info("update: %{dnsname}: will remove %{dnsname} %9i %{typerdatadesc}", diff->origin, rrsig_rr->fqdn, rrsig_rr->ttl, &rd);
4495 }
4496 #endif
4497 if((rrsig_rr->state & ZONE_DIFF_RR_REMOVED) == 0)
4498 {
4499 rrsig_rr->state &= ~ZONE_DIFF_RR_ADD;
4500 rrsig_rr->state |= ZONE_DIFF_RR_REMOVE;
4501 #if DEBUG
4502 rdata_desc rd = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
4503 log_debug("update: %{dnsname}: will remove %{dnsname} %9i %{typerdatadesc}", diff->origin, rrsig_rr->fqdn, rrsig_rr->ttl, &rd);
4504 #endif
4505 ptr_vector_append(remove, rrsig_rr);
4506 rrsig_rr->state |= ZONE_DIFF_RR_REMOVED;
4507 }
4508 }
4509 }
4510 }
4511 continue;
4512 }
4513
4514 yassert(rrsig_label != NULL);
4515
4516 zone_diff_fqdn_rr_set *rrsig_label_rrset = zone_diff_fqdn_rr_set_add(rrsig_label, TYPE_RRSIG);
4517
4518 yassert(rrsig_label_rrset != NULL);
4519
4520 // take note that some RRSIG records will be added
4521
4522 rrsig_state_mask |= ZONE_DIFF_RR_ADD;
4523
4524 bool canonize = TRUE;
4525
4526 ptr_vector *keys;
4527
4528 yassert(rr_set->rtype != TYPE_RRSIG);
4529
4530 // use the adequate DNSKEY collection
4531
4532 keys = (rr_set->rtype != TYPE_DNSKEY)?zsks:ksks;
4533
4534 // for all keys from said collection
4535
4536 for(int j = 0; j <= ptr_vector_last_index(keys); ++j)
4537 {
4538 const dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, j);
4539
4540 // check if the key is to be used (using the key_mask)
4541
4542 if((rr_set->key_mask & (1ULL << j)) == 0)
4543 {
4544 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4545 if(rr_set->rtype == TYPE_DNSKEY)
4546 {
4547 log_info("update: %{dnsname} DNSKEY will not use key %03d %05d as the signature doesn't need an update", diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4548 }
4549 #endif
4550
4551 #if DEBUG
4552 zone_diff_label_rr* rr = ptr_vector_get(&rrset, 0);
4553
4554 log_debug2("update: %{dnsname}: %{dnsname} %{dnstype} does not need a signature update for key %03d %05d",
4555 diff->origin,
4556 rr->fqdn, &rr->rtype,
4557 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4558 #endif
4559 continue; // skip
4560 }
4561
4562 // check if the key has private components
4563
4564 if(!dnskey_is_private(key))
4565 {
4566 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4567 if(rr_set->rtype == TYPE_DNSKEY)
4568 {
4569 log_info("update: %{dnsname} DNSKEY cannot use key %03d %05d as it is not private",
4570 diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4571 }
4572 #endif
4573 log_debug("update: %{dnsname}: key K%{dnsname}+%03d+%05d is not private", diff->origin,
4574 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4575 continue;
4576 }
4577
4578 if(dnskey_is_deactivated(key, time(NULL) - 5)) // don't generate it if it's about to expire
4579 {
4580 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4581 if(rr_set->rtype == TYPE_DNSKEY)
4582 {
4583 log_info("update: %{dnsname} DNSKEY cannot use key %03d %05d as its deactivated",
4584 diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4585 }
4586 #endif
4587 log_debug("update: %{dnsname}: key K%{dnsname}+%03d+%05d is about to be deactivated", diff->origin,
4588 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4589 continue;
4590 }
4591
4592 zone_diff_label_rr *rrsig_rr = NULL;
4593
4594 ya_result ret;
4595
4596 s32 maxinterval = diff_generate_signature_interval(diff);
4597
4598 // rrset_to_sign;
4599 if(ISOK(ret = dnskey_sign_rrset_with_maxinterval(key, &rrset, canonize, &rrv, maxinterval, (void **)&rrsig_rr)))
4600 {
4601 canonize = FALSE;
4602
4603 // add the key to the add set
4604
4605 #if DYNUPDATE_DIFF_DETAILED_DNSKEY_LOG
4606 if(rr_set->rtype == TYPE_DNSKEY)
4607 {
4608 log_info("update: %{dnsname} DNSKEY has been signed with key %03d %05d", diff->origin, dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4609 }
4610 #endif
4611
4612 log_debug2("update: %{dnsname}: signed %{dnsname} %{dnstype} rrset with key %03d %05d",diff->origin,
4613 rrsig_rr->fqdn, &rr_set->rtype,
4614 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4615
4616 s32 signature_valid_until = rrsig_get_valid_until_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size);
4617
4618 // if the signature expires in this time
4619
4620 if(signature_valid_until > 0)
4621 {
4622 if(signature_valid_until < dnskey_get_inactive_epoch(key))
4623 {
4624 s32 signature_regeneration_time = signature_valid_until - diff->rrsig_validity_regeneration;
4625
4626 if(zone->progressive_signature_update.earliest_signature_expiration > signature_regeneration_time)
4627 {
4628 zone->progressive_signature_update.earliest_signature_expiration = signature_regeneration_time;
4629 }
4630 }
4631 else
4632 {
4633 if(zone->progressive_signature_update.earliest_signature_expiration > signature_valid_until)
4634 {
4635 zone->progressive_signature_update.earliest_signature_expiration = signature_valid_until;
4636 }
4637 }
4638 }
4639
4640 rrsig_rr->state |= rrsig_state_mask;
4641 #if 0 /* fix */
4642 #else
4643 #if DEBUG
4644 {
4645 rdata_desc rrsig_rr_desc = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
4646 log_debug6("update: %{dnsname}: signature <= %p [%02x] %{dnsname} %i %{typerdatadesc}", diff->origin, rrsig_rr, rrsig_rr->state, rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_rr_desc);
4647 }
4648 #endif
4649 zone_diff_label_rr *final_rrsig_rr = zone_diff_fqdn_rr_set_rr_add_get(rrsig_label_rrset, rrsig_rr); // replace is right (should be unique)
4650 #if DEBUG
4651 {
4652 rdata_desc rrsig_rr_desc = {final_rrsig_rr->rtype, final_rrsig_rr->rdata_size, final_rrsig_rr->rdata};
4653 log_debug6("update: %{dnsname}: signature => %p [%02x] %{dnsname} %i %{typerdatadesc}", diff->origin, final_rrsig_rr, final_rrsig_rr->state, final_rrsig_rr->fqdn, final_rrsig_rr->ttl, &rrsig_rr_desc);
4654 }
4655 #endif
4656 if((final_rrsig_rr->state & ZONE_DIFF_RR_IN_ZONE) == 0)
4657 {
4658 ptr_vector_append(add, final_rrsig_rr);
4659
4660 if(rrsig_label != NULL)
4661 {
4662 // int rrsig_count = 0;
4663
4664 FOREACH_PTR_SET(void*,value, &rrsig_label_rrset->rr)
4665 {
4666 zone_diff_label_rr* rrsig_rr = (zone_diff_label_rr*)value;
4667
4668 if((rrsig_rr->state & (ZONE_DIFF_RR_IN_ZONE|ZONE_DIFF_RR_REMOVE|ZONE_DIFF_RR_REMOVED)) == ZONE_DIFF_RR_IN_ZONE) // if the key is marked as being removed, no need to remove it twice
4669 {
4670 // key is kept or added
4671
4672 u16 ctype = rrsig_get_type_covered_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size); // type covered by the signature
4673 if(ctype == rr_set->rtype)
4674 {
4675 u16 keytag = rrsig_get_key_tag_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size);
4676
4677 if(keytag == dnskey_get_tag_const(key))
4678 {
4679 u8 keyalg = rrsig_get_algorithm_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size);
4680
4681 if(keyalg == dnskey_get_algorithm(key))
4682 {
4683 #if DEBUG
4684 rdata_desc rrsig_rr_desc = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
4685 log_debug6("update: %{dnsname}: [%02x] %{dnsname} %i %{typerdatadesc} is obsolete", diff->origin, rrsig_rr->state, rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_rr_desc);
4686 #endif
4687 rrsig_rr->state |= ZONE_DIFF_RR_REMOVE;
4688 ptr_vector_append(remove, rrsig_rr);
4689 rrsig_rr->state |= ZONE_DIFF_RR_REMOVED;
4690 }
4691 }
4692 }
4693 }
4694 }
4695 }
4696 }
4697 #endif
4698 //(void)rrsig_rr_set;
4699 }
4700 else
4701 {
4702 log_warn("update: %{dnsname}: failed to sign with key %03d %05d: %r",
4703 diff->origin,
4704 dnskey_get_algorithm(key), dnskey_get_tag_const(key), ret);
4705 // ...
4706 }
4707 } // for each key
4708
4709 // remove signatures not covered by an active key
4710
4711 if(rrsig_label != NULL)
4712 {
4713 int rrsig_count = 0;
4714 int rrsig_known = 0;
4715 int rrsig_ignored = 0;
4716
4717 FOREACH_PTR_SET(void*,value, &rrsig_label_rrset->rr)
4718 {
4719 ++rrsig_known;
4720
4721 zone_diff_label_rr* rrsig_rr = (zone_diff_label_rr*)value;
4722 #if DEBUG
4723 rdata_desc rrsig_rr_desc = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
4724 log_debug6("update: %{dnsname}: [%02x] %{dnsname} %i %{typerdatadesc}", diff->origin, rrsig_rr->state, rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_rr_desc);
4725 #endif
4726 if(rrsig_rr->state & ZONE_DIFF_RR_REMOVE) // if the key is marked as being removed, no need to remove it twice
4727 {
4728 rrsig_label->rrsig_removed = 1;
4729 continue;
4730 }
4731
4732 // key is kept or added
4733
4734 u16 ctype = rrsig_get_type_covered_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size); // type covered by the signature
4735 if(ctype == rr_set->rtype)
4736 {
4737 u16 keytag = rrsig_get_key_tag_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size);
4738 u8 keyalg = rrsig_get_algorithm_from_rdata(rrsig_rr->rdata, rrsig_rr->rdata_size);
4739
4740 bool keep = FALSE;
4741
4742 ++rrsig_ignored;
4743
4744 for(int j = 0; j <= ptr_vector_last_index(keys); ++j)
4745 {
4746 const dnssec_key *key = (dnssec_key*)ptr_vector_get(keys, j);
4747
4748 if((dnskey_get_algorithm(key) == keyalg) && (dnskey_get_tag_const(key) == keytag))
4749 {
4750 --rrsig_ignored;
4751 ++rrsig_count;
4752 keep = TRUE;
4753 break;
4754 }
4755 }
4756
4757 if(keep)
4758 {
4759 if(rrsig_rr->state & ZONE_DIFF_RR_ADD)
4760 {
4761 rrsig_label->rrsig_added = 1; // new
4762 }
4763 else
4764 {
4765 rrsig_label->rrsig_kept = 1; // already in zone
4766 }
4767 }
4768 else
4769 {
4770 #if DEBUG
4771 rdata_desc rd = {rrsig_rr->rtype, rrsig_rr->rdata_size, rrsig_rr->rdata};
4772 log_debug("update: %{dnsname}: will remove %{dnsname} %9i %{typerdatadesc}", diff->origin, rrsig_rr->fqdn, rrsig_rr->ttl, &rd);
4773 #endif
4774 rrsig_rr->state |= ZONE_DIFF_RR_REMOVE;
4775 ptr_vector_append(remove, rrsig_rr);
4776 rrsig_rr->state |= ZONE_DIFF_RR_REMOVED;
4777 }
4778 }
4779 } // for all RRSIG in the RRSIG rrset
4780
4781 if(rrsig_count == 0)
4782 {
4783 // record set cannot be properly signed
4784
4785 log_warn("update: %{dnsname}: %{dnsname} %{dnstype} not covered by a signature (%i signatures in the set, %i ignored for the type)",
4786 diff->origin, rr_fqdn, &rr_set->rtype,
4787 rrsig_known, rrsig_ignored);
4788
4789 if(rrsig_label != NULL)
4790 {
4791 int rrsig_index = 0;
4792 FOREACH_PTR_SET(void*,value, &rrsig_label_rrset->rr)
4793 {
4794 zone_diff_label_rr* rrsig_rr = (zone_diff_label_rr*)value;
4795
4796 rdata_desc rrsig_record = {TYPE_RRSIG, rrsig_rr->rdata_size, rrsig_rr->rdata};
4797 log_warn("update: %{dnsname}: %02i [%02x] %{dnsname} %5i %{typerdatadesc}", diff->origin, rrsig_index, rrsig_rr->state, rrsig_rr->fqdn, rrsig_rr->ttl, &rrsig_record);
4798 ++rrsig_index;
4799 }
4800 }
4801
4802 dnskey_signature_finalize(&ds);
4803 ptr_vector_destroy(&rrset);
4804
4805 return DNSSEC_ERROR_RRSIG_NOUSABLEKEYS;
4806 }
4807 else
4808 {
4809 // record set cannot be properly signed and has no valid signatures
4810 #if DEBUG
4811 log_debug1("update: %{dnsname}: %{dnsname} %{dnstype} is covered by a signature", diff->origin, rr_fqdn, &rr_set->rtype);
4812 #endif
4813 }
4814 } // if(rrsig_label != NULL)
4815 } // for(int i = 0; i <= ptr_vector_last_index(rrset_to_sign_vector); ++i) // FOR EACH RRSET
4816
4817 dnskey_signature_finalize(&ds);
4818 ptr_vector_destroy(&rrset);
4819
4820 return SUCCESS;
4821 }
4822
4823 void
zone_diff_store_diff_dnskey_get_keys(zone_diff * diff,ptr_vector * ksks,ptr_vector * zsks)4824 zone_diff_store_diff_dnskey_get_keys(zone_diff *diff, ptr_vector *ksks, ptr_vector *zsks)
4825 {
4826 // remove all signing keys that are about to be removed
4827 // add all activated signing keys that are being added
4828
4829 const zone_diff_fqdn *apex = diff->apex;
4830 const zone_diff_fqdn_rr_set *dnskey_rrset = zone_diff_fqdn_rr_get_const(apex, TYPE_DNSKEY);
4831
4832 if(dnskey_rrset != NULL)
4833 {
4834 // for all keys, handle added and removed ones
4835
4836 time_t now = time(NULL);
4837
4838 dnssec_key *key;
4839
4840 ptr_set_iterator rr_iter;
4841 ptr_set_iterator_init(&dnskey_rrset->rr, &rr_iter);
4842 while(ptr_set_iterator_hasnext(&rr_iter))
4843 {
4844 ptr_node *node = ptr_set_iterator_next_node(&rr_iter);
4845 zone_diff_label_rr *rr = (zone_diff_label_rr *)node->key;
4846 #if DEBUG
4847 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': key listed (%02x)", diff->origin,
4848 dnskey_get_algorithm_from_rdata(rr->rdata),
4849 dnskey_get_tag_from_rdata(rr->rdata, rr->rdata_size), rr->state);
4850 #endif
4851 if((rr->state & ZONE_DIFF_RR_REMOVE) == 0) // exists or is being added
4852 {
4853 key = NULL;
4854 ya_result ret = dnssec_keystore_load_private_key_from_rdata(rr->rdata, rr->rdata_size, rr->fqdn, &key);
4855
4856 if(ISOK(ret))
4857 {
4858 ptr_vector *keys = NULL;
4859
4860 if(dnskey_get_flags(key) == DNSKEY_FLAGS_KSK)
4861 {
4862 keys = ksks;
4863 }
4864 else if(dnskey_get_flags(key) == DNSKEY_FLAGS_ZSK)
4865 {
4866 keys = zsks;
4867 }
4868
4869 // if key is activated, and not already in the (signing) set, add it
4870 #if DEBUG
4871 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': key found, exists or is about to be added", diff->origin,
4872 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4873 #endif
4874 if(dnskey_is_activated_lenient(key, now, 5))
4875 {
4876 #if DEBUG
4877 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': private key is active", diff->origin,
4878 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4879 #endif
4880
4881 #if DEBUG
4882 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': private key added in signers", diff->origin,
4883 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4884 #endif
4885 ptr_vector_append(keys, key);
4886 }
4887 else
4888 {
4889 #if DEBUG
4890 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': private key is not active", diff->origin,
4891 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4892 #endif
4893 }
4894 }
4895 else // key is being removed
4896 {
4897 ya_result ret = dnssec_keystore_load_public_key_from_rdata(rr->rdata, rr->rdata_size, rr->fqdn, &key);
4898
4899 if(ISOK(ret))
4900 {
4901 #if DEBUG
4902 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': key found, about to be removed", diff->origin,
4903 dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4904 #endif
4905 ptr_vector *keys = NULL;
4906
4907 if(dnskey_get_flags(key) == DNSKEY_FLAGS_KSK)
4908 {
4909 keys = ksks;
4910 }
4911 else if(dnskey_get_flags(key) == DNSKEY_FLAGS_ZSK)
4912 {
4913 keys = zsks;
4914 }
4915 #if DEBUG
4916 log_debug("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': private key not loaded: %r", diff->origin,
4917 dnskey_get_algorithm_from_rdata(rr->rdata),
4918 dnskey_get_tag_from_rdata(rr->rdata, rr->rdata_size), ret);
4919 #endif
4920 ptr_vector_append(keys, key);
4921 }
4922 else
4923 {
4924 log_err("update: DNSKEY: 'K%{dnsname}+%03d+%05hd': public key not loaded: %r", diff->origin,
4925 dnskey_get_algorithm_from_rdata(rr->rdata),
4926 dnskey_get_tag_from_rdata(rr->rdata, rr->rdata_size), ret);
4927 }
4928 }
4929 }
4930 }
4931
4932 } // else would be surprising
4933
4934 #if DEBUG
4935 for(int i = 0; i <= ptr_vector_last_index(ksks); ++i)
4936 {
4937 dnssec_key *key = (dnssec_key*)ptr_vector_get(ksks, i);
4938 log_debug3("update: DNSKEY: KSK: 'K%{dnsname}+%03d+%05hd': final state", diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4939 }
4940
4941 for(int i = 0; i <= ptr_vector_last_index(zsks); ++i)
4942 {
4943 dnssec_key *key = (dnssec_key*)ptr_vector_get(zsks, i);
4944 log_debug3("update: DNSKEY: ZSK: 'K%{dnsname}+%03d+%05hd': final state", diff->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4945 }
4946 #endif
4947 }
4948
4949 static ya_result
zone_diff_verify_dnskey_presence(zone_diff * diff,zdb_zone * zone,ptr_vector * rrset_to_sign,ptr_vector * ksks,ptr_vector * zsks)4950 zone_diff_verify_dnskey_presence(zone_diff *diff, zdb_zone *zone, ptr_vector *rrset_to_sign, ptr_vector *ksks, ptr_vector *zsks)
4951 {
4952 ya_result ret = SUCCESS;
4953 u8 maintain_mode = zone_get_maintain_mode(zone);
4954
4955 if(maintain_mode > ZDB_ZONE_MAINTAIN_NOSEC)
4956 {
4957 for(int i = 0; i <= ptr_vector_last_index(ksks); ++i)
4958 {
4959 dnssec_key *key = (dnssec_key*)ptr_vector_get(ksks, i);
4960 log_debug3("update: DNSKEY: KSK: 'K%{dnsname}+%03d+%05hd': key visible", zone->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4961 }
4962
4963 for(int i = 0; i <= ptr_vector_last_index(zsks); ++i)
4964 {
4965 dnssec_key *key = (dnssec_key*)ptr_vector_get(zsks, i);
4966 log_debug3("update: DNSKEY: ZSK: 'K%{dnsname}+%03d+%05hd': key visible", zone->origin, dnskey_get_algorithm(key), dnskey_get_tag_const(key));
4967 }
4968
4969 zone_diff_fqdn *apex = zone_diff_fqdn_get(diff, diff->origin);
4970
4971 if(!zone_diff_will_have_rrset_type(apex, TYPE_DNSKEY))
4972 {
4973 log_err("update: %{dnsname}: there are no DNSKEY in the zone", zone->origin);
4974 ret = ZDB_ERROR_ZONE_NO_ACTIVE_DNSKEY_FOUND;
4975 }
4976
4977 for(int i = 0; i <= ptr_vector_last_index(rrset_to_sign); ++i)
4978 {
4979 zone_diff_fqdn_rr_set *rr_set = (zone_diff_fqdn_rr_set*)ptr_vector_get(rrset_to_sign, i);
4980
4981 if(!diff->rrsig_update_allowed)
4982 {
4983 if(rr_set->rtype != TYPE_DNSKEY)
4984 {
4985 if(ptr_vector_last_index(zsks) < 0)
4986 {
4987 log_warn("update: %{dnsname}: %{dnstype} record set is being modified but no ZSK can sign it", zone->origin, &rr_set->rtype);
4988 }
4989 }
4990 else
4991 {
4992 if(ptr_vector_last_index(ksks) < 0)
4993 {
4994 log_warn("update: %{dnsname} DNSKEY record set is being modified but no KSK can sign it", zone->origin);
4995 }
4996 }
4997 }
4998 }
4999 }
5000
5001 return ret;
5002 }
5003
5004 static ya_result
zone_diff_store_diff(zone_diff * diff,zdb_zone * zone,ptr_vector * remove,ptr_vector * add)5005 zone_diff_store_diff(zone_diff *diff, zdb_zone *zone, ptr_vector *remove, ptr_vector *add)
5006 {
5007 // for all fqdn
5008 // for all rrset
5009 // for all marked rr (add or remove)
5010 // put the rr(s) in the relevant vector
5011 // proceed with dnssec on the side
5012 // if changed and the rr must be signed
5013 // put all signatures rr in the remove set
5014 // generate relevant signatures and add them to the add set
5015
5016 // add the dnssec changes, including signatures
5017
5018 // then, because it's Y2 and not Y3, apply the changes into the DB with the journal ready to write
5019
5020 // so ..
5021
5022 ya_result ret;
5023
5024 if(FAIL(ret = zone_diff_set_soa(diff, NULL)))
5025 {
5026 return ret;
5027 }
5028
5029 /**************************************************************************
5030 * DIFF COMPUTATIONS
5031 **************************************************************************/
5032
5033 // initialise the chain(s)
5034
5035 dnssec_chain dc;
5036
5037 u8 maintain_mode = zone_get_maintain_mode(zone);
5038
5039 switch(maintain_mode)
5040 {
5041 case ZDB_ZONE_MAINTAIN_NSEC3:
5042 case ZDB_ZONE_MAINTAIN_NSEC3_OPTOUT:
5043 {
5044 dnssec_chain_init(&dc, (maintain_mode == ZDB_ZONE_MAINTAIN_NSEC3)?dynupdate_nsec3_chain_get_vtbl():dynupdate_nsec3_optout_chain_get_vtbl(), diff);
5045
5046 nsec3_zone *n3 = zone->nsec.nsec3;
5047
5048 while(n3 != NULL)
5049 {
5050 const u8 *nsec3param_rdata = n3->rdata;
5051 u8 nsec3_chain_status = 0;
5052 nsec3_zone_get_status_from_rdata(zone, nsec3param_rdata, NSEC3_ZONE_RDATA_SIZE(n3), &nsec3_chain_status);
5053
5054 dnssec_chain_add_chain(&dc, (dnssec_chain_head_t)n3, (nsec3_chain_status & NSEC3_ZONE_REMOVING) != 0);
5055 n3 = n3->next;
5056 }
5057 break;
5058 }
5059 case ZDB_ZONE_MAINTAIN_NSEC:
5060 {
5061 u8 nsec_chain_status = 0;
5062 nsec_zone_get_status(zone, &nsec_chain_status);
5063
5064 dnssec_chain_init(&dc, dynupdate_nsec_chain_get_vtbl(), diff);
5065 dnssec_chain_add_chain(&dc, (dnssec_chain_head_t)zone->nsec.nsec, (nsec_chain_status & NSEC_ZONE_REMOVING) != 0);
5066 break;
5067 }
5068 default:
5069 {
5070 dnssec_chain_init(&dc, dynupdate_nosec_chain_get_vtbl(), diff);
5071 break;
5072 }
5073 }
5074
5075 // update statuses, validates
5076
5077 if(ISOK(ret = zone_diff_validate(diff)))
5078 {
5079 ptr_vector ksks = PTR_VECTOR_EMPTY;
5080 ptr_vector zsks = PTR_VECTOR_EMPTY;
5081 ptr_vector rrset_to_sign = PTR_VECTOR_EMPTY;
5082
5083 // store changes in vectors and get the RR sets to sign
5084
5085 s32 mandatory_changes = zone_diff_get_changes(diff, &rrset_to_sign, &ksks, &zsks, remove, add);
5086
5087 #if DYNUPDATE_DIFF_DETAILED_LOG
5088 for(int i = 0; i <= ptr_vector_last_index(remove); ++i)
5089 {
5090 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(remove, i);
5091 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5092
5093 log_debug3("update: changes: %{dnsname}: - %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
5094 }
5095
5096 for(int i = 0; i <= ptr_vector_last_index(add); ++i)
5097 {
5098 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(add, i);
5099 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5100
5101 log_debug3("update: changes: %{dnsname}: + %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
5102 }
5103 #endif
5104
5105 #if DEBUG
5106 log_debug1("update: %{dnsname}: diff changes edited", zone->origin);
5107 zone_diff_log(diff, MODULE_MSG_HANDLE, MSG_DEBUG2);
5108 #endif
5109
5110 const bool changes_happened = (mandatory_changes > 0);
5111
5112 if(changes_happened)
5113 {
5114 ret = zone_diff_verify_dnskey_presence(diff, zone, &rrset_to_sign, &ksks, &zsks);
5115
5116 if(ISOK(ret))
5117 {
5118 // sign the records, store the changes in vectors
5119
5120 ret = zone_diff_sign(diff, zone, &rrset_to_sign, &ksks, &zsks, remove, add);
5121
5122 #if DYNUPDATE_DIFF_DETAILED_LOG
5123 for(int i = 0; i <= ptr_vector_last_index(remove); ++i)
5124 {
5125 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(remove, i);
5126 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5127
5128 log_debug3("update: sign: %{dnsname}: - %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
5129 }
5130
5131 for(int i = 0; i <= ptr_vector_last_index(add); ++i)
5132 {
5133 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(add, i);
5134 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5135
5136 log_debug3("update: sign: %{dnsname}: + %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
5137 }
5138 #endif
5139
5140 ptr_vector_destroy(&rrset_to_sign);
5141
5142 if(ISOK(ret))
5143 {
5144 zone_diff_get_chain_changes(diff, &dc);
5145
5146 // chain deletes should use the existing maps if possible (speed) or generate from the local state (all 'exists')
5147 // chain adds should use the local state (all exists not removed + all adds)
5148 #if DEBUG
5149 zone_diff_log(diff, MODULE_MSG_HANDLE, MSG_DEBUG2);
5150 #endif
5151 dnssec_chain_store_diff(&dc, diff, &zsks, remove, add);
5152
5153 #if DYNUPDATE_DIFF_DETAILED_LOG
5154 for(int i = 0; i <= ptr_vector_last_index(remove); ++i)
5155 {
5156 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(remove, i);
5157 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5158
5159 log_debug3("update: store: %{dnsname}: - %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
5160 }
5161
5162 for(int i = 0; i <= ptr_vector_last_index(add); ++i)
5163 {
5164 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(add, i);
5165 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5166
5167 log_debug3("update: store: %{dnsname}: + %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
5168 }
5169 #endif
5170 }
5171 }
5172 else
5173 {
5174 zone_diff_label_rr_vector_clear(remove);
5175 zone_diff_label_rr_vector_clear(add);
5176 ptr_vector_destroy(&rrset_to_sign);
5177 }
5178 }
5179 else
5180 {
5181 zone_diff_label_rr_vector_clear(remove);
5182 zone_diff_label_rr_vector_clear(add);
5183 ptr_vector_destroy(&rrset_to_sign);
5184
5185 if(FAIL(mandatory_changes))
5186 {
5187 log_warn("update: %{dnsname} update rejected: %r", zone->origin, mandatory_changes);
5188 }
5189 }
5190
5191 dnssec_keystore_release_keys_from_vector(&zsks);
5192 dnssec_keystore_release_keys_from_vector(&ksks);
5193
5194 ptr_vector_destroy(&zsks);
5195 ptr_vector_destroy(&ksks);
5196 }
5197
5198 dnssec_chain_finalize(&dc);
5199
5200 return ret;
5201 }
5202
5203 #if ZDB_HAS_DNSSEC_SUPPORT
5204
5205 /**
5206 * Get all DNSKEY records from the zone.
5207 * Load the private keys of these DNSKEY records in the keystore.
5208 *
5209 * @param zone
5210 * @return
5211 */
5212
5213 ya_result
dynupdate_diff_load_private_keys(zdb_zone * zone)5214 dynupdate_diff_load_private_keys(zdb_zone *zone)
5215 {
5216 ya_result return_code = SUCCESS;
5217
5218 // ensure all the private keys are available or servfail
5219
5220 const zdb_packed_ttlrdata *dnskey_rrset = zdb_zone_get_dnskey_rrset(zone); // zone is locked
5221
5222 int ksk_count = 0;
5223 int zsk_count = 0;
5224
5225 if(dnskey_rrset != NULL)
5226 {
5227 do
5228 {
5229 u16 flags = DNSKEY_FLAGS(*dnskey_rrset);
5230 u8 algorithm = DNSKEY_ALGORITHM(*dnskey_rrset);
5231 u16 tag = DNSKEY_TAG(*dnskey_rrset); // note: expensive
5232 dnssec_key *key = NULL;
5233
5234 if(!((flags == DNSKEY_FLAGS_KSK) && zdb_zone_get_rrsig_push_allowed(zone)))
5235 {
5236 if(ISOK(return_code = dnssec_keystore_load_private_key_from_parameters(algorithm, tag, flags, zone->origin, &key))) // key properly released
5237 {
5238 dnskey_release(key);
5239 }
5240 else
5241 {
5242 log_warn("update: unable to load the private key 'K%{dnsname}+%03d+%05hd': %r", zone->origin, algorithm, tag, return_code);
5243 }
5244 }
5245 else
5246 {
5247 // on an RRSIG-push-allowed zone, don't try to load a KSK
5248 }
5249
5250 if(flags == DNSKEY_FLAGS_KSK)
5251 {
5252 ++ksk_count;
5253 }
5254 else if(flags == DNSKEY_FLAGS_ZSK)
5255 {
5256 ++zsk_count;
5257 }
5258
5259 dnskey_rrset = dnskey_rrset->next;
5260 }
5261 while(dnskey_rrset != NULL);
5262
5263 return_code = ksk_count + zsk_count;
5264 }
5265 else
5266 {
5267 log_warn("update: there are no private keys in the zone %{dnsname}", zone->origin);
5268
5269 return_code = DNSSEC_ERROR_RRSIG_NOZONEKEYS;
5270 }
5271
5272 return return_code;
5273 }
5274
5275 #endif
5276
5277 /**
5278 * Writes the del then add records to the journal,
5279 * deletes the records marked as volatile,
5280 * exchanges the locks of the zone,
5281 * replays the journal
5282 * exchanges the locks back.
5283 *
5284 * Returns the result of the replay or SUCCESS if there was nothing to replay.
5285 *
5286 * @param zone
5287 * @param secondary_lock
5288 * @param del_vector
5289 * @param add_vector
5290 * @return
5291 */
5292
5293 ya_result
dynupdate_diff_write_to_journal_and_replay(zdb_zone * zone,u8 secondary_lock,ptr_vector * del_vector,ptr_vector * add_vector)5294 dynupdate_diff_write_to_journal_and_replay(zdb_zone *zone, u8 secondary_lock, ptr_vector *del_vector, ptr_vector *add_vector)
5295 {
5296 ya_result ret = 0;
5297
5298 bool changes_occurred = (ptr_vector_size(add_vector) + ptr_vector_size(del_vector)) > 2;
5299
5300 if(changes_occurred)
5301 {
5302 // instead of storing to a buffer and back, could write an inputstream
5303 // translating the ptr_vector content on the fly
5304
5305 s32 total_size_in_bytes = 0;
5306
5307 for(int i = 0; i <= ptr_vector_last_index(del_vector); ++i)
5308 {
5309 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(del_vector, i);
5310 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5311
5312 log_debug2("update: %{dnsname}: - %{dnsname} %9i %{typerdatadesc} ; (W+R)", zone->origin, rr->fqdn, rr->ttl, &rd);
5313
5314 total_size_in_bytes += dnsname_len(rr->fqdn);
5315 total_size_in_bytes += 10;
5316 total_size_in_bytes += rr->rdata_size;
5317 }
5318
5319 for(int i = 0; i <= ptr_vector_last_index(add_vector); ++i)
5320 {
5321 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(add_vector, i);
5322 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
5323
5324 log_debug2("update: %{dnsname}: + %{dnsname} %9i %{typerdatadesc} ; (W+R)", zone->origin, rr->fqdn, rr->ttl, &rd);
5325
5326 #if DEBUG
5327 switch(rr->rtype)
5328 {
5329 case TYPE_NSEC:
5330 {
5331 const u8 *fqdn = rr->rdata;
5332 const u8 *tbm = &fqdn[dnsname_len(fqdn)];
5333
5334 if((tbm - fqdn) == 0)
5335 {
5336 log_err("NSEC record has no type bitmap");
5337 abort();
5338 }
5339
5340 break;
5341 }
5342 default:
5343 {
5344 break;
5345 }
5346 }
5347 #endif
5348
5349 total_size_in_bytes += dnsname_len(rr->fqdn);
5350 total_size_in_bytes += 10;
5351 total_size_in_bytes += rr->rdata_size;
5352 }
5353
5354 log_debug("update: %{dnsname}: writing message", zone->origin);
5355
5356 output_stream baos;
5357
5358 bytearray_output_stream_init(&baos, NULL, total_size_in_bytes);
5359
5360 for(int i = 0; i <= ptr_vector_last_index(del_vector); ++i)
5361 {
5362 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(del_vector, i);
5363
5364 output_stream_write_dnsname(&baos, rr->fqdn);
5365 output_stream_write_u16(&baos, rr->rtype);
5366 output_stream_write_u16(&baos, rr->rclass);
5367 output_stream_write_nu32(&baos, rr->ttl);
5368 output_stream_write_nu16(&baos, rr->rdata_size);
5369 output_stream_write(&baos, rr->rdata, rr->rdata_size);
5370
5371 if((rr->state & ZONE_DIFF_RR_VOLATILE) != 0)
5372 {
5373 zone_diff_label_rr_delete(rr);
5374 }
5375 }
5376
5377 for(int i = 0; i <= ptr_vector_last_index(add_vector); ++i)
5378 {
5379 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(add_vector, i);
5380
5381 output_stream_write_dnsname(&baos, rr->fqdn);
5382 output_stream_write_u16(&baos, rr->rtype);
5383 output_stream_write_u16(&baos, rr->rclass);
5384 output_stream_write_nu32(&baos, rr->ttl);
5385 output_stream_write_nu16(&baos, rr->rdata_size);
5386 output_stream_write(&baos, rr->rdata, rr->rdata_size);
5387
5388 if((rr->state & ZONE_DIFF_RR_VOLATILE) != 0)
5389 {
5390 zone_diff_label_rr_delete(rr);
5391 }
5392 }
5393
5394 log_debug1("update: %{dnsname}: message ready", zone->origin);
5395
5396 input_stream bais;
5397
5398 bytearray_input_stream_init(&bais, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos), FALSE);
5399
5400 log_debug("update: %{dnsname}: acquiring journal", zone->origin);
5401
5402 journal* jnl = NULL;
5403 if(ISOK(ret = journal_acquire_from_zone_ex(&jnl, zone, TRUE)))
5404 {
5405 jnl->vtbl->minimum_serial_update(jnl, zone->text_serial);
5406
5407 u32 journal_max_size = zone->wire_size / 3;
5408 zdb_zone_info_get_zone_max_journal_size(zone->origin, &journal_max_size);
5409 jnl->vtbl->maximum_size_update(jnl, journal_max_size);
5410
5411 if(ISOK(ret = journal_append_ixfr_stream(jnl, &bais))) // writes a single page
5412 {
5413 log_debug("update: %{dnsname}: wrote %i bytes to the journal", zone->origin, total_size_in_bytes);
5414
5415 bytearray_input_stream_reset(&bais);
5416
5417 u32 current_serial = 0;
5418
5419 if(secondary_lock != 0)
5420 {
5421 zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, secondary_lock);
5422 }
5423
5424 ret = zdb_icmtl_replay_commit(zone, &bais, ¤t_serial);
5425
5426 if(secondary_lock != 0)
5427 {
5428 zdb_zone_exchange_locks(zone, secondary_lock, ZDB_ZONE_MUTEX_SIMPLEREADER);
5429 }
5430
5431 if(ISOK(ret))
5432 {
5433 log_info("update: %{dnsname}: applied %u changes (%u bytes), serial=%u", zone->origin, ret, total_size_in_bytes, current_serial);
5434
5435 ret = total_size_in_bytes;
5436 }
5437 else
5438 {
5439 log_err("update: %{dnsname}: could not apply changes: %r", zone->origin, ret);
5440 }
5441 }
5442 else if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
5443 {
5444 log_info("update: %{dnsname}: could not write %i bytes to the journal as it is full and the zone needs to be locally stored first", zone->origin, total_size_in_bytes);
5445 }
5446 else
5447 {
5448 log_err("update: %{dnsname}: could not write %i bytes to the journal: %r", zone->origin, total_size_in_bytes, ret);
5449 }
5450
5451 journal_release(jnl);
5452 }
5453 else
5454 {
5455 log_err("update: %{dnsname}: could not acquire journal: %r", zone->origin, ret);
5456 }
5457
5458 input_stream_close(&bais);
5459 output_stream_close(&baos);
5460 }
5461
5462 return ret;
5463 }
5464
5465 /**
5466 *
5467 * Computes the diff of an update.
5468 *
5469 * @param zone
5470 * @param reader
5471 * @param count
5472 * @param dryrun
5473 * @return
5474 */
5475
5476 ya_result
dynupdate_diff(zdb_zone * zone,packet_unpack_reader_data * reader,u16 count,u8 secondary_lock,bool dryrun)5477 dynupdate_diff(zdb_zone *zone, packet_unpack_reader_data *reader, u16 count, u8 secondary_lock, bool dryrun)
5478 {
5479 yassert(zdb_zone_islocked(zone));
5480
5481 #if DEBUG
5482 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i)",
5483 zone->origin, zone, reader, count, secondary_lock, dryrun);
5484 #endif
5485
5486 if(zdb_zone_invalid(zone))
5487 {
5488 #if DEBUG
5489 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with ZDB_ERROR_ZONE_INVALID",
5490 zone->origin, zone, reader, count, secondary_lock, dryrun);
5491 #endif
5492 return ZDB_ERROR_ZONE_INVALID;
5493 }
5494
5495 if(count == 0)
5496 {
5497 #if DEBUG
5498 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) success with count == 0",
5499 zone->origin, zone, reader, count, secondary_lock, dryrun);
5500 #endif
5501 return SUCCESS;
5502 }
5503
5504 if(packet_reader_opcode(reader) != (OPCODE_UPDATE >> OPCODE_SHIFT))
5505 {
5506 #if DEBUG
5507 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) not an update message",
5508 zone->origin, zone, reader, count, secondary_lock, dryrun);
5509 #endif
5510 return INVALID_STATE_ERROR;
5511 }
5512
5513 // if the status was already set, stop
5514
5515 if((zdb_zone_set_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF) & ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF) != 0)
5516 {
5517 return INVALID_STATE_ERROR; // already
5518 }
5519
5520 zdb_packed_ttlrdata* soa = zdb_record_find(&zone->apex->resource_record_set, TYPE_SOA);
5521
5522 if(soa == NULL)
5523 {
5524 #if DEBUG
5525 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with ZDB_ERROR_NOSOAATAPEX",
5526 zone->origin, zone, reader, count, secondary_lock, dryrun);
5527 #endif
5528
5529 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5530
5531 return ZDB_ERROR_NOSOAATAPEX;
5532 }
5533
5534 #if DEBUG
5535 {
5536 u32 soa_serial = 0;
5537 rr_soa_get_serial(ZDB_PACKEDRECORD_PTR_RDATAPTR(soa), ZDB_PACKEDRECORD_PTR_RDATASIZE(soa), &soa_serial);
5538 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) from serial %u",
5539 zone->origin, zone, reader, count, secondary_lock, dryrun, soa_serial);
5540 }
5541 #endif
5542
5543 zone_diff diff;
5544 zone_diff_init(&diff, zone, zdb_zone_get_rrsig_push_allowed(zone));
5545
5546 dnsname_vector name_path;
5547
5548 #if DEBUG
5549 memset(&name_path, 0xff, sizeof(name_path));
5550 #endif
5551
5552 u8 *rname;
5553 u8 *rdata;
5554 //u32 rname_size;
5555 u32 rttl;
5556 ya_result ret; // = SUCCESS;
5557 ya_result ret_status = 0;
5558 //s32 zsk_key_update_mask = 0;
5559 u16 rtype;
5560 u16 rclass;
5561 u16 rdata_size;
5562 s8 has_valid_ksk = -1; // unknown (don't care yet)
5563
5564 u8 wire[MAX_DOMAIN_LENGTH + 10 + 65535];
5565
5566 #if DEBUG
5567 //rdata = (u8*)~0; // DEBUG
5568 //rname_size = ~0; // DEBUG
5569 //rttl = ~0; // DEBUG
5570 rtype = ~0; // DEBUG
5571 rclass = ~0; // DEBUG
5572 //rdata_size = ~0; // DEBUG
5573 #endif
5574
5575 bool changes_occurred = FALSE;
5576
5577 #if ZDB_HAS_DNSSEC_SUPPORT
5578 // zone load private keys
5579
5580 bool dnssec_zone = zdb_zone_is_maintained(zone);
5581 bool check_for_last_nsec3param_removal = FALSE;
5582
5583 if(dnssec_zone)
5584 {
5585 dynupdate_diff_load_private_keys(zone);
5586 }
5587 #endif
5588
5589 log_debug1("update: %{dnsname}: reading message", zone->origin);
5590
5591 // marks the SOA as being automatically removed (as the serial will increase)
5592
5593 zone_diff_record_remove_automated(&diff, zone->apex, zone->origin, TYPE_SOA, soa->ttl, ZDB_PACKEDRECORD_PTR_RDATASIZE(soa), ZDB_PACKEDRECORD_PTR_RDATAPTR(soa));
5594
5595 int record_index = 0;
5596
5597 do
5598 {
5599 u8 *p = wire;
5600 int s = sizeof(wire);
5601
5602 if(FAIL(ret = packet_reader_read_fqdn(reader, p, s)))
5603 {
5604 log_err("update: %{dnsname}: failed reading next record fqdn: %r", zone->origin, ret);
5605
5606 zone_diff_finalize(&diff);
5607
5608 #if DEBUG
5609 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed at fqdn with %r",
5610 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5611 #endif
5612 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5613
5614 return RCODE_ERROR_CODE(RCODE_FORMERR);
5615 }
5616
5617 rname = p;
5618 //rname_size = ret;
5619 p += ret;
5620 s -= ret;
5621
5622 if(!dnsname_locase_verify_charspace(rname))
5623 {
5624 log_err("update: %{dnsname}: fqdn contains illegal characters", zone->origin);
5625 log_memdump(MODULE_MSG_HANDLE,MSG_ERR, rname, dnsname_len(rname), 32);
5626
5627 zone_diff_finalize(&diff);
5628
5629 #if DEBUG
5630 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5631 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5632 #endif
5633
5634 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5635
5636 return RCODE_ERROR_CODE(RCODE_FORMERR);
5637 }
5638
5639 if(!dnsname_is_subdomain(rname, zone->origin))
5640 {
5641 log_err("update: %{dnsname}: %{dnsname} is not a sub-domain", zone->origin, rname);
5642
5643 zone_diff_finalize(&diff);
5644
5645 #if DEBUG
5646 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5647 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_NOTZONE));
5648 #endif
5649 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5650
5651 return RCODE_ERROR_CODE(RCODE_NOTZONE);
5652 }
5653
5654 if((ret = packet_reader_read(reader, p, 10)) != 10)
5655 {
5656 ret = UNEXPECTED_EOF;
5657
5658 log_err("update: %{dnsname}: failed reading next record fields: %r", zone->origin, ret);
5659
5660 zone_diff_finalize(&diff);
5661
5662 #if DEBUG
5663 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5664 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5665 #endif
5666
5667 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5668
5669 return RCODE_ERROR_CODE(RCODE_FORMERR);
5670 }
5671
5672 rtype = GET_U16_AT(p[0]);
5673 rclass = GET_U16_AT(p[2]);
5674 rttl = ntohl(GET_U32_AT(p[4]));
5675 rdata_size = ntohs(GET_U16_AT(p[8]));
5676
5677 if((rdata_size > 0) && (rclass == CLASS_ANY))
5678 {
5679 log_err("update: %{dnsname}: next record has non-empty rdata with class ANY: %r", zone->origin, RCODE_ERROR_CODE(RCODE_FORMERR));
5680
5681 zone_diff_finalize(&diff);
5682
5683 #if DEBUG
5684 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5685 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5686 #endif
5687 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5688
5689 return RCODE_ERROR_CODE(RCODE_FORMERR);
5690 }
5691
5692 /*
5693 * Simple consistency test:
5694 */
5695
5696 if((rdata_size == 0) && (rclass != CLASS_ANY))
5697 {
5698 log_err("update: %{dnsname}: next record has empty rdata with non-ANY class: %r", zone->origin, RCODE_ERROR_CODE(RCODE_FORMERR));
5699
5700 zone_diff_finalize(&diff);
5701
5702 #if DEBUG
5703 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5704 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5705 #endif
5706 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5707
5708 return RCODE_ERROR_CODE(RCODE_FORMERR);
5709 }
5710
5711 if(rdata_size > 0)
5712 {
5713 if(FAIL(ret = packet_reader_read_rdata(reader, rtype, rdata_size, p, s)))
5714 {
5715 log_err("update: %{dnsname}: failed reading next record rdata: %r", zone->origin, ret);
5716
5717 zone_diff_finalize(&diff);
5718
5719 #if DEBUG
5720 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5721 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5722 #endif
5723 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5724
5725 return RCODE_ERROR_CODE(RCODE_FORMERR);
5726 }
5727
5728 rdata = p;
5729 rdata_size = ret;
5730
5731 rdata_desc wire_rdatadesc = {rtype, rdata_size, rdata};
5732 log_debug1("update: %{dnsname}: record [%2i]: %{dnsname} %i %{dnsclass} %{dnstype} %{rdatadesc}",
5733 zone->origin, record_index, rname, rttl, &rclass, &rtype, &wire_rdatadesc);
5734 }
5735 else
5736 {
5737 rdata = NULL;
5738
5739 log_debug1("update: %{dnsname}: record [%2i]: %{dnsname} %i %{dnsclass} %{dnstype}",
5740 zone->origin, record_index, rname, rttl, &rclass, &rtype);
5741 }
5742
5743 ++record_index;
5744
5745 dnsname_to_dnsname_vector(rname, &name_path);
5746
5747 s32 idx;
5748
5749 for(idx = 0; idx < zone->origin_vector.size; idx++)
5750 {
5751 if(!dnslabel_equals(zone->origin_vector.labels[zone->origin_vector.size - idx], name_path.labels[name_path.size - idx]))
5752 {
5753 log_err("update: %{dnsname}: %{dnsname} manual add/del of %{dnstype} records refused", zone->origin, rname, &rtype);
5754
5755 zone_diff_finalize(&diff);
5756 #if DEBUG
5757 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5758 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_NOTZONE));
5759 #endif
5760 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5761
5762 return RCODE_ERROR_CODE(RCODE_NOTZONE);
5763 }
5764 }
5765
5766 if((rtype == TYPE_NSEC) || (rtype == TYPE_NSEC3))
5767 {
5768 // reject any dynupdate operation on a dnssec-maintained record.
5769
5770 log_err("update: %{dnsname}: %{dnsname} manual add/del of %{dnstype} records refused", zone->origin, rname, &rtype);
5771
5772 zone_diff_finalize(&diff);
5773
5774 #if DEBUG
5775 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5776 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
5777 #endif
5778 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5779
5780 return RCODE_ERROR_CODE(RCODE_REFUSED);
5781 }
5782
5783 #if ZDB_HAS_NSEC3_SUPPORT // sanity checks
5784 // If the record is an NSEC3PARAM at the APEX
5785 if(rtype == TYPE_NSEC3PARAM)
5786 {
5787 if(!dnsname_equals_ignorecase(zone->origin, rname))
5788 {
5789 // reject adding NSEC3PARAM anywhere else than in the apex
5790
5791 log_err("update: %{dnsname}: %{dnsname} NSEC3PARAM : type is only allowed in the apex", zone->origin, rname);
5792
5793 zone_diff_finalize(&diff);
5794
5795 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5796
5797 return RCODE_ERROR_CODE(RCODE_REFUSED);
5798 }
5799
5800 if(!ZONE_HAS_NSEC3PARAM(zone) && zdb_zone_has_nsec_chain(zone))
5801 {
5802 // don't add/del NSEC3PARAM on a zone that is not already NSEC3 (it works if the zone is not secure but only if the zone has keys already. So for now : disabled)
5803
5804 log_err("update: %{dnsname}: %{dnsname} NSEC3PARAM add/del refused on an non-dnssec3 zone", zone->origin, rname);
5805
5806 zone_diff_finalize(&diff);
5807
5808 #if DEBUG
5809 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5810 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
5811 #endif
5812 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5813
5814 return RCODE_ERROR_CODE(RCODE_REFUSED);
5815 }
5816 else
5817 {
5818 if((rdata != NULL) && (NSEC3_RDATA_ALGORITHM(rdata) != NSEC3_DIGEST_ALGORITHM_SHA1))
5819 {
5820 // don't touch an unsupported digest
5821
5822 log_err("update: %{dnsname}: %{dnsname} NSEC3PARAM with unsupported digest algorithm %d", zone->origin, rname, NSEC3_RDATA_ALGORITHM(rdata));
5823 #if DEBUG
5824 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5825 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_NOTIMP));
5826 #endif
5827 zone_diff_finalize(&diff);
5828
5829 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5830
5831 return RCODE_ERROR_CODE(RCODE_NOTIMP);
5832 }
5833
5834 if(rclass == CLASS_ANY) // remove all
5835 {
5836 // don't remove all NSEC3PARAMs from an NSEC3 zone
5837
5838 log_err("update: %{dnsname}: %{dnsname} cannot remove all NSEC3PARAM of an NSEC3 zone", zone->origin, rname);
5839
5840 zone_diff_finalize(&diff);
5841 #if DEBUG
5842 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5843 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
5844 #endif
5845 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5846
5847 return RCODE_ERROR_CODE(RCODE_REFUSED);
5848 }
5849 else if(rclass == CLASS_NONE) // remove one
5850 {
5851 /// @note important: don't remove the first NSEC3PARAM from an NSEC3 zone if no other is available
5852 /// also note that given the new mechanisms, an NSEC3PARAM being added will not count as one until
5853 /// the whole chain has been created
5854 /// This condition is tested later.
5855
5856 check_for_last_nsec3param_removal = TRUE;
5857 }
5858 else
5859 {
5860 // scan-build false positive : assumes rdata_size < 0 => impossible
5861 // or ((rdata_size == 0) & (rclass == CLASS_ANY)) => this would branch in the first "if" a few lines above
5862 ret = nsec3_zone_set_status(zone, ZDB_ZONE_MUTEX_DYNUPDATE, NSEC3PARAM_RDATA_ALGORITHM(rdata), 0, NSEC3PARAM_RDATA_ITERATIONS(rdata), NSEC3PARAM_RDATA_SALT(rdata), NSEC3PARAM_RDATA_SALT_LEN(rdata), NSEC3_ZONE_ENABLED|NSEC3_ZONE_GENERATING);
5863 continue;
5864 }
5865 }
5866 } // type == TYPE_NSEC3PARAM
5867 #endif // ZDB_HAS_NSEC3_SUPPORT
5868
5869 if(rclass == CLASS_NONE)
5870 {
5871 assert(rdata != NULL);
5872
5873 // delete from an rrset
5874
5875 if(rttl != 0)
5876 {
5877 zone_diff_finalize(&diff);
5878
5879 log_err("update: %{dnsname}: %{dnsname} record delete expected a TTL set to 0", zone->origin, rname);
5880
5881 #if DEBUG
5882 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5883 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
5884 #endif
5885 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5886
5887 return RCODE_ERROR_CODE(RCODE_FORMERR);
5888 }
5889
5890 if(name_path.size <= zone->origin_vector.size)
5891 {
5892 if((rtype == TYPE_SOA) || (rtype == TYPE_ANY))
5893 {
5894 // refused
5895
5896 log_err("update: %{dnsname}: refused", zone->origin);
5897
5898 zone_diff_finalize(&diff);
5899
5900 #if DEBUG
5901 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
5902 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
5903 #endif
5904 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
5905
5906 return RCODE_ERROR_CODE(RCODE_REFUSED);
5907 }
5908
5909 if(rtype == TYPE_DNSKEY)
5910 {
5911 u16 key_flags = DNSKEY_FLAGS_FROM_RDATA(rdata); // scan-build false positive
5912 // (rdata == NULL) && (rdata_size == 0) can only occur if (rclass == CLASS_ANY)
5913 // the condition is tested and exited for a FORMERR around line 5557
5914
5915 if(key_flags == DNSKEY_FLAGS_ZSK)
5916 {
5917 ret_status |= DYNUPDATE_DIFF_RETURN_DNSKEY_REMOVED;
5918 }
5919
5920 if(has_valid_ksk < 0)
5921 {
5922 has_valid_ksk = dnssec_keystore_has_usable_ksk(zone->origin, time(NULL))?1:0;
5923 }
5924 }
5925 }
5926
5927 #if DEBUG
5928 log_debug("update: %{dnsname}: delete %{dnsname} %{dnstype} any", zone->origin, rname, &rtype);
5929 #endif
5930 zdb_rr_label* rr_label = zdb_rr_label_find_exact(zone->apex, name_path.labels, (name_path.size - zone->origin_vector.size) - 1);
5931 if(rr_label != NULL)
5932 {
5933 #if DEBUG
5934 if(RR_LABEL_IRRELEVANT(rr_label)) // debug
5935 {
5936 log_debug("update: %{dnsname}: %{dnsname} is irrelevant (0)", zone->origin, rname);
5937 }
5938 #endif
5939 zdb_packed_ttlrdata *rr;
5940 if((rr = zdb_record_find(&rr_label->resource_record_set, rtype)) != NULL)
5941 {
5942 bool exists = FALSE;
5943 do
5944 {
5945 if(ZDB_PACKEDRECORD_PTR_RDATASIZE(rr) == rdata_size)
5946 {
5947 // scan-build false positive : rdata cannot be NULL
5948 // (rdata == NULL) && (rdata_size == 0) can only occur if (rclass == CLASS_ANY)
5949 // the condition is tested and exited for a FORMERR around line 5557
5950
5951 if(memcmp(ZDB_PACKEDRECORD_PTR_RDATAPTR(rr), rdata, rdata_size) == 0)
5952 {
5953 exists = TRUE;
5954 break;
5955 }
5956 }
5957 rr = rr->next;
5958 }
5959 while(rr != NULL);
5960
5961 if(exists)
5962 {
5963 if(rr_label != zone->apex)
5964 {
5965 #if 0 /* fix */
5966 #else
5967 zone_diff_add_fqdn_children(&diff, rname, rr_label);
5968 zone_diff_add_fqdn_parents_up_to_below_apex(&diff, rname, zone);
5969 #endif
5970 }
5971 #if 0 /* fix */
5972 #else
5973 if(!zone_diff_record_remove_existing(&diff, rr_label, rname, rtype, rttl, rdata_size, rdata))
5974 {
5975 rdata_desc rd = {rtype, rdata_size, rdata};
5976 log_warn("update: %{dnsname}: delete %{dnsname} %{typerdatadesc} not in zone", zone->origin, rname, &rd);
5977 }
5978 #endif
5979 }
5980 else
5981 {
5982 log_debug("update: %{dnsname}: delete %{dnsname} NONE %{dnstype}: no record match", zone->origin, rname, &rtype);
5983 }
5984 }
5985 else
5986 {
5987 log_debug("update: %{dnsname}: delete %{dnsname} NONE %{dnstype}: no type match", zone->origin, rname, &rtype);
5988 }
5989 }
5990 else
5991 {
5992 log_debug("update: %{dnsname}: delete %{dnsname} NONE %{dnstype}: no label match", zone->origin, rname, &rtype);
5993 }
5994 }
5995 else if(rclass == CLASS_ANY) // delete all RRSETs
5996 {
5997 if((rttl != 0) || (rdata_size != 0))
5998 {
5999 log_err("update: %{dnsname}: format error", zone->origin);
6000
6001 zone_diff_finalize(&diff);
6002 #if DEBUG
6003 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
6004 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_FORMERR));
6005 #endif
6006 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
6007
6008 return RCODE_ERROR_CODE(RCODE_FORMERR);
6009 }
6010
6011 if(name_path.size <= zone->origin_vector.size)
6012 {
6013 if((rtype == TYPE_SOA) || (rtype == TYPE_ANY))
6014 {
6015 // refused
6016
6017 log_err("update: %{dnsname}: refused", zone->origin);
6018 zone_diff_finalize(&diff);
6019 #if DEBUG
6020 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
6021 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
6022 #endif
6023 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
6024
6025 return RCODE_ERROR_CODE(RCODE_REFUSED);
6026 }
6027
6028 if(rtype == TYPE_DNSKEY)
6029 {
6030 // get all keys from the zone_diff
6031 // if one of these keys is a ZSK, set the ret_status flag accordingly
6032
6033 const zone_diff_fqdn *apex = zone_diff_fqdn_get_const(&diff, zone->origin);
6034 const zone_diff_fqdn_rr_set *dnskey_rrset = zone_diff_fqdn_rr_get_const(apex, TYPE_DNSKEY);
6035
6036 if(dnskey_rrset != NULL)
6037 {
6038 ptr_set_iterator rr_iter;
6039
6040 ptr_set_iterator_init(&dnskey_rrset->rr, &rr_iter);
6041
6042 while(ptr_set_iterator_hasnext(&rr_iter))
6043 {
6044 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
6045 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
6046 if((rr->state & ZONE_DIFF_RR_IN_ZONE) != 0)
6047 {
6048 u16 key_flags = DNSKEY_FLAGS_FROM_RDATA(rr->rdata);
6049 if(key_flags == DNSKEY_FLAGS_ZSK)
6050 {
6051 ret_status |= DYNUPDATE_DIFF_RETURN_DNSKEY_REMOVED;
6052 }
6053
6054 if(has_valid_ksk < 0)
6055 {
6056 has_valid_ksk = dnssec_keystore_has_usable_ksk(zone->origin, time(NULL))?1:0;
6057 }
6058
6059 diff.may_add_dnskey = TRUE;
6060 break;
6061 }
6062 }
6063
6064 diff.may_remove_dnskey = TRUE;
6065
6066 if(has_valid_ksk < 0)
6067 {
6068 has_valid_ksk = dnssec_keystore_has_usable_ksk(zone->origin, time(NULL))?1:0;
6069 }
6070 }
6071 else
6072 {
6073 diff.may_remove_dnskey = FALSE;
6074 has_valid_ksk = FALSE;
6075 }
6076 }
6077 }
6078
6079 if(rtype != TYPE_ANY)
6080 {
6081 // delete an rrset
6082
6083 #if DEBUG
6084 log_debug2("update: %{dnsname}: delete %{dnsname} %{dnstype} ...", zone->origin, rname, &rtype);
6085 #endif
6086 zdb_rr_label *rr_label = zdb_rr_label_find_exact(zone->apex, name_path.labels, (name_path.size - zone->origin_vector.size) - 1);
6087 if(rr_label != NULL)
6088 {
6089 #if DEBUG
6090 if(RR_LABEL_IRRELEVANT(rr_label)) // debug
6091 {
6092 log_debug2("update: %{dnsname}: %{dnsname} is irrelevant (1)", zone->origin, rname);
6093 }
6094 #endif
6095 if(zdb_record_find(&rr_label->resource_record_set, rtype) != NULL)
6096 {
6097 if(rr_label != zone->apex)
6098 {
6099 #if 0 /* fix */
6100 #else
6101 zone_diff_add_fqdn_children(&diff, rname, rr_label);
6102 zone_diff_add_fqdn_parents_up_to_below_apex(&diff, rname, zone);
6103 #endif
6104 }
6105 zone_diff_record_remove_all(&diff, rr_label, rname, rtype);
6106 }
6107 else
6108 {
6109 log_debug("update: %{dnsname}: delete %{dnsname} %{dnstype} ANY: no type match", zone->origin, rname, &rtype);
6110 }
6111 }
6112 else
6113 {
6114 log_debug("update: %{dnsname}: delete %{dnsname} %{dnstype} ANY: no label match", zone->origin, rname, &rtype);
6115 }
6116 }
6117 else
6118 {
6119 // delete all rrsets
6120
6121 #if DEBUG
6122 log_debug2("update: %{dnsname}: delete %{dnsname} %{dnstype} ...", zone->origin, rname, &rtype);
6123 #endif
6124 zdb_rr_label* rr_label = zdb_rr_label_find_exact(zone->apex, name_path.labels, (name_path.size - zone->origin_vector.size) - 1);
6125 if(rr_label != NULL)
6126 {
6127 #if DEBUG
6128 if(RR_LABEL_IRRELEVANT(rr_label)) // debug
6129 {
6130 log_debug2("update: %{dnsname}: %{dnsname} is irrelevant (2)", zone->origin, rname);
6131 }
6132 if(RR_LABEL_EMPTY_TERMINAL(rr_label))
6133 {
6134 log_debug2("update: %{dnsname}: %{dnsname} is an empty terminal (2)", zone->origin, rname);
6135 }
6136 #endif
6137 if(rr_label != zone->apex)
6138 {
6139 #if 0 /* fix */
6140 #else
6141 zone_diff_add_fqdn_children(&diff, rname, rr_label);
6142 zone_diff_add_fqdn_parents_up_to_below_apex(&diff, rname, zone);
6143 #endif
6144 zone_diff_record_remove_all_sets(&diff, rr_label, rname);
6145 }
6146 else
6147 {
6148 // apex
6149
6150 log_err("update: %{dnsname}: removing all records from the apex is forbidden", zone->origin);
6151
6152 zone_diff_finalize(&diff);
6153
6154 #if DEBUG
6155 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
6156 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
6157 #endif
6158 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
6159
6160 return RCODE_ERROR_CODE(RCODE_REFUSED);
6161 }
6162 }
6163 else
6164 {
6165 log_debug("update: %{dnsname}: delete %{dnsname} %{dnstype} ANY: no label match", zone->origin, rname, &rtype);
6166 }
6167 }
6168 }
6169 else
6170 {
6171 // add record to an rrset
6172
6173 assert(rdata != NULL); // to help scan-build
6174
6175 // scan-build false positive : rdata cannot be NULL
6176 // (rdata == NULL) && (rdata_size == 0) can only occur if (rclass == CLASS_ANY)
6177 // the condition is tested and exited for a FORMERR around line 5557
6178
6179 zdb_rr_label* rr_label = zdb_rr_label_find_exact(zone->apex, name_path.labels, (name_path.size - zone->origin_vector.size) - 1);
6180 zone_diff_record_add(&diff, rr_label, rname, rtype, rttl, rdata_size, rdata);
6181
6182 const u8 *above_fqdn = rname;
6183 for(int index = 1; index < name_path.size; ++index)
6184 {
6185 zdb_rr_label* above_rr_label = zdb_rr_label_find_exact(zone->apex, name_path.labels + index, (name_path.size - index - zone->origin_vector.size) - 1);
6186 above_fqdn += above_fqdn[0] + 1;
6187 zone_diff_fqdn_add(&diff, above_fqdn, above_rr_label);
6188 }
6189
6190 if(rr_label != NULL)
6191 {
6192 if(rr_label != zone->apex)
6193 {
6194 #if 0 /* fix */
6195 #else
6196 zone_diff_add_fqdn_children(&diff, rname, rr_label);
6197 zone_diff_add_fqdn_parents_up_to_below_apex(&diff, rname, zone);
6198 #endif
6199 }
6200 else
6201 {
6202 if(rtype == TYPE_DNSKEY)
6203 {
6204 u16 key_flags = DNSKEY_FLAGS_FROM_RDATA(rdata);
6205 if(key_flags == DNSKEY_FLAGS_ZSK)
6206 {
6207 ret_status |= DYNUPDATE_DIFF_RETURN_DNSKEY_ADDED;
6208 }
6209
6210 diff.may_add_dnskey = TRUE;
6211 }
6212 }
6213 }
6214 }
6215 }
6216 while(--count > 0);
6217
6218 if(check_for_last_nsec3param_removal)
6219 {
6220 bool at_least_one_nsec3param_remains = FALSE;
6221
6222 // look if there is any NSEC3PARAM remaining in the zone
6223 const zone_diff_fqdn *apex = zone_diff_fqdn_get_const(&diff, zone->origin);
6224 const zone_diff_fqdn_rr_set *nsec3param_rrset = zone_diff_fqdn_rr_get_const(apex, TYPE_NSEC3PARAM);
6225
6226 if(nsec3param_rrset != NULL)
6227 {
6228 ptr_set_iterator rr_iter;
6229
6230 ptr_set_iterator_init(&nsec3param_rrset->rr, &rr_iter);
6231
6232 while(ptr_set_iterator_hasnext(&rr_iter))
6233 {
6234 ptr_node *rr_node = ptr_set_iterator_next_node(&rr_iter);
6235 zone_diff_label_rr *rr = (zone_diff_label_rr*)rr_node->value;
6236 if((rr->state & (ZONE_DIFF_RR_ADD|ZONE_DIFF_RR_REMOVE)) != ZONE_DIFF_RR_REMOVE)
6237 {
6238 at_least_one_nsec3param_remains = TRUE;
6239 break;
6240 }
6241 }
6242
6243 if(!at_least_one_nsec3param_remains)
6244 {
6245 log_err("update: %{dnsname}: %{dnsname} cannot remove the last NSEC3PARAM of an NSEC3 zone", zone->origin, rname);
6246
6247 zone_diff_finalize(&diff);
6248
6249 #if DEBUG
6250 log_err("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) failed with %r",
6251 zone->origin, zone, reader, count, secondary_lock, dryrun, RCODE_ERROR_CODE(RCODE_REFUSED));
6252 #endif
6253 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
6254
6255 return RCODE_ERROR_CODE(RCODE_REFUSED);
6256 }
6257 }
6258 // else there was no NSEC3PARAM to begin with
6259 }
6260
6261 if(ISOK(ret) && !dryrun)
6262 {
6263 ptr_vector add = PTR_VECTOR_EMPTY;
6264 ptr_vector del = PTR_VECTOR_EMPTY;
6265
6266 #if DEBUG
6267 log_debug1("update: %{dnsname}: storing diff", zone->origin);
6268 zone_diff_log(&diff, MODULE_MSG_HANDLE, MSG_DEBUG2);
6269 #endif
6270 if(ISOK(ret = zone_diff_store_diff(&diff, zone, &del, &add)))
6271 {
6272 zdb_zone_error_status_clear(zone, ZDB_ZONE_ERROR_STATUS_DIFF_FAILEDNOUSABLE_KEYS);
6273
6274 #if DEBUG
6275 log_debug1("update: %{dnsname}: stored diff", zone->origin);
6276
6277 for(int i = 0; i <= ptr_vector_last_index(&del); ++i)
6278 {
6279 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&del, i);
6280 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
6281 log_debug1("update: %{dnsname}: - %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
6282 }
6283
6284 for(int i = 0; i <= ptr_vector_last_index(&add); ++i)
6285 {
6286 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&add, i);
6287 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
6288 log_debug1("update: %{dnsname}: + %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
6289 }
6290 #endif
6291
6292 changes_occurred = (ptr_vector_size(&add) + ptr_vector_size(&del)) > 2;
6293
6294 #if DEBUG
6295 log_debug1("update: %{dnsname}: changes: %i", zone->origin, changes_occurred);
6296 #endif
6297
6298 if(changes_occurred)
6299 {
6300 // instead of storing to a buffer and back, could write an inputstream
6301 // translating the ptr_vector content on the fly
6302
6303 s32 total = 0;
6304
6305 for(int i = 0; i <= ptr_vector_last_index(&del); ++i)
6306 {
6307 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&del, i);
6308 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
6309
6310 log_debug2("update: %{dnsname}: - %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
6311
6312 total += dnsname_len(rr->fqdn);
6313 total += 10;
6314 total += rr->rdata_size;
6315 }
6316
6317 for(int i = 0; i <= ptr_vector_last_index(&add); ++i)
6318 {
6319 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&add, i);
6320 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
6321
6322 log_debug2("update: %{dnsname}: + %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
6323
6324 total += dnsname_len(rr->fqdn);
6325 total += 10;
6326 total += rr->rdata_size;
6327 }
6328
6329 output_stream baos;
6330
6331 bytearray_output_stream_init(&baos, NULL, total);
6332
6333 for(int i = 0; i <= ptr_vector_last_index(&del); ++i)
6334 {
6335 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&del, i);
6336 /*
6337 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
6338 log_debug("update: %{dnsname}: - %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
6339 */
6340 output_stream_write_dnsname(&baos, rr->fqdn);
6341 output_stream_write_u16(&baos, rr->rtype);
6342 output_stream_write_u16(&baos, rr->rclass);
6343 output_stream_write_nu32(&baos, rr->ttl);
6344 output_stream_write_nu16(&baos, rr->rdata_size);
6345 output_stream_write(&baos, rr->rdata, rr->rdata_size);
6346 }
6347
6348 for(int i = 0; i <= ptr_vector_last_index(&add); ++i)
6349 {
6350 zone_diff_label_rr *rr = (zone_diff_label_rr*)ptr_vector_get(&add, i);
6351 /*
6352 rdata_desc rd = {rr->rtype, rr->rdata_size, rr->rdata};
6353 log_debug("update: %{dnsname}: + %{dnsname} %9i %{typerdatadesc}", zone->origin, rr->fqdn, rr->ttl, &rd);
6354 */
6355 output_stream_write_dnsname(&baos, rr->fqdn);
6356 output_stream_write_u16(&baos, rr->rtype);
6357 output_stream_write_u16(&baos, rr->rclass);
6358 output_stream_write_nu32(&baos, rr->ttl);
6359 output_stream_write_nu16(&baos, rr->rdata_size);
6360 output_stream_write(&baos, rr->rdata, rr->rdata_size);
6361 }
6362
6363 input_stream bais;
6364
6365 bytearray_input_stream_init(&bais, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos), FALSE);
6366
6367 journal* jnl = NULL;
6368 if(ISOK(ret = journal_acquire_from_zone_ex(&jnl, zone, TRUE)))
6369 {
6370 jnl->vtbl->minimum_serial_update(jnl, zone->text_serial);
6371
6372 u32 journal_max_size = zone->wire_size / 3;
6373 zdb_zone_info_get_zone_max_journal_size(zone->origin, &journal_max_size);
6374 jnl->vtbl->maximum_size_update(jnl, journal_max_size);
6375
6376 if(ISOK(ret = journal_append_ixfr_stream(jnl, &bais))) // writes a single page
6377 {
6378 log_debug("update: %{dnsname}: wrote %i bytes to the journal", zone->origin, total);
6379
6380 bytearray_input_stream_reset(&bais);
6381
6382 u32 current_serial = 0;
6383
6384 if(secondary_lock != 0)
6385 {
6386 zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, secondary_lock);
6387 }
6388
6389 ret = zdb_icmtl_replay_commit(zone, &bais, ¤t_serial);
6390
6391 if(secondary_lock != 0)
6392 {
6393 zdb_zone_exchange_locks(zone, secondary_lock, ZDB_ZONE_MUTEX_SIMPLEREADER);
6394 }
6395
6396 if(ISOK(ret))
6397 {
6398 log_debug("update: %{dnsname}: applied journal changes", zone->origin);
6399
6400 if(ret_status & (DYNUPDATE_DIFF_RETURN_DNSKEY_ADDED|DYNUPDATE_DIFF_RETURN_DNSKEY_REMOVED))
6401 {
6402 ret_status |= DYNUPDATE_DIFF_RETURN_DNSKEY_UPDATED;
6403 }
6404 }
6405 else
6406 {
6407 log_err("update: %{dnsname}: could not apply journal changes: %r", zone->origin, ret);
6408 }
6409 }
6410 else
6411 {
6412 if(ret == ZDB_JOURNAL_SERIAL_RANGE_LOCKED)
6413 {
6414 log_notice("update: %{dnsname}: could not write %i bytes to the journal as it is full and busy", zone->origin, total);
6415 }
6416 else if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
6417 {
6418 log_info("update: %{dnsname}: could not write %i bytes to the journal as it is full and the zone needs to be locally stored first", zone->origin, total);
6419 }
6420 else
6421 {
6422 log_err("update: %{dnsname}: could not write %i bytes to the journal: %r", zone->origin, total, ret);
6423 }
6424 }
6425
6426 journal_release(jnl);
6427 }
6428
6429 input_stream_close(&bais);
6430 output_stream_close(&baos);
6431 }
6432 } // storediff succeeded
6433 else
6434 {
6435 if(zdb_zone_error_status_getnot_set(zone, ZDB_ZONE_ERROR_STATUS_DIFF_FAILEDNOUSABLE_KEYS))
6436 {
6437 log_err("update: %{dnsname}: diff failed: %r", zone->origin, ret);
6438 }
6439 }
6440
6441 zone_diff_label_rr_vector_clear(&del);
6442 zone_diff_label_rr_vector_clear(&add);
6443
6444 ptr_vector_destroy(&add);
6445 ptr_vector_destroy(&del);
6446 }
6447
6448 #if DEBUG
6449 {
6450 zdb_packed_ttlrdata *soa = zdb_record_find(&zone->apex->resource_record_set, TYPE_SOA);
6451 if(soa != NULL)
6452 {
6453 u32 soa_serial = 0;
6454 rr_soa_get_serial(ZDB_PACKEDRECORD_PTR_RDATAPTR(soa), ZDB_PACKEDRECORD_PTR_RDATASIZE(soa), &soa_serial);
6455 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) to serial %u",
6456 zone->origin, zone, reader, count, secondary_lock, dryrun, soa_serial);
6457 }
6458 else
6459 {
6460 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) has no SOA anymore",
6461 zone->origin, zone, reader, count, secondary_lock, dryrun);
6462 }
6463 }
6464 #endif
6465
6466 log_debug("update: %{dnsname}: done", zone->origin);
6467
6468 zone_diff_finalize(&diff);
6469
6470 if(ISOK(ret))
6471 {
6472 ret = ret_status;
6473 }
6474
6475 #if DEBUG
6476 log_debug("dynupdate_diff(%{dnsname}@%p, %p, %i, %x, %i) returned with %r",
6477 zone->origin, zone, reader, count, secondary_lock, dryrun, ret);
6478 #endif
6479 zdb_zone_clear_status(zone, ZDB_ZONE_STATUS_IN_DYNUPDATE_DIFF);
6480
6481 return ret;
6482 }
6483