1 /* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #include <assert.h>
18
19 #include "knot/common/log.h"
20 #include "knot/conf/conf.h"
21 #include "knot/dnssec/zone-events.h"
22 #include "knot/updates/apply.h"
23 #include "knot/zone/zone.h"
24 #include "libknot/errcode.h"
25
log_dnssec_next(const knot_dname_t * zone,knot_time_t refresh_at)26 static void log_dnssec_next(const knot_dname_t *zone, knot_time_t refresh_at)
27 {
28 char time_str[64] = { 0 };
29 struct tm time_gm = { 0 };
30 time_t refresh = refresh_at;
31 localtime_r(&refresh, &time_gm);
32 strftime(time_str, sizeof(time_str), KNOT_LOG_TIME_FORMAT, &time_gm);
33 if (refresh_at == 0) {
34 log_zone_warning(zone, "DNSSEC, next signing not scheduled");
35 } else {
36 log_zone_info(zone, "DNSSEC, next signing at %s", time_str);
37 }
38 }
39
event_dnssec_reschedule(conf_t * conf,zone_t * zone,const zone_sign_reschedule_t * refresh,bool zone_changed)40 void event_dnssec_reschedule(conf_t *conf, zone_t *zone,
41 const zone_sign_reschedule_t *refresh, bool zone_changed)
42 {
43 time_t now = time(NULL);
44 time_t ignore = -1;
45 knot_time_t refresh_at = refresh->next_sign;
46
47 if (knot_time_cmp(refresh->next_rollover, refresh_at) < 0) {
48 refresh_at = refresh->next_rollover;
49 }
50
51 log_dnssec_next(zone->name, (time_t)refresh_at);
52
53 if (refresh->plan_ds_check) {
54 zone->timers.next_ds_check = now;
55 }
56
57 if (refresh->last_nsec3resalt) {
58 zone->timers.last_resalt = refresh->last_nsec3resalt;
59 }
60
61 zone_events_schedule_at(zone,
62 ZONE_EVENT_DNSSEC, refresh_at ? (time_t)refresh_at : ignore,
63 ZONE_EVENT_DS_CHECK, refresh->plan_ds_check ? now : ignore,
64 ZONE_EVENT_NSEC3RESALT, refresh->next_nsec3resalt ? refresh->next_nsec3resalt : ignore,
65 ZONE_EVENT_NOTIFY, zone_changed ? now : ignore
66 );
67 }
68
event_dnssec(conf_t * conf,zone_t * zone)69 int event_dnssec(conf_t *conf, zone_t *zone)
70 {
71 assert(zone);
72
73 zone_sign_reschedule_t resch = { 0 };
74 zone_sign_roll_flags_t r_flags = KEY_ROLL_ALLOW_ALL;
75 int sign_flags = 0;
76 bool zone_changed = false;
77
78 if (zone_get_flag(zone, ZONE_FORCE_RESIGN, true)) {
79 log_zone_info(zone->name, "DNSSEC, dropping previous "
80 "signatures, re-signing zone");
81 sign_flags = ZONE_SIGN_DROP_SIGNATURES;
82 } else {
83 log_zone_info(zone->name, "DNSSEC, signing zone");
84 sign_flags = 0;
85 }
86
87 if (zone_get_flag(zone, ZONE_FORCE_KSK_ROLL, true)) {
88 r_flags |= KEY_ROLL_FORCE_KSK_ROLL;
89 }
90 if (zone_get_flag(zone, ZONE_FORCE_ZSK_ROLL, true)) {
91 r_flags |= KEY_ROLL_FORCE_ZSK_ROLL;
92 }
93
94 zone_update_t up;
95 int ret = zone_update_init(&up, zone, UPDATE_INCREMENTAL);
96 if (ret != KNOT_EOK) {
97 return ret;
98 }
99
100 ret = knot_dnssec_zone_sign(&up, conf, sign_flags, r_flags, 0, &resch);
101 if (ret != KNOT_EOK) {
102 goto done;
103 }
104
105 zone_changed = !zone_update_no_change(&up);
106
107 ret = zone_update_commit(conf, &up);
108 if (ret != KNOT_EOK) {
109 goto done;
110 }
111
112 done:
113 // Schedule dependent events
114 event_dnssec_reschedule(conf, zone, &resch, zone_changed);
115
116 if (ret != KNOT_EOK) {
117 zone_update_clear(&up);
118 }
119 return ret;
120 }
121