From 6b2fd40269a69044ecc13e063fca3eae04be36d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Witold=20Kr=C4=99cicki?= Date: Wed, 9 Oct 2019 17:38:44 +0200 Subject: [PATCH] Jitter signatures times when adding dynamic records. When doing regular signing expiry time is jittered to make sure that the re-signing times are not clumped together. This expands this behaviour to expiry times of dynamically added records. When incrementally re-signing a zone use the full jitter range if the server appears to have been offline for greater than 5 minutes otherwise use a small jitter range of 3600 seconds. This will stop the signatures becoming more clustered if the server has been off line for a significant period of time (> 5 minutes). --- lib/dns/update.c | 22 +++++++++++++++++++++- lib/dns/zone.c | 48 ++++++++++++++++++++++++++++++++++++++---------- lib/ns/update.c | 6 +++--- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/lib/dns/update.c b/lib/dns/update.c index 48aa23b30d..25827d4b54 100644 --- a/lib/dns/update.c +++ b/lib/dns/update.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -1389,6 +1390,25 @@ struct dns_update_state { sign_nsec, update_nsec3, process_nsec3, sign_nsec3 } state; }; +static uint32_t +dns__jitter_expire(dns_zone_t *zone, uint32_t sigvalidityinterval) { + /* Spread out signatures over time */ + if (sigvalidityinterval >= 3600U) { + uint32_t expiryinterval = dns_zone_getsigresigninginterval(zone); + + if (sigvalidityinterval < 7200U) { + expiryinterval = 1200; + } else if (expiryinterval > sigvalidityinterval) { + expiryinterval = sigvalidityinterval; + } else { + expiryinterval = sigvalidityinterval - expiryinterval; + } + uint32_t jitter = isc_random_uniform(expiryinterval); + sigvalidityinterval -= jitter; + } + return (sigvalidityinterval); +} + isc_result_t dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *oldver, dns_dbversion_t *newver, @@ -1440,7 +1460,7 @@ dns_update_signaturesinc(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db, isc_stdtime_get(&now); state->inception = now - 3600; /* Allow for some clock skew. */ - state->expire = now + sigvalidityinterval; + state->expire = now + dns__jitter_expire(zone, sigvalidityinterval); state->keyexpire = dns_zone_getkeyvalidityinterval(zone); if (state->keyexpire == 0) { state->keyexpire = state->expire; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index cea7c31ec4..6d54179557 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -6613,8 +6613,8 @@ zone_resigninc(dns_zone_t *zone) { dst_key_t *zone_keys[DNS_MAXZONEKEYS]; bool check_ksk, keyset_kskonly = false; isc_result_t result; - isc_stdtime_t now, inception, soaexpire, expire, stop; - uint32_t jitter, sigvalidityinterval; + isc_stdtime_t now, inception, soaexpire, expire, fullexpire, stop; + uint32_t sigvalidityinterval, expiryinterval; unsigned int i; unsigned int nkeys = 0; unsigned int resign; @@ -6662,20 +6662,34 @@ zone_resigninc(dns_zone_t *zone) { sigvalidityinterval = zone->sigvalidityinterval; inception = now - 3600; /* Allow for clock skew. */ soaexpire = now + sigvalidityinterval; + expiryinterval = dns_zone_getsigresigninginterval(zone); + if (expiryinterval > sigvalidityinterval) { + expiryinterval = sigvalidityinterval; + } else { + expiryinterval = sigvalidityinterval - expiryinterval; + } + /* * Spread out signatures over time if they happen to be * clumped. We don't do this for each add_sigs() call as - * we still want some clustering to occur. + * we still want some clustering to occur. In normal operations + * the records should be re-signed as they fall due and they should + * already be spread out. However if the server is off for a + * period we need to ensure that the clusters don't become + * synchronised by using the full jitter range. */ if (sigvalidityinterval >= 3600U) { + uint32_t normaljitter, fulljitter; if (sigvalidityinterval > 7200U) { - jitter = isc_random_uniform(3600); + normaljitter = isc_random_uniform(3600); + fulljitter = isc_random_uniform(expiryinterval); } else { - jitter = isc_random_uniform(1200); + normaljitter = fulljitter = isc_random_uniform(1200); } - expire = soaexpire - jitter - 1; + expire = soaexpire - normaljitter - 1; + fullexpire = soaexpire - fulljitter - 1; } else { - expire = soaexpire - 1; + expire = fullexpire = soaexpire - 1; } stop = now + 5; @@ -6715,9 +6729,17 @@ zone_resigninc(dns_zone_t *zone) { break; } + /* + * If re-signing is over 5 minutes late use 'fullexpire' + * to redistribute the signature over the complete + * re-signing window, otherwise only add a small amount + * of jitter. + */ result = add_sigs(db, version, name, zone, covers, zonediff.diff, zone_keys, nkeys, zone->mctx, - inception, expire, check_ksk, keyset_kskonly); + inception, + resign > (now - 300) ? expire : fullexpire, + check_ksk, keyset_kskonly); if (result != ISC_R_SUCCESS) { dns_zone_log(zone, ISC_LOG_ERROR, "zone_resigninc:add_sigs -> %s", @@ -7677,7 +7699,7 @@ zone_nsec3chain(dns_zone_t *zone) { bool first; isc_result_t result; isc_stdtime_t now, inception, soaexpire, expire; - uint32_t jitter, sigvalidityinterval; + uint32_t jitter, sigvalidityinterval, expiryinterval; unsigned int i; unsigned int nkeys = 0; uint32_t nodes; @@ -7749,6 +7771,12 @@ zone_nsec3chain(dns_zone_t *zone) { sigvalidityinterval = dns_zone_getsigvalidityinterval(zone); inception = now - 3600; /* Allow for clock skew. */ soaexpire = now + sigvalidityinterval; + expiryinterval = dns_zone_getsigresigninginterval(zone); + if (expiryinterval > sigvalidityinterval) { + expiryinterval = sigvalidityinterval; + } else { + expiryinterval = sigvalidityinterval - expiryinterval; + } /* * Spread out signatures over time if they happen to be @@ -7757,7 +7785,7 @@ zone_nsec3chain(dns_zone_t *zone) { */ if (sigvalidityinterval >= 3600U) { if (sigvalidityinterval > 7200U) { - jitter = isc_random_uniform(3600); + jitter = isc_random_uniform(expiryinterval); } else { jitter = isc_random_uniform(1200); } diff --git a/lib/ns/update.c b/lib/ns/update.c index 5cc5c1728d..3baf428bd8 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -3181,14 +3181,14 @@ update_action(isc_task_t *task, isc_event_t *event) { CHECK(dns_nsec3param_deletechains(db, ver, zone, true, &diff)); } else if (has_dnskey && isdnssec(db, ver, privatetype)) { - uint32_t interval; dns_update_log_t log; + uint32_t interval = dns_zone_getsigvalidityinterval(zone); - interval = dns_zone_getsigvalidityinterval(zone); log.func = update_log_cb; log.arg = client; result = dns_update_signatures(&log, zone, db, oldver, - ver, &diff, interval); + ver, &diff, + interval); if (result != ISC_R_SUCCESS) { update_log(client, zone, -- GitLab