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 nsec3 NSEC3 functions
36 * @ingroup dnsdbdnssec
37 * @brief
38 *
39 *
40 *
41 * @{
42 */
43 /*------------------------------------------------------------------------------
44 *
45 * USE INCLUDES */
46 #include "dnsdb/dnsdb-config.h"
47 #include <stdio.h>
48 #include <stdlib.h>
49
50 #include <dnscore/logger.h>
51
52 #include "dnsdb/nsec3_item.h"
53 #include "dnsdb/nsec3_owner.h"
54 #include "dnsdb/nsec3_zone.h"
55
56 #include "dnsdb/zdb_zone_label_iterator.h"
57
58 #define MODULE_MSG_HANDLE g_dnssec_logger
59
60 extern logger_handle *g_dnssec_logger;
61
62 /******************************************************************************
63 *
64 * NSEC3 - tools : nsec3_zone (nsec3param's alter ego)
65 *
66 *****************************************************************************/
67
68 /*
69 * Compares two nsec3_zone (binary compare <0 / = / >0 : less/equal/bigger)
70 */
71
72 int
nsec3param_compare_by_rdata(const u8 * a_rdata,const u8 * b_rdata)73 nsec3param_compare_by_rdata(const u8 *a_rdata, const u8 *b_rdata)
74 {
75 int c;
76
77 c = a_rdata[0];
78 c -= b_rdata[0];
79
80 if(c == 0)
81 {
82 c = a_rdata[2];
83 c -= b_rdata[2];
84
85 if(c == 0)
86 {
87 c = a_rdata[3];
88 c -= b_rdata[3];
89
90 if(c == 0)
91 {
92 c = a_rdata[4]; // size of the salt
93 c -= b_rdata[4];
94
95 if(c == 0)
96 {
97 c = memcmp(&a_rdata[5], &b_rdata[5], a_rdata[4]);
98 }
99 }
100 }
101 }
102
103 return c;
104 }
105
106 /*
107 * Compares two nsec3_zone (binary compare <0 / = / >0 : less/equal/bigger)
108 */
109
110
111
112 int
nsec3_zone_compare(nsec3_zone * a,nsec3_zone * b)113 nsec3_zone_compare(nsec3_zone* a, nsec3_zone* b)
114 {
115 return nsec3param_compare_by_rdata(a->rdata, b->rdata);
116 }
117
118 /*
119 * Retrieves the nsec3_zone* (NSEC3PARAM alter-ego) from an item.
120 *
121 * This is done by looking for the NSEC3 root then looking for which nsec3_zone
122 * contains the ptr. It requires up to 30 moves. (slow)
123 *
124 * I could also mark the nsec3 records and store the mark on every record but
125 * it would be expensive (memory).
126 *
127 */
128
129 nsec3_zone*
nsec3_zone_from_item(const zdb_zone * zone,const nsec3_zone_item * item)130 nsec3_zone_from_item(const zdb_zone* zone, const nsec3_zone_item* item)
131 {
132 const nsec3_zone_item* root = item;
133
134 while(root->parent != NULL)
135 {
136 root = root->parent;
137 }
138
139 nsec3_zone* n3 = zone->nsec.nsec3;
140
141 while(n3 != NULL)
142 {
143 if(n3->items == root)
144 {
145 break;
146 }
147
148 n3 = n3->next;
149 }
150
151 return n3;
152 }
153
154 /*
155 * Recursively empties nsec3_zone_item
156 *
157 * Does not destroys the nodes, only the payload : owners, stars, bitmap, rrsig
158 *
159 * This should be followed by the destruction of the items
160 */
161
162 static void
nsec3_zone_item_empties_recursively(nsec3_zone_item * item)163 nsec3_zone_item_empties_recursively(nsec3_zone_item* item)
164 {
165 if(item != NULL)
166 {
167 nsec3_zone_item_empties(item);
168
169 nsec3_zone_item_empties_recursively(item->children.lr.left);
170 nsec3_zone_item_empties_recursively(item->children.lr.right);
171 }
172 }
173
174 /**
175 * Detaches an nsec3 chain from the zone.
176 *
177 * @param zone
178 * @param n3
179 * @return
180 */
181
182 bool
nsec3_zone_detach(zdb_zone * zone,nsec3_zone * n3)183 nsec3_zone_detach(zdb_zone *zone, nsec3_zone *n3)
184 {
185 nsec3_zone *first = zone->nsec.nsec3;
186
187 if(first == n3)
188 {
189 zone->nsec.nsec3 = n3->next;
190 }
191 else
192 {
193 while(first->next != n3)
194 {
195 first = first->next;
196
197 if(first == NULL)
198 {
199 return FALSE;
200 }
201 }
202
203 first->next = n3->next;
204 }
205
206 n3->next = NULL;
207
208 return TRUE;
209 }
210
211 /*
212 * Destroys the nsec3param alter-ego from the database.
213 *
214 * The zdb_rr_label are also affected by the call.
215 *
216 * The NSEC3PARAM record is not changed.
217 *
218 */
219
220 void
nsec3_zone_destroy(zdb_zone * zone,nsec3_zone * n3)221 nsec3_zone_destroy(zdb_zone *zone, nsec3_zone *n3)
222 {
223 int n3_index = 0;
224
225 /*
226 *
227 * Check for existence of n3 into zone
228 *
229 * For every nsec3 record found in zone:
230 *
231 * Get the self(s), unlink
232 * Get the star(s), unlink
233 * Destroy nsec3 record signature
234 * Destroy nsec3 record
235 */
236
237 // get the pointer chaining to n3
238
239 nsec3_zone **n3p = &zone->nsec.nsec3;
240
241 yassert(*n3p != NULL);
242
243 while(*n3p != n3)
244 {
245 ++n3_index;
246 n3p = &(*n3p)->next;
247
248 yassert(*n3p != NULL);
249 }
250
251 *n3p = n3->next;
252 n3->next = NULL;
253 nsec3_zone_item_empties_recursively(n3->items);
254 nsec3_destroy(&n3->items);
255 nsec3_zone_free(n3);
256
257 // Every single label must have its chain updated
258
259 zdb_zone_label_iterator label_iterator;
260 zdb_zone_label_iterator_init(&label_iterator, zone);
261
262 if(n3_index == 0)
263 {
264 while(zdb_zone_label_iterator_hasnext(&label_iterator))
265 {
266 zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
267
268 if(label->nsec.nsec3 != NULL)
269 {
270 struct nsec3_label_extension *n3_ext = label->nsec.nsec3;
271 if(n3_ext != NULL)
272 {
273 label->nsec.nsec3 = nsec3_label_extension_next(n3_ext);
274 yassert(nsec3_label_extension_self(n3_ext) == NULL && nsec3_label_extension_star(n3_ext) == NULL);
275 nsec3_label_extension_free(n3_ext);
276 }
277 }
278 }
279 }
280 else
281 {
282 while(zdb_zone_label_iterator_hasnext(&label_iterator))
283 {
284 #if DEBUG
285 u8 fqdn[256];
286 zdb_zone_label_iterator_nextname(&label_iterator, fqdn);
287 #endif
288
289 zdb_rr_label* label = zdb_zone_label_iterator_next(&label_iterator);
290
291 if(label->nsec.nsec3 != NULL)
292 {
293 struct nsec3_label_extension **n3_extp = nsec3_label_extension_next_ptr(label->nsec.nsec3);
294 struct nsec3_label_extension *n3_ext = *n3_extp;
295 for(int i = 1; i < n3_index; ++i)
296 {
297 n3_extp = nsec3_label_extension_next_ptr(n3_ext);
298 n3_ext = *n3_extp;
299 }
300 *n3_extp = nsec3_label_extension_next(n3_ext);
301
302 #if DEBUG
303 if(nsec3_label_extension_self(n3_ext) != NULL)
304 {
305 log_debug2("%{dnsname} self %{digest32h}", fqdn, nsec3_label_extension_self(n3_ext)->digest);
306 }
307 if(nsec3_label_extension_star(n3_ext) != NULL)
308 {
309 log_debug2("%{dnsname} star %{digest32h}", fqdn, nsec3_label_extension_star(n3_ext)->digest);
310 }
311 #endif
312
313 yassert(nsec3_label_extension_self(n3_ext) == NULL && nsec3_label_extension_star(n3_ext) == NULL); // both are expected to be cleared
314 nsec3_label_extension_free(n3_ext);
315 }
316 }
317 }
318 }
319
320
321
322 /*
323 * Adds the nsec3_zone (NSEC3PARAM "alter-ego") to the zone.
324 *
325 * Updates labels flags + nsec3 item references placeholders
326 * using nsec3_insert_empty_nsec3
327 *
328 * Uses nsec3zone_compare
329 *
330 * Used by nsec3_add_nsec3param and nsec3_load_add_nsec3param
331 *
332 */
333
334 nsec3_zone*
nsec3_zone_add_from_rdata(zdb_zone * zone,u16 nsec3param_rdata_size,const u8 * nsec3param_rdata)335 nsec3_zone_add_from_rdata(zdb_zone* zone, u16 nsec3param_rdata_size, const u8* nsec3param_rdata)
336 {
337 /* Check that the rdata is big enough */
338 yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
339
340 nsec3_zone* n3 = nsec3_zone_get_from_rdata(zone, nsec3param_rdata_size, nsec3param_rdata);
341
342 if(n3 == NULL)
343 {
344 n3 = nsec3_zone_new(nsec3param_rdata, nsec3param_rdata_size);
345
346 /*
347 * Insertion has to be sorted on the Algorithm + Iterations + Salt_len + Salt
348 */
349
350 nsec3_zone** current = &zone->nsec.nsec3;
351 nsec3_zone* next_n3 = zone->nsec.nsec3;
352 u32 n3_pos = 0;
353
354 for(;;)
355 {
356 /*
357 if((next_n3 == NULL) || (nsec3_zone_compare(n3, next_n3) < 0))
358 */
359 if(next_n3 == NULL)
360 {
361 n3->next = next_n3;
362
363 *current = n3;
364
365 /*
366 * For every existing label in the database: add a nsec3 node for
367 * the current n3 record (same position in the list).
368 */
369
370 //nsec3_insert_empty_nsec3(zone, n3_pos);
371
372 break;
373 }
374
375 current = &next_n3->next;
376 next_n3 = next_n3->next;
377 n3_pos++;
378 }
379 }
380
381 return n3;
382 }
383
384 nsec3_zone*
nsec3_zone_new(const u8 * nsec3param_rdata,u16 nsec3param_rdata_size)385 nsec3_zone_new(const u8 *nsec3param_rdata, u16 nsec3param_rdata_size)
386 {
387 nsec3_zone *n3;
388 u32 nsec3param_rdata_realsize = NSEC3PARAM_RDATA_SIZE_FROM_RDATA(nsec3param_rdata);
389 yassert(nsec3param_rdata_size >= nsec3param_rdata_realsize);
390 (void)nsec3param_rdata_size;
391 ZALLOC_ARRAY_OR_DIE(nsec3_zone*, n3, sizeof(nsec3_zone) + nsec3param_rdata_realsize, NSEC3_ZONE_TAG);
392 n3->next = NULL;
393 n3->items = NULL;
394 memcpy(n3->rdata, nsec3param_rdata, nsec3param_rdata_realsize);
395
396 return n3;
397 }
398
nsec3_zone_free(nsec3_zone * n3)399 void nsec3_zone_free(nsec3_zone *n3)
400 {
401 yassert(nsec3_isempty(&n3->items));
402 yassert(n3->next == NULL);
403 ZFREE_ARRAY(n3, sizeof(nsec3_zone) + NSEC3PARAM_MINIMUM_LENGTH + n3->rdata[4]);
404 }
405
406 ya_result
nsec3_zone_chain_count(zdb_zone * zone)407 nsec3_zone_chain_count(zdb_zone* zone)
408 {
409 ya_result ret = 0;;
410 nsec3_zone* n3 = zone->nsec.nsec3;
411 while(n3 != NULL)
412 {
413 ++ret;
414 n3 = n3->next;
415 }
416 return ret;
417 }
418
419
420 /**
421 *
422 * Adds the nsec3_zone (NSEC3PARAM "alter-ego") to the zone.
423 *
424 * Updates labels flags + nsec3 item references placeholders
425 * using nsec3_insert_empty_nsec3
426 *
427 * Uses nsec3zone_compare
428 *
429 * Used by nsec3_add_nsec3param and nsec3_load_add_nsec3param
430 *
431 * @note Does not add the record.
432 *
433 * @param zone
434 * @param nsec3param_rdata
435 * @param nsec3param_rdata_size
436 *
437 * @return an error code
438 */
439
440 ya_result
nsec3_zone_chain_add_with_rdata(zdb_zone * zone,const u8 * nsec3param_rdata,u16 nsec3param_rdata_size)441 nsec3_zone_chain_add_with_rdata(zdb_zone* zone, const u8* nsec3param_rdata, u16 nsec3param_rdata_size)
442 {
443 /* Check that the rdata is big enough */
444 yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
445 ya_result ret = 0;
446
447 nsec3_zone* n3 = zone->nsec.nsec3;
448 nsec3_zone** n3p;
449 if(n3 != NULL)
450 {
451 if(memcmp(n3->rdata, nsec3param_rdata, nsec3param_rdata_size) == 0)
452 {
453 // duplicate
454 return ERROR;
455 }
456
457 ++ret;
458
459 while(n3->next != NULL)
460 {
461 n3 = n3->next;
462
463 if(memcmp(n3->rdata, nsec3param_rdata, nsec3param_rdata_size) == 0)
464 {
465 // duplicate
466 return ERROR;
467 }
468
469 ++ret;
470 }
471 // add after n3
472 n3p = &n3->next;
473 }
474 else
475 {
476 // create n3
477 n3p = &zone->nsec.nsec3;
478 }
479
480 n3 = nsec3_zone_new(nsec3param_rdata, nsec3param_rdata_size);
481 *n3p = n3;
482
483 return ret;
484 }
485
486 /**
487 * Returns the index of an NSEC3PARAM in the zone, or an error code
488 *
489 * @param zone
490 * @param nsec3param_rdata
491 * @param nsec3param_rdata_size
492 * @return
493 */
494
495 ya_result
nsec3_zone_chain_get_index_from_rdata(zdb_zone * zone,const u8 * nsec3param_rdata,u16 nsec3param_rdata_size)496 nsec3_zone_chain_get_index_from_rdata(zdb_zone* zone, const u8* nsec3param_rdata, u16 nsec3param_rdata_size)
497 {
498 /* Check that the rdata is big enough */
499 yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
500 ya_result ret = 0;
501
502 nsec3_zone* n3 = zone->nsec.nsec3;
503
504 while(n3 != NULL)
505 {
506 if(memcmp(n3->rdata, nsec3param_rdata, nsec3param_rdata_size) == 0)
507 {
508 // return the index of the match
509 return ret;
510 }
511
512 ++ret;
513
514 n3 = n3->next;
515 }
516
517 return ERROR;
518 }
519
520 /*
521 * Returns the zone's matching nsec3_zone* or NULL
522 *
523 * The rdata can be of an NSEC3PARAM or of an NSEC3
524 *
525 */
526
527 nsec3_zone*
nsec3_zone_get_from_rdata(const zdb_zone * zone,u16 nsec3param_rdata_size,const u8 * nsec3param_rdata)528 nsec3_zone_get_from_rdata(const zdb_zone* zone, u16 nsec3param_rdata_size, const u8* nsec3param_rdata)
529 {
530 /* Check that the rdata is big enough */
531 yassert(nsec3param_rdata_size >= NSEC3PARAM_MINIMUM_LENGTH);
532 (void)nsec3param_rdata_size;
533
534 nsec3_zone* n3;
535
536 for(n3 = zone->nsec.nsec3; n3 != NULL; n3 = n3->next)
537 {
538 /* test the first 32 bits in one go */
539 u32 a = GET_U32_AT(n3->rdata[0]);
540 u32 b = GET_U32_AT(nsec3param_rdata[0]);
541
542 a &= NU32(0xff00ffff);
543 b &= NU32(0xff00ffff);
544
545 if(a == b)
546 {
547 u8 len = NSEC3_ZONE_SALT_LEN(n3);
548 if(NSEC3PARAM_RDATA_SALT_LEN(nsec3param_rdata) == len)
549 {
550 if(memcmp(NSEC3_ZONE_SALT(n3), NSEC3PARAM_RDATA_SALT(nsec3param_rdata), len) == 0)
551 {
552 break;
553 }
554 }
555 }
556 }
557
558 return n3;
559 }
560
561 /** @} */
562