Implement SKR import

When 'rndc skr import' is called, read the file contents and store the
data in the zone's skr structure.

(cherry picked from commit 037382c4a5)
This commit is contained in:
Matthijs Mekking
2024-08-22 10:17:08 +00:00
parent 27fd4e5687
commit f516e461fd
5 changed files with 358 additions and 39 deletions
+9 -2
View File
@@ -16751,8 +16751,15 @@ named_server_skr(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
goto cleanup;
}
CHECK(putstr(text, "import command not implemented"));
CHECK(putnull(text));
result = dns_zone_import_skr(zone, skrfile);
if (result != ISC_R_SUCCESS) {
CHECK(putstr(text, "import failed: "));
CHECK(putstr(text, isc_result_totext(result)));
CHECK(putnull(text));
} else {
/* Schedule a rekey */
dns_zone_rekey(zone, false);
}
cleanup:
if (zone != NULL) {
+6 -25
View File
@@ -54,26 +54,6 @@ struct dns_skrbundle {
ISC_LINK(dns_skrbundle_t) link;
};
void
dns_skrbundle_create(isc_mem_t *mctx, dns_name_t *name,
dns_rdataclass_t rdclass, isc_stdtime_t inception,
dns_skrbundle_t **bp);
/*%<
* Create a single bundle.
*
* Requires:
* \li *bp != NULL && *bp == NULL
*/
void
dns_skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple);
/*%<
* Add a single tuple to a key bundle.
*
* \li 'bundle' is a valid bundle
* \li '*tuple' is a valid tuple
*/
isc_result_t
dns_skrbundle_getsig(dns_skrbundle_t *bundle, dst_key_t *key,
dns_rdatatype_t covering_type, dns_rdata_t *sigrdata);
@@ -101,14 +81,15 @@ dns_skr_create(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
* \li *skrp != NULL && *skrp == NULL
*/
void
dns_skr_addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep);
isc_result_t
dns_skr_read(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
dns_rdataclass_t rdclass, dns_ttl_t dnskeyttl, dns_skr_t **skrp);
/*%<
* Add a single bundle to a SKR.
* Read a SKR from 'filename'.
*
* Requires:
* \li 'skr' is a valid SKR
* \li 'bundle' is a valid bundle
* \li mctx != NULL
* \li *skrp != NULL && *skrp == NULL
*/
dns_skrbundle_t *
+14
View File
@@ -34,6 +34,7 @@
#include <dns/masterdump.h>
#include <dns/rdatastruct.h>
#include <dns/rpz.h>
#include <dns/skr.h>
#include <dns/types.h>
#include <dns/xfrin.h>
#include <dns/zt.h>
@@ -2750,6 +2751,19 @@ dns_zone_check_dnskey_nsec3(dns_zone_t *zone, dns_db_t *db,
* 'false' if the zone would have NSEC only DNSKEYs and an NSEC3 chain.
*/
isc_result_t
dns_zone_import_skr(dns_zone_t *zone, const char *file);
/**<
* Import a Signed Key Response (SKR) from file.
*
* Requires:
* \li 'zone' to be a valid zone.
* \li 'file' is not NULL.
*
* Returns:
* \li ISC_R_SUCCESS if there were no errors loading the SKR.
*/
#if DNS_ZONE_TRACE
#define dns_zone_ref(ptr) dns_zone__ref(ptr, __func__, __FILE__, __LINE__)
#define dns_zone_unref(ptr) dns_zone__unref(ptr, __func__, __FILE__, __LINE__)
+279 -12
View File
@@ -13,19 +13,132 @@
/*! \file */
#include <dns/skr.h>
#include <isc/lex.h>
#include <isc/log.h>
void
dns_skrbundle_create(isc_mem_t *mctx, dns_name_t *name,
dns_rdataclass_t rdclass, isc_stdtime_t inception,
dns_skrbundle_t **bp) {
#include <dns/callbacks.h>
#include <dns/fixedname.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdatatype.h>
#include <dns/skr.h>
#include <dns/time.h>
#include <dns/ttl.h>
#define CHECK(op) \
do { \
result = (op); \
if (result != ISC_R_SUCCESS) \
goto failure; \
} while (0)
#define READLINE(lex, opt, token)
#define NEXTTOKEN(lex, opt, token) \
{ \
ret = isc_lex_gettoken(lex, opt, token); \
if (ret != ISC_R_SUCCESS) \
goto cleanup; \
}
#define BADTOKEN() \
{ \
ret = ISC_R_UNEXPECTEDTOKEN; \
goto cleanup; \
}
#define TOKENSIZ (8 * 1024)
#define STR(t) ((t).value.as_textregion.base)
static isc_result_t
parse_rr(isc_lex_t *lex, isc_mem_t *mctx, char *owner, dns_name_t *origin,
dns_rdataclass_t rdclass, isc_buffer_t *buf, dns_ttl_t *ttl,
dns_rdatatype_t *rdtype, dns_rdata_t **rdata) {
dns_rdatacallbacks_t callbacks;
dns_fixedname_t dfname;
dns_name_t *dname = NULL;
dns_rdataclass_t clas;
isc_buffer_t b;
isc_token_t token;
unsigned int opt = ISC_LEXOPT_EOL;
isc_result_t ret = ISC_R_SUCCESS;
isc_lex_setcomments(lex, ISC_LEXCOMMENT_DNSMASTERFILE);
/* Read the domain name */
if (!strcmp(owner, "@")) {
BADTOKEN();
}
dname = dns_fixedname_initname(&dfname);
isc_buffer_init(&b, owner, strlen(owner));
isc_buffer_add(&b, strlen(owner));
ret = dns_name_fromtext(dname, &b, dns_rootname, 0, NULL);
if (ret != ISC_R_SUCCESS) {
return (ret);
}
if (dns_name_compare(dname, origin) != 0) {
return (DNS_R_BADOWNERNAME);
}
isc_buffer_clear(&b);
/* Read the next word: either TTL, class, or type */
NEXTTOKEN(lex, opt, &token);
if (token.type != isc_tokentype_string) {
BADTOKEN();
}
/* If it's a TTL, read the next one */
ret = dns_ttl_fromtext(&token.value.as_textregion, ttl);
if (ret == ISC_R_SUCCESS) {
NEXTTOKEN(lex, opt, &token);
}
if (token.type != isc_tokentype_string) {
BADTOKEN();
}
/* If it's a class, read the next one */
ret = dns_rdataclass_fromtext(&clas, &token.value.as_textregion);
if (ret == ISC_R_SUCCESS) {
if (clas != rdclass) {
BADTOKEN();
}
NEXTTOKEN(lex, opt, &token);
}
if (token.type != isc_tokentype_string) {
BADTOKEN();
}
/* Must be the record type */
ret = dns_rdatatype_fromtext(rdtype, &token.value.as_textregion);
if (ret != ISC_R_SUCCESS) {
BADTOKEN();
}
switch (*rdtype) {
case dns_rdatatype_dnskey:
case dns_rdatatype_cdnskey:
case dns_rdatatype_cds:
case dns_rdatatype_rrsig:
/* Allowed record types */
break;
default:
BADTOKEN();
}
dns_rdatacallbacks_init(&callbacks);
ret = dns_rdata_fromtext(*rdata, rdclass, *rdtype, lex, dname, 0, mctx,
buf, &callbacks);
cleanup:
isc_lex_setcomments(lex, 0);
return (ret);
}
static void
skrbundle_create(isc_mem_t *mctx, isc_stdtime_t inception,
dns_skrbundle_t **bp) {
dns_skrbundle_t *b;
REQUIRE(bp != NULL && *bp == NULL);
UNUSED(name);
UNUSED(rdclass);
b = isc_mem_get(mctx, sizeof(*b));
b->magic = DNS_SKRBUNDLE_MAGIC;
b->inception = inception;
@@ -36,8 +149,8 @@ dns_skrbundle_create(isc_mem_t *mctx, dns_name_t *name,
*bp = b;
}
void
dns_skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple) {
static void
skrbundle_addtuple(dns_skrbundle_t *bundle, dns_difftuple_t **tuple) {
REQUIRE(DNS_DIFFTUPLE_VALID(*tuple));
REQUIRE(DNS_SKRBUNDLE_VALID(bundle));
REQUIRE(DNS_DIFF_VALID(&bundle->diff));
@@ -116,8 +229,8 @@ dns_skr_create(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
*skrp = skr;
}
void
dns_skr_addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep) {
static void
addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep) {
REQUIRE(DNS_SKR_VALID(skr));
REQUIRE(DNS_SKRBUNDLE_VALID(*bundlep));
@@ -125,6 +238,160 @@ dns_skr_addbundle(dns_skr_t *skr, dns_skrbundle_t **bundlep) {
*bundlep = NULL;
}
isc_result_t
dns_skr_read(isc_mem_t *mctx, const char *filename, dns_name_t *origin,
dns_rdataclass_t rdclass, dns_ttl_t dnskeyttl, dns_skr_t **skrp) {
isc_result_t result;
dns_skrbundle_t *bundle = NULL;
char bundlebuf[1024];
uint32_t bundle_id;
isc_lex_t *lex = NULL;
isc_lexspecials_t specials;
isc_token_t token;
unsigned int opt = ISC_LEXOPT_EOL;
REQUIRE(DNS_SKR_VALID(*skrp));
isc_lex_create(mctx, TOKENSIZ, &lex);
memset(specials, 0, sizeof(specials));
specials['('] = 1;
specials[')'] = 1;
specials['"'] = 1;
isc_lex_setspecials(lex, specials);
result = isc_lex_openfile(lex, filename);
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_ZONE, ISC_LOG_ERROR,
"unable to open ksr file %s: %s", filename,
isc_result_totext(result));
isc_lex_destroy(&lex);
return (result);
}
for (result = isc_lex_gettoken(lex, opt, &token);
result == ISC_R_SUCCESS;
result = isc_lex_gettoken(lex, opt, &token))
{
if (token.type == isc_tokentype_eol) {
continue;
}
if (token.type != isc_tokentype_string) {
CHECK(DNS_R_SYNTAX);
}
if (strcmp(STR(token), ";;") == 0) {
/* New bundle */
CHECK(isc_lex_gettoken(lex, opt, &token));
if (token.type != isc_tokentype_string ||
strcmp(STR(token), "SignedKeyResponse") != 0)
{
CHECK(DNS_R_SYNTAX);
}
/* Version */
CHECK(isc_lex_gettoken(lex, opt, &token));
if (token.type != isc_tokentype_string ||
strcmp(STR(token), "1.0") != 0)
{
CHECK(DNS_R_SYNTAX);
}
/* Date and time of bundle */
CHECK(isc_lex_gettoken(lex, opt, &token));
if (token.type != isc_tokentype_string) {
CHECK(DNS_R_SYNTAX);
}
if (strcmp(STR(token), "generated") == 0) {
/* Final bundle */
goto readline;
}
if (token.type != isc_tokentype_string) {
CHECK(DNS_R_SYNTAX);
}
/* Add previous bundle */
if (bundle != NULL) {
addbundle(*skrp, &bundle);
}
/* Create new bundle */
sscanf(STR(token), "%s", bundlebuf);
CHECK(dns_time32_fromtext(bundlebuf, &bundle_id));
bundle = NULL;
skrbundle_create(mctx, (isc_stdtime_t)bundle_id,
&bundle);
readline:
/* Read remainder of header line */
do {
CHECK(isc_lex_gettoken(lex, opt, &token));
} while (token.type != isc_tokentype_eol);
} else {
isc_buffer_t buf;
dns_rdata_t *rdata = NULL;
u_char rdatabuf[DST_KEY_MAXSIZE];
dns_rdatatype_t rdtype;
/* Parse record */
rdata = isc_mem_get(mctx, sizeof(*rdata));
dns_rdata_init(rdata);
isc_buffer_init(&buf, rdatabuf, sizeof(rdatabuf));
result = parse_rr(lex, mctx, STR(token), origin,
rdclass, &buf, &dnskeyttl, &rdtype,
&rdata);
if (result != ISC_R_SUCCESS) {
isc_log_write(
dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(1),
"read skr file %s(%lu) parse rr "
"failed: %s",
filename, isc_lex_getsourceline(lex),
isc_result_totext(result));
isc_mem_put(mctx, rdata, sizeof(*rdata));
goto failure;
}
/* Create new diff tuple */
dns_diffop_t op = (rdtype == dns_rdatatype_rrsig)
? DNS_DIFFOP_ADDRESIGN
: DNS_DIFFOP_ADD;
dns_difftuple_t *tuple = NULL;
dns_difftuple_create((*skrp)->mctx, op, origin,
dnskeyttl, rdata, &tuple);
skrbundle_addtuple(bundle, &tuple);
INSIST(tuple == NULL);
isc_mem_put(mctx, rdata, sizeof(*rdata));
}
}
if (result != ISC_R_EOF) {
CHECK(DNS_R_SYNTAX);
}
result = ISC_R_SUCCESS;
/* Add final bundle */
if (bundle != NULL) {
addbundle(*skrp, &bundle);
}
failure:
if (result != ISC_R_SUCCESS) {
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_ZONE, ISC_LOG_DEBUG(1),
"read skr file %s(%lu) failed: %s", filename,
isc_lex_getsourceline(lex),
isc_result_totext(result));
}
/* Clean up */
isc_lex_destroy(&lex);
return (result);
}
dns_skrbundle_t *
dns_skr_lookup(dns_skr_t *skr, isc_stdtime_t time, uint32_t sigval) {
dns_skrbundle_t *b, *next;
+50
View File
@@ -79,11 +79,13 @@
#include <dns/request.h>
#include <dns/resolver.h>
#include <dns/rriterator.h>
#include <dns/skr.h>
#include <dns/soa.h>
#include <dns/ssu.h>
#include <dns/stats.h>
#include <dns/time.h>
#include <dns/tsig.h>
#include <dns/ttl.h>
#include <dns/update.h>
#include <dns/xfrin.h>
#include <dns/zone.h>
@@ -499,6 +501,12 @@ struct dns_zone {
dns_update_state_t *rss_state;
isc_stats_t *gluecachestats;
/*%
* Offline KSK signed key responses.
*/
dns_skr_t *skr;
dns_skrbundle_t *skrbundle;
};
#define zonediff_init(z, d) \
@@ -1273,6 +1281,10 @@ zone_free(dns_zone_t *zone) {
if (!ISC_LIST_EMPTY(zone->checkds_ok)) {
clear_keylist(&zone->checkds_ok, zone->mctx);
}
if (zone->skr != NULL) {
zone->skrbundle = NULL;
dns_skr_detach(&zone->skr);
}
zone->journalsize = -1;
if (zone->journal != NULL) {
@@ -5734,6 +5746,21 @@ dns_zone_getkasp(dns_zone_t *zone) {
return (kasp);
}
static void
dns_zone_setskr(dns_zone_t *zone, dns_skr_t *skr) {
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
zone->skrbundle = NULL;
if (zone->skr != NULL) {
dns_skr_detach(&zone->skr);
}
if (skr != NULL) {
dns_skr_attach(skr, &zone->skr);
}
UNLOCK_ZONE(zone);
}
void
dns_zone_setoption(dns_zone_t *zone, dns_zoneopt_t option, bool value) {
REQUIRE(DNS_ZONE_VALID(zone));
@@ -24229,3 +24256,26 @@ dns_zone_makedb(dns_zone_t *zone, dns_db_t **dbp) {
return (ISC_R_SUCCESS);
}
isc_result_t
dns_zone_import_skr(dns_zone_t *zone, const char *file) {
dns_skr_t *skr = NULL;
isc_result_t result;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(zone->kasp != NULL);
REQUIRE(file != NULL);
dns_skr_create(zone->mctx, file, &zone->origin, zone->rdclass, &skr);
CHECK(dns_skr_read(zone->mctx, file, &zone->origin, zone->rdclass,
dns_kasp_dnskeyttl(zone->kasp), &skr));
dns_zone_setskr(zone, skr);
dnssec_log(zone, ISC_LOG_DEBUG(1), "imported skr file %s", file);
failure:
dns_skr_detach(&skr);
return (result);
}