diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c index d7d28aace6..f36f087fd0 100644 --- a/lib/dns/dst_api.c +++ b/lib/dns/dst_api.c @@ -469,6 +469,16 @@ dst_key_isexternal(dst_key_t *key) { return (key->external); } +void +dst_key_setmodified(dst_key_t *key, bool value) { + key->modified = value; +} + +bool +dst_key_ismodified(dst_key_t *key) { + return (key->modified); +} + isc_result_t dst_key_getfilename(dns_name_t *name, dns_keytag_t id, unsigned int alg, int type, const char *directory, isc_mem_t *mctx, @@ -610,6 +620,7 @@ dst_key_fromnamedfile(const char *filename, const char *dirname, int type, (pubkey->key_flags & DNS_KEYFLAG_TYPEMASK) == DNS_KEYTYPE_NOKEY) { RETERR(computeid(pubkey)); + pubkey->modified = false; *keyp = pubkey; pubkey = NULL; goto out; @@ -663,6 +674,7 @@ dst_key_fromnamedfile(const char *filename, const char *dirname, int type, RETERR(DST_R_INVALIDPRIVATEKEY); } + key->modified = false; *keyp = key; key = NULL; @@ -1016,6 +1028,8 @@ dst_key_setbool(dst_key_t *key, int type, bool value) { REQUIRE(type <= DST_MAX_BOOLEAN); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || !key->boolset[type] || + key->bools[type] != value; key->bools[type] = value; key->boolset[type] = true; isc_mutex_unlock(&key->mdlock); @@ -1027,6 +1041,7 @@ dst_key_unsetbool(dst_key_t *key, int type) { REQUIRE(type <= DST_MAX_BOOLEAN); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || key->boolset[type]; key->boolset[type] = false; isc_mutex_unlock(&key->mdlock); } @@ -1054,6 +1069,8 @@ dst_key_setnum(dst_key_t *key, int type, uint32_t value) { REQUIRE(type <= DST_MAX_NUMERIC); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || !key->numset[type] || + key->nums[type] != value; key->nums[type] = value; key->numset[type] = true; isc_mutex_unlock(&key->mdlock); @@ -1065,6 +1082,7 @@ dst_key_unsetnum(dst_key_t *key, int type) { REQUIRE(type <= DST_MAX_NUMERIC); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || key->numset[type]; key->numset[type] = false; isc_mutex_unlock(&key->mdlock); } @@ -1091,6 +1109,8 @@ dst_key_settime(dst_key_t *key, int type, isc_stdtime_t when) { REQUIRE(type <= DST_MAX_TIMES); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || !key->timeset[type] || + key->times[type] != when; key->times[type] = when; key->timeset[type] = true; isc_mutex_unlock(&key->mdlock); @@ -1102,6 +1122,7 @@ dst_key_unsettime(dst_key_t *key, int type) { REQUIRE(type <= DST_MAX_TIMES); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || key->timeset[type]; key->timeset[type] = false; isc_mutex_unlock(&key->mdlock); } @@ -1129,6 +1150,8 @@ dst_key_setstate(dst_key_t *key, int type, dst_key_state_t state) { REQUIRE(type <= DST_MAX_KEYSTATES); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || !key->keystateset[type] || + key->keystates[type] != state; key->keystates[type] = state; key->keystateset[type] = true; isc_mutex_unlock(&key->mdlock); @@ -1140,6 +1163,7 @@ dst_key_unsetstate(dst_key_t *key, int type) { REQUIRE(type <= DST_MAX_KEYSTATES); isc_mutex_lock(&key->mdlock); + key->modified = key->modified || key->keystateset[type]; key->keystateset[type] = false; isc_mutex_unlock(&key->mdlock); } @@ -2704,4 +2728,6 @@ dst_key_copy_metadata(dst_key_t *to, dst_key_t *from) { dst_key_unsetstate(to, i); } } + + dst_key_setmodified(to, dst_key_ismodified(from)); } diff --git a/lib/dns/dst_internal.h b/lib/dns/dst_internal.h index 9a0b3ac905..9f5e8ee3b6 100644 --- a/lib/dns/dst_internal.h +++ b/lib/dns/dst_internal.h @@ -122,6 +122,7 @@ struct dst_key { bool inactive; /*%< private key not present as it is * inactive */ bool external; /*%< external key */ + bool modified; /*%< set to true if key file metadata has changed */ int fmt_major; /*%< private key format, major version * */ diff --git a/lib/dns/include/dst/dst.h b/lib/dns/include/dst/dst.h index c53a1adccf..8fe32ab15c 100644 --- a/lib/dns/include/dst/dst.h +++ b/lib/dns/include/dst/dst.h @@ -1106,6 +1106,26 @@ dst_key_isexternal(dst_key_t *key); * 'key' to be valid. */ +void +dst_key_setmodified(dst_key_t *key, bool value); +/*%< + * If 'value' is true, this marks the key to indicate that key file metadata + * has been modified. If 'value' is false, this resets the value, for example + * after you have written the key to file. + * + * Requires: + * 'key' to be valid. + */ + +bool +dst_key_ismodified(dst_key_t *key); +/*%< + * Check if the key file has been modified. + * + * Requires: + * 'key' to be valid. + */ + bool dst_key_haskasp(dst_key_t *key); /*%< diff --git a/lib/dns/keymgr.c b/lib/dns/keymgr.c index 660b8cd26f..4d9ccfbd9e 100644 --- a/lib/dns/keymgr.c +++ b/lib/dns/keymgr.c @@ -1511,6 +1511,7 @@ transition: /* It is safe to make the transition. */ dst_key_setstate(dkey->key, i, next_state); dst_key_settime(dkey->key, keystatetimes[i], now); + INSIST(dst_key_ismodified(dkey->key)); changed = true; } } @@ -2179,9 +2180,10 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass, for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL; dkey = ISC_LIST_NEXT(dkey, link)) { - if (!dkey->purge) { + if (dst_key_ismodified(dkey->key) && !dkey->purge) { dns_dnssec_get_hints(dkey, now); RETERR(dst_key_tofile(dkey->key, options, directory)); + dst_key_setmodified(dkey->key, false); } } @@ -2201,6 +2203,13 @@ failure: } } + if (isc_log_wouldlog(dns_lctx, ISC_LOG_DEBUG(3))) { + char namebuf[DNS_NAME_FORMATSIZE]; + dns_name_format(origin, namebuf, sizeof(namebuf)); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC, + DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(3), + "keymgr: %s done", namebuf); + } return (result); } @@ -2278,6 +2287,9 @@ keymgr_checkds(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, dns_dnssec_get_hints(ksk_key, now); result = dst_key_tofile(ksk_key->key, options, directory); + if (result == ISC_R_SUCCESS) { + dst_key_setmodified(ksk_key->key, false); + } isc_dir_close(&dir); return (result); @@ -2578,6 +2590,9 @@ dns_keymgr_rollover(dns_kasp_t *kasp, dns_dnsseckeylist_t *keyring, dns_dnssec_get_hints(key, now); result = dst_key_tofile(key->key, options, directory); + if (result == ISC_R_SUCCESS) { + dst_key_setmodified(key->key, false); + } isc_dir_close(&dir); return (result);