diff --git a/src/knot/dnssec/context.c b/src/knot/dnssec/context.c index 1beaf3e5080db791cfcc2523828e62b69c019488..cb3cfdc1ed4f8a178643f2051cc98946f7892cef 100644 --- a/src/knot/dnssec/context.c +++ b/src/knot/dnssec/context.c @@ -22,6 +22,7 @@ #include "libknot/libknot.h" #include "knot/dnssec/context.h" #include "knot/dnssec/kasp/keystore.h" +#include "knot/dnssec/key_records.h" #include "knot/server/dthreads.h" knot_dynarray_define(parent, knot_kasp_parent_t, DYNARRAY_VISIBILITY_NORMAL) @@ -228,6 +229,16 @@ int kdnssec_ctx_init(conf_t *conf, kdnssec_ctx_t *ctx, const knot_dname_t *zone_ ctx->now = knot_time(); + key_records_init(ctx, &ctx->offline_records); + if (ctx->policy->offline_ksk) { + ret = kasp_db_load_offline_records(ctx->kasp_db, ctx->zone->dname, + ctx->now, &ctx->offline_next_time, + &ctx->offline_records); + if (ret != KNOT_EOK && ret != KNOT_ENOENT) { + goto init_error; + } + } + return KNOT_EOK; init_error: kdnssec_ctx_deinit(ctx); @@ -266,7 +277,7 @@ void kdnssec_ctx_deinit(kdnssec_ctx_t *ctx) } free(ctx->policy); } - knot_rrset_free(ctx->offline_rrsig, NULL); + key_records_clear(&ctx->offline_records); dnssec_keystore_deinit(ctx->keystore); kasp_zone_free(&ctx->zone); free(ctx->kasp_zone_path); diff --git a/src/knot/dnssec/context.h b/src/knot/dnssec/context.h index df4ee33b19814ecce722df2c6ccbfc8c1e4b040e..55a2f3c364dffbbc309e5d080a57117113fa277d 100644 --- a/src/knot/dnssec/context.h +++ b/src/knot/dnssec/context.h @@ -44,7 +44,8 @@ typedef struct { unsigned dbus_event; - knot_rrset_t *offline_rrsig; + key_records_t offline_records; + knot_time_t offline_next_time; } kdnssec_ctx_t; /*! diff --git a/src/knot/dnssec/zone-events.c b/src/knot/dnssec/zone-events.c index 8ecd03803588ca6578259ad7a716000f7628aa88..cf6efbf98234f948a1dfbb5a032770f3cdf7e4f8 100644 --- a/src/knot/dnssec/zone-events.c +++ b/src/knot/dnssec/zone-events.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -123,6 +123,7 @@ int knot_dnssec_zone_sign(zone_update_t *update, const knot_dname_t *zone_name = update->new_cont->apex->owner; kdnssec_ctx_t ctx = { 0 }; zone_keyset_t keyset = { 0 }; + knot_time_t zone_expire = 0; int result = kdnssec_ctx_init(conf, &ctx, zone_name, zone_kaspdb(update->zone), NULL); if (result != KNOT_EOK) { @@ -191,8 +192,7 @@ int knot_dnssec_zone_sign(zone_update_t *update, log_zone_info(zone_name, "DNSSEC, signing started"); - knot_time_t next_resign = 0; - result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx, &next_resign); + result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to update DNSKEY records (%s)", knot_strerror(result)); @@ -213,7 +213,6 @@ int knot_dnssec_zone_sign(zone_update_t *update, goto done; } - knot_time_t zone_expire = 0; result = knot_zone_sign(update, &keyset, &ctx, &zone_expire); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to sign zone content (%s)", @@ -259,7 +258,7 @@ int knot_dnssec_zone_sign(zone_update_t *update, done: if (result == KNOT_EOK) { - reschedule->next_sign = schedule_next(&ctx, &keyset, next_resign, zone_expire); + reschedule->next_sign = schedule_next(&ctx, &keyset, ctx.offline_next_time, zone_expire); } else { reschedule->next_sign = knot_dnssec_failover_delay(&ctx); reschedule->next_rollover = 0; @@ -280,7 +279,7 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) const knot_dname_t *zone_name = update->new_cont->apex->owner; kdnssec_ctx_t ctx = { 0 }; zone_keyset_t keyset = { 0 }; - knot_time_t expire_at = 0; + knot_time_t zone_expire = 0; int result = kdnssec_ctx_init(conf, &ctx, zone_name, zone_kaspdb(update->zone), NULL); if (result != KNOT_EOK) { @@ -309,9 +308,8 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) goto done; } - if (zone_update_changes_dnskey(update) || ctx.policy->offline_ksk) { - // TODO: move offline rrsigs filling out of knot_zone_sign_update_dnskeys(). - result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx, &expire_at); + if (zone_update_changes_dnskey(update)) { + result = knot_zone_sign_update_dnskeys(update, &keyset, &ctx); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to update DNSKEY records (%s)", knot_strerror(result)); @@ -325,7 +323,7 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) goto done; } - result = knot_zone_sign_update(update, &keyset, &ctx, &expire_at); + result = knot_zone_sign_update(update, &keyset, &ctx, &zone_expire); if (result != KNOT_EOK) { log_zone_error(zone_name, "DNSSEC, failed to sign changeset (%s)", knot_strerror(result)); @@ -379,8 +377,10 @@ int knot_dnssec_sign_update(zone_update_t *update, conf_t *conf) log_zone_info(zone_name, "DNSSEC, incrementally signed"); done: - if (result == KNOT_EOK && expire_at != 0) { - zone_events_schedule_at(update->zone, ZONE_EVENT_DNSSEC, (time_t)expire_at); // this is usually NOOP since signing planned earlier + if (result == KNOT_EOK) { + knot_time_t next = knot_time_min(ctx.offline_next_time, zone_expire); + // NOTE: this is usually NOOP since signing planned earlier + zone_events_schedule_at(update->zone, ZONE_EVENT_DNSSEC, next ? next : -1); } free_zone_keys(&keyset); diff --git a/src/knot/dnssec/zone-sign.c b/src/knot/dnssec/zone-sign.c index 5193c4f67828262df9e984431623e0f67ecc1553..ffa10c4817668eafb22921d86eb11d1eb00919bc 100644 --- a/src/knot/dnssec/zone-sign.c +++ b/src/knot/dnssec/zone-sign.c @@ -223,11 +223,11 @@ static int add_missing_rrsigs(const knot_rrset_t *covered, int result = (!rrsig_covers_type(rrsigs, covered->type) ? KNOT_EOK : knot_synth_rrsig(covered->type, &rrsigs->rrs, &to_remove.rrs, NULL)); - if (result == KNOT_EOK && sign_ctx->dnssec_ctx->offline_rrsig != NULL && - knot_dname_cmp(sign_ctx->dnssec_ctx->offline_rrsig->owner, covered->owner) == 0 && - rrsig_covers_type(sign_ctx->dnssec_ctx->offline_rrsig, covered->type)) { + if (result == KNOT_EOK && sign_ctx->dnssec_ctx->offline_records.rrsig.rrs.count > 0 && + knot_dname_cmp(sign_ctx->dnssec_ctx->offline_records.rrsig.owner, covered->owner) == 0 && + rrsig_covers_type(&sign_ctx->dnssec_ctx->offline_records.rrsig, covered->type)) { result = knot_synth_rrsig(covered->type, - &sign_ctx->dnssec_ctx->offline_rrsig->rrs, &to_add.rrs, NULL); + &sign_ctx->dnssec_ctx->offline_records.rrsig.rrs, &to_add.rrs, NULL); if (result == KNOT_EOK) { // don't remove what shall be added result = knot_rdataset_subtract(&to_remove.rrs, &to_add.rrs, NULL); @@ -845,8 +845,7 @@ int knot_zone_sign_add_dnskeys(zone_keyset_t *zone_keys, const kdnssec_ctx_t *dn int knot_zone_sign_update_dnskeys(zone_update_t *update, zone_keyset_t *zone_keys, - kdnssec_ctx_t *dnssec_ctx, - knot_time_t *next_resign) + kdnssec_ctx_t *dnssec_ctx) { if (update == NULL || zone_keys == NULL || dnssec_ctx == NULL) { return KNOT_EINVAL; @@ -857,62 +856,56 @@ int knot_zone_sign_update_dnskeys(zone_update_t *update, } const zone_node_t *apex = update->new_cont->apex; - key_records_t add_r, rem_r, orig_r; - memset(&add_r, 0, sizeof(add_r)); - memset(&rem_r, 0, sizeof(rem_r)); - key_records_from_apex(apex, &orig_r); knot_rrset_t soa = node_rrset(apex, KNOT_RRTYPE_SOA); if (knot_rrset_empty(&soa)) { return KNOT_EINVAL; } + key_records_t orig_r; + key_records_from_apex(apex, &orig_r); + changeset_t ch; int ret = changeset_init(&ch, apex->owner); if (ret != KNOT_EOK) { return ret; } -#define CHECK_RET if (ret != KNOT_EOK) goto cleanup - if (!dnssec_ctx->policy->incremental) { // remove all. This will cancel out with additions later ret = key_records_to_changeset(&orig_r, &ch, true, 0); - CHECK_RET; + if (ret != KNOT_EOK) { + return ret; + } } + key_records_t add_r, rem_r; key_records_init(dnssec_ctx, &add_r); key_records_init(dnssec_ctx, &rem_r); +#define CHECK_RET if (ret != KNOT_EOK) goto cleanup + if (dnssec_ctx->policy->offline_ksk) { - ret = kasp_db_load_offline_records(dnssec_ctx->kasp_db, apex->owner, dnssec_ctx->now, next_resign, &add_r); - if (ret == KNOT_EOK) { - log_zone_info(dnssec_ctx->zone->dname, - "DNSSEC, using offline records, DNSKEYs %hu, CDNSKEYs %hu, CDs %hu, RRSIGs %hu", - add_r.dnskey.rrs.count, add_r.cdnskey.rrs.count, add_r.cds.rrs.count, add_r.rrsig.rrs.count); - } else { - log_zone_warning(dnssec_ctx->zone->dname, "DNSSEC, failed to load offline records (%s)", - knot_strerror(ret)); - } + key_records_t *r = &dnssec_ctx->offline_records; + log_zone_info(dnssec_ctx->zone->dname, + "DNSSEC, using offline records, DNSKEYs %hu, CDNSKEYs %hu, CDs %hu, RRSIGs %hu", + r->dnskey.rrs.count, r->cdnskey.rrs.count, r->cds.rrs.count, r->rrsig.rrs.count); + ret = key_records_to_changeset(r, &ch, false, CHANGESET_CHECK); + CHECK_RET; } else { ret = knot_zone_sign_add_dnskeys(zone_keys, dnssec_ctx, &add_r, &rem_r, &orig_r); + CHECK_RET; + ret = key_records_to_changeset(&rem_r, &ch, true, CHANGESET_CHECK); + CHECK_RET; + ret = key_records_to_changeset(&add_r, &ch, false, CHANGESET_CHECK); + CHECK_RET; } - CHECK_RET; - ret = key_records_to_changeset(&rem_r, &ch, true, CHANGESET_CHECK); - CHECK_RET; - ret = key_records_to_changeset(&add_r, &ch, false, CHANGESET_CHECK); - CHECK_RET; if (dnssec_ctx->policy->ds_push && node_rrtype_exists(ch.add->apex, KNOT_RRTYPE_CDS)) { // there is indeed a change to CDS update->zone->timers.next_ds_push = time(NULL) + dnssec_ctx->policy->propagation_delay; zone_events_schedule_at(update->zone, ZONE_EVENT_DS_PUSH, update->zone->timers.next_ds_push); } - assert(knot_rrset_empty(&rem_r.rrsig)); - if (!knot_rrset_empty(&add_r.rrsig)) { - dnssec_ctx->offline_rrsig = knot_rrset_copy(&add_r.rrsig, NULL); - } - ret = zone_update_apply_changeset(update, &ch); #undef CHECK_RET diff --git a/src/knot/dnssec/zone-sign.h b/src/knot/dnssec/zone-sign.h index c3990a52928a3051d389349d4cc1f190bf8a03b7..ba6e2b22f09b5b88b837889ceb96a7e8d40407cc 100644 --- a/src/knot/dnssec/zone-sign.h +++ b/src/knot/dnssec/zone-sign.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -51,8 +51,7 @@ int knot_zone_sign_add_dnskeys(zone_keyset_t *zone_keys, const kdnssec_ctx_t *dn */ int knot_zone_sign_update_dnskeys(zone_update_t *update, zone_keyset_t *zone_keys, - kdnssec_ctx_t *dnssec_ctx, - knot_time_t *next_resign); + kdnssec_ctx_t *dnssec_ctx); /*! * \brief Check if key can be used to sign given RR.