From 7d2b185f16b165e311e5b451324fe9ab9898dced Mon Sep 17 00:00:00 2001 From: Evan Hunt Date: Fri, 10 Jan 2014 17:53:21 -0800 Subject: [PATCH] [master] new dnssec-coverage options 3702. [func] 'dnssec-coverage -l' option specifies a length of time to check for coverage; events further into the future are ignored. 'dnssec-coverage -z' checks only ZSK events, and 'dnssec-coverage -k' checks only KSK events. (Thanks to Peter Palfrader.) [RT #35168] --- CHANGES | 7 +++ bin/python/dnssec-coverage.docbook | 47 +++++++++++++++++-- bin/python/dnssec-coverage.py.in | 73 +++++++++++++++++++++++------- bin/tests/system/coverage/setup.sh | 30 ++++++++++++ bin/tests/system/coverage/tests.sh | 26 +++++++++-- 5 files changed, 158 insertions(+), 25 deletions(-) diff --git a/CHANGES b/CHANGES index 394e45f879..5014103180 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +3702. [func] 'dnssec-coverage -l' option specifies a length + of time to check for coverage; events further into + the future are ignored. 'dnssec-coverage -z' + checks only ZSK events, and 'dnssec-coverage -k' + checks only KSK events. (Thanks to Peter Palfrader.) + [RT #35168] + 3701. [func] named-checkconf can now obscure shared secrets when printing by specifying '-x'. [RT #34465] diff --git a/bin/python/dnssec-coverage.docbook b/bin/python/dnssec-coverage.docbook index 7657b080de..91b028de22 100644 --- a/bin/python/dnssec-coverage.docbook +++ b/bin/python/dnssec-coverage.docbook @@ -44,11 +44,14 @@ dnssec-coverage + + + zone @@ -86,6 +89,16 @@ OPTIONS + + -K directory + + + Sets the directory in which keys can be found. Defaults to the + current working directory. + + + + -f file @@ -100,11 +113,18 @@ - -K directory + -l duration - Sets the directory in which keys can be found. Defaults to the - current working directory. + The length of time to check for DNSSEC coverage. Key events + scheduled further into the future than + will be ignored, and assumed to be correct. + + + The value of can be set in seconds, + or in larger units of time by adding a suffix: 'mi' for minutes, + 'h' for hours, 'd' for days, 'w' for weeks, 'mo' for months, + 'y' for years. @@ -185,6 +205,27 @@ + + -k + + + Only check KSK coverage; ignore ZSK events. Cannot be + used with . + + + + + + -z + + + Only check ZSK coverage; ignore KSK events. Cannot be + used with . + + + + + -c compilezone path diff --git a/bin/python/dnssec-coverage.py.in b/bin/python/dnssec-coverage.py.in index 5d2714dedb..da00326990 100755 --- a/bin/python/dnssec-coverage.py.in +++ b/bin/python/dnssec-coverage.py.in @@ -15,6 +15,10 @@ # PERFORMANCE OF THIS SOFTWARE. ############################################################################ +# changes 2014-01-08, Peter Palfrader: +# - support checking only X days into the future. +# - support checking only KSK keys or only ZSK keys. + import argparse import os import glob @@ -506,6 +510,13 @@ def check_events(eventsList, ksk): eventgroups.append(eventgroup) for eventgroup in eventgroups: + if (args.checklimit and + calendar.timegm(eventgroup[0].when) > args.checklimit): + print("Ignoring events after %s" % + time.strftime("%a %b %d %H:%M:%S UTC %Y", + time.gmtime(args.checklimit))) + return True + (active, published) = \ process_events(eventgroup, active, published) @@ -548,21 +559,23 @@ def check_zones(eventsList): zonesfound = True for alg in eventsList[zone]: - vspace() - print("Checking scheduled KSK events for zone %s, algorithm %s..." % - (zone, algname(alg))) - if not check_events(eventsList[zone][alg], True): - foundprob = True - else: - print ("No errors found") + if not args.no_ksk: + vspace() + print("Checking scheduled KSK events for zone %s, algorithm %s..." % + (zone, algname(alg))) + if not check_events(eventsList[zone][alg], True): + foundprob = True + else: + print ("No errors found") - vspace() - print("Checking scheduled ZSK events for zone %s, algorithm %s..." % - (zone, algname(alg))) - if not check_events(eventsList[zone][alg], False): - foundprob = True - else: - print ("No errors found") + if not args.no_zsk: + vspace() + print("Checking scheduled ZSK events for zone %s, algorithm %s..." % + (zone, algname(alg))) + if not check_events(eventsList[zone][alg], False): + foundprob = True + else: + print ("No errors found") if not zonesfound: print("ERROR: No key events found for %s in '%s'" % @@ -637,17 +650,28 @@ def parse_args(): help='zone master file', metavar='file') parser.add_argument('-m', dest='maxttl', type=str, help='the longest TTL in the zone(s)', - metavar='int') + metavar='time') parser.add_argument('-d', dest='keyttl', type=str, - help='the DNSKEY TTL', metavar='int') + help='the DNSKEY TTL', metavar='time') parser.add_argument('-r', dest='resign', default='1944000', type=int, help='the RRSIG refresh interval ' 'in seconds [default: 22.5 days]', - metavar='int') + metavar='time') parser.add_argument('-c', dest='compilezone', default=compilezone, type=str, help='path to \'named-compilezone\'', metavar='path') + parser.add_argument('-l', dest='checklimit', + type=str, default='0', + help='Length of time to check for ' + 'DNSSEC coverage [default: 0 (unlimited)]', + metavar='time') + parser.add_argument('-z', dest='no_ksk', + action='store_true', default=False, + help='Only check zone-signing keys (ZSKs)') + parser.add_argument('-k', dest='no_zsk', + action='store_true', default=False, + help='Only check key-signing keys (KSKs)') parser.add_argument('-D', '--debug', dest='debug_mode', action='store_true', default=False, help='Turn on debugging output') @@ -655,6 +679,10 @@ def parse_args(): args = parser.parse_args() + if args.no_zsk and args.no_ksk: + print("ERROR: -z and -k cannot be used together."); + exit(1) + # convert from time arguments to seconds try: if args.maxttl: @@ -677,6 +705,17 @@ def parse_args(): except: pass + try: + if args.checklimit: + lim = args.checklimit + r = parse_time(args.checklimit) + if r == 0: + args.checklimit = None + else: + args.checklimit = time.time() + r + except: + pass + # if we've got the values we need from the command line, stop now if args.maxttl and args.keyttl: return diff --git a/bin/tests/system/coverage/setup.sh b/bin/tests/system/coverage/setup.sh index 95b35dd387..0c0fdbc2ff 100644 --- a/bin/tests/system/coverage/setup.sh +++ b/bin/tests/system/coverage/setup.sh @@ -105,3 +105,33 @@ zsk2=`$KEYGEN -K $dir -S $zsk1` # allow only 1 day between publication and activation $SETTIME -K $dir -P +269d $zsk2 > /dev/null 2>&1 ksk1=`$KEYGEN -K $dir -3fk example.com` + +# Test 9: KSK goes inactive before successor is active, but checking ZSKs +dir=09-check-zsk +rm -f $dir/K*.key +rm -f $dir/K*.private +ksk1=`$KEYGEN -K $dir -3fk example.com` +$SETTIME -K $dir -I +9mo -D +1y $ksk1 > /dev/null 2>&1 +ksk2=`$KEYGEN -K $dir -S $ksk1` +$SETTIME -K $dir -I +7mo $ksk1 > /dev/null 2>&1 +zsk1=`$KEYGEN -K $dir -3 example.com` + +# Test 10: ZSK goes inactive before successor is active, but checking KSKs +dir=10-check-ksk +rm -f $dir/K*.key +rm -f $dir/K*.private +zsk1=`$KEYGEN -K $dir -3 example.com` +$SETTIME -K $dir -I +9mo -D +1y $zsk1 > /dev/null 2>&1 +zsk2=`$KEYGEN -K $dir -S $zsk1` +$SETTIME -K $dir -I +7mo $zsk1 > /dev/null 2>&1 +ksk1=`$KEYGEN -K $dir -3fk example.com` + +# Test 11: ZSK goes inactive before successor is active, but after cutoff +dir=11-cutoff +rm -f $dir/K*.key +rm -f $dir/K*.private +zsk1=`$KEYGEN -K $dir -3 example.com` +$SETTIME -K $dir -I +18mo -D +2y $zsk1 > /dev/null 2>&1 +zsk2=`$KEYGEN -K $dir -S $zsk1` +$SETTIME -K $dir -I +16mo $zsk1 > /dev/null 2>&1 +ksk1=`$KEYGEN -K $dir -3fk example.com` diff --git a/bin/tests/system/coverage/tests.sh b/bin/tests/system/coverage/tests.sh index bbc72a062f..a404a4665f 100644 --- a/bin/tests/system/coverage/tests.sh +++ b/bin/tests/system/coverage/tests.sh @@ -42,22 +42,38 @@ for dir in [0-9][0-9]-*; do $COVERAGE $args -K $dir example.com > coverage.$n 2>&1 # check that return code matches expectations - [ $? -eq $retcode ] || ret=1 + found=$? + if [ $found -ne $retcode ]; then + echo "retcode was $found expected $retcode" + ret=1 + fi # check for correct number of errors found=`grep ERROR coverage.$n | wc -l` - [ $found -eq $error ] || ret=1 + if [ $found -ne $error ]; then + echo "error count was $found expected $error" + ret=1 + fi # check for correct number of warnings found=`grep WARNING coverage.$n | wc -l` - [ $found -eq $warn ] || ret=1 + if [ $found -ne $warn ]; then + echo "warning count was $found expected $warn" + ret=1 + fi # check for correct number of OKs found=`grep "No errors found" coverage.$n | wc -l` - [ $found -eq $ok ] || ret=1 + if [ $found -ne $ok ]; then + echo "good count was $found expected $ok" + ret=1 + fi found=`matchall coverage.$n "$match"` - [ "$found" = "FAIL" ] && ret=1 + if [ "$found" = "FAIL" ]; then + echo "no match on '$match'" + ret=1 + fi n=`expr $n + 1` if [ $ret != 0 ]; then echo "I:failed"; fi