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