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 database Routines for database manipulations
36 * @ingroup yadifad
37 * @brief database functions
38 *
39 * Implementation of routines for the database
40 * - add zone file(s)
41 * - clear zone file(s)
42 * - print zone files(s)
43 * - load db
44 * - unload db
45 * - lookup database result of a message
46 *
47 * @{
48 */
49 /*------------------------------------------------------------------------------
50 *
51 * USE INCLUDES */
52
53 #include "server-config.h"
54
55 #include <dnscore/logger.h>
56 #include <dnscore/timeformat.h>
57 #include <dnscore/dnskey-keyring.h>
58 #include <dnscore/thread_pool.h>
59
60 #include <dnsdb/dnssec.h>
61 #include <dnsdb/rrsig.h>
62 #include <dnsdb/zdb_rr_label.h>
63 #include <dnsdb/zdb_zone.h>
64 #include <dnsdb/zdb_zone_process.h>
65 #include <dnsdb/zdb_icmtl.h>
66 #include <dnsdb/dynupdate-diff.h>
67 #include <dnsdb/dynupdate-message.h>
68 #include <dnsdb/zdb-zone-maintenance.h>
69 #include <dnsdb/zdb-zone-path-provider.h>
70 #include <dnsdb/dnssec-keystore.h>
71
72 #include "database-service.h"
73 #include "database-service-zone-resignature.h"
74
75 #include "notify.h"
76 #include "zone-signature-policy.h"
77
78 #if HAS_EVENT_DYNAMIC_MODULE
79 #include "dynamic-module-handler.h"
80 #endif
81
82 #ifndef HAS_DYNUPDATE_DIFF_ENABLED
83 #error "HAS_DYNUPDATE_DIFF_ENABLED not defined"
84 #endif
85
86 #if !HAS_RRSIG_MANAGEMENT_SUPPORT
87 #error "RRSIG management support disabled : this file should not be compiled"
88 #endif
89
90 #define MODULE_MSG_HANDLE g_server_logger
91
92 #define DBUPSIGP_TAG 0x5047495350554244
93 #define RESIGALR_TAG 0x524c414749534552
94
95 ya_result zone_policy_process(zone_desc_s *zone_desc);
96
97 static struct thread_pool_s *database_service_zone_resignature_publish_dnskey_tp = NULL;
98 static mutex_t database_service_zone_resignature_publish_dnskey_mtx = MUTEX_INITIALIZER;
99
100 extern logger_handle *g_server_logger;
101 extern zone_data_set database_zone_desc;
102
103 struct database_service_zone_resignature_init_callback_s
104 {
105 zone_desc_s *zone_desc;
106 dnskey_keyring keyring;
107 u64 total_signature_valitity_time; // to compute the mean validity period
108 u32 signature_count;
109 u32 missing_signatures_count;
110 u32 unverifiable_signatures_count;
111 u32 earliest_expiration_epoch;
112 u32 smallest_validity_period;
113 u32 biggest_validity_period;
114 };
115
116 struct database_service_zone_resignature_alarm_s
117 {
118 zone_desc_s *zone_desc;
119 zdb_zone *zone;
120 };
121
122 typedef struct database_service_zone_resignature_alarm_s database_service_zone_resignature_alarm_s;
123
124 #define DSZZRPRM_TAG 0x4d5250525a5a5344
125
126 struct database_service_zone_resignature_dnskey_alarm_args
127 {
128 u8 *domain;
129 u16 flags;
130 u16 tag;
131 u8 algorithm;
132 };
133
134 typedef struct database_service_zone_resignature_dnskey_alarm_args database_service_zone_resignature_dnskey_alarm_args;
135
136 struct database_service_zone_resignature_parms_s
137 {
138 zone_desc_s *zone_desc;
139 };
140
141 typedef struct database_service_zone_resignature_parms_s database_service_zone_resignature_parms_s;
142
143 static u32
database_service_zone_resignature_dnskey_alarm_unique_key(const dnssec_key * key,u32 operation)144 database_service_zone_resignature_dnskey_alarm_unique_key(const dnssec_key *key, u32 operation)
145 {
146 u32 tag = dnskey_get_tag_const(key);
147 u32 alg = dnskey_get_algorithm(key);
148
149 return operation | (tag << 8) | (alg << 24);
150 }
151
152 database_service_zone_resignature_dnskey_alarm_args*
database_service_zone_resignature_dnskey_alarm_args_new(const dnssec_key * key)153 database_service_zone_resignature_dnskey_alarm_args_new(const dnssec_key *key)
154 {
155 database_service_zone_resignature_dnskey_alarm_args *ret;
156 ZALLOC_OBJECT_OR_DIE(ret,database_service_zone_resignature_dnskey_alarm_args, RESIGALR_TAG);
157 ret->domain = dnsname_zdup(dnskey_get_domain(key));
158 ret->tag = dnskey_get_tag_const(key);
159 ret->algorithm = dnskey_get_algorithm(key);
160 ret->flags = key->flags;
161 return ret;
162 }
163
164 void
database_service_zone_resignature_dnskey_alarm_args_free(database_service_zone_resignature_dnskey_alarm_args * args)165 database_service_zone_resignature_dnskey_alarm_args_free(database_service_zone_resignature_dnskey_alarm_args *args)
166 {
167 dnsname_zfree(args->domain);
168 ZFREE(args,database_service_zone_resignature_dnskey_alarm_args);
169 }
170
171 static ya_result
database_service_zone_add_dnskey(dnssec_key * key)172 database_service_zone_add_dnskey(dnssec_key *key)
173 {
174 // make a dynupdate query update that adds the record
175
176 dynupdate_message dmsg;
177 packet_unpack_reader_data reader;
178 dynupdate_message_init(&dmsg, dnskey_get_domain(key), CLASS_IN);
179 ya_result ret;
180
181 if(ISOK(ret = dynupdate_message_add_dnskey(&dmsg, 86400, key)))
182 {
183 dynupdate_message_set_reader(&dmsg, &reader);
184 u16 count = dynupdate_message_get_count(&dmsg);
185
186 packet_reader_skip(&reader, DNS_HEADER_LENGTH); // eof checked below
187 packet_reader_skip_fqdn(&reader); // eof checked below
188 packet_reader_skip(&reader, 4); // eof checked below
189
190 if(!packet_reader_eof(&reader))
191 {
192 // the update is ready : push it
193
194 zdb_zone *zone = zdb_acquire_zone_read_double_lock_from_fqdn(g_config->database, dnskey_get_domain(key), ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
195 if(zone != NULL)
196 {
197 for(;;)
198 {
199 u32 reader_offset = reader.offset;
200
201 ret = dynupdate_diff(zone, &reader, count, ZDB_ZONE_MUTEX_DYNUPDATE, DYNUPDATE_DIFF_RUN);
202
203 if(ISOK(ret))
204 {
205 // done
206 log_info("dnskey: %{dnsname}: +%03d+%05d/%d key added",
207 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)));
208 //args->domain, args->algorithm, args->tag, ntohs(args->flags));
209 #if HAS_EVENT_DYNAMIC_MODULE
210 if(dynamic_module_dnskey_interface_chain_available())
211 {
212 dynamic_module_on_dnskey_publish(key);
213 }
214 #endif
215 notify_slaves(zone->origin);
216
217 zdb_zone_set_maintained(zone, TRUE);
218 }
219 else if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
220 {
221 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d could not add key as the journal is full",
222 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)));
223
224 // trigger a background store of the zone
225
226 //zdb_zone_info_background_store_zone(dnskey_get_domain(key));
227 zdb_zone_info_store_locked_zone(dnskey_get_domain(key));
228
229 reader.offset = reader_offset;
230
231 continue;
232 }
233
234 break;
235 }
236
237 zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
238
239 zdb_zone_release(zone);
240 }
241 }
242 else
243 {
244 ret = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
245 }
246 }
247
248 if(FAIL(ret))
249 {
250 log_err("dnskey: %{dnsname}: +%03d+%05d/%d could not add key: %r",
251 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)), ret);
252 }
253
254 dynupdate_message_finalize(&dmsg);
255
256 return ret;
257 }
258
259 static ya_result
database_service_zone_update_published_keys_flush(const u8 * fqdn,dynupdate_message * dmsg)260 database_service_zone_update_published_keys_flush(const u8 *fqdn, dynupdate_message *dmsg)
261 {
262 ya_result ret;
263 packet_unpack_reader_data reader;
264
265 dynupdate_message_set_reader(dmsg, &reader);
266 u16 count = dynupdate_message_get_count(dmsg);
267
268 packet_reader_skip(&reader, DNS_HEADER_LENGTH); // eof checked below
269 packet_reader_skip_fqdn(&reader); // eof checked below
270 packet_reader_skip(&reader, 4); // eof checked below
271
272 if(!packet_reader_eof(&reader))
273 {
274 // the update is ready : push it
275
276 zdb_zone *zone = zdb_acquire_zone_read_double_lock_from_fqdn(g_config->database, fqdn, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
277 if(zone != NULL)
278 {
279 for(;;)
280 {
281 u32 reader_offset = reader.offset;
282
283 ret = dynupdate_diff(zone, &reader, count, ZDB_ZONE_MUTEX_DYNUPDATE, DYNUPDATE_DIFF_RUN);
284
285 if(ISOK(ret))
286 {
287 // done
288
289 #if HAS_EVENT_DYNAMIC_MODULE
290 if(dynamic_module_dnskey_interface_chain_available())
291 {
292 dynamic_module_on_dnskey_publish(key);
293 }
294 #endif
295 }
296 else if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
297 {
298 log_warn("dnskey: %{dnsname}: the journal is full", fqdn);
299
300 // trigger a background store of the zone
301
302 zdb_zone_info_store_locked_zone(fqdn);
303
304 reader.offset = reader_offset;
305
306 continue; // try again
307 }
308
309 break;
310 }
311
312 zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
313
314 zdb_zone_release(zone);
315 }
316 else
317 {
318 ret = ZDB_ERROR_ZONE_NOT_IN_DATABASE;
319 }
320 }
321 else
322 {
323 ret = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
324 }
325
326 return ret;
327 }
328
329 static ya_result
database_service_zone_update_published_keys(const u8 * fqdn)330 database_service_zone_update_published_keys(const u8 *fqdn)
331 {
332 // make a dynupdate query update that adds the record
333
334 ptr_vector publish_keys = EMPTY_PTR_VECTOR;
335 ptr_vector delete_keys = EMPTY_PTR_VECTOR;
336
337 if(dnssec_keystore_acquire_publish_delete_keys_from_fqdn_to_vectors(fqdn, &publish_keys, &delete_keys) == 0)
338 {
339 return SUCCESS; // nothing to do
340 }
341
342 dynupdate_message dmsg;
343
344 dynupdate_message_init(&dmsg, fqdn, CLASS_IN);
345 ya_result ret = SUCCESS;
346 int record_count = 0;
347 bool some_work_done = FALSE;
348
349 for(int i = 0; i <= ptr_vector_last_index(&publish_keys); ++i)
350 {
351 dnssec_key *key = (dnssec_key*)ptr_vector_get(&publish_keys, i);
352
353 if(ISOK(ret = dynupdate_message_add_dnskey(&dmsg, 86400, key)))
354 {
355 log_info("dnskey: %{dnsname}: +%03d+%05d/%d key will be published %T => %T => %T => %T",
356 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)),
357 dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key), dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key)
358 );
359 ++record_count;
360 }
361 else
362 {
363 // full ?
364 if(record_count > 0)
365 {
366 // flush
367 if(FAIL(ret = database_service_zone_update_published_keys_flush(fqdn, &dmsg)))
368 {
369 log_err("dnskey: %{dnsname}: key publication failed: %r", fqdn, ret);
370 break;
371 }
372
373 some_work_done = TRUE;
374 --i;
375 record_count = 0;
376 dynupdate_message_reset(&dmsg, fqdn, CLASS_IN);
377 }
378 else
379 {
380 log_err("dnskey: %{dnsname}: key publication message creation failed: %r", fqdn, ret);
381 break;
382 }
383 }
384 }
385
386 if(ISOK(ret))
387 {
388 for(int i = 0; i <= ptr_vector_last_index(&delete_keys); ++i)
389 {
390 dnssec_key *key = (dnssec_key*)ptr_vector_get(&delete_keys, i);
391 if(ISOK(ret = dynupdate_message_del_dnskey(&dmsg, key)))
392 {
393 log_info("dnskey: %{dnsname}: +%03d+%05d/%d key will be unpublished %T => %T => %T => %T",
394 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)),
395 dnskey_get_publish_epoch(key), dnskey_get_activate_epoch(key), dnskey_get_inactive_epoch(key), dnskey_get_delete_epoch(key));
396 ++record_count;
397 }
398 else
399 {
400 // full ?
401 if(record_count > 0)
402 {
403 // flush
404 if(FAIL(ret = database_service_zone_update_published_keys_flush(fqdn, &dmsg)))
405 {
406 log_err("dnskey: %{dnsname}: key deletion failed: %r", fqdn, ret);
407 break;
408 }
409
410 some_work_done = TRUE;
411 --i;
412 record_count = 0;
413 dynupdate_message_reset(&dmsg, fqdn, CLASS_IN);
414 }
415 else
416 {
417 log_err("dnskey: %{dnsname}: key deletion message creation failed: %r", fqdn, ret);
418 break;
419 }
420 }
421 }
422 }
423
424 if(ISOK(ret))
425 {
426 if(record_count > 0)
427 {
428 if(ISOK(ret = database_service_zone_update_published_keys_flush(fqdn, &dmsg)))
429 {
430 some_work_done = TRUE;
431 }
432 else
433 {
434 log_err("dnskey: %{dnsname}: key publication failed: %r (last stage)", fqdn, ret);
435 }
436 }
437 }
438
439 // does the zone needs to have its chain(s) processed ?
440
441 zone_desc_s *zone_desc = zone_acquirebydnsname(fqdn);
442 if(zone_desc != NULL)
443 {
444 zone_lock(zone_desc, ZONE_LOCK_READONLY);
445 zone_policy_process_dnssec_chain(zone_desc);
446 zone_unlock(zone_desc, ZONE_LOCK_READONLY);
447 zone_release(zone_desc);
448 }
449
450 dynupdate_message_finalize(&dmsg);
451
452 dnssec_keystore_release_keys_from_vector(&delete_keys);
453 dnssec_keystore_release_keys_from_vector(&publish_keys);
454
455 if(some_work_done)
456 {
457 notify_slaves(fqdn);
458
459 zdb_zone *zone = zdb_acquire_zone_read_double_lock_from_fqdn(g_config->database, fqdn, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
460 if(zone != NULL)
461 {
462 zdb_zone_set_maintained(zone, TRUE);
463 zdb_zone_set_maintenance_paused(zone, FALSE);
464 zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
465 zdb_zone_release(zone);
466 }
467 }
468
469 return ret;
470 }
471
472 static ya_result
database_service_zone_remove_dnskey(dnssec_key * key)473 database_service_zone_remove_dnskey(dnssec_key *key)
474 {
475 // make a dynupdate query update that removes the record
476
477 dynupdate_message dmsg;
478 packet_unpack_reader_data reader;
479 dynupdate_message_init(&dmsg, dnskey_get_domain(key), CLASS_IN);
480 ya_result ret;
481
482 if(ISOK(ret = dynupdate_message_del_dnskey(&dmsg, key)))
483 {
484 dynupdate_message_set_reader(&dmsg, &reader);
485 u16 count = dynupdate_message_get_count(&dmsg);
486
487 packet_reader_skip(&reader, DNS_HEADER_LENGTH); // eof checked below
488 packet_reader_skip_fqdn(&reader); // eof checked below
489 packet_reader_skip(&reader, 4); // eof checked below
490
491 // the update is ready : push it
492
493 if(!packet_reader_eof(&reader))
494 {
495 zdb_zone *zone = zdb_acquire_zone_read_double_lock_from_fqdn(g_config->database, dnskey_get_domain(key), ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
496 if(zone != NULL)
497 {
498 for(;;)
499 {
500 u32 reader_offset = reader.offset;
501 ret = dynupdate_diff(zone, &reader, count, ZDB_ZONE_MUTEX_DYNUPDATE, DYNUPDATE_DIFF_RUN);
502
503 if(ISOK(ret))
504 {
505 // done
506 log_info("dnskey: %{dnsname}: +%03d+%05d/%d key removed",
507 dnskey_get_domain(key),
508 dnskey_get_algorithm(key),
509 dnskey_get_tag_const(key),
510 ntohs(dnskey_get_flags(key)));
511 #if HAS_EVENT_DYNAMIC_MODULE
512 if(dynamic_module_dnskey_interface_chain_available())
513 {
514 dynamic_module_on_dnskey_delete(key);
515 }
516 #endif
517 notify_slaves(zone->origin);
518 }
519 else if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
520 {
521 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d could not remove key as the journal is full",
522 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)));
523
524 // trigger a background store of the zone
525
526 //zdb_zone_info_background_store_zone(dnskey_get_domain(key));
527
528 zdb_zone_info_store_locked_zone(dnskey_get_domain(key));
529
530 reader.offset = reader_offset;
531
532 continue;
533 }
534
535 break;
536 }
537
538 zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_DYNUPDATE);
539
540 zdb_zone_release(zone);
541 }
542 }
543 else
544 {
545 ret = MAKE_DNSMSG_ERROR(RCODE_FORMERR);
546 }
547 }
548
549 if(FAIL(ret))
550 {
551 log_err("dnskey: %{dnsname}: +%03d+%05d/%d could not remove key: %r",
552 dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag_const(key), ntohs(dnskey_get_flags(key)), ret);
553 }
554
555 dynupdate_message_finalize(&dmsg);
556
557 return ret;
558 }
559
560 static void*
database_service_zone_resignature_publish_dnskey_thread(void * args_)561 database_service_zone_resignature_publish_dnskey_thread(void *args_)
562 {
563 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
564
565 if(ISOK(database_service_zone_update_published_keys(args->domain)))
566 {
567 log_info("dnskey: %{dnsname}: DNSKEY rrset updated", args->domain);
568 }
569 else // failed, try to do the one
570 {
571 log_info("dnskey: %{dnsname}: +%03d+%05d/%d publish", args->domain, args->algorithm, args->tag, ntohs(args->flags));
572
573 // grab the key, ensure it should still be published, publish it
574
575 dnssec_key *key;
576 ya_result ret;
577
578 if(ISOK(ret = dnssec_keystore_load_private_key_from_parameters(args->algorithm, args->tag, args->flags, args->domain, &key))) // key properly released
579 {
580 assert(key != NULL);
581
582 time_t now = time(NULL);
583
584 if(dnskey_is_published(key, now) && !dnskey_is_expired_now(key)) // do not smart-add an expired key (even if it's never unpublished)
585 {
586 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: publish: in its publish time window", args->domain, args->algorithm, args->tag, ntohs(args->flags));
587
588 // has private KSK keys available now ?
589
590 if(dnssec_keystore_has_usable_ksk(dnskey_get_domain(key), now))
591 {
592 if(ISOK(ret = database_service_zone_update_published_keys(dnskey_get_domain(key))))
593 {
594
595 }
596 else
597 {
598 if(FAIL(ret = database_service_zone_add_dnskey(key)))
599 {
600 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: publish: key not published: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
601 }
602 }
603 }
604 else
605 {
606 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: publish: key not published as there is no usable KSK at this time", args->domain, args->algorithm, args->tag, ntohs(args->flags));
607
608 ret = DNSSEC_ERROR_RRSIG_NOUSABLEKEYS;
609 }
610 }
611 else if(dnskey_is_unpublished(key, now))
612 {
613 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: publish: key should not be published anymore", args->domain, args->algorithm, args->tag, ntohs(args->flags));
614
615 // delete the key if it's in the zone
616
617 if(ISOK(ret = database_service_zone_remove_dnskey(key)))
618 {
619 // remove the key from the store and rename the files
620
621 dnssec_keystore_delete_key(key);
622 }
623 else
624 {
625 // the key was not removed
626
627 // if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
628 // try again later (zone_policy_process will be called)
629
630 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: publish: unpublish failed: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
631 }
632 }
633 else
634 {
635 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: publish: key should not be published yet", args->domain, args->algorithm, args->tag, ntohs(args->flags));
636 }
637
638 dnskey_release(key);
639
640 zone_desc_s *zone_desc = zone_acquirebydnsname(args->domain);
641 if(zone_desc != NULL)
642 {
643 if(ISOK(ret = zone_policy_process(zone_desc)))
644 {
645 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: publish: post-publish policy process done", args->domain, args->algorithm, args->tag, ntohs(args->flags));
646 }
647 else
648 {
649 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: publish: post-publish policy process failed: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
650 }
651 zone_release(zone_desc);
652 }
653 }
654 else
655 {
656 assert(key == NULL);
657
658 log_err("dnskey: %{dnsname}: +%03d+%05d/%d:publish: cancelled: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
659 }
660
661 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: publish: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
662
663 database_service_zone_resignature_dnskey_alarm_args_free(args);
664 }
665
666 return NULL;
667 }
668
669 static ya_result
database_service_zone_resignature_publish_dnskey_alarm(void * args_,bool cancel)670 database_service_zone_resignature_publish_dnskey_alarm(void *args_, bool cancel)
671 {
672 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
673 ya_result ret = SUCCESS;
674
675 if(!cancel)
676 {
677 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: publish ...", args->domain, args->algorithm, args->tag, ntohs(args->flags));
678
679 if(thread_pool_try_enqueue_call(database_service_zone_resignature_publish_dnskey_tp,
680 database_service_zone_resignature_publish_dnskey_thread,
681 args,
682 NULL,
683 "dnskey-publish alarm") == LOCK_TIMEOUT)
684 {
685 ret = ALARM_REARM;
686 }
687 }
688 else
689 {
690 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: publish alarm cancelled", args->domain, args->algorithm, args->tag, ntohs(args->flags));
691 database_service_zone_resignature_dnskey_alarm_args_free(args);
692 }
693
694 return ret;
695 }
696
697 static void*
database_service_zone_resignature_unpublish_dnskey_thread(void * args_)698 database_service_zone_resignature_unpublish_dnskey_thread(void *args_)
699 {
700 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
701
702 if(ISOK(database_service_zone_update_published_keys(args->domain))) // fails -> works
703 {
704 log_info("dnskey: %{dnsname}: DNSKEY rrset updated", args->domain);
705 }
706 else // failed, try to do the one
707 {
708 ya_result ret;
709
710 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish", args->domain, args->algorithm, args->tag, ntohs(args->flags));
711
712 // grab the key, ensure it should still be published, publish it
713
714 dnssec_key *key = NULL;
715 if(ISOK(ret = dnssec_keystore_load_private_key_from_parameters(args->algorithm, args->tag, args->flags, args->domain, &key))) // key properly released
716 {
717 assert(key != NULL);
718
719 if(dnskey_is_unpublished(key, time(NULL)))
720 {
721 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: out of its publish time window", args->domain, args->algorithm, args->tag, ntohs(args->flags));
722
723 if(ISOK(ret = database_service_zone_remove_dnskey(key)))
724 {
725 // remove the key from the store and rename the files
726
727 dnssec_keystore_delete_key(key);
728 }
729 else
730 {
731 // the key was not removed
732
733 // if(ret == ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY)
734 // try again later (zone_policy_process will be called)
735
736 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
737 }
738 }
739 else
740 {
741 if(dnskey_has_explicit_delete(key))
742 {
743 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: key should not be unpublished (not until %T)", args->domain, args->algorithm, args->tag, ntohs(args->flags), key->epoch_delete);
744 }
745 else
746 {
747 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: key should not be unpublished (ever)", args->domain, args->algorithm, args->tag, ntohs(args->flags));
748 }
749 }
750
751 dnskey_release(key);
752
753 zone_desc_s *zone_desc = zone_acquirebydnsname(args->domain);
754
755 if(zone_desc != NULL)
756 {
757 if(ISOK(ret = zone_policy_process(zone_desc)))
758 {
759 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: post-unpublish policy process done", args->domain, args->algorithm, args->tag, ntohs(args->flags));
760 }
761 else
762 {
763 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: post-unpublish policy process failed: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
764 }
765 zone_release(zone_desc);
766 }
767 }
768 else
769 {
770 assert(key == NULL);
771 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish cancelled: private key not available: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
772 }
773
774 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: unpublish: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
775 }
776
777 database_service_zone_resignature_dnskey_alarm_args_free(args);
778
779 return NULL;
780 }
781
782 static ya_result
database_service_zone_resignature_unpublish_dnskey_alarm(void * args_,bool cancel)783 database_service_zone_resignature_unpublish_dnskey_alarm(void *args_, bool cancel)
784 {
785 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
786 ya_result ret = SUCCESS;
787
788 if(!cancel)
789 {
790 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: removal ...", args->domain, args->algorithm, args->tag, ntohs(args->flags));
791
792 if(thread_pool_try_enqueue_call(database_service_zone_resignature_publish_dnskey_tp,
793 database_service_zone_resignature_unpublish_dnskey_thread,
794 args,
795 NULL,
796 "dnskey-unpublish alarm") == LOCK_TIMEOUT)
797 {
798 ret = ALARM_REARM;
799 }
800 }
801 else
802 {
803 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: removal alarm cancelled", args->domain, args->algorithm, args->tag, ntohs(args->flags));
804
805 database_service_zone_resignature_dnskey_alarm_args_free(args);
806 }
807
808 return ret;
809 }
810
811 static void*
database_service_zone_resignature_activate_dnskey_thread(void * args_)812 database_service_zone_resignature_activate_dnskey_thread(void *args_)
813 {
814 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
815
816 dnssec_key *key = NULL;
817 ya_result ret = dnssec_keystore_load_private_key_from_parameters(args->algorithm, args->tag, args->flags, args->domain, &key);
818 if(ISOK(ret))
819 {
820 u32 state = dnskey_state_get(key);
821
822 if((state & DNSKEY_KEY_IS_ACTIVE) == 0) // not active yet ?
823 {
824 time_t now = time(NULL);
825
826 if((state & DNSKEY_KEY_IS_IN_ZONE) == 0) // not in zone yet ?
827 {
828 // will be automatically added, except if there is no signing key for this
829
830 bool can_edit_dnskey_rrsig = dnssec_keystore_has_usable_ksk(dnskey_get_domain(key), now);
831
832 if(!can_edit_dnskey_rrsig)
833 {
834 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: is not in the zone and cannot be added (no KSK can be used)",
835 args->domain, args->algorithm, args->tag, ntohs(args->flags));
836 dnskey_release(key);
837 database_service_zone_resignature_dnskey_alarm_args_free(args);
838 return NULL;
839 }
840
841 if(ISOK(ret = database_service_zone_update_published_keys(args->domain)))
842 {
843 log_info("dnskey: %{dnsname}: DNSKEY rrset updated, triggered by key activation", args->domain);
844 }
845 else
846 {
847 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: is not in the zone and cannot be added: %r",
848 args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
849
850 dnskey_release(key);
851 database_service_zone_resignature_dnskey_alarm_args_free(args);
852 return NULL;
853 }
854 }
855
856 zone_desc_s *zone_desc = zone_acquirebydnsname(args->domain);
857
858 if(zone_desc != NULL)
859 {
860 dnskey_state_enable(key, DNSKEY_KEY_IS_ACTIVE);
861
862 database_service_zone_dnssec_maintenance(zone_desc);
863
864 #if HAS_EVENT_DYNAMIC_MODULE
865 if(dynamic_module_dnskey_interface_chain_available())
866 {
867 dnssec_key *key = NULL;
868 ya_result ret = dnssec_keystore_load_private_key_from_parameters(args->algorithm, args->tag, args->flags, args->domain, &key);
869 if(ISOK(ret))
870 {
871 dynamic_module_on_dnskey_activate(key);
872 dnskey_release(key);
873 }
874 else
875 {
876 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: could not load key to notify deactivation to module",
877 args->domain, args->algorithm, args->tag, ntohs(args->flags));
878 }<
879 }
880 #endif
881 zone_release(zone_desc);
882 }
883 }
884
885 dnskey_release(key);
886
887 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: activation", args->domain, args->algorithm, args->tag, ntohs(args->flags));
888 }
889 else
890 {
891 zone_desc_s *zone_desc = zone_acquirebydnsname(args->domain);
892
893 if(zone_desc != NULL)
894 {
895 if(zone_rrsig_nsupdate_allowed(zone_desc))
896 {
897 if(args->flags == DNSKEY_FLAGS_ZSK)
898 {
899 log_notice("dnskey: %{dnsname}: +%03d+%05d/%d: activation failed: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
900 }
901 else if(args->flags == DNSKEY_FLAGS_KSK)
902 {
903 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: activation failed, which is probably expected: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
904 }
905 else
906 {
907 log_warn("dnskey: %{dnsname}: could not activate +%03d+%05d/%d: %r, and flags aren't ZSK nor KSK", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
908 }
909 }
910 else
911 {
912 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: activation failed: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
913 }
914 zone_release(zone_desc);
915 }
916 else
917 {
918 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: activation failed: %r", args->domain, args->algorithm, args->tag, ntohs(args->flags), ret);
919 }
920 }
921
922 database_service_zone_resignature_dnskey_alarm_args_free(args);
923
924 return NULL;
925 }
926
927 static ya_result
database_service_zone_resignature_activate_dnskey_alarm(void * args_,bool cancel)928 database_service_zone_resignature_activate_dnskey_alarm(void *args_, bool cancel)
929 {
930 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
931 ya_result ret = SUCCESS;
932
933 if(!cancel)
934 {
935 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: activation ...", args->domain, args->algorithm, args->tag, ntohs(args->flags));
936
937 if(thread_pool_try_enqueue_call(database_service_zone_resignature_publish_dnskey_tp,
938 database_service_zone_resignature_activate_dnskey_thread,
939 args,
940 NULL,
941 "dnskey-activate alarm") == LOCK_TIMEOUT)
942 {
943 ret = ALARM_REARM;
944 }
945 }
946 else
947 {
948 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: activation alarm cancelled", args->domain, args->algorithm, args->tag, ntohs(args->flags));
949 database_service_zone_resignature_dnskey_alarm_args_free(args);
950 }
951
952 return ret;
953 }
954
955 static void*
database_service_zone_resignature_deactivate_dnskey_thread(void * args_)956 database_service_zone_resignature_deactivate_dnskey_thread(void *args_)
957 {
958 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
959
960 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: deactivation", args->domain, args->algorithm, args->tag, ntohs(args->flags));
961
962 zone_desc_s *zone_desc = zone_acquirebydnsname(args->domain);
963 if(zone_desc != NULL)
964 {
965 database_service_zone_dnssec_maintenance(zone_desc);
966
967 #if HAS_EVENT_DYNAMIC_MODULE
968 if(dynamic_module_dnskey_interface_chain_available())
969 {
970 dnssec_key *key = NULL;
971 ya_result ret = dnssec_keystore_load_private_key_from_parameters(args->algorithm, args->tag, args->flags, args->domain, &key);
972 if(ISOK(ret))
973 {
974 dynamic_module_on_dnskey_inactive(key);
975 dnskey_release(key);
976 }
977 else
978 {
979 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: could not load key to notify deactivation to module",
980 args->domain, args->algorithm, args->tag, ntohs(args->flags));
981 }
982 }
983 #endif
984
985 zone_release(zone_desc);
986 }
987
988 database_service_zone_resignature_dnskey_alarm_args_free(args);
989
990 return NULL;
991 }
992
993 static ya_result
database_service_zone_resignature_deactivate_dnskey_alarm(void * args_,bool cancel)994 database_service_zone_resignature_deactivate_dnskey_alarm(void *args_, bool cancel)
995 {
996 database_service_zone_resignature_dnskey_alarm_args *args = (database_service_zone_resignature_dnskey_alarm_args*)args_;
997 ya_result ret = SUCCESS;
998
999 if(!cancel)
1000 {
1001 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: deactivation ...", args->domain, args->algorithm, args->tag, ntohs(args->flags));
1002
1003 if(thread_pool_try_enqueue_call(database_service_zone_resignature_publish_dnskey_tp,
1004 database_service_zone_resignature_deactivate_dnskey_thread,
1005 args,
1006 NULL,
1007 "dnskey-deactivate alarm") == LOCK_TIMEOUT)
1008 {
1009 ret = ALARM_REARM;
1010 }
1011 }
1012 else
1013 {
1014 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: deactivation alarm cancelled", args->domain, args->algorithm, args->tag, ntohs(args->flags));
1015 database_service_zone_resignature_dnskey_alarm_args_free(args);
1016 }
1017
1018 return ret;
1019 }
1020
1021 void
database_service_zone_dnskey_set_alarms_for_key(zdb_zone * zone,dnssec_key * key)1022 database_service_zone_dnskey_set_alarms_for_key(zdb_zone *zone, dnssec_key *key)
1023 {
1024 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: setting alarms", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1025
1026 time_t now = time(NULL);
1027
1028 zdb_zone_lock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER);
1029 bool in_zone = zdb_zone_contains_dnskey_record_for_key(zone, key);
1030 //bool signs = zdb_zone_apex_contains_rrsig_record_by_key(zone, key);
1031 zdb_zone_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER);
1032
1033 u32 state = dnskey_state_get(key);
1034
1035 s32 publish_epoch = dnskey_get_publish_epoch(key);
1036 s32 active_epoch = dnskey_get_activate_epoch(key);
1037 s32 inactive_epoch = dnskey_get_inactive_epoch(key);
1038 s32 delete_epoch = dnskey_get_delete_epoch(key);
1039
1040 bool give_up = FALSE;
1041
1042 if(publish_epoch > active_epoch)
1043 {
1044 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: publication after activation %T > %T, setting publication to activation", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), publish_epoch, active_epoch);
1045 publish_epoch = active_epoch;
1046 }
1047
1048 if(inactive_epoch > delete_epoch)
1049 {
1050 log_warn("dnskey: %{dnsname}: +%03d+%05d/%d: deactivation after delete %T > %T, setting delete to deactivation", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), inactive_epoch, delete_epoch);
1051 delete_epoch = inactive_epoch;
1052 }
1053
1054 if((give_up |= (publish_epoch >= delete_epoch)))
1055 {
1056 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: publication at or after deletion %T >= %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), publish_epoch, delete_epoch);
1057 }
1058
1059 if((give_up |= (active_epoch >= inactive_epoch)))
1060 {
1061 log_err("dnskey: %{dnsname}: +%03d+%05d/%d: activation at or after deactivation %T >= %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), publish_epoch, delete_epoch);
1062 }
1063
1064 if(give_up)
1065 {
1066 log_notice("dnskey: %{dnsname}: +%03d+%05d/%d: gave up setting alarms", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1067 return;
1068 }
1069
1070 s32 when;
1071
1072 // if the key will need to be published
1073
1074 if(now < delete_epoch)
1075 {
1076 // and the key hasn't been published already
1077
1078 bool publish_queued = FALSE;
1079
1080 if(!in_zone)
1081 {
1082 // follow the rule, if the key is not in the zone and should be, arm its publication even if it's never activated
1083
1084 if((state & DNSKEY_KEY_PUBLISH_ARMED) == 0)
1085 {
1086 // mark the key as timed for publication and arm said publication
1087 // once the key is added, activation will occur too if needed
1088
1089 when = publish_epoch;
1090
1091 dnskey_state_enable(key, DNSKEY_KEY_PUBLISH_ARMED);
1092
1093 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: will be published at %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), when);
1094
1095 alarm_event_node *event = alarm_event_new(
1096 when,
1097 database_service_zone_resignature_dnskey_alarm_unique_key(key, ALARM_KEY_ZONE_DNSKEY_PUBLISH),
1098 database_service_zone_resignature_publish_dnskey_alarm,
1099 database_service_zone_resignature_dnskey_alarm_args_new(key),
1100 ALARM_DUP_REMOVE_LATEST,
1101 "dnskey publish to zone");
1102
1103 alarm_set(zone->alarm_handle, event);
1104
1105 publish_queued = TRUE;
1106 }
1107 else
1108 {
1109 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: already marked to be published", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1110 }
1111 }
1112
1113 // if the key needs to be activated ...
1114
1115 if(now < inactive_epoch)
1116 {
1117 if((state & DNSKEY_KEY_ACTIVATE_ARMED) == 0)
1118 {
1119 // mark the key as timed for activation and arm said activation
1120
1121 when = MAX(active_epoch, now - 5);
1122
1123 if(!(publish_queued && (when <= publish_epoch)))
1124 {
1125 dnskey_state_enable(key, DNSKEY_KEY_ACTIVATE_ARMED);
1126 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: will be activated at %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), when);
1127
1128 // set alarm
1129
1130 alarm_event_node *event = alarm_event_new(
1131 when,
1132 database_service_zone_resignature_dnskey_alarm_unique_key(key, ALARM_KEY_ZONE_DNSKEY_ACTIVATE),
1133 database_service_zone_resignature_activate_dnskey_alarm,
1134 database_service_zone_resignature_dnskey_alarm_args_new(key),
1135 ALARM_DUP_REMOVE_LATEST,
1136 "dnskey activate from zone");
1137
1138 alarm_set(zone->alarm_handle, event);
1139 }
1140 else
1141 {
1142 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: will be activated along with publication at %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), MAX(publish_epoch, now));
1143 }
1144 }
1145 else
1146 {
1147 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: already marked to be activated", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1148 }
1149 }
1150 } // if now < delete epoch
1151
1152 // the actions to take if the key was not in the zone or needed to be activated are made.
1153
1154 // deactivate, remove ...
1155
1156 if(in_zone)
1157 {
1158 if(now <= inactive_epoch)
1159 {
1160 if((state & DNSKEY_KEY_DEACTIVATE_ARMED) != 0)
1161 {
1162 // mark the key as timed for activation and arm said activation
1163
1164 dnskey_state_enable(key, DNSKEY_KEY_DEACTIVATE_ARMED);
1165
1166 when = inactive_epoch;
1167
1168 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: will be deactivated at %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), when);
1169
1170 // set alarm
1171
1172 alarm_event_node *event = alarm_event_new(
1173 when,
1174 database_service_zone_resignature_dnskey_alarm_unique_key(key, ALARM_KEY_ZONE_DNSKEY_DEACTIVATE),
1175 database_service_zone_resignature_deactivate_dnskey_alarm,
1176 database_service_zone_resignature_dnskey_alarm_args_new(key),
1177 ALARM_DUP_REMOVE_LATEST,
1178 "dnskey deactivate from zone");
1179
1180 alarm_set(zone->alarm_handle, event);
1181 }
1182 else
1183 {
1184 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: already marked to be deactivated", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1185 }
1186 }
1187
1188 if((state & DNSKEY_KEY_DELETE_ARMED) == 0)
1189 {
1190 dnskey_state_enable(key, DNSKEY_KEY_DELETE_ARMED);
1191
1192 when = delete_epoch;
1193
1194 log_info("dnskey: %{dnsname}: +%03d+%05d/%d: will be unpublished at %T", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)), when);
1195
1196 alarm_event_node *event = alarm_event_new(
1197 when,
1198 database_service_zone_resignature_dnskey_alarm_unique_key(key, ALARM_KEY_ZONE_DNSKEY_UNPUBLISH),
1199 database_service_zone_resignature_unpublish_dnskey_alarm,
1200 database_service_zone_resignature_dnskey_alarm_args_new(key),
1201 ALARM_DUP_REMOVE_LATEST,
1202 "dnskey unpublish from zone");
1203
1204 alarm_set(zone->alarm_handle, event);
1205 }
1206 else
1207 {
1208 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: already marked to be unpublished", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1209 }
1210 } // in zone
1211
1212 log_debug("dnskey: %{dnsname}: +%03d+%05d/%d: alarms have been set", dnskey_get_domain(key), dnskey_get_algorithm(key), dnskey_get_tag(key), ntohs(dnskey_get_flags(key)));
1213 }
1214
1215 /**
1216 *
1217 * Fetches all (smart signing) events of all the keys of a zone and arms them.
1218 *
1219 * @param zone
1220 */
1221
1222 void
database_service_zone_dnskey_set_alarms(zdb_zone * zone)1223 database_service_zone_dnskey_set_alarms(zdb_zone *zone)
1224 {
1225 // set alarms for the timings of the keys
1226 // (publish, activate, inactivate, unpublish)
1227 // this should probably only be done after the zone is mounted (else race could occur)
1228
1229 log_info("database-service: %{dnsname}: set DNSKEY alarms", zone->origin);
1230
1231 time_t now = time(NULL);
1232
1233 for(int i = 0; ; ++i)
1234 {
1235 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_at_index(zone->origin, i);
1236
1237 if(key == NULL)
1238 {
1239 break;
1240 }
1241
1242 if(dnskey_get_flags(key) != (DNSKEY_FLAG_ZONEKEY | DNSKEY_FLAG_KEYSIGNINGKEY))
1243 {
1244 if(!dnskey_is_activated(key, now))
1245 {
1246 continue;
1247 }
1248
1249 if(!dnskey_is_private(key))
1250 {
1251 continue;
1252 }
1253
1254 break;
1255 }
1256
1257 database_service_zone_dnskey_set_alarms_for_key(zone, key);
1258
1259 dnskey_release(key);
1260 }
1261
1262 for(int i = 0; ; ++i)
1263 {
1264 dnssec_key *key = dnssec_keystore_acquire_key_from_fqdn_at_index(zone->origin, i);
1265
1266 if(key == NULL)
1267 {
1268 break;
1269 }
1270
1271 database_service_zone_dnskey_set_alarms_for_key(zone, key);
1272
1273 dnskey_release(key);
1274 }
1275
1276 log_debug("database-service: %{dnsname}: DNSKEY alarms have been set", zone->origin);
1277 }
1278
1279 static ya_result
database_service_zone_dnskey_set_alarms_on_all_zones_callback(zone_desc_s * zone_desc,void * args)1280 database_service_zone_dnskey_set_alarms_on_all_zones_callback(zone_desc_s *zone_desc, void *args)
1281 {
1282 (void)args;
1283 bool is_master;
1284
1285 zone_lock(zone_desc, ZONE_LOCK_READONLY);
1286 is_master = (zone_desc->type == ZT_MASTER);
1287 zdb_zone *zone = zone_get_loaded_zone(zone_desc);
1288 zone_unlock(zone_desc, ZONE_LOCK_READONLY);
1289
1290 if(!is_master)
1291 {
1292 if(zone != NULL)
1293 {
1294 zdb_zone_release(zone);
1295 }
1296
1297 log_debug("%{dnsname}: not master, skipping setting of the DNSKEY alarm (part of a batch)", zone_origin(zone_desc));
1298
1299 return SUCCESS;
1300 }
1301
1302 if(zone != NULL)
1303 {
1304 if(zdb_zone_is_maintained(zone))
1305 {
1306 log_debug("%{dnsname}: setting DNSKEY alarm (part of a batch)", zone->origin);
1307 database_service_zone_dnskey_set_alarms(zone);
1308 }
1309 else
1310 {
1311 log_debug("%{dnsname}: not maintained, skipping setting of the DNSKEY alarm (part of a batch)", zone->origin);
1312 }
1313
1314 zdb_zone_release(zone);
1315 }
1316 return SUCCESS;
1317 }
1318
1319 void
database_service_zone_dnskey_set_alarms_on_all_zones()1320 database_service_zone_dnskey_set_alarms_on_all_zones()
1321 {
1322 zone_desc_for_all(database_service_zone_dnskey_set_alarms_on_all_zones_callback, NULL);
1323 }
1324
1325 static database_service_zone_resignature_parms_s*
database_service_zone_resignature_parms_alloc(zone_desc_s * zone_desc)1326 database_service_zone_resignature_parms_alloc(zone_desc_s *zone_desc)
1327 {
1328 database_service_zone_resignature_parms_s *parm;
1329
1330 ZALLOC_OBJECT_OR_DIE( parm, database_service_zone_resignature_parms_s, DSZZRPRM_TAG);
1331 parm->zone_desc = zone_desc;
1332
1333 return parm;
1334 }
1335
1336 void
database_service_zone_resignature_parms_free(database_service_zone_resignature_parms_s * parm)1337 database_service_zone_resignature_parms_free(database_service_zone_resignature_parms_s *parm)
1338 {
1339 #if DEBUG
1340 memset(parm, 0xff, sizeof(database_service_zone_resignature_parms_s));
1341 #endif
1342 ZFREE_OBJECT(parm);
1343 }
1344
1345
1346 #if ZDB_HAS_DNSSEC_SUPPORT && ZDB_HAS_RRSIG_MANAGEMENT_SUPPORT
1347
1348 static void*
database_service_zone_dnssec_maintenance_thread(void * parms_)1349 database_service_zone_dnssec_maintenance_thread(void *parms_)
1350 {
1351 database_service_zone_resignature_parms_s *parms = (database_service_zone_resignature_parms_s*)parms_;
1352 zone_desc_s *zone_desc = parms->zone_desc;
1353 ya_result return_code;
1354
1355 if(zone_desc == NULL)
1356 {
1357 // this happening probably means a buffer overrun has occurred, likely a corruption of the memory heap
1358
1359 log_err("zone sign: database_service_zone_dnssec_maintenance_thread called with a NULL descriptor");
1360 logger_flush(); // yes, it's important to flush for this
1361 database_service_zone_resignature_parms_free(parms);
1362 return NULL;
1363 }
1364
1365 yassert(zone_desc != NULL);
1366
1367 if(!zone_maintains_dnssec(zone_desc))
1368 {
1369 log_warn("zone sign: %{dnsname}: resignature triggered although the feature was explicitly disabled : ignoring request.", zone_origin(zone_desc));
1370
1371 database_service_zone_resignature_parms_free(parms);
1372
1373 database_fire_zone_processed(zone_desc);
1374 zone_release(zone_desc);
1375 return NULL;
1376 }
1377
1378 if(dnscore_shuttingdown())
1379 {
1380 log_warn("zone sign: %{dnsname}: resignature called while shutting down : ignoring request.", zone_origin(zone_desc));
1381
1382 database_service_zone_resignature_parms_free(parms);
1383
1384 database_fire_zone_processed(zone_desc);
1385 zone_release(zone_desc);
1386 return NULL;
1387 }
1388
1389 zone_lock(zone_desc, ZONE_LOCK_SIGNATURE);
1390
1391 const u32 must_be_off = ZONE_STATUS_LOAD | ZONE_STATUS_LOADING | \
1392 ZONE_STATUS_DROP | ZONE_STATUS_DROPPING | \
1393 ZONE_STATUS_SAVING_ZONE_FILE | ZONE_STATUS_SAVING_AXFR_FILE | \
1394 ZONE_STATUS_SIGNATURES_UPDATING | ZONE_STATUS_DYNAMIC_UPDATE | \
1395 ZONE_STATUS_DYNAMIC_UPDATING;
1396
1397 #if DEBUG
1398 log_debug("database_service_zone_dnssec_maintenance(%{dnsname}@%p=%i)", zone_origin(zone_desc), zone_desc, zone_desc->rc);
1399 #endif
1400
1401 if((zone_get_status(zone_desc) & must_be_off) != 0)
1402 {
1403 log_err("zone sign: %{dnsname}: conflicting status: %08x instead of 0", zone_origin(zone_desc), (zone_get_status(zone_desc) & must_be_off));
1404
1405 zone_unlock(zone_desc, ZONE_LOCK_SIGNATURE);
1406
1407 database_service_zone_resignature_parms_free(parms);
1408
1409 database_fire_zone_processed(zone_desc);
1410 zone_release(zone_desc);
1411 return NULL;
1412 }
1413
1414 zone_set_status(zone_desc, ZONE_STATUS_SIGNATURES_UPDATING);
1415
1416 // do a bunch of signatures
1417
1418 zdb_zone *zone = zone_get_loaded_zone(zone_desc);
1419
1420 if(zone != NULL)
1421 {
1422 // should have a starting point, cylcing trough the nodes
1423 // that way there will be no increasingly long scans
1424
1425 if(zdb_zone_is_maintained(zone))
1426 {
1427 log_debug("zone sign: %{dnsname}: signatures update", zone_origin(zone_desc));
1428
1429 if(FAIL(return_code = zdb_zone_maintenance(zone)))
1430 {
1431 #if DEBUG
1432 log_info("zone sign: %{dnsname}: failed with %r and earliest signature expiration happens at %T", zone_origin(zone_desc), return_code, zone->progressive_signature_update.earliest_signature_expiration);
1433 #endif
1434 switch(return_code)
1435 {
1436 case ZDB_ERROR_ZONE_IS_NOT_DNSSEC:
1437 log_warn("zone sign: %{dnsname}: unable to sign, it has not been configured as DNSSEC (disabling maintenance)", zone_origin(zone_desc));
1438 zdb_zone_set_maintained(zone, FALSE);
1439 break;
1440 case ZDB_ERROR_ZONE_IS_ALREADY_BEING_SIGNED:
1441 log_info("zone sign: %{dnsname}: could not refresh signatures, it is already being signed", zone_origin(zone_desc));
1442 break;
1443 case ZDB_ERROR_ZONE_NO_ZSK_PRIVATE_KEY_FILE:
1444 log_warn("zone sign: %{dnsname}: unable to try to refresh signatures because there are no private keys available (pausing maintenance)", zone_origin(zone_desc));
1445 //zdb_zone_set_maintained(zone, FALSE);
1446 zdb_zone_set_maintenance_paused(zone, TRUE);
1447 break;
1448 case DNSSEC_ERROR_UNSUPPORTEDKEYALGORITHM:
1449 log_warn("zone sign: %{dnsname}: unable to refresh signatures because there is a key with an unsupported algorithm (disabling maintenance)", zone_origin(zone_desc));
1450 zdb_zone_set_maintained(zone, FALSE);
1451 break;
1452 case ZDB_JOURNAL_MUST_SAFEGUARD_CONTINUITY:
1453 log_info("zone sign: %{dnsname}: unable to sign, the journal is full (pausing maintenance)", zone_origin(zone_desc));
1454 zdb_zone_info_background_store_zone(zone_origin(zone_desc));
1455 zdb_zone_set_maintenance_paused(zone, TRUE);
1456 break;
1457 default:
1458 log_err("zone sign: %{dnsname}: signature failed: %r", zone_origin(zone_desc), return_code);
1459 break;
1460 }
1461 }
1462 else if(return_code == 0) // no signature have been done, let's scan the current status
1463 {
1464 log_debug("zone sign: %{dnsname}: earliest signature expiration at %T", zone_origin(zone_desc), zone->progressive_signature_update.earliest_signature_expiration);
1465
1466 time_t soon = time(NULL) + 1;
1467 if(zone->progressive_signature_update.earliest_signature_expiration < soon)
1468 {
1469 // queue
1470 database_zone_update_signatures(zone->origin, zone_desc, zone);
1471 }
1472 else
1473 {
1474 // alarm queue
1475 database_zone_update_signatures_at(zone, zone->progressive_signature_update.earliest_signature_expiration);
1476 }
1477 }
1478 else // let's just restart this asap
1479 {
1480 log_debug("zone sign: %{dnsname}: quota reached, signature will resume as soon as possible", zone_origin(zone_desc));
1481
1482 database_zone_update_signatures_resume(zone->origin, zone_desc, zone);
1483
1484 if((zdb_zone_get_status(zone) & ZDB_ZONE_STATUS_MODIFIED) != 0)
1485 {
1486 notify_slaves(zone_origin(zone_desc));
1487 }
1488 }
1489 }
1490 else
1491 {
1492 log_info("zone sign: %{dnsname}: maintenance disabled", zone_origin(zone_desc));
1493 database_zone_update_signatures_allow_queue(zone->origin, zone_desc, zone);
1494 }
1495
1496 zdb_zone_release(zone);
1497 }
1498 else
1499 {
1500 log_err("zone sign: %{dnsname}: zone has not been loaded yet", zone_origin(zone_desc));
1501 }
1502
1503 // release
1504
1505 zone_clear_status(zone_desc, ZONE_STATUS_PROCESSING|ZONE_STATUS_SIGNATURES_UPDATE|ZONE_STATUS_SIGNATURES_UPDATING|ZONE_STATUS_PROCESSING);
1506
1507 log_debug("zone sign: %{dnsname}: signatures update end", zone_origin(zone_desc));
1508
1509 database_service_zone_resignature_parms_free(parms);
1510
1511 zone_unlock(zone_desc, ZONE_LOCK_SIGNATURE);
1512
1513 database_fire_zone_processed(zone_desc);
1514 zone_release(zone_desc);
1515
1516 return NULL;
1517 }
1518
1519 ya_result
database_service_zone_dnssec_maintenance_lock_for(zone_desc_s * zone_desc,u8 zone_desc_owner)1520 database_service_zone_dnssec_maintenance_lock_for(zone_desc_s *zone_desc, u8 zone_desc_owner) // one thread for all the program
1521 {
1522 yassert(zone_desc != NULL);
1523
1524 const u8 *origin = zone_origin(zone_desc);
1525
1526 log_debug1("database_service_zone_dnssec_maintenance(%{dnsname}@%p=%i)", origin, zone_desc, zone_desc->rc);
1527
1528 if(!zone_maintains_dnssec(zone_desc))
1529 {
1530 log_debug1("database_service_zone_dnssec_maintenance: %{dnsname} has signature maintenance disabled", origin);
1531 return FEATURE_NOT_SUPPORTED;
1532 }
1533
1534 log_debug1("zone sign: %{dnsname}: locking zone for signature update", origin);
1535
1536 if(zone_desc_owner != 0)
1537 {
1538 if(FAIL(zone_lock(zone_desc, ZONE_LOCK_SIGNATURE)))
1539 {
1540 log_err("zone sign: %{dnsname}: failed to lock zone settings", origin);
1541
1542 return INVALID_STATE_ERROR;
1543 }
1544 }
1545
1546 log_debug("zone sign: %{dnsname}", origin);
1547
1548 if(zone_get_status(zone_desc) & (ZONE_STATUS_SIGNATURES_UPDATE|ZONE_STATUS_SIGNATURES_UPDATING))
1549 {
1550 // already loading
1551 #if DEBUG
1552 zone_desc_log(MODULE_MSG_HANDLE, MSG_DEBUG1, zone_desc, "database_service_zone_resignature");
1553 #endif
1554 log_debug("zone sign: %{dnsname}: already having its signatures updated", origin);
1555
1556 ya_result ret;
1557
1558 if(zone_desc->loaded_zone != NULL)
1559 {
1560 database_zone_update_signatures_at(zone_desc->loaded_zone, time(NULL) + 5);
1561 ret = SERVICE_ALREADY_RUNNING;
1562 }
1563 else
1564 {
1565 log_err("zone sign: %{dnsname}: zone not bound", origin);
1566 ret = ZDB_READER_ZONENOTLOADED;
1567 }
1568
1569 if(zone_desc_owner != 0)
1570 {
1571 zone_unlock(zone_desc, ZONE_LOCK_SIGNATURE); // locked in this call
1572 }
1573
1574 return ret;
1575 }
1576
1577 log_debug("zone sign: %{dnsname}: zone signatures update begin", origin);
1578
1579 zone_clear_status(zone_desc, ZONE_STATUS_STARTING_UP);
1580 zone_set_status(zone_desc, ZONE_STATUS_SIGNATURES_UPDATE);
1581
1582 database_service_zone_resignature_parms_s *database_zone_resignature_parms = database_service_zone_resignature_parms_alloc(zone_desc);
1583 zone_acquire(zone_desc);
1584 database_service_zone_resignature_queue_thread(database_service_zone_dnssec_maintenance_thread, database_zone_resignature_parms, NULL, "database_zone_resignature_thread");
1585
1586 log_debug1("zone sign: %{dnsname}: unlocking zone for signature update", origin);
1587
1588 if(zone_desc_owner != 0)
1589 {
1590 zone_unlock(zone_desc, ZONE_LOCK_SIGNATURE); // locked in this call
1591 }
1592
1593 return SUCCESS;
1594 }
1595
1596 ya_result
database_service_zone_dnssec_maintenance(zone_desc_s * zone_desc)1597 database_service_zone_dnssec_maintenance(zone_desc_s *zone_desc) // one thread for all the program
1598 {
1599 ya_result ret = database_service_zone_dnssec_maintenance_lock_for(zone_desc, ZONE_LOCK_SIGNATURE);
1600 return ret;
1601 }
1602
1603 ya_result
database_service_zone_resignature_init()1604 database_service_zone_resignature_init()
1605 {
1606 mutex_lock(&database_service_zone_resignature_publish_dnskey_mtx);
1607
1608 if(database_service_zone_resignature_publish_dnskey_tp == NULL)
1609 {
1610 if(!g_config->hidden_master)
1611 {
1612 database_service_zone_resignature_publish_dnskey_tp = thread_pool_init_ex(1, 1024, "keypub");
1613 }
1614 else
1615 {
1616 database_service_zone_resignature_publish_dnskey_tp = thread_pool_init_ex(8, 0x100000, "keypub");
1617 }
1618 }
1619 mutex_unlock(&database_service_zone_resignature_publish_dnskey_mtx);
1620
1621 return (database_service_zone_resignature_publish_dnskey_tp != NULL)?SUCCESS:ERROR;
1622 }
1623
1624 ya_result
database_service_zone_resignature_finalize()1625 database_service_zone_resignature_finalize()
1626 {
1627 mutex_lock(&database_service_zone_resignature_publish_dnskey_mtx);
1628
1629 if(database_service_zone_resignature_publish_dnskey_tp != NULL)
1630 {
1631 thread_pool_destroy(database_service_zone_resignature_publish_dnskey_tp);
1632 database_service_zone_resignature_publish_dnskey_tp = NULL;
1633 }
1634 mutex_unlock(&database_service_zone_resignature_publish_dnskey_mtx);
1635
1636 return (database_service_zone_resignature_publish_dnskey_tp != NULL)?SUCCESS:ERROR;
1637 }
1638
1639 #endif
1640
1641 /**
1642 * @}
1643 */
1644