Commit 3fbf23de authored by Libor Peltan's avatar Libor Peltan Committed by Daniel Salzman

ksk rollover: parent DS check implemented +test

parent b864bafe
...@@ -229,6 +229,7 @@ src/knot/events/handlers/nsec3resalt.c ...@@ -229,6 +229,7 @@ src/knot/events/handlers/nsec3resalt.c
src/knot/events/handlers/refresh.c src/knot/events/handlers/refresh.c
src/knot/events/handlers/update.c src/knot/events/handlers/update.c
src/knot/events/handlers/key_rollover.c src/knot/events/handlers/key_rollover.c
src/knot/events/handlers/parent_ds_query.c
src/knot/events/log.c src/knot/events/log.c
src/knot/events/log.h src/knot/events/log.h
src/knot/events/replan.c src/knot/events/replan.c
......
...@@ -289,6 +289,7 @@ libknotd_la_SOURCES = \ ...@@ -289,6 +289,7 @@ libknotd_la_SOURCES = \
knot/events/handlers/refresh.c \ knot/events/handlers/refresh.c \
knot/events/handlers/update.c \ knot/events/handlers/update.c \
knot/events/handlers/key_rollover.c \ knot/events/handlers/key_rollover.c \
knot/events/handlers/parent_ds_query.c \
knot/events/log.c \ knot/events/log.c \
knot/events/log.h \ knot/events/log.h \
knot/events/replan.c \ knot/events/replan.c \
......
...@@ -203,6 +203,8 @@ static const yp_item_t desc_policy[] = { ...@@ -203,6 +203,8 @@ static const yp_item_t desc_policy[] = {
{ C_NSEC3_SALT_LEN, YP_TINT, YP_VINT = { 0, UINT8_MAX, 8 }, CONF_IO_FRLD_ZONES }, { C_NSEC3_SALT_LEN, YP_TINT, YP_VINT = { 0, UINT8_MAX, 8 }, CONF_IO_FRLD_ZONES },
{ C_NSEC3_SALT_LIFETIME, YP_TINT, YP_VINT = { 1, UINT32_MAX, DAYS(30), YP_STIME }, { C_NSEC3_SALT_LIFETIME, YP_TINT, YP_VINT = { 1, UINT32_MAX, DAYS(30), YP_STIME },
CONF_IO_FRLD_ZONES }, CONF_IO_FRLD_ZONES },
{ C_KSK_SUBMITTION_CHECK,YP_TREF, YP_VREF = { C_RMT }, YP_FMULTI | CONF_IO_FRLD_ZONES, { check_ref } },
{ C_KSK_SUBMITTION_CHECK_INTERVAL, YP_TINT, YP_VINT = { 1, UINT32_MAX, HOURS(1), YP_STIME }, CONF_IO_FRLD_ZONES },
{ C_COMMENT, YP_TSTR, YP_VNONE }, { C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL } { NULL }
}; };
...@@ -292,10 +294,10 @@ const yp_item_t conf_scheme[] = { ...@@ -292,10 +294,10 @@ const yp_item_t conf_scheme[] = {
{ C_LOG, YP_TGRP, YP_VGRP = { desc_log }, YP_FMULTI | CONF_IO_FRLD_LOG }, { C_LOG, YP_TGRP, YP_VGRP = { desc_log }, YP_FMULTI | CONF_IO_FRLD_LOG },
{ C_STATS, YP_TGRP, YP_VGRP = { desc_stats }, CONF_IO_FRLD_SRV }, { C_STATS, YP_TGRP, YP_VGRP = { desc_stats }, CONF_IO_FRLD_SRV },
{ C_KEYSTORE, YP_TGRP, YP_VGRP = { desc_keystore }, YP_FMULTI, { check_keystore } }, { C_KEYSTORE, YP_TGRP, YP_VGRP = { desc_keystore }, YP_FMULTI, { check_keystore } },
{ C_POLICY, YP_TGRP, YP_VGRP = { desc_policy }, YP_FMULTI, { check_policy } },
{ C_KEY, YP_TGRP, YP_VGRP = { desc_key }, YP_FMULTI, { check_key } }, { C_KEY, YP_TGRP, YP_VGRP = { desc_key }, YP_FMULTI, { check_key } },
{ C_ACL, YP_TGRP, YP_VGRP = { desc_acl }, YP_FMULTI, { check_acl } }, { C_ACL, YP_TGRP, YP_VGRP = { desc_acl }, YP_FMULTI, { check_acl } },
{ C_RMT, YP_TGRP, YP_VGRP = { desc_remote }, YP_FMULTI, { check_remote } }, { C_RMT, YP_TGRP, YP_VGRP = { desc_remote }, YP_FMULTI, { check_remote } },
{ C_POLICY, YP_TGRP, YP_VGRP = { desc_policy }, YP_FMULTI, { check_policy } },
{ C_TPL, YP_TGRP, YP_VGRP = { desc_template }, YP_FMULTI, { check_template } }, { C_TPL, YP_TGRP, YP_VGRP = { desc_template }, YP_FMULTI, { check_template } },
{ C_ZONE, YP_TGRP, YP_VGRP = { desc_zone }, YP_FMULTI | CONF_IO_FZONE, { check_zone } }, { C_ZONE, YP_TGRP, YP_VGRP = { desc_zone }, YP_FMULTI | CONF_IO_FZONE, { check_zone } },
{ C_INCL, YP_TSTR, YP_VNONE, CONF_IO_FDIFF_ZONES | CONF_IO_FRLD_ALL, { include_file } }, { C_INCL, YP_TSTR, YP_VNONE, CONF_IO_FDIFF_ZONES | CONF_IO_FRLD_ALL, { include_file } },
......
...@@ -60,7 +60,10 @@ ...@@ -60,7 +60,10 @@
#define C_KASP_DB_MAPSIZE "\x0F""kasp-db-mapsize" #define C_KASP_DB_MAPSIZE "\x0F""kasp-db-mapsize"
#define C_KEY "\x03""key" #define C_KEY "\x03""key"
#define C_KEYSTORE "\x08""keystore" #define C_KEYSTORE "\x08""keystore"
#define C_KSK_LIFETIME "\x0C""ksk-lifetime"
#define C_KSK_SIZE "\x08""ksk-size" #define C_KSK_SIZE "\x08""ksk-size"
#define C_KSK_SUBMITTION_CHECK "\x14""ksk-submittion-check"
#define C_KSK_SUBMITTION_CHECK_INTERVAL "\x1D""ksk-submittion-check-interval"
#define C_LISTEN "\x06""listen" #define C_LISTEN "\x06""listen"
#define C_LOG "\x03""log" #define C_LOG "\x03""log"
#define C_MANUAL "\x06""manual" #define C_MANUAL "\x06""manual"
...@@ -117,7 +120,6 @@ ...@@ -117,7 +120,6 @@
#define C_ZONE "\x04""zone" #define C_ZONE "\x04""zone"
#define C_ZONEFILE_SYNC "\x0D""zonefile-sync" #define C_ZONEFILE_SYNC "\x0D""zonefile-sync"
#define C_ZSK_LIFETIME "\x0C""zsk-lifetime" #define C_ZSK_LIFETIME "\x0C""zsk-lifetime"
#define C_KSK_LIFETIME "\x0C""ksk-lifetime"
#define C_ZSK_SIZE "\x08""zsk-size" #define C_ZSK_SIZE "\x08""zsk-size"
enum { enum {
......
...@@ -179,7 +179,7 @@ static roll_action next_action(kdnssec_ctx_t *ctx) ...@@ -179,7 +179,7 @@ static roll_action next_action(kdnssec_ctx_t *ctx)
restype = SUBMIT; restype = SUBMIT;
break; break;
case DNSSEC_KEY_STATE_READY: case DNSSEC_KEY_STATE_READY:
break; // TODO !!! break;
case DNSSEC_KEY_STATE_ACTIVE: case DNSSEC_KEY_STATE_ACTIVE:
if (!is_ksk_published) { if (!is_ksk_published) {
keytime = ksk_publish_time(key->timing.active, ctx); keytime = ksk_publish_time(key->timing.active, ctx);
...@@ -279,7 +279,7 @@ static int exec_remove_old_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key) ...@@ -279,7 +279,7 @@ static int exec_remove_old_key(kdnssec_ctx_t *ctx, knot_kasp_key_t *key)
return kdnssec_delete_key(ctx, key); return kdnssec_delete_key(ctx, key);
} }
int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, bool *keys_changed, time_t *next_rollover) int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_t *zone, bool *keys_changed, time_t *next_rollover)
{ {
if (ctx->policy->manual) { if (ctx->policy->manual) {
return KNOT_EOK; return KNOT_EOK;
...@@ -312,6 +312,11 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, bool *keys_changed, time_t *nex ...@@ -312,6 +312,11 @@ int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, bool *keys_changed, time_t *nex
break; break;
case SUBMIT: case SUBMIT:
ret = submit_key(ctx, next.key); ret = submit_key(ctx, next.key);
if (zone == NULL) {
return KNOT_EINVAL;
}
zone_events_schedule_now(zone, ZONE_EVENT_PARENT_DS_Q);
// "now" it won't probably succeed, but it replans itself for proper interval
break; break;
case REPLACE: case REPLACE:
ret = exec_new_signatures(ctx, next.key); ret = exec_new_signatures(ctx, next.key);
...@@ -354,3 +359,17 @@ int knot_dnssec_ksk_submittion_confirm(kdnssec_ctx_t *ctx, uint16_t for_key) ...@@ -354,3 +359,17 @@ int knot_dnssec_ksk_submittion_confirm(kdnssec_ctx_t *ctx, uint16_t for_key)
} }
return KNOT_ENOENT; return KNOT_ENOENT;
} }
bool zone_has_key_submittion(const kdnssec_ctx_t *ctx)
{
assert(ctx->zone);
for (size_t i = 0; i < ctx->zone->num_keys; i++) {
knot_kasp_key_t *key = &ctx->zone->keys[i];
if (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK &&
get_key_state(key, ctx->now) == DNSSEC_KEY_STATE_READY) {
return true;
}
}
return false;
}
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <time.h> #include <time.h>
#include "knot/dnssec/context.h" #include "knot/dnssec/context.h"
#include "knot/zone/zone.h"
/*! /*!
* \brief Perform correct ZSK and KSK rollover action and plan next one. * \brief Perform correct ZSK and KSK rollover action and plan next one.
...@@ -37,6 +38,8 @@ ...@@ -37,6 +38,8 @@
* *
* \return KNOT_E* * \return KNOT_E*
*/ */
int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, bool *keys_changed, time_t *next_rollover); int knot_dnssec_key_rollover(kdnssec_ctx_t *ctx, zone_t *zone, bool *keys_changed, time_t *next_rollover);
int knot_dnssec_ksk_submittion_confirm(kdnssec_ctx_t *ctx, uint16_t for_key); int knot_dnssec_ksk_submittion_confirm(kdnssec_ctx_t *ctx, uint16_t for_key);
bool zone_has_key_submittion(const kdnssec_ctx_t *ctx);
...@@ -646,6 +646,15 @@ static bool cds_rdata_match(zone_key_t *key, ...@@ -646,6 +646,15 @@ static bool cds_rdata_match(zone_key_t *key,
return (ret == KNOT_EOK && res == 0); return (ret == KNOT_EOK && res == 0);
} }
bool knot_match_key_ds(zone_key_t *key, const knot_rdata_t *rdata)
{
dnssec_binary_t rdata_bin = {
.data = knot_rdata_data(rdata),
.size = knot_rdata_rdlen(rdata)
};
return cds_rdata_match(key, &rdata_bin);
}
/*! /*!
* \brief Check if DNSKEY/DS is present in public zone key set. * \brief Check if DNSKEY/DS is present in public zone key set.
*/ */
......
...@@ -125,4 +125,6 @@ int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys, ...@@ -125,4 +125,6 @@ int knot_zone_sign_nsecs_in_changeset(const zone_keyset_t *zone_keys,
bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node, bool knot_zone_sign_rr_should_be_signed(const zone_node_t *node,
const knot_rrset_t *rrset); const knot_rrset_t *rrset);
bool knot_match_key_ds(zone_key_t *key, const knot_rdata_t *rdata);
/*! @} */ /*! @} */
...@@ -48,6 +48,7 @@ static const event_info_t EVENT_INFO[] = { ...@@ -48,6 +48,7 @@ static const event_info_t EVENT_INFO[] = {
{ ZONE_EVENT_UTHAW, event_uthaw, "update thaw" }, { ZONE_EVENT_UTHAW, event_uthaw, "update thaw" },
{ ZONE_EVENT_NSEC3RESALT, event_nsec3resalt, "NSEC3 resalt" }, { ZONE_EVENT_NSEC3RESALT, event_nsec3resalt, "NSEC3 resalt" },
{ ZONE_EVENT_KEY_ROLLOVER, event_key_rollover, "KEY rollover" }, { ZONE_EVENT_KEY_ROLLOVER, event_key_rollover, "KEY rollover" },
{ ZONE_EVENT_PARENT_DS_Q, event_parent_ds_q, "parent DS query" },
{ 0 } { 0 }
}; };
...@@ -79,6 +80,7 @@ bool ufreeze_applies(zone_event_type_t type) ...@@ -79,6 +80,7 @@ bool ufreeze_applies(zone_event_type_t type)
case ZONE_EVENT_DNSSEC: case ZONE_EVENT_DNSSEC:
case ZONE_EVENT_NSEC3RESALT: case ZONE_EVENT_NSEC3RESALT:
case ZONE_EVENT_KEY_ROLLOVER: case ZONE_EVENT_KEY_ROLLOVER:
case ZONE_EVENT_PARENT_DS_Q:
return true; return true;
default: default:
return false; return false;
......
...@@ -41,6 +41,7 @@ typedef enum zone_event_type { ...@@ -41,6 +41,7 @@ typedef enum zone_event_type {
ZONE_EVENT_UTHAW, ZONE_EVENT_UTHAW,
ZONE_EVENT_NSEC3RESALT, ZONE_EVENT_NSEC3RESALT,
ZONE_EVENT_KEY_ROLLOVER, ZONE_EVENT_KEY_ROLLOVER,
ZONE_EVENT_PARENT_DS_Q,
// terminator // terminator
ZONE_EVENT_COUNT, ZONE_EVENT_COUNT,
} zone_event_type_t; } zone_event_type_t;
......
...@@ -41,3 +41,5 @@ int event_uthaw(conf_t *conf, zone_t *zone); ...@@ -41,3 +41,5 @@ int event_uthaw(conf_t *conf, zone_t *zone);
int event_nsec3resalt(conf_t *conf, zone_t *zone); int event_nsec3resalt(conf_t *conf, zone_t *zone);
/*! \brief ZSK rollover related actions (key creation, publishing, deleting...). */ /*! \brief ZSK rollover related actions (key creation, publishing, deleting...). */
int event_key_rollover(conf_t *conf, zone_t *zone); int event_key_rollover(conf_t *conf, zone_t *zone);
/*! \brief When CDS/CDNSKEY published, look for matching DS */
int event_parent_ds_q(conf_t *conf, zone_t *zone);
...@@ -29,7 +29,7 @@ int event_key_rollover(conf_t *conf, zone_t *zone) ...@@ -29,7 +29,7 @@ int event_key_rollover(conf_t *conf, zone_t *zone)
return ret; return ret;
} }
ret = knot_dnssec_key_rollover(&kctx, &keys_updated, &next_rollover); ret = knot_dnssec_key_rollover(&kctx, zone, &keys_updated, &next_rollover);
kdnssec_ctx_deinit(&kctx); kdnssec_ctx_deinit(&kctx);
if (next_rollover) { if (next_rollover) {
......
/* Copyright (C) 2017 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
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include "knot/zone/zone.h"
#include "knot/common/log.h"
#include "knot/conf/conf.h"
#include "knot/dnssec/context.h"
#include "knot/dnssec/key-events.h"
#include "knot/dnssec/zone-keys.h"
#include "knot/dnssec/zone-sign.h" // match key and DS rdata
#include "knot/query/layer.h"
#include "knot/query/query.h"
#include "knot/query/requestor.h"
struct ds_query_data {
zone_t *zone;
conf_t *conf;
const struct sockaddr *remote;
zone_key_t *key;
bool ds_ok;
};
static int ds_query_begin(knot_layer_t *layer, void *params)
{
layer->data = params;
return KNOT_STATE_PRODUCE;
}
static int ds_query_produce(knot_layer_t *layer, knot_pkt_t *pkt)
{
struct ds_query_data *data = layer->data;
query_init_pkt(pkt);
int r = knot_pkt_put_question(pkt, data->zone->name, KNOT_CLASS_IN, KNOT_RRTYPE_DS);
if (r != KNOT_EOK) {
return KNOT_STATE_FAIL;
}
return KNOT_STATE_CONSUME;
}
static int ds_query_consume(knot_layer_t *layer, knot_pkt_t *pkt)
{
struct ds_query_data *data = layer->data;
if (knot_pkt_ext_rcode(pkt) != KNOT_RCODE_NOERROR) {
ns_log(LOG_WARNING, data->zone->name, LOG_OPERATION_PARENT,
LOG_DIRECTION_OUT, data->remote, "failed (%s)", knot_pkt_ext_rcode_name(pkt));
return KNOT_STATE_FAIL;
}
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
bool match = false;
for (size_t j = 0; j < answer->count; j++) {
const knot_rrset_t *rr = knot_pkt_rr(answer, j);
if (!rr || rr->type != KNOT_RRTYPE_DS || rr->rrs.rr_count != 1) {
ns_log(LOG_WARNING, data->zone->name, LOG_OPERATION_PARENT,
LOG_DIRECTION_OUT, data->remote, "malformed message");
return KNOT_STATE_FAIL;
}
if (knot_match_key_ds(data->key, knot_rdataset_at(&rr->rrs, 0))) {
match = true;
break;
}
}
ns_log(LOG_INFO, data->zone->name, LOG_OPERATION_PARENT,
LOG_DIRECTION_OUT, data->remote, "KSK submittion attempt: %s",
(match ? "positive" : "negative"));
if (match) data->ds_ok = true;
return KNOT_STATE_DONE;
}
static const knot_layer_api_t ds_query_api = {
.begin = ds_query_begin,
.produce = ds_query_produce,
.consume = ds_query_consume,
.reset = NULL,
.finish = NULL,
};
static int try_ds(conf_t *conf, zone_t *zone, const conf_remote_t *parent, zone_key_t *key)
{
// TODO: Abstract interface to issue DNS queries. This is almost copy-pasted.
assert(zone);
assert(parent);
struct ds_query_data data = {
.zone = zone,
.conf = conf,
.remote = (struct sockaddr *)&parent->addr,
.key = key,
.ds_ok = false,
};
struct knot_requestor requestor;
knot_requestor_init(&requestor, &ds_query_api, &data, NULL);
knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, NULL);
if (!pkt) {
knot_requestor_clear(&requestor);
return KNOT_ENOMEM;
}
const struct sockaddr *dst = (struct sockaddr *)&parent->addr;
const struct sockaddr *src = (struct sockaddr *)&parent->via;
struct knot_request *req = knot_request_make(NULL, dst, src, pkt, &parent->key, 0);
if (!req) {
knot_request_free(req, NULL);
knot_requestor_clear(&requestor);
return KNOT_ENOMEM;
}
int timeout = conf->cache.srv_tcp_reply_timeout * 1000;
int ret = knot_requestor_exec(&requestor, req, timeout);
knot_request_free(req, NULL);
knot_requestor_clear(&requestor);
// alternative: we could put answer back through ctx instead of errcode
if (ret == KNOT_EOK && !data.ds_ok) {
ret = KNOT_ENORECORD;
}
return ret;
}
static bool parents_have_ds(zone_t *zone, conf_t *conf, zone_key_t *key) {
conf_val_t policy = conf_zone_get(conf, C_DNSSEC_POLICY, zone->name);
uint8_t *policy_name = (uint8_t *)conf_str(&policy);
size_t policy_name_len = strlen((const char *)policy_name) + 1;
conf_val_t parents = conf_rawid_get(conf, C_POLICY, C_KSK_SUBMITTION_CHECK,
policy_name, policy_name_len);
bool success = false;
while (parents.code == KNOT_EOK) {
success = false;
conf_val_t addr = conf_id_get(conf, C_RMT, C_ADDR, &parents);
size_t addr_count = conf_val_count(&addr);
for (size_t i = 0; i < addr_count; i++) {
conf_remote_t parent = conf_remote(conf, &parents, i);
int ret = try_ds(conf, zone, &parent, key);
if (ret == KNOT_EOK) {
success = true;
break;
}
}
if (!success) {
// TODO dnssec warning, or not ?
}
conf_val_next(&parents);
}
return success;
}
int event_parent_ds_q(conf_t *conf, zone_t *zone)
{
conf_val_t policy = conf_zone_get(conf, C_DNSSEC_POLICY, zone->name);
kdnssec_ctx_t ctx = { 0 };
int ret = kdnssec_ctx_init(&ctx, zone->name, &policy);
if (ret != KNOT_EOK) {
return ret;
}
zone_keyset_t keyset = { 0 };
ret = load_zone_keys(ctx.zone, ctx.keystore, false, ctx.now, &keyset);
if (ret != KNOT_EOK) {
return ret;
}
for (size_t i = 0; i < keyset.count; i++) {
zone_key_t *key = &keyset.keys[i];
if (dnssec_key_get_flags(key->key) == DNSKEY_FLAGS_KSK &&
key->is_ready && !key->is_active) {
if (parents_have_ds(zone, conf, key)) {
ret = knot_dnssec_ksk_submittion_confirm(&ctx, dnssec_key_get_keytag(key->key)); // TODO get rid of keytag
} else {
ret = KNOT_ENOENT;
}
}
}
if (ret != KNOT_EOK) {
uint8_t *policy_name = (uint8_t *)conf_str(&policy);
size_t policy_name_len = strlen((const char *)policy_name) + 1;
conf_val_t check_interval = conf_rawid_get(conf, C_POLICY, C_KSK_SUBMITTION_CHECK_INTERVAL,
policy_name, policy_name_len);
time_t next_check = time(NULL) + conf_int(&check_interval);
zone_events_schedule_at(zone, ZONE_EVENT_PARENT_DS_Q, next_check);
} else {
zone_events_schedule_now(zone, ZONE_EVENT_DNSSEC);
}
free_zone_keys(&keyset);
kdnssec_ctx_deinit(&ctx);
return KNOT_EOK; // allways ok, if failure it has been rescheduled
}
...@@ -453,7 +453,7 @@ static int get_online_key(dnssec_key_t **key_ptr, knotd_mod_t *mod) ...@@ -453,7 +453,7 @@ static int get_online_key(dnssec_key_t **key_ptr, knotd_mod_t *mod)
bool ignore1 = false; bool ignore1 = false;
time_t ignore2 = 0; time_t ignore2 = 0;
r = knot_dnssec_key_rollover(&kctx, &ignore1, &ignore2); r = knot_dnssec_key_rollover(&kctx, NULL, &ignore1, &ignore2);
if (r != DNSSEC_EOK) { if (r != DNSSEC_EOK) {
goto fail; goto fail;
} }
......
...@@ -26,6 +26,7 @@ enum log_operation { ...@@ -26,6 +26,7 @@ enum log_operation {
LOG_OPERATION_NOTIFY, LOG_OPERATION_NOTIFY,
LOG_OPERATION_REFRESH, LOG_OPERATION_REFRESH,
LOG_OPERATION_UPDATE, LOG_OPERATION_UPDATE,
LOG_OPERATION_PARENT,
}; };
enum log_direction { enum log_direction {
...@@ -46,6 +47,8 @@ static inline const char *log_operation_name(enum log_operation operation) ...@@ -46,6 +47,8 @@ static inline const char *log_operation_name(enum log_operation operation)
return "refresh"; return "refresh";
case LOG_OPERATION_UPDATE: case LOG_OPERATION_UPDATE:
return "DDNS"; return "DDNS";
case LOG_OPERATION_PARENT:
return "parent DS check";
default: default:
return "?"; return "?";
} }
......
...@@ -244,7 +244,12 @@ int zone_load_post(conf_t *conf, zone_t *zone, zone_contents_t *contents, ...@@ -244,7 +244,12 @@ int zone_load_post(conf_t *conf, zone_t *zone, zone_contents_t *contents,
} }
ignore1 = false; ignore2 = 0; ignore1 = false; ignore2 = 0;
ret = knot_dnssec_key_rollover(&kctx, &ignore1, &ignore2); ret = knot_dnssec_key_rollover(&kctx, zone, &ignore1, &ignore2);
if (zone_has_key_submittion(&kctx)) {
zone_events_schedule_now(zone, ZONE_EVENT_PARENT_DS_Q);
}
kdnssec_ctx_deinit(&kctx); kdnssec_ctx_deinit(&kctx);
if (ret != KNOT_EOK) { if (ret != KNOT_EOK) {
changeset_clear(&change); changeset_clear(&change);
......
$ORIGIN com.
$TTL 1200
@ SOA ns admin 20110100 7 7 16 600
ns AAAA ::0
$ORIGIN com.
$TTL 1200
@ SOA ns admin 20110101 25 25 80 600
ns AAAA ::0
example.com. 3600 DS 48031 7 2 19C30FF016E701DB8D9A600EEF5F29F3B5B5197AE78648AA8ED5308E341A7FFD
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAsDQulN1onk4XnGGF
LhWmRudSBpBty4XbOyFBikeE9N3S1MMqzszuMbOeiXXdVwIcPgmDl5N1t3ClBJJg
SH++JQIDAQABAkAVegbDdkkuIm6WTPyipVjjA4bn7eq0B9i02FTYuebmwX7xg9rr
jcMRXEaA6yGqP62mvVWBNx91yaUvRji3RNqBAiEAxrljK01EgXdgE49l9SdV78Mf
A2e6con84vgbMb9B7S0CIQDi/Sj9WH1Q8DAqibaaM3mrUCHfOVBWeS2rdRbo4UJf
2QIhAI6PmkQLN1UFdYgyvDsF0BGj0dDYjhnzQdb1lFS41yu1AiEAtC0JvVfhWT7e
rNVVeb9EY8Sermb7KzjTFJdD0SUFH7kCIGvczpFwGty6p3MPatS2vc7A8Z8gvAe3
tE5uJQObc+Z+
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAomNuj0gH5HYjdC0r
7i0mxtBp5rr9dzPPSUwS72ZCFPsq3b8sdfAh2cZsvGQgkYCPPZV0Zx+kUP3WyGFy
9xqiCQIDAQABAkA6KMKALpwlBurLwSHqu+EXc616JZ6CAtxKtCRT+ZvRR1GWcEJ6
O8TeIU4YjWK7N8CQcgmeCX5bKbAW/DxUdksBAiEAy3xujDpOidIhBbYwq/E6a3/Q
EnQ/FGfq6cw3hWI/4k0CIQDMS9ShKl/QouORUlW1zCKWIK/7sAHuncYx6E9pH7uE
rQIgRzrGg8XBSlNJBfPRs86ccZbrIhqZHi6GN9MpuEI9NJ0CIQCgNjuqpDN9x7AV
L+99YXgiKcI46/+n5F0gmGFmPHdvBQIgEQcjUUtC1+qDOlulSjvheIi/Al5c9SRs
AXhDSTXtN3A=
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAu9eosHX/Ag8J0r71
lT9tzQeWbEZRAOZY8w+zC4hqTvtAZeE9SsB+ppoNM8bvdaxLVQNIIKKqOxsteOZY
xMFicQIDAQABAkEAtXq84oeNsRqAXhjaQbB/T8gV31PsLNdfdq1jSTAprVVOmHSk
CfKq30FOdIXnlLum2kypxejpdHGocI1rqZLzBQIhAOoPNuh/k3NeEau2VZt9dENN
JL4ByVpMG2gMjiucHl57AiEAzXNc16CmvEfQ/i3JhEhbb1I8o7QGsOk9v8MP/DEz
pQMCIF8EcCjwaX6DKK9JpPUrd8A+l/TeqswSa2nQ9wIzLYzzAiEAzBl4+DV+rrjh
pEE0WpfPTe3yk+Z6ZzGuyFwt+ymd1qUCIBzE561e4uE5tyPB46ybM/029/GFa89z
0D1ZBKVF7AWi
-----END PRIVATE KEY-----
-----BEGIN PRIVATE KEY-----
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEA0u57CJSNnnkVPSqx
tX+LqlnAEkroE+zadaZACE/AvYh2sKP+ktZxOphEN5wNXjI+zsfQTyyKazcHaZOT
XFlSIQIDAQABAkAYjdRaqlhWA0hap3aqZx+OBAac2oVrlF3V5jV8AjSwm1T4gbDq
iV+ARxIgqP6bAVa+rVC1hUQVAjRGI6fioSgBAiEA3zFS9A6salJdprW4Hxoudn5Q
oEidH2+tVaFmtmgW5sECIQDx78ZOQi7bmQz/s6Zp0cqcdLRHyfVojqwL5vtvHX+j
YQIgPk/uAfdqyZBPVzDaw8wydqCTb/x16YXrVcHnBDwRUMECIQDesivie08wedga
Qp5Kx35tt4r+jarkfHdnWU1VwVxs4QIhAJnSVxhAiKBW+RXuW+sW8NTVvCSjOp8y
uEK+Tq88J7qx
-----END PRIVATE KEY-----
#!/usr/bin/env python3
"""
Check if keytag conflict is correctly handled by Knot.
"""
import collections
import os
import shutil
import datetime
import subprocess
from subprocess import check_call
from dnstest.utils import *
from dnstest.keys import Keymgr
from dnstest.test import Test
# check zone if keys are present and used for signing
def check_zone5(server, min_dnskeys, min_rrsigs, min_cdnskeys, msg):
dnskeys = server.dig("example.com", "DNSKEY")
found_dnskeys = dnskeys.count("DNSKEY")
soa = server.dig("example.com", "DNSKEY", dnssec=True)
found_rrsigs = soa.count("RRSIG")
cdnskey = server.dig("example.com", "CDNSKEY")
found_cdnskeys = cdnskey.count("CDNSKEY")
check_log("RRSIGs: %d (expected %d)" % (found_rrsigs, min_rrsigs));
check_log("DNSKEYs: %d (expected %d)" % (found_dnskeys, min_dnskeys));
check_log("CDNSKEYs: %d (expected %d)" % (found_cdnskeys, min_cdnskeys));
if found_rrsigs != min_rrsigs:
set_err("BAD RRSIG COUNT: " + msg)
detail_log("!RRSIGs not published and activated as expected: " + msg)
if found_dnskeys != min_dnskeys:
set_err("BAD DNSKEY COUNT: " + msg)
detail_log("!DNSKEYs not published and activated as expected: " + msg)
if found_cdnskeys != min_cdnskeys:
set_err("BAD CDNSKEY COUNT: " + msg)
detail_log("!CDNSKEYs not published and activated as expected: " + msg)
detail_log(SEP)
t = Test()
parent = t.server("knot")
parent_zone = t.zone("com.", storage=".")
t.link(parent_zone, parent)
child = t.server("knot")
child_zone = t.zone("example.com.")
t.link(child_zone, child)
child.dnssec(child_zone).enable = True
child.dnssec(child_zone).manual = False
child.dnssec(child_zone).zsk_lifetime = 99999
child.dnssec(child_zone).ksk_lifetime = 300 # this can be possibly left also infinity
child.dnssec(child_zone).propagation_delay = 17
child.dnssec(child_zone).ksk_submittion_check = [ parent ]
child.dnssec(child_zone).ksk_submittion_check_interval = 2
# install KASP db (one always enabled, one for testing)
shutil.copytree(os.path.join(t.data_dir, "keys"), child.keydir)
# parameters
ZONE = "example.com."
KSK1 = "7a3500c7feac3fd99f09a208a83b97f7455fa3e0"
KSK2 = "7e7492f7dcaf4d819a29eb30ad80c04f830d76cf"
ZSK1 = "6abddc73bcb46c4e6078cf764290ac315fff03f0"
ZSK2 = "301d3fc5392e83ea02312dc5bdc1a9f0b7937ddf"
t.rel_sleep(0)
# note that some of these paraneters will be immediately or later modified by automated key management
child.key_set(ZONE, KSK1, publish="t-2y", ready="t-1y", active="t-1y", retire="t+10y", remove="t+20y")
# KSK1's retire and remove shall be reconfigured by Knot to soon as KSK2 takes place
child.key_set(ZONE, KSK2, publish="t+0", ready="t+1h", active="t+10y", retire="t+11y", remove="t+12y")
child.key_set(ZONE, ZSK1, publish="t-20", ready="t-10", active="t-10", retire="t+15y", remove="t+20y")
# ZSK1 simply valid for all the time
child.key_set(ZONE, ZSK2, publish="t-2", ready="t+14y", active="t+14y", retire="t+31y", remove="t+36y")
# ZSK2 only reason: prevents Knot from publishing another ZSK
t.start()
child.zone_wait(child_zone)