...
 
Commits (4)
  • Witold Krecicki's avatar
    Jitter signatures times when adding dynamic records. · bc96d7b3
    Witold Krecicki authored
    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).
    
    Manually edits: resolve conflicts, replace isc_random_uniform
    with isc_random_jitter.
    
    (cherry picked from commit 6b2fd402)
    bc96d7b3
  • Matthijs Mekking's avatar
    Test jitter distribution · 32b5cae3
    Matthijs Mekking authored
    Test jitter distribution in NSEC3 dynamic zone and for a zone that has old
    signatures.  In both cases the generated signatures should be spread nicely.
    
    (cherry picked from commit 540b90fd)
    32b5cae3
  • Ondřej Surý's avatar
    Add CHANGES · 653da9d5
    Ondřej Surý authored
    653da9d5
  • Matthijs Mekking's avatar
    Update copyrights · 26252892
    Matthijs Mekking authored
    26252892
5315. [bug] Apply the inital RRSIG expiration spread fixed
to all dynamically created records in the zone
including NSEC3. Also fix the signature clusters
when the server has been offline for prolonged
period of times. [GL #1256]
5314. [func] Added a new statistics variable "tcp-highwater"
that reports the maximum number of simultaneous TCP
clients BIND has handled while running. [GL #1206]
......
......@@ -39,6 +39,7 @@ rm -f ns3/inacksk2.example.db
rm -f ns3/inacksk3.example.db
rm -f ns3/inaczsk2.example.db
rm -f ns3/inaczsk3.example.db
rm -f ns3/jitter.nsec3.example.db
rm -f ns3/kg.out ns3/s.out ns3/st.out
rm -f ns3/nozsk.example.db ns3/inaczsk.example.db
rm -f ns3/nsec.example.db
......
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
;
; This Source Code Form is subject to the terms of the Mozilla Public
; License, v. 2.0. If a copy of the MPL was not distributed with this
; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;
; See the COPYRIGHT file distributed with this work for additional
; information regarding copyright ownership.
$TTL 300 ; 5 minutes
@ IN SOA mname1. . (
2000042407 ; serial
20 ; refresh (20 seconds)
20 ; retry (20 seconds)
1814400 ; expire (3 weeks)
3600 ; minimum (1 hour)
)
NS ns
ns A 10.53.0.3
......@@ -52,6 +52,21 @@ ksk=`$KEYGEN -q -3 -r $RANDFILE -fk $zone 2> kg.out` || dumpit kg.out
$KEYGEN -q -3 -r $RANDFILE $zone > kg.out 2>&1 || dumpit kg.out
$DSFROMKEY $ksk.key > dsset-${zone}$TP
#
# Jitter/NSEC3 test zone
#
setup jitter.nsec3.example
cp $infile $zonefile
count=1
while [ $count -le 100 ]
do
echo "label${count} IN TXT label${count}" >> $zonefile
count=`expr $count + 1`
done
# Don't create keys just yet, because the scenario we want to test
# is an unsigned zone that has a NSEC3PARAM record added with
# dynamic update before the keys are generated.
#
# OPTOUT/NSEC3 test zone
#
......@@ -150,9 +165,16 @@ $DSFROMKEY $ksk.key > dsset-${zone}$TP
#
setup oldsigs.example
cp $infile $zonefile
count=1
while [ $count -le 100 ]
do
echo "label${count} IN TXT label${count}" >> $zonefile
count=`expr $count + 1`
done
$KEYGEN -q -r $RANDFILE -fk $zone > kg.out 2>&1 || dumpit kg.out
$KEYGEN -q -r $RANDFILE $zone > kg.out 2>&1 || dumpit kg.out
$SIGNER -PS -s now-1y -e now-6mo -o $zone -f $zonefile $infile > s.out 2>&1 || dumpit s.out
$SIGNER -PS -s now-1y -e now-6mo -o $zone -f $zonefile.signed $zonefile > s.out 2>&1 || dumpit s.out
mv $zonefile.signed $zonefile
#
# NSEC3->NSEC transition test zone.
......
......@@ -96,6 +96,14 @@ zone "nsec3.nsec3.example" {
auto-dnssec maintain;
};
zone "jitter.nsec3.example" {
type master;
file "jitter.nsec3.example.db";
allow-update { any; };
auto-dnssec maintain;
sig-validity-interval 10 2;
};
zone "secure.nsec3.example" {
type master;
file "secure.nsec3.example.db";
......@@ -179,6 +187,7 @@ zone "oldsigs.example" {
file "oldsigs.example.db";
allow-update { any; };
auto-dnssec maintain;
sig-validity-interval 10 2;
};
zone "prepub.example" {
......
......@@ -50,6 +50,43 @@ checkprivate () {
return 1
}
# Check the signatures expiration times. First check how many signatures
# there are in total ($rrsigs). Then see what the distribution of signature
# expiration times is ($expiretimes). Ignore the time part for a better
# modelled distribution.
checkjitter () {
_file=$1
_ret=0
cat $_file | awk '$4 == "RRSIG" {print substr($9,1,8)}' | sort | uniq -c | cat_i
_rrsigs=$(cat $_file | awk '$4 == "RRSIG" {print $4}' | cat_i | wc -l)
_expiretimes=$(cat $_file | awk '$4 == "RRSIG" {print substr($9,1,8)}' | sort | uniq -c | awk '{print $1}')
_count=0
_total=0
for _num in $_expiretimes
do
_total=$(($_total + $_num))
done
# Make sure the total number of numbers matches the number of RRSIGs.
test $_total -eq $_rrsigs || _ret=1
# Calculate mean: The number of signatures divided over 8 days.
_mean=$(($_total / 8))
# We expect the number of signatures not to exceed twice the mean.
_limit=$(($_mean * 2))
# Add an additional margin.
_limit=$(($_limit + 10))
# Find outliers.
for _num in $_expiretimes
do
if [ $_num -gt $_limit ]; then
echo_i "error: too many RRSIG records ($_num) with the same expiration time"
_ret=1
fi
done
return $_ret
}
#
# The NSEC record at the apex of the zone and its RRSIG records are
# added as part of the last step in signing a zone. We wait for the
......@@ -334,6 +371,15 @@ do
sleep 1
done
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
# Check jitter distribution.
echo_i "checking expired signatures were jittered correctly ($n)"
ret=0
$DIG $DIGOPTS axfr oldsigs.example @10.53.0.3 > dig.out.ns3.test$n || ret=1
checkjitter dig.out.ns3.test$n || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "checking NSEC->NSEC3 conversion succeeded ($n)"
......@@ -943,6 +989,36 @@ n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "checking jitter in a newly signed NSEC3 zone ($n)"
ret=0
# Use DNS UPDATE to add an NSEC3PARAM record into the zone.
$NSUPDATE > nsupdate.out.test$n 2>&1 <<END || ret=1
server 10.53.0.3 ${PORT}
zone jitter.nsec3.example.
update add jitter.nsec3.example. 3600 NSEC3PARAM 1 0 10 BEEF
send
END
[ $ret != 0 ] && echo_i "error: dynamic update add NSEC3PARAM failed"
# Create DNSSEC keys in the zone directory.
$KEYGEN -r $RANDFILE -a rsasha256 -b 2048 -3 -q -K ns3 jitter.nsec3.example > /dev/null
# Trigger zone signing.
$RNDCCMD 10.53.0.3 sign jitter.nsec3.example. 2>&1 | sed 's/^/ns3 /' | cat_i
# Wait until zone has been signed.
for i in 0 1 2 3 4 5 6 7 8 9; do
failed=0
$DIG $DIGOPTS axfr jitter.nsec3.example @10.53.0.3 > dig.out.ns3.test$n || failed=1
grep "NSEC3PARAM" dig.out.ns3.test$n > /dev/null || failed=1
[ $failed -eq 0 ] && break
echo_i "waiting ... ($i)"
sleep 2
done
[ $failed != 0 ] && echo_i "error: no NSEC3PARAM found in AXFR" && ret=1
# Check jitter distribution.
checkjitter dig.out.ns3.test$n || ret=1
n=`expr $n + 1`
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "checking that serial number and RRSIGs are both updated (rt21045) ($n)"
ret=0
oldserial=`$DIG $DIGOPTS +short soa prepub.example @10.53.0.3 | awk '$0 !~ /SOA/ {print $3}'`
......
......@@ -21,6 +21,7 @@
#include <isc/netaddr.h>
#include <isc/platform.h>
#include <isc/print.h>
#include <isc/random.h>
#include <isc/serial.h>
#include <isc/stats.h>
#include <isc/stdtime.h>
......@@ -1380,6 +1381,27 @@ 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);
uint32_t jitter;
isc_random_get(&jitter);
if (sigvalidityinterval < 7200U) {
expiryinterval = 1200;
} else if (expiryinterval > sigvalidityinterval) {
expiryinterval = sigvalidityinterval;
} else {
expiryinterval = sigvalidityinterval - expiryinterval;
}
jitter %= 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,
......@@ -1433,7 +1455,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);
/*
* Do we look at the KSK flag on the DNSKEY to determining which
......
......@@ -6542,8 +6542,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;
......@@ -6591,21 +6591,37 @@ 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) {
isc_random_get(&jitter);
uint32_t normaljitter, fulljitter;
isc_random_get(&normaljitter);
isc_random_get(&fulljitter);
if (sigvalidityinterval > 7200U) {
jitter %= 3600;
normaljitter %= 3600;
fulljitter %= expiryinterval;
} else {
jitter %= 1200;
normaljitter %= 1200;
fulljitter %= 1200;
}
expire = soaexpire - jitter - 1;
expire = soaexpire - normaljitter - 1;
fullexpire = soaexpire - fulljitter - 1;
} else {
expire = soaexpire - 1;
expire = fullexpire = soaexpire - 1;
}
stop = now + 5;
......@@ -6645,9 +6661,16 @@ 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, covers, zonediff.diff,
zone_keys, nkeys, zone->mctx, inception,
expire, check_ksk, keyset_kskonly);
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",
......@@ -7540,7 +7563,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;
......@@ -7612,6 +7635,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
......@@ -7621,7 +7650,7 @@ zone_nsec3chain(dns_zone_t *zone) {
if (sigvalidityinterval >= 3600U) {
isc_random_get(&jitter);
if (sigvalidityinterval > 7200U) {
jitter %= 3600;
jitter %= expiryinterval;
} else {
jitter %= 1200;
}
......
......@@ -618,6 +618,7 @@
./bin/tests/system/autosign/ns3/inaczsk2.example.db.in ZONE 2017,2018,2019
./bin/tests/system/autosign/ns3/inaczsk3.example.db.in ZONE 2017,2018,2019
./bin/tests/system/autosign/ns3/insecure.example.db ZONE 2009,2016,2018,2019
./bin/tests/system/autosign/ns3/jitter.nsec3.example.db.in ZONE 2019
./bin/tests/system/autosign/ns3/keygen.sh SH 2009,2010,2011,2012,2014,2015,2016,2017,2018,2019
./bin/tests/system/autosign/ns3/named.conf.in CONF-C 2018,2019
./bin/tests/system/autosign/ns3/nozsk.example.db.in ZONE 2011,2016,2018,2019
......