mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-30 22:15:20 +00:00
[master] add dnssec-coverage tool
3528. [func] New "dnssec-coverage" command scans the timing metadata for a set of DNSSEC keys and reports if a lapse in signing coverage has been scheduled inadvertently. (Note: This tool depends on python; it will not be built or installed on systems that do not have a python interpreter.) [RT #28098]
This commit is contained in:
7
CHANGES
7
CHANGES
@@ -1,3 +1,10 @@
|
|||||||
|
3528. [func] New "dnssec-coverage" command scans the timing
|
||||||
|
metadata for a set of DNSSEC keys and reports if a
|
||||||
|
lapse in signing coverage has been scheduled
|
||||||
|
inadvertently. (Note: This tool depends on python;
|
||||||
|
it will not be built or installed on systems that
|
||||||
|
do not have a python interpreter.) [RT #28098]
|
||||||
|
|
||||||
3527. [compat] Add a URI to allow applications to explicitly
|
3527. [compat] Add a URI to allow applications to explicitly
|
||||||
request a particular XML schema from the statistics
|
request a particular XML schema from the statistics
|
||||||
channel, returning 404 if not supported. [RT #32481]
|
channel, returning 404 if not supported. [RT #32481]
|
||||||
|
2
bin/python/.gitignore
vendored
2
bin/python/.gitignore
vendored
@@ -1,2 +1,4 @@
|
|||||||
dnssec-checkds
|
dnssec-checkds
|
||||||
dnssec-checkds.py
|
dnssec-checkds.py
|
||||||
|
dnssec-coverage
|
||||||
|
dnssec-coverage.py
|
||||||
|
@@ -22,17 +22,19 @@ top_srcdir = @top_srcdir@
|
|||||||
|
|
||||||
PYTHON = @PYTHON@
|
PYTHON = @PYTHON@
|
||||||
|
|
||||||
TARGETS = dnssec-checkds
|
TARGETS = dnssec-checkds dnssec-coverage
|
||||||
SRCS = dnssec-checkds.py
|
SRCS = dnssec-checkds.py dnssec-coverage.py
|
||||||
|
|
||||||
MANPAGES = dnssec-checkds.8
|
MANPAGES = dnssec-checkds.8 dnssec-coverage.8
|
||||||
HTMLPAGES = dnssec-checkds.html
|
HTMLPAGES = dnssec-checkds.html dnssec-coverage.html
|
||||||
MANOBJS = ${MANPAGES} ${HTMLPAGES}
|
MANOBJS = ${MANPAGES} ${HTMLPAGES}
|
||||||
|
|
||||||
@BIND9_MAKE_RULES@
|
@BIND9_MAKE_RULES@
|
||||||
|
|
||||||
dnssec-checkds: dnssec-checkds.py
|
dnssec-checkds: dnssec-checkds.py
|
||||||
|
|
||||||
|
dnssec-coverage: dnssec-coverage.py
|
||||||
|
|
||||||
doc man:: ${MANOBJS}
|
doc man:: ${MANOBJS}
|
||||||
|
|
||||||
docclean manclean maintainer-clean::
|
docclean manclean maintainer-clean::
|
||||||
@@ -44,10 +46,12 @@ installdirs:
|
|||||||
|
|
||||||
install:: ${TARGETS} installdirs
|
install:: ${TARGETS} installdirs
|
||||||
${INSTALL_PROGRAM} dnssec-checkds@EXEEXT@ ${DESTDIR}${sbindir}
|
${INSTALL_PROGRAM} dnssec-checkds@EXEEXT@ ${DESTDIR}${sbindir}
|
||||||
|
${INSTALL_PROGRAM} dnssec-coverage@EXEEXT@ ${DESTDIR}${sbindir}
|
||||||
${INSTALL_DATA} ${srcdir}/dnssec-checkds.8 ${DESTDIR}${mandir}/man8
|
${INSTALL_DATA} ${srcdir}/dnssec-checkds.8 ${DESTDIR}${mandir}/man8
|
||||||
|
${INSTALL_DATA} ${srcdir}/dnssec-coverage.8 ${DESTDIR}${mandir}/man8
|
||||||
|
|
||||||
clean distclean::
|
clean distclean::
|
||||||
rm -f ${TARGETS}
|
rm -f ${TARGETS}
|
||||||
|
|
||||||
distclean::
|
distclean::
|
||||||
rm -f dnssec-checkds.py
|
rm -f dnssec-checkds.py dnssec-coverage.py
|
||||||
|
228
bin/python/dnssec-coverage.docbook
Normal file
228
bin/python/dnssec-coverage.docbook
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"
|
||||||
|
[<!ENTITY mdash "—">]>
|
||||||
|
<!--
|
||||||
|
- Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
-
|
||||||
|
- Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
- purpose with or without fee is hereby granted, provided that the above
|
||||||
|
- copyright notice and this permission notice appear in all copies.
|
||||||
|
-
|
||||||
|
- THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
- AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
- OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
- PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<refentry id="man.dnssec-coverage">
|
||||||
|
<refentryinfo>
|
||||||
|
<date>April 16, 2012</date>
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle><application>dnssec-coverage</application></refentrytitle>
|
||||||
|
<manvolnum>8</manvolnum>
|
||||||
|
<refmiscinfo>BIND9</refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname><application>dnssec-coverage</application></refname>
|
||||||
|
<refpurpose>checks future DNSKEY coverage for a zone</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<docinfo>
|
||||||
|
<copyright>
|
||||||
|
<year>2012</year>
|
||||||
|
<holder>Internet Systems Consortium, Inc. ("ISC")</holder>
|
||||||
|
</copyright>
|
||||||
|
</docinfo>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>dnssec-coverage</command>
|
||||||
|
<arg><option>-K <replaceable class="parameter">directory</replaceable></option></arg>
|
||||||
|
<arg><option>-f <replaceable class="parameter">file</replaceable></option></arg>
|
||||||
|
<arg><option>-d <replaceable class="parameter">DNSKEY TTL</replaceable></option></arg>
|
||||||
|
<arg><option>-m <replaceable class="parameter">max TTL</replaceable></option></arg>
|
||||||
|
<arg><option>-r <replaceable class="parameter">interval</replaceable></option></arg>
|
||||||
|
<arg><option>-c <replaceable class="parameter">compilezone path</replaceable></option></arg>
|
||||||
|
<arg choice="opt">zone</arg>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>DESCRIPTION</title>
|
||||||
|
<para><command>dnssec-coverage</command>
|
||||||
|
verifies that the DNSSEC keys for a given zone or a set of zones
|
||||||
|
have timing metadata set properly to ensure no future lapses in DNSSEC
|
||||||
|
coverage.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If <option>zone</option> is specified, then keys found in
|
||||||
|
the key repository matching that zone are scanned, and an ordered
|
||||||
|
list is generated of the events scheduled for that key (i.e.,
|
||||||
|
publication, activation, inactivation, deletion). The list of
|
||||||
|
events is walked in order of occurrence. Warnings are generated
|
||||||
|
if any event is scheduled which could cause the zone to enter a
|
||||||
|
state in which validation failures might occur: for example, if
|
||||||
|
the number of published or active keys for a given algorithm drops
|
||||||
|
to zero, or if a key is deleted from the zone too soon after a new
|
||||||
|
key is rolled, and cached data signed by the prior key has not had
|
||||||
|
time to expire from resolver caches.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
If <option>zone</option> is not specified, then all keys in the
|
||||||
|
key repository will be scanned, and all zones for which there are
|
||||||
|
keys will be analyzed. (Note: This method of reporting is only
|
||||||
|
accurate if all the zones that have keys in a given repository
|
||||||
|
share the same TTL parameters.)
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>OPTIONS</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>-f <replaceable class="parameter">file</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
If a <option>file</option> is specified, then the zone is
|
||||||
|
read from that file; the largest TTL and the DNSKEY TTL are
|
||||||
|
determined directly from the zone data, and the
|
||||||
|
<option>-m</option> and <option>-d</option> options do
|
||||||
|
not need to be specified on the command line.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>-K <replaceable class="parameter">directory</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Sets the directory in which keys can be found. Defaults to the
|
||||||
|
current working directory.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>-m <replaceable class="parameter">maximum TTL</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Sets the value to be used as the maximum TTL for the zone or
|
||||||
|
zones being analyzed when determining whether there is a
|
||||||
|
possibility of validation failure. When a zone-signing key is
|
||||||
|
deactivated, there must be enough time for the record in the
|
||||||
|
zone with the longest TTL to have expired from resolver caches
|
||||||
|
before that key can be purged from the DNSKEY RRset. If that
|
||||||
|
condition does not apply, a warning will be generated.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The length of the TTL 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.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This option is mandatory unless the <option>-f</option> has
|
||||||
|
been used to specify a zone file. (If <option>-f</option> has
|
||||||
|
been specified, this option may still be used; it will overrde
|
||||||
|
the value found in the file.)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>-d <replaceable class="parameter">DNSKEY TTL</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Sets the value to be used as the DNSKEY TTL for the zone or
|
||||||
|
zones being analyzed when determining whether there is a
|
||||||
|
possibility of validation failure. When a key is rolled (that
|
||||||
|
is, replaced with a new key), there must be enough time
|
||||||
|
for the old DNSKEY RRset to have expired from resolver caches
|
||||||
|
before the new key is activated and begins generating
|
||||||
|
signatures. If that condition does not apply, a warning
|
||||||
|
will be generated.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The length of the TTL 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.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
This option is mandatory unless the <option>-f</option> has
|
||||||
|
been used to specify a zone file, or a default key TTL was
|
||||||
|
set with the <option>-L</option> to
|
||||||
|
<command>dnssec-keygen</command>. (If either of those is true,
|
||||||
|
this option may still be used; it will overrde the value found
|
||||||
|
in the zone or key file.)
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>-r <replaceable class="parameter">resign interval</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Sets the value to be used as the resign interval for the zone
|
||||||
|
or zones being analyzed when determining whether there is a
|
||||||
|
possibility of validation failure. This value defaults to
|
||||||
|
22.5 days, which is also the default in
|
||||||
|
<command>named</command>. However, if it has been changed
|
||||||
|
by the <option>sig-validity-interval</option> option in
|
||||||
|
<filename>named.conf</filename>, then it should also be
|
||||||
|
changed here.
|
||||||
|
</para>
|
||||||
|
<para>
|
||||||
|
The length of the interval 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.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term>-c <replaceable class="parameter">compilezone path</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Specifies a path to a <command>named-compilezone</command> binary.
|
||||||
|
Used for testing.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>SEE ALSO</title>
|
||||||
|
<para>
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>dnssec-checkds</refentrytitle><manvolnum>8</manvolnum>
|
||||||
|
</citerefentry>,
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>dnssec-dsfromkey</refentrytitle><manvolnum>8</manvolnum>
|
||||||
|
</citerefentry>,
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>dnssec-keygen</refentrytitle><manvolnum>8</manvolnum>
|
||||||
|
</citerefentry>,
|
||||||
|
<citerefentry>
|
||||||
|
<refentrytitle>dnssec-signzone</refentrytitle><manvolnum>8</manvolnum>
|
||||||
|
</citerefentry>
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>AUTHOR</title>
|
||||||
|
<para><corpauthor>Internet Systems Consortium</corpauthor>
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
</refentry><!--
|
||||||
|
- Local variables:
|
||||||
|
- mode: sgml
|
||||||
|
- End:
|
||||||
|
-->
|
737
bin/python/dnssec-coverage.py.in
Executable file
737
bin/python/dnssec-coverage.py.in
Executable file
@@ -0,0 +1,737 @@
|
|||||||
|
#!@PYTHON@
|
||||||
|
############################################################################
|
||||||
|
# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
############################################################################
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
import calendar
|
||||||
|
from collections import defaultdict
|
||||||
|
import pprint
|
||||||
|
|
||||||
|
prog='dnssec-coverage'
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Class Event
|
||||||
|
########################################################################
|
||||||
|
class Event:
|
||||||
|
""" A discrete key metadata event, e.g., Publish, Activate, Inactive,
|
||||||
|
Delete. Stores the date of the event, and identifying information about
|
||||||
|
the key to which the event will occur."""
|
||||||
|
|
||||||
|
def __init__(self, _what, _key):
|
||||||
|
now = time.time()
|
||||||
|
self.what = _what
|
||||||
|
self.when = _key.metadata[_what]
|
||||||
|
self.key = _key
|
||||||
|
self.keyid = _key.keyid
|
||||||
|
self.sep = _key.sep
|
||||||
|
self.zone = _key.zone
|
||||||
|
self.alg = _key.alg
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return repr((self.when, self.what, self.keyid, self.sep,
|
||||||
|
self.zone, self.alg))
|
||||||
|
|
||||||
|
def showtime(self):
|
||||||
|
return time.strftime("%a %b %d %H:%M:%S UTC %Y", self.when)
|
||||||
|
|
||||||
|
def showkey(self):
|
||||||
|
return self.key.showkey()
|
||||||
|
|
||||||
|
def showkeytype(self):
|
||||||
|
return self.key.showkeytype()
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Class Key
|
||||||
|
########################################################################
|
||||||
|
class Key:
|
||||||
|
"""An individual DNSSEC key. Identified by path, zone, algorithm, keyid.
|
||||||
|
Contains a dictionary of metadata events."""
|
||||||
|
|
||||||
|
def __init__(self, keyname):
|
||||||
|
directory = os.path.dirname(keyname)
|
||||||
|
key = os.path.basename(keyname)
|
||||||
|
(zone, alg, keyid) = key.split('+')
|
||||||
|
keyid = keyid.split('.')[0]
|
||||||
|
key = [zone, alg, keyid]
|
||||||
|
key_file = directory + os.sep + '+'.join(key) + ".key"
|
||||||
|
private_file = directory + os.sep + '+'.join(key) + ".private"
|
||||||
|
|
||||||
|
self.zone = zone[1:-1]
|
||||||
|
self.alg = int(alg)
|
||||||
|
self.keyid = int(keyid)
|
||||||
|
|
||||||
|
kfp = file(key_file, "r")
|
||||||
|
for line in kfp:
|
||||||
|
if line[0] == ';':
|
||||||
|
continue
|
||||||
|
tokens = line.split()
|
||||||
|
if not tokens:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if tokens[1].lower() in ('in', 'ch', 'hs'):
|
||||||
|
septoken = 3
|
||||||
|
self.ttl = args.keyttl
|
||||||
|
if not self.ttl:
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Unable to determine TTL for DNSKEY %s." %
|
||||||
|
self.showkey())
|
||||||
|
print("\t Using 1 day (86400 seconds); re-run with the -d "
|
||||||
|
"option for more\n\t accurate results.")
|
||||||
|
self.ttl = 86400
|
||||||
|
else:
|
||||||
|
septoken = 4
|
||||||
|
self.ttl = int(tokens[1]) if not args.keyttl else args.keyttl
|
||||||
|
|
||||||
|
if (int(tokens[septoken]) & 0x1) == 1:
|
||||||
|
self.sep = True
|
||||||
|
else:
|
||||||
|
self.sep = False
|
||||||
|
kfp.close()
|
||||||
|
|
||||||
|
pfp = file(private_file, "rU")
|
||||||
|
propDict = dict()
|
||||||
|
for propLine in pfp:
|
||||||
|
propDef = propLine.strip()
|
||||||
|
if len(propDef) == 0:
|
||||||
|
continue
|
||||||
|
if propDef[0] in ('!', '#'):
|
||||||
|
continue
|
||||||
|
punctuation = [propDef.find(c) for c in ':= '] + [len(propDef)]
|
||||||
|
found = min([ pos for pos in punctuation if pos != -1 ])
|
||||||
|
name = propDef[:found].rstrip()
|
||||||
|
value = propDef[found:].lstrip(":= ").rstrip()
|
||||||
|
propDict[name] = value
|
||||||
|
|
||||||
|
if("Publish" in propDict):
|
||||||
|
propDict["Publish"] = time.strptime(propDict["Publish"],
|
||||||
|
"%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
if("Activate" in propDict):
|
||||||
|
propDict["Activate"] = time.strptime(propDict["Activate"],
|
||||||
|
"%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
if("Inactive" in propDict):
|
||||||
|
propDict["Inactive"] = time.strptime(propDict["Inactive"],
|
||||||
|
"%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
if("Delete" in propDict):
|
||||||
|
propDict["Delete"] = time.strptime(propDict["Delete"],
|
||||||
|
"%Y%m%d%H%M%S")
|
||||||
|
|
||||||
|
if("Revoke" in propDict):
|
||||||
|
propDict["Revoke"] = time.strptime(propDict["Revoke"],
|
||||||
|
"%Y%m%d%H%M%S")
|
||||||
|
pfp.close()
|
||||||
|
self.metadata = propDict
|
||||||
|
|
||||||
|
def showkey(self):
|
||||||
|
return "%s/%03d/%05d" % (self.zone, self.alg, self.keyid);
|
||||||
|
|
||||||
|
def showkeytype(self):
|
||||||
|
return ("KSK" if self.sep else "ZSK")
|
||||||
|
|
||||||
|
# ensure that the gap between Publish and Activate is big enough
|
||||||
|
def check_prepub(self):
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
if (not "Activate" in self.metadata):
|
||||||
|
debug_print("No Activate information in key: %s" % self.showkey())
|
||||||
|
return False
|
||||||
|
a = calendar.timegm(self.metadata["Activate"])
|
||||||
|
|
||||||
|
if (not "Publish" in self.metadata):
|
||||||
|
debug_print("No Publish information in key: %s" % self.showkey())
|
||||||
|
if a > now:
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Key %s (%s) is scheduled for activation but \n"
|
||||||
|
"\t not for publication." %
|
||||||
|
(self.showkey(), self.showkeytype()))
|
||||||
|
return False
|
||||||
|
p = calendar.timegm(self.metadata["Publish"])
|
||||||
|
|
||||||
|
now = time.time()
|
||||||
|
if p < now and a < now:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if p == a:
|
||||||
|
vspace()
|
||||||
|
print ("WARNING: %s (%s) is scheduled to be published and\n"
|
||||||
|
"\t activated at the same time. This could result in a\n"
|
||||||
|
"\t coverage gap if the zone was previously signed." %
|
||||||
|
(self.showkey(), self.showkeytype()))
|
||||||
|
print("\t Activation should be at least %s after publication."
|
||||||
|
% duration(self.ttl))
|
||||||
|
return True
|
||||||
|
|
||||||
|
if a < p:
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Key %s (%s) is active before it is published" %
|
||||||
|
(self.showkey(), self.showkeytype()))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (a - p < self.ttl):
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Key %s (%s) is activated too soon after\n"
|
||||||
|
"\t publication; this could result in coverage gaps due to\n"
|
||||||
|
"\t resolver caches containing old data."
|
||||||
|
% (self.showkey(), self.showkeytype()))
|
||||||
|
print("\t Activation should be at least %s after publication." %
|
||||||
|
duration(self.ttl))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
# ensure that the gap between Inactive and Delete is big enough
|
||||||
|
def check_postpub(self, timespan = None):
|
||||||
|
if not timespan:
|
||||||
|
timespan = self.ttl
|
||||||
|
|
||||||
|
now = time.time()
|
||||||
|
|
||||||
|
if (not "Delete" in self.metadata):
|
||||||
|
debug_print("No Delete information in key: %s" % self.showkey())
|
||||||
|
return False
|
||||||
|
d = calendar.timegm(self.metadata["Delete"])
|
||||||
|
|
||||||
|
if (not "Inactive" in self.metadata):
|
||||||
|
debug_print("No Inactive information in key: %s" % self.showkey())
|
||||||
|
if d > now:
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Key %s (%s) is scheduled for deletion but\n"
|
||||||
|
"\t not for inactivation." %
|
||||||
|
(self.showkey(), self.showkeytype()))
|
||||||
|
return False
|
||||||
|
i = calendar.timegm(self.metadata["Inactive"])
|
||||||
|
|
||||||
|
if d < now and i < now:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if (d < i):
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Key %s (%s) is scheduled for deletion before\n"
|
||||||
|
"\t inactivation." % (self.showkey(), self.showkeytype()))
|
||||||
|
return False
|
||||||
|
|
||||||
|
if (d - i < timespan):
|
||||||
|
vspace()
|
||||||
|
print("WARNING: Key %s (%s) scheduled for deletion too soon after\n"
|
||||||
|
"\t deactivation; this may result in coverage gaps due to\n"
|
||||||
|
"\t resolver caches containing old data."
|
||||||
|
% (self.showkey(), self.showkeytype()))
|
||||||
|
print("\t Deletion should be at least %s after inactivation." %
|
||||||
|
duration(timespan))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# class Zone
|
||||||
|
########################################################################
|
||||||
|
class Zone:
|
||||||
|
"""Stores data about a specific zone"""
|
||||||
|
|
||||||
|
def __init__(self, _name, _keyttl = None, _maxttl = None):
|
||||||
|
self.name = _name
|
||||||
|
self.keyttl = _keyttl
|
||||||
|
self.maxttl = _maxttl
|
||||||
|
|
||||||
|
def load(self, filename):
|
||||||
|
if not args.compilezone:
|
||||||
|
sys.stderr.write(prog + ': FATAL: "named-compilezone" not found\n')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if not self.name:
|
||||||
|
return
|
||||||
|
|
||||||
|
maxttl = keyttl = None
|
||||||
|
|
||||||
|
fp = os.popen("%s -o - %s %s 2> /dev/null" %
|
||||||
|
(args.compilezone, self.name, filename))
|
||||||
|
for line in fp:
|
||||||
|
fields = line.split()
|
||||||
|
if not maxttl or int(fields[1]) > maxttl:
|
||||||
|
maxttl = int(fields[1])
|
||||||
|
if fields[3] == "DNSKEY":
|
||||||
|
keyttl = int(fields[1])
|
||||||
|
fp.close()
|
||||||
|
|
||||||
|
self.keyttl = keyttl
|
||||||
|
self.maxttl = maxttl
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# debug_print:
|
||||||
|
############################################################################
|
||||||
|
def debug_print(debugVar):
|
||||||
|
"""pretty print a variable iff debug mode is enabled"""
|
||||||
|
if not args.debug_mode:
|
||||||
|
return
|
||||||
|
if type(debugVar) == str:
|
||||||
|
print("DEBUG: " + debugVar)
|
||||||
|
else:
|
||||||
|
print("DEBUG: " + pprint.pformat(debugVar))
|
||||||
|
return
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# vspace:
|
||||||
|
############################################################################
|
||||||
|
_firstline = True
|
||||||
|
def vspace():
|
||||||
|
"""adds vertical space between two sections of output text if and only
|
||||||
|
if this is *not* the first section being printed"""
|
||||||
|
global _firstline
|
||||||
|
if _firstline:
|
||||||
|
_firstline = False
|
||||||
|
else:
|
||||||
|
print
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# vreset:
|
||||||
|
############################################################################
|
||||||
|
def vreset():
|
||||||
|
"""reset vertical spacing"""
|
||||||
|
global _firstline
|
||||||
|
_firstline = True
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# getunit
|
||||||
|
############################################################################
|
||||||
|
def getunit(secs, size):
|
||||||
|
"""given a number of seconds, and a number of seconds in a larger unit of
|
||||||
|
time, calculate how many of the larger unit there are and return both
|
||||||
|
that and a remainder value"""
|
||||||
|
bigunit = secs // size
|
||||||
|
if bigunit:
|
||||||
|
secs %= size
|
||||||
|
return (bigunit, secs)
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# addtime
|
||||||
|
############################################################################
|
||||||
|
def addtime(output, unit, t):
|
||||||
|
"""add a formatted unit of time to an accumulating string"""
|
||||||
|
if t:
|
||||||
|
output += ("%s%d %s%s" %
|
||||||
|
((", " if output else ""),
|
||||||
|
t, unit, ("s" if t > 1 else "")))
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# duration:
|
||||||
|
############################################################################
|
||||||
|
def duration(secs):
|
||||||
|
"""given a length of time in seconds, print a formatted human duration
|
||||||
|
in larger units of time
|
||||||
|
"""
|
||||||
|
# define units:
|
||||||
|
minute = 60
|
||||||
|
hour = minute * 60
|
||||||
|
day = hour * 24
|
||||||
|
month = day * 30
|
||||||
|
year = day * 365
|
||||||
|
|
||||||
|
# calculate time in units:
|
||||||
|
(years, secs) = getunit(secs, year)
|
||||||
|
(months, secs) = getunit(secs, month)
|
||||||
|
(days, secs) = getunit(secs, day)
|
||||||
|
(hours, secs) = getunit(secs, hour)
|
||||||
|
(minutes, secs) = getunit(secs, minute)
|
||||||
|
|
||||||
|
output = ''
|
||||||
|
output = addtime(output, "year", years)
|
||||||
|
output = addtime(output, "month", months)
|
||||||
|
output = addtime(output, "day", days)
|
||||||
|
output = addtime(output, "hour", hours)
|
||||||
|
output = addtime(output, "minute", minutes)
|
||||||
|
output = addtime(output, "second", secs)
|
||||||
|
return output
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# parse_time
|
||||||
|
############################################################################
|
||||||
|
def parse_time(s):
|
||||||
|
"""convert a formatted time (e.g., 1y, 6mo, 15mi, etc) into seconds"""
|
||||||
|
s = s.strip()
|
||||||
|
|
||||||
|
# if s is an integer, we're done already
|
||||||
|
try:
|
||||||
|
n = int(s)
|
||||||
|
return n
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# try to parse as a number with a suffix indicating unit of time
|
||||||
|
r = re.compile('([0-9][0-9]*)\s*([A-Za-z]*)')
|
||||||
|
m = r.match(s)
|
||||||
|
if not m:
|
||||||
|
raise Exception("Cannot parse %s" % s)
|
||||||
|
(n, unit) = m.groups()
|
||||||
|
n = int(n)
|
||||||
|
unit = unit.lower()
|
||||||
|
if unit[0] == 'y':
|
||||||
|
return n * 31536000
|
||||||
|
elif unit[0] == 'm' and unit[1] == 'o':
|
||||||
|
return n * 2592000
|
||||||
|
elif unit[0] == 'w':
|
||||||
|
return n * 604800
|
||||||
|
elif unit[0] == 'd':
|
||||||
|
return n * 86400
|
||||||
|
elif unit[0] == 'h':
|
||||||
|
return n * 3600
|
||||||
|
elif unit[0] == 'm' and unit[1] == 'i':
|
||||||
|
return n * 60
|
||||||
|
elif unit[0] == 's':
|
||||||
|
return n
|
||||||
|
else:
|
||||||
|
raise Exception("Invalid suffix %s" % unit)
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# algname:
|
||||||
|
############################################################################
|
||||||
|
def algname(alg):
|
||||||
|
"""return the mnemonic for a DNSSEC algorithm"""
|
||||||
|
names = (None, 'RSAMD5', 'DH', 'DSA', 'ECC', 'RSASHA1',
|
||||||
|
'NSEC3DSA', 'NSEC3RSASHA1', 'RSASHA256', None,
|
||||||
|
'RSASHA512', None, 'ECCGOST', 'ECDSAP256SHA256',
|
||||||
|
'ECDSAP384SHA384')
|
||||||
|
name = None
|
||||||
|
if alg in range(len(names)):
|
||||||
|
name = names[alg]
|
||||||
|
return (name if name else str(alg))
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# list_events:
|
||||||
|
############################################################################
|
||||||
|
def list_events(eventgroup):
|
||||||
|
"""print a list of the events in an eventgroup"""
|
||||||
|
if not eventgroup:
|
||||||
|
return
|
||||||
|
print (" " + eventgroup[0].showtime() + ":")
|
||||||
|
for event in eventgroup:
|
||||||
|
print (" %s: %s (%s)" %
|
||||||
|
(event.what, event.showkey(), event.showkeytype()))
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# process_events:
|
||||||
|
############################################################################
|
||||||
|
def process_events(eventgroup, active, published):
|
||||||
|
"""go through the events in an event group in time-order, add to active
|
||||||
|
list upon Activate event, add to published list upon Publish event,
|
||||||
|
remove from active list upon Inactive event, and remove from published
|
||||||
|
upon Delete event. Emit warnings when inconsistant states are reached"""
|
||||||
|
for event in eventgroup:
|
||||||
|
if event.what == "Activate":
|
||||||
|
active.add(event.keyid)
|
||||||
|
elif event.what == "Publish":
|
||||||
|
published.add(event.keyid)
|
||||||
|
elif event.what == "Inactive":
|
||||||
|
if event.keyid not in active:
|
||||||
|
vspace()
|
||||||
|
print ("\tWARNING: %s (%s) scheduled to become inactive "
|
||||||
|
"before it is active" %
|
||||||
|
(event.showkey(), event.showkeytype()))
|
||||||
|
else:
|
||||||
|
active.remove(event.keyid)
|
||||||
|
elif event.what == "Delete":
|
||||||
|
if event.keyid in published:
|
||||||
|
published.remove(event.keyid)
|
||||||
|
else:
|
||||||
|
vspace()
|
||||||
|
print ("WARNING: key %s (%s) is scheduled for deletion before "
|
||||||
|
"it is published, at %s" %
|
||||||
|
(event.showkey(), event.showkeytype()))
|
||||||
|
elif event.what == "Revoke":
|
||||||
|
# We don't need to worry about the logic of this one;
|
||||||
|
# just stop counting this key as either active or published
|
||||||
|
if event.keyid in published:
|
||||||
|
published.remove(event.keyid)
|
||||||
|
if event.keyid in active:
|
||||||
|
active.remove(event.keyid)
|
||||||
|
|
||||||
|
return (active, published)
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# check_events:
|
||||||
|
############################################################################
|
||||||
|
def check_events(eventsList, ksk):
|
||||||
|
"""create lists of events happening at the same time, check for
|
||||||
|
inconsistancies"""
|
||||||
|
active = set()
|
||||||
|
published = set()
|
||||||
|
eventgroups = list()
|
||||||
|
eventgroup = list()
|
||||||
|
keytype = ("KSK" if ksk else "ZSK")
|
||||||
|
|
||||||
|
# collect up all events that have the same time
|
||||||
|
eventsfound = False
|
||||||
|
for event in eventsList:
|
||||||
|
# if checking ZSKs, skip KSKs, and vice versa
|
||||||
|
if (ksk and not event.sep) or (event.sep and not ksk):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# we found an appropriate (ZSK or KSK event)
|
||||||
|
eventsfound = True
|
||||||
|
|
||||||
|
# add event to current eventgroup
|
||||||
|
if (not eventgroup or eventgroup[0].when == event.when):
|
||||||
|
eventgroup.append(event)
|
||||||
|
|
||||||
|
# if we're at the end of the list, we're done. if
|
||||||
|
# we've found an event with a later time, start a new
|
||||||
|
# eventgroup
|
||||||
|
if (eventgroup[0].when != event.when):
|
||||||
|
eventgroups.append(eventgroup)
|
||||||
|
eventgroup = list()
|
||||||
|
eventgroup.append(event)
|
||||||
|
|
||||||
|
if eventgroup:
|
||||||
|
eventgroups.append(eventgroup)
|
||||||
|
|
||||||
|
for eventgroup in eventgroups:
|
||||||
|
(active, published) = \
|
||||||
|
process_events(eventgroup, active, published)
|
||||||
|
|
||||||
|
list_events(eventgroup)
|
||||||
|
|
||||||
|
# and then check for inconsistencies:
|
||||||
|
if len(active) == 0:
|
||||||
|
print ("ERROR: No %s's are active after this event" % keytype)
|
||||||
|
return False
|
||||||
|
elif len(published) == 0:
|
||||||
|
sys.stdout.write("ERROR: ")
|
||||||
|
print ("ERROR: No %s's are published after this event" % keytype)
|
||||||
|
return False
|
||||||
|
elif len(published.intersection(active)) == 0:
|
||||||
|
sys.stdout.write("ERROR: ")
|
||||||
|
print (("ERROR: No %s's are both active and published " +
|
||||||
|
"after this event") % keytype)
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not eventsfound:
|
||||||
|
print ("ERROR: No %s events found in '%s'" %
|
||||||
|
(keytype, args.path))
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# check_zones:
|
||||||
|
# ############################################################################
|
||||||
|
def check_zones(eventsList):
|
||||||
|
"""scan events per zone, algorithm, and key type, in order of occurrance,
|
||||||
|
noting inconsistent states when found"""
|
||||||
|
global foundprob
|
||||||
|
|
||||||
|
foundprob = False
|
||||||
|
zonesfound = False
|
||||||
|
for zone in eventsList:
|
||||||
|
if args.zone and zone != args.zone:
|
||||||
|
continue
|
||||||
|
|
||||||
|
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")
|
||||||
|
|
||||||
|
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'" %
|
||||||
|
(args.zone, args.path))
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# fill_eventsList:
|
||||||
|
############################################################################
|
||||||
|
def fill_eventsList(eventsList):
|
||||||
|
"""populate the list of events"""
|
||||||
|
for zone, algorithms in keyDict.items():
|
||||||
|
for alg, keys in algorithms.items():
|
||||||
|
for keyid, keydata in keys.items():
|
||||||
|
if("Publish" in keydata.metadata):
|
||||||
|
eventsList[zone][alg].append(Event("Publish", keydata))
|
||||||
|
if("Activate" in keydata.metadata):
|
||||||
|
eventsList[zone][alg].append(Event("Activate", keydata))
|
||||||
|
if("Inactive" in keydata.metadata):
|
||||||
|
eventsList[zone][alg].append(Event("Inactive", keydata))
|
||||||
|
if("Delete" in keydata.metadata):
|
||||||
|
eventsList[zone][alg].append(Event("Delete", keydata))
|
||||||
|
|
||||||
|
eventsList[zone][alg] = sorted(eventsList[zone][alg],
|
||||||
|
key=lambda event: event.when)
|
||||||
|
|
||||||
|
foundprob = False
|
||||||
|
if not keyDict:
|
||||||
|
print("ERROR: No key events found in '%s'" % args.path)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# set_path:
|
||||||
|
############################################################################
|
||||||
|
def set_path(command, default=None):
|
||||||
|
"""find the location of a specified command. if a default is supplied
|
||||||
|
and it works, we use it; otherwise we search PATH for a match. If
|
||||||
|
not found, error and exit"""
|
||||||
|
fpath = default
|
||||||
|
if not fpath or not os.path.isfile(fpath) or not os.access(fpath, os.X_OK):
|
||||||
|
path = os.environ["PATH"]
|
||||||
|
if not path:
|
||||||
|
path = os.path.defpath
|
||||||
|
for directory in path.split(os.pathsep):
|
||||||
|
fpath = directory + os.sep + command
|
||||||
|
if os.path.isfile(fpath) or os.access(fpath, os.X_OK):
|
||||||
|
break
|
||||||
|
fpath = None
|
||||||
|
|
||||||
|
return fpath
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# parse_args:
|
||||||
|
############################################################################
|
||||||
|
def parse_args():
|
||||||
|
"""Read command line arguments, set global 'args' structure"""
|
||||||
|
global args
|
||||||
|
|
||||||
|
compilezone = set_path('named-compilezone',
|
||||||
|
'@prefix@/sbin/named-compilezone')
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser(description=prog + ': checks future ' +
|
||||||
|
'DNSKEY coverage for a zone')
|
||||||
|
|
||||||
|
parser.add_argument('zone', type=str, help='zone to check')
|
||||||
|
parser.add_argument('-K', dest='path', default='.', type=str,
|
||||||
|
help='a directory containing keys to process',
|
||||||
|
metavar='dir')
|
||||||
|
parser.add_argument('-f', dest='filename', type=str,
|
||||||
|
help='zone master file', metavar='file')
|
||||||
|
parser.add_argument('-m', dest='maxttl', type=str,
|
||||||
|
help='the longest TTL in the zone(s)',
|
||||||
|
metavar='int')
|
||||||
|
parser.add_argument('-d', dest='keyttl', type=str,
|
||||||
|
help='the DNSKEY TTL', metavar='int')
|
||||||
|
parser.add_argument('-r', dest='resign', default='1944000',
|
||||||
|
type=int, help='the RRSIG refresh interval '
|
||||||
|
'in seconds [default: 22.5 days]',
|
||||||
|
metavar='int')
|
||||||
|
parser.add_argument('-c', dest='compilezone',
|
||||||
|
default=compilezone, type=str,
|
||||||
|
help='path to \'named-compilezone\'',
|
||||||
|
metavar='path')
|
||||||
|
parser.add_argument('-D', '--debug', dest='debug_mode',
|
||||||
|
action='store_true', default=False,
|
||||||
|
help='Turn on debugging output')
|
||||||
|
parser.add_argument('-v', '--version', action='version', version='9.9.1')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# convert from time arguments to seconds
|
||||||
|
try:
|
||||||
|
if args.maxttl:
|
||||||
|
m = parse_time(args.maxttl)
|
||||||
|
args.maxttl = m
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.keyttl:
|
||||||
|
k = parse_time(args.keyttl)
|
||||||
|
args.keyttl = k
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.resign:
|
||||||
|
r = parse_time(args.resign)
|
||||||
|
args.resign = r
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# if we've got the values we need from the command line, stop now
|
||||||
|
if args.maxttl and args.keyttl:
|
||||||
|
return
|
||||||
|
|
||||||
|
# load keyttl and maxttl data from zonefile
|
||||||
|
if args.zone and args.filename:
|
||||||
|
try:
|
||||||
|
zone = Zone(args.zone)
|
||||||
|
zone.load(args.filename)
|
||||||
|
if not args.maxttl:
|
||||||
|
args.maxttl = zone.maxttl
|
||||||
|
if not args.keyttl:
|
||||||
|
args.keyttl = zone.maxttl
|
||||||
|
except Exception as e:
|
||||||
|
print("Unable to load zone data from %s: " % args.filename, e)
|
||||||
|
|
||||||
|
if not args.maxttl:
|
||||||
|
vspace()
|
||||||
|
print ("WARNING: Maximum TTL value was not specified. Using 1 week\n"
|
||||||
|
"\t (604800 seconds); re-run with the -m option to get more\n"
|
||||||
|
"\t accurate results.")
|
||||||
|
args.maxttl = 604800
|
||||||
|
|
||||||
|
############################################################################
|
||||||
|
# Main
|
||||||
|
############################################################################
|
||||||
|
def main():
|
||||||
|
global keyDict
|
||||||
|
|
||||||
|
parse_args()
|
||||||
|
path=args.path
|
||||||
|
|
||||||
|
print ("PHASE 1--Loading keys to check for internal timing problems")
|
||||||
|
keyDict = defaultdict(lambda : defaultdict(dict))
|
||||||
|
files = glob.glob(os.path.join(path, '*.private'))
|
||||||
|
for infile in files:
|
||||||
|
key = Key(infile)
|
||||||
|
if args.zone and key.zone != args.zone:
|
||||||
|
continue
|
||||||
|
keyDict[key.zone][key.alg][key.keyid] = key
|
||||||
|
key.check_prepub()
|
||||||
|
if key.sep:
|
||||||
|
key.check_postpub()
|
||||||
|
else:
|
||||||
|
key.check_postpub(args.maxttl + args.resign)
|
||||||
|
|
||||||
|
vspace()
|
||||||
|
print ("PHASE 2--Scanning future key events for coverage failures")
|
||||||
|
vreset()
|
||||||
|
|
||||||
|
eventsList = defaultdict(lambda : defaultdict(list))
|
||||||
|
fill_eventsList(eventsList)
|
||||||
|
check_zones(eventsList)
|
||||||
|
|
||||||
|
if foundprob:
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@@ -44,6 +44,7 @@ REVOKE=$TOP/bin/dnssec/dnssec-revoke
|
|||||||
SETTIME=$TOP/bin/dnssec/dnssec-settime
|
SETTIME=$TOP/bin/dnssec/dnssec-settime
|
||||||
DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
|
DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
|
||||||
CHECKDS=$TOP/bin/python/dnssec-checkds
|
CHECKDS=$TOP/bin/python/dnssec-checkds
|
||||||
|
COVERAGE=$TOP/bin/python/dnssec-coverage
|
||||||
CHECKZONE=$TOP/bin/check/named-checkzone
|
CHECKZONE=$TOP/bin/check/named-checkzone
|
||||||
CHECKCONF=$TOP/bin/check/named-checkconf
|
CHECKCONF=$TOP/bin/check/named-checkconf
|
||||||
PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -s ${SLOT:-0} -p 1234"
|
PK11GEN="$TOP/bin/pkcs11/pkcs11-keygen -s ${SLOT:-0} -p 1234"
|
||||||
@@ -57,8 +58,8 @@ ARPANAME=$TOP/bin/tools/arpaname
|
|||||||
# load on the machine to make it unusable to other users.
|
# load on the machine to make it unusable to other users.
|
||||||
# v6synth
|
# v6synth
|
||||||
SUBDIRS="acl additional allow_query addzone autosign builtin
|
SUBDIRS="acl additional allow_query addzone autosign builtin
|
||||||
cacheclean checkconf @CHECKDS@ checknames checkzone database
|
cacheclean checkconf @CHECKDS@ checknames checkzone @COVERAGE@
|
||||||
dlv dlvauto dlz dlzexternal dlzredir dname dns64 dnssec
|
database dlv dlvauto dlz dlzexternal dlzredir dname dns64 dnssec
|
||||||
dsdigest ecdsa formerr forward glue gost ixfr inline limits
|
dsdigest ecdsa formerr forward glue gost ixfr inline limits
|
||||||
logfileconfig lwresd masterfile masterformat metadata
|
logfileconfig lwresd masterfile masterformat metadata
|
||||||
notify nsupdate pending pkcs11 redirect resolver rndc rpz
|
notify nsupdate pending pkcs11 redirect resolver rndc rpz
|
||||||
|
10
bin/tests/system/coverage/01-ksk-inactive/README
Normal file
10
bin/tests/system/coverage/01-ksk-inactive/README
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
This set includes one KSK rollover. The KSK is deactivated prior to
|
||||||
|
its replacement being activated. Tool output should resemble:
|
||||||
|
|
||||||
|
Checking KSK events for zone example.com, algorithm 7:
|
||||||
|
ERROR: After 2012-31-Jul (20:59:14):
|
||||||
|
Inactive: example.com/007/45435 (KSK)
|
||||||
|
No KSK's are active
|
||||||
|
|
||||||
|
Checking ZSK events for zone example.com, algorithm 7:
|
||||||
|
OK
|
6
bin/tests/system/coverage/01-ksk-inactive/expect
Normal file
6
bin/tests/system/coverage/01-ksk-inactive/expect
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
args="-d 1h -m 2h"
|
||||||
|
warn=0
|
||||||
|
error=1
|
||||||
|
ok=1
|
||||||
|
retcode=1
|
||||||
|
match="No KSK's are active"
|
10
bin/tests/system/coverage/02-zsk-inactive/README
Normal file
10
bin/tests/system/coverage/02-zsk-inactive/README
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
This set includes one ZSK rollover. The first ZSK is deactivated
|
||||||
|
prior to its replacement being activated. Tool output should resemble:
|
||||||
|
|
||||||
|
Checking KSK events for zone example.com, algorithm 7:
|
||||||
|
OK
|
||||||
|
|
||||||
|
Checking ZSK events for zone example.com, algorithm 7:
|
||||||
|
ERROR: After 2012-05-Dec (20:39:32):
|
||||||
|
Inactive: example.com/005/08376 (ZSK)
|
||||||
|
No ZSK's are active
|
6
bin/tests/system/coverage/02-zsk-inactive/expect
Normal file
6
bin/tests/system/coverage/02-zsk-inactive/expect
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
args="-d 1h -m 2h"
|
||||||
|
warn=0
|
||||||
|
error=1
|
||||||
|
ok=1
|
||||||
|
retcode=1
|
||||||
|
match="No ZSK's are active"
|
10
bin/tests/system/coverage/03-ksk-unpublished/README
Normal file
10
bin/tests/system/coverage/03-ksk-unpublished/README
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
This set contains one KSK rollover. The KSK is unpublished before its
|
||||||
|
successor is published. Tool output should resemble:
|
||||||
|
|
||||||
|
Checking KSK events for zone example.com, algorithm 7:
|
||||||
|
ERROR: After 2012-06-Oct (21:07:57):
|
||||||
|
Delete: example.com/007/23040 (KSK)
|
||||||
|
No KSK's are published
|
||||||
|
|
||||||
|
Checking ZSK events for zone example.com, algorithm 7:
|
||||||
|
OK
|
7
bin/tests/system/coverage/03-ksk-unpublished/expect
Normal file
7
bin/tests/system/coverage/03-ksk-unpublished/expect
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
args="-d 1h -m 2h"
|
||||||
|
warn=1
|
||||||
|
error=1
|
||||||
|
ok=1
|
||||||
|
retcode=1
|
||||||
|
match="WARNING: Key .* (KSK) is scheduled for deletion before
|
||||||
|
No KSK's are published"
|
10
bin/tests/system/coverage/04-zsk-unpublished/README
Normal file
10
bin/tests/system/coverage/04-zsk-unpublished/README
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
This set contains one ZSK rollover. The ZSK is unpublished before its
|
||||||
|
successor is published. Tool output should resemble:
|
||||||
|
|
||||||
|
Checking KSK events for zone example.com, algorithm 7:
|
||||||
|
OK
|
||||||
|
|
||||||
|
Checking ZSK events for zone example.com, algorithm 7:
|
||||||
|
ERROR: After 2012-06-Oct (21:13:45):
|
||||||
|
Delete: example.com/007/25967 (ZSK)
|
||||||
|
No ZSK's are published
|
7
bin/tests/system/coverage/04-zsk-unpublished/expect
Normal file
7
bin/tests/system/coverage/04-zsk-unpublished/expect
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
args="-d 1h -m 2h"
|
||||||
|
warn=1
|
||||||
|
error=1
|
||||||
|
ok=1
|
||||||
|
retcode=1
|
||||||
|
match="WARNING: Key .* (ZSK) is scheduled for deletion before
|
||||||
|
No ZSK's are published"
|
12
bin/tests/system/coverage/05-ksk-unpub-active/README
Normal file
12
bin/tests/system/coverage/05-ksk-unpub-active/README
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
This set includes one KSK rollover. The first KSK is deleted
|
||||||
|
and its successor published prior to the first KSK being deactivated
|
||||||
|
and its successor activated. Tool output should resemble:
|
||||||
|
|
||||||
|
Checking KSK events for zone example.com, algorithm 7:
|
||||||
|
ERROR: After 2012-05-Dec (21:22:19):
|
||||||
|
Delete: example.com/007/06219 (KSK)
|
||||||
|
Publish: example.com/007/20559 (KSK)
|
||||||
|
No KSK's are both active and published
|
||||||
|
|
||||||
|
Checking ZSK events for zone example.com, algorithm 7:
|
||||||
|
OK
|
7
bin/tests/system/coverage/05-ksk-unpub-active/expect
Normal file
7
bin/tests/system/coverage/05-ksk-unpub-active/expect
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
args="-d 1h -m 2h"
|
||||||
|
warn=1
|
||||||
|
error=1
|
||||||
|
ok=1
|
||||||
|
retcode=1
|
||||||
|
match="WARNING: Key .* (KSK) is scheduled for deletion before
|
||||||
|
No KSK's are both active and published"
|
12
bin/tests/system/coverage/06-zsk-unpub-active/README
Normal file
12
bin/tests/system/coverage/06-zsk-unpub-active/README
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
This set includes one KSK rollover. The first KSK is deleted
|
||||||
|
and its successor published prior to the first KSK being deactivated
|
||||||
|
and its successor activated. Tool output should resemble:
|
||||||
|
|
||||||
|
Checking KSK events for zone example.com, algorithm 7:
|
||||||
|
OK
|
||||||
|
|
||||||
|
Checking ZSK events for zone example.com, algorithm 7:
|
||||||
|
ERROR: After 2012-05-Dec (20:44:18):
|
||||||
|
Delete: example.com/007/26369 (ZSK)
|
||||||
|
Publish: example.com/007/21029 (ZSK)
|
||||||
|
No ZSK's are both active and published
|
7
bin/tests/system/coverage/06-zsk-unpub-active/expect
Normal file
7
bin/tests/system/coverage/06-zsk-unpub-active/expect
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
args="-d 1h -m 2h"
|
||||||
|
warn=1
|
||||||
|
error=1
|
||||||
|
ok=1
|
||||||
|
retcode=1
|
||||||
|
match="WARNING: Key .* (ZSK) is scheduled for deletion before
|
||||||
|
No ZSK's are both active and published"
|
4
bin/tests/system/coverage/07-ksk-ttl/README
Normal file
4
bin/tests/system/coverage/07-ksk-ttl/README
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
This set includes a KSK rollover, with insufficient delay between
|
||||||
|
prepublication and rollover.
|
||||||
|
|
||||||
|
Expected tool output TBD.
|
7
bin/tests/system/coverage/07-ksk-ttl/expect
Normal file
7
bin/tests/system/coverage/07-ksk-ttl/expect
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
args="-d 1w -m 2w"
|
||||||
|
warn=1
|
||||||
|
error=0
|
||||||
|
ok=2
|
||||||
|
retcode=0
|
||||||
|
match="WARNING: Key .* (KSK) is activated too soon after
|
||||||
|
Activation should be at least 7 days after publication."
|
4
bin/tests/system/coverage/08-zsk-ttl/README
Normal file
4
bin/tests/system/coverage/08-zsk-ttl/README
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
This set includes a KSK rollover, with insufficient delay between
|
||||||
|
prepublication and rollover.
|
||||||
|
|
||||||
|
Expected tool output TBD.
|
7
bin/tests/system/coverage/08-zsk-ttl/expect
Normal file
7
bin/tests/system/coverage/08-zsk-ttl/expect
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
args="-d 1w -m 2w"
|
||||||
|
warn=1
|
||||||
|
error=0
|
||||||
|
ok=2
|
||||||
|
retcode=0
|
||||||
|
match="WARNING: Key .* (ZSK) is activated too soon after
|
||||||
|
Activation should be at least 7 days after publication."
|
6
bin/tests/system/coverage/clean.sh
Normal file
6
bin/tests/system/coverage/clean.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
rm -f named-compilezone
|
||||||
|
rm -f */K*.key
|
||||||
|
rm -f */K*.private
|
||||||
|
rm -rf coverage.*
|
||||||
|
rm -f random.data
|
106
bin/tests/system/coverage/setup.sh
Normal file
106
bin/tests/system/coverage/setup.sh
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
SYSTEMTESTTOP=..
|
||||||
|
. $SYSTEMTESTTOP/conf.sh
|
||||||
|
|
||||||
|
KEYGEN="$KEYGEN -qr random.data"
|
||||||
|
|
||||||
|
sh clean.sh
|
||||||
|
|
||||||
|
ln -s $CHECKZONE named-compilezone
|
||||||
|
../../../tools/genrandom 400 random.data
|
||||||
|
|
||||||
|
# Test 1: KSK goes inactive before successor is active
|
||||||
|
dir=01-ksk-inactive
|
||||||
|
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 2: ZSK goes inactive before successor is active
|
||||||
|
dir=02-zsk-inactive
|
||||||
|
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 3: KSK is unpublished before its successor is published
|
||||||
|
dir=03-ksk-unpublished
|
||||||
|
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 -D +6mo $ksk1 > /dev/null 2>&1
|
||||||
|
zsk1=`$KEYGEN -K $dir -3 example.com`
|
||||||
|
|
||||||
|
# Test 4: ZSK is unpublished before its successor is published
|
||||||
|
dir=04-zsk-unpublished
|
||||||
|
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 -D +6mo $zsk1 > /dev/null 2>&1
|
||||||
|
ksk1=`$KEYGEN -K $dir -3fk example.com`
|
||||||
|
|
||||||
|
# Test 5: KSK deleted and successor published before KSK is deactivated
|
||||||
|
# and successor activated.
|
||||||
|
dir=05-ksk-unpub-active
|
||||||
|
rm -f $dir/K*.key
|
||||||
|
rm -f $dir/K*.private
|
||||||
|
ksk1=`$KEYGEN -K $dir -3fk example.com`
|
||||||
|
$SETTIME -K $dir -I +9mo -D +8mo $ksk1 > /dev/null 2>&1
|
||||||
|
ksk2=`$KEYGEN -K $dir -S $ksk1`
|
||||||
|
zsk1=`$KEYGEN -K $dir -3 example.com`
|
||||||
|
|
||||||
|
# Test 6: ZSK deleted and successor published before ZSK is deactivated
|
||||||
|
# and successor activated.
|
||||||
|
dir=06-zsk-unpub-active
|
||||||
|
rm -f $dir/K*.key
|
||||||
|
rm -f $dir/K*.private
|
||||||
|
zsk1=`$KEYGEN -K $dir -3 example.com`
|
||||||
|
$SETTIME -K $dir -I +9mo -D +8mo $zsk1 > /dev/null 2>&1
|
||||||
|
zsk2=`$KEYGEN -K $dir -S $zsk1`
|
||||||
|
ksk1=`$KEYGEN -K $dir -3fk example.com`
|
||||||
|
|
||||||
|
# Test 7: KSK rolled with insufficient delay after prepublication.
|
||||||
|
dir=07-ksk-ttl
|
||||||
|
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`
|
||||||
|
# allow only 1 day between publication and activation
|
||||||
|
$SETTIME -K $dir -P +269d $ksk2 > /dev/null 2>&1
|
||||||
|
zsk1=`$KEYGEN -K $dir -3 example.com`
|
||||||
|
|
||||||
|
# Test 8: ZSK rolled with insufficient delay after prepublication.
|
||||||
|
dir=08-zsk-ttl
|
||||||
|
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`
|
||||||
|
# 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`
|
67
bin/tests/system/coverage/tests.sh
Normal file
67
bin/tests/system/coverage/tests.sh
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
||||||
|
#
|
||||||
|
# Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
# purpose with or without fee is hereby granted, provided that the above
|
||||||
|
# copyright notice and this permission notice appear in all copies.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||||
|
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||||
|
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||||
|
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||||
|
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||||
|
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
# PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
|
||||||
|
SYSTEMTESTTOP=..
|
||||||
|
. $SYSTEMTESTTOP/conf.sh
|
||||||
|
|
||||||
|
COVERAGE="$COVERAGE -c ./named-compilezone"
|
||||||
|
|
||||||
|
status=0
|
||||||
|
n=1
|
||||||
|
|
||||||
|
matchall () {
|
||||||
|
file=$1
|
||||||
|
echo "$2" | while read matchline; do
|
||||||
|
grep "$matchline" $file > /dev/null 2>&1 || {
|
||||||
|
echo "FAIL"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "I:checking for DNSSEC key coverage issues"
|
||||||
|
ret=0
|
||||||
|
for dir in [0-9][0-9]-*; do
|
||||||
|
ret=0
|
||||||
|
echo "I:$dir"
|
||||||
|
args= warn= error= ok= retcode= match=
|
||||||
|
. $dir/expect
|
||||||
|
$COVERAGE $args -K $dir example.com > coverage.$n 2>&1
|
||||||
|
|
||||||
|
# check that return code matches expectations
|
||||||
|
[ $? -eq $retcode ] || ret=1
|
||||||
|
|
||||||
|
# check for correct number of errors
|
||||||
|
found=`grep ERROR coverage.$n | wc -l`
|
||||||
|
[ $found -eq $error ] || ret=1
|
||||||
|
|
||||||
|
# check for correct number of warnings
|
||||||
|
found=`grep WARNING coverage.$n | wc -l`
|
||||||
|
[ $found -eq $warn ] || ret=1
|
||||||
|
|
||||||
|
# check for correct number of OKs
|
||||||
|
found=`grep "No errors found" coverage.$n | wc -l`
|
||||||
|
[ $found -eq $ok ] || ret=1
|
||||||
|
|
||||||
|
found=`matchall coverage.$n "$match"`
|
||||||
|
[ "$found" = "FAIL" ] && ret=1
|
||||||
|
|
||||||
|
n=`expr $n + 1`
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "I:exit status: $status"
|
||||||
|
exit $status
|
@@ -1236,6 +1236,18 @@ israw1 signer/signer.out.7 || ret=1
|
|||||||
if [ $ret != 0 ]; then echo "I:failed"; fi
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
status=`expr $status + $ret`
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:checking dnssec-signzone output format ($n)"
|
||||||
|
ret=0
|
||||||
|
(
|
||||||
|
cd signer
|
||||||
|
$SIGNER -O full -f - -Sxt -o example example.db > signer.out.3 2>&1
|
||||||
|
$SIGNER -O text -f - -Sxt -o example example.db > signer.out.4 2>&1
|
||||||
|
) || ret=1
|
||||||
|
awk '/IN *SOA/ {if (NF != 11) exit(1)}' signer/signer.out.3 || ret=1
|
||||||
|
awk '/IN *SOA/ {if (NF != 7) exit(1)}' signer/signer.out.4 || ret=1
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
echo "I:checking validated data are not cached longer than originalttl ($n)"
|
echo "I:checking validated data are not cached longer than originalttl ($n)"
|
||||||
ret=0
|
ret=0
|
||||||
$DIG $DIGOPTS +ttl +noauth a.ttlpatch.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
|
$DIG $DIGOPTS +ttl +noauth a.ttlpatch.example. @10.53.0.3 a > dig.out.ns3.test$n || ret=1
|
||||||
@@ -2011,5 +2023,14 @@ n=`expr $n + 1`
|
|||||||
if [ $ret != 0 ]; then echo "I:failed"; fi
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
status=`expr $status + $ret`
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
|
echo "I:check dnssec-dsfromkey from stdin($n)"
|
||||||
|
ret=0
|
||||||
|
$DIG $DIGOPTS dnskey algroll. @10.53.0.2 | \
|
||||||
|
$DSFROMKEY -f - algroll. > dig.out.ns2.test$n || ret=1
|
||||||
|
diff -b dig.out.ns2.test$n ns1/dsset-algroll. > /dev/null 2>&1 || ret=1
|
||||||
|
n=`expr $n + 1`
|
||||||
|
if [ $ret != 0 ]; then echo "I:failed"; fi
|
||||||
|
status=`expr $status + $ret`
|
||||||
|
|
||||||
echo "I:exit status: $status"
|
echo "I:exit status: $status"
|
||||||
exit $status
|
exit $status
|
||||||
|
8
configure
vendored
8
configure
vendored
@@ -1339,6 +1339,7 @@ ISC_PLATFORM_NORETURN_PRE
|
|||||||
ISC_PLATFORM_HAVELONGLONG
|
ISC_PLATFORM_HAVELONGLONG
|
||||||
ISC_SOCKADDR_LEN_T
|
ISC_SOCKADDR_LEN_T
|
||||||
PYTHON_TOOLS
|
PYTHON_TOOLS
|
||||||
|
COVERAGE
|
||||||
CHECKDS
|
CHECKDS
|
||||||
PYTHON
|
PYTHON
|
||||||
PERL
|
PERL
|
||||||
@@ -12206,6 +12207,7 @@ $as_echo "found, using $PYTHON" >&6; }
|
|||||||
unspec)
|
unspec)
|
||||||
PYTHON=""
|
PYTHON=""
|
||||||
|
|
||||||
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found, python disabled" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found, python disabled" >&5
|
||||||
$as_echo "not found, python disabled" >&6; }
|
$as_echo "not found, python disabled" >&6; }
|
||||||
;;
|
;;
|
||||||
@@ -12221,13 +12223,16 @@ esac
|
|||||||
|
|
||||||
PYTHON_TOOLS=''
|
PYTHON_TOOLS=''
|
||||||
CHECKDS=''
|
CHECKDS=''
|
||||||
|
COVERAGE=''
|
||||||
if test "X$PYTHON" != "X"; then
|
if test "X$PYTHON" != "X"; then
|
||||||
PYTHON_TOOLS=python
|
PYTHON_TOOLS=python
|
||||||
CHECKDS=checkds
|
CHECKDS=checkds
|
||||||
|
COVERAGE=coverage
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Special processing of paths depending on whether --prefix,
|
# Special processing of paths depending on whether --prefix,
|
||||||
# --sysconfdir or --localstatedir arguments were given. What's
|
# --sysconfdir or --localstatedir arguments were given. What's
|
||||||
@@ -20838,7 +20843,7 @@ ac_config_commands="$ac_config_commands chmod"
|
|||||||
# elsewhere if there's a good reason for doing so.
|
# elsewhere if there's a good reason for doing so.
|
||||||
#
|
#
|
||||||
|
|
||||||
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/dsdigest/prereq.sh bin/tests/system/ecdsa/prereq.sh bin/tests/system/dlzredir/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/geoip/Makefile bin/tests/system/gost/prereq.sh bin/tests/system/lwresd/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/check-secure-delegation.pl contrib/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/export/Makefile lib/export/dns/Makefile lib/export/dns/include/Makefile lib/export/dns/include/dns/Makefile lib/export/dns/include/dst/Makefile lib/export/irs/Makefile lib/export/irs/include/Makefile lib/export/irs/include/irs/Makefile lib/export/isc/$thread_dir/Makefile lib/export/isc/$thread_dir/include/Makefile lib/export/isc/$thread_dir/include/isc/Makefile lib/export/isc/Makefile lib/export/isc/include/Makefile lib/export/isc/include/isc/Makefile lib/export/isc/nls/Makefile lib/export/isc/unix/Makefile lib/export/isc/unix/include/Makefile lib/export/isc/unix/include/isc/Makefile lib/export/isccfg/Makefile lib/export/isccfg/include/Makefile lib/export/isccfg/include/isccfg/Makefile lib/export/samples/Makefile lib/export/samples/Makefile-postinstall lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile unit/Makefile unit/unittest.sh"
|
ac_config_files="$ac_config_files make/Makefile make/mkdep Makefile bin/Makefile bin/check/Makefile bin/confgen/Makefile bin/confgen/unix/Makefile bin/dig/Makefile bin/dnssec/Makefile bin/named/Makefile bin/named/unix/Makefile bin/nsupdate/Makefile bin/pkcs11/Makefile bin/python/Makefile bin/python/dnssec-checkds.py bin/python/dnssec-coverage.py bin/rndc/Makefile bin/tests/Makefile bin/tests/atomic/Makefile bin/tests/db/Makefile bin/tests/dst/Makefile bin/tests/dst/Kdh.+002+18602.key bin/tests/dst/Kdh.+002+18602.private bin/tests/dst/Kdh.+002+48957.key bin/tests/dst/Kdh.+002+48957.private bin/tests/dst/Ktest.+001+00002.key bin/tests/dst/Ktest.+001+54622.key bin/tests/dst/Ktest.+001+54622.private bin/tests/dst/Ktest.+003+23616.key bin/tests/dst/Ktest.+003+23616.private bin/tests/dst/Ktest.+003+49667.key bin/tests/dst/dst_2_data bin/tests/dst/t2_data_1 bin/tests/dst/t2_data_2 bin/tests/dst/t2_dsasig bin/tests/dst/t2_rsasig bin/tests/hashes/Makefile bin/tests/headerdep_test.sh bin/tests/master/Makefile bin/tests/mem/Makefile bin/tests/names/Makefile bin/tests/net/Makefile bin/tests/rbt/Makefile bin/tests/resolver/Makefile bin/tests/sockaddr/Makefile bin/tests/system/Makefile bin/tests/system/conf.sh bin/tests/system/dlz/prereq.sh bin/tests/system/dlzexternal/Makefile bin/tests/system/dlzexternal/ns1/named.conf bin/tests/system/dsdigest/prereq.sh bin/tests/system/ecdsa/prereq.sh bin/tests/system/dlzredir/prereq.sh bin/tests/system/filter-aaaa/Makefile bin/tests/system/geoip/Makefile bin/tests/system/gost/prereq.sh bin/tests/system/lwresd/Makefile bin/tests/system/rpz/Makefile bin/tests/system/rsabigexponent/Makefile bin/tests/system/tkey/Makefile bin/tests/system/tsiggss/Makefile bin/tests/tasks/Makefile bin/tests/timers/Makefile bin/tests/virtual-time/Makefile bin/tests/virtual-time/conf.sh bin/tools/Makefile contrib/check-secure-delegation.pl contrib/zone-edit.sh doc/Makefile doc/arm/Makefile doc/doxygen/Doxyfile doc/doxygen/Makefile doc/doxygen/doxygen-input-filter doc/misc/Makefile doc/xsl/Makefile doc/xsl/isc-docbook-chunk.xsl doc/xsl/isc-docbook-html.xsl doc/xsl/isc-docbook-latex.xsl doc/xsl/isc-manpage.xsl isc-config.sh lib/Makefile lib/bind9/Makefile lib/bind9/include/Makefile lib/bind9/include/bind9/Makefile lib/dns/Makefile lib/dns/include/Makefile lib/dns/include/dns/Makefile lib/dns/include/dst/Makefile lib/dns/tests/Makefile lib/export/Makefile lib/export/dns/Makefile lib/export/dns/include/Makefile lib/export/dns/include/dns/Makefile lib/export/dns/include/dst/Makefile lib/export/irs/Makefile lib/export/irs/include/Makefile lib/export/irs/include/irs/Makefile lib/export/isc/$thread_dir/Makefile lib/export/isc/$thread_dir/include/Makefile lib/export/isc/$thread_dir/include/isc/Makefile lib/export/isc/Makefile lib/export/isc/include/Makefile lib/export/isc/include/isc/Makefile lib/export/isc/nls/Makefile lib/export/isc/unix/Makefile lib/export/isc/unix/include/Makefile lib/export/isc/unix/include/isc/Makefile lib/export/isccfg/Makefile lib/export/isccfg/include/Makefile lib/export/isccfg/include/isccfg/Makefile lib/export/samples/Makefile lib/export/samples/Makefile-postinstall lib/irs/Makefile lib/irs/include/Makefile lib/irs/include/irs/Makefile lib/irs/include/irs/netdb.h lib/irs/include/irs/platform.h lib/isc/$arch/Makefile lib/isc/$arch/include/Makefile lib/isc/$arch/include/isc/Makefile lib/isc/$thread_dir/Makefile lib/isc/$thread_dir/include/Makefile lib/isc/$thread_dir/include/isc/Makefile lib/isc/Makefile lib/isc/include/Makefile lib/isc/include/isc/Makefile lib/isc/include/isc/platform.h lib/isc/tests/Makefile lib/isc/nls/Makefile lib/isc/unix/Makefile lib/isc/unix/include/Makefile lib/isc/unix/include/isc/Makefile lib/isccc/Makefile lib/isccc/include/Makefile lib/isccc/include/isccc/Makefile lib/isccfg/Makefile lib/isccfg/include/Makefile lib/isccfg/include/isccfg/Makefile lib/lwres/Makefile lib/lwres/include/Makefile lib/lwres/include/lwres/Makefile lib/lwres/include/lwres/netdb.h lib/lwres/include/lwres/platform.h lib/lwres/man/Makefile lib/lwres/unix/Makefile lib/lwres/unix/include/Makefile lib/lwres/unix/include/lwres/Makefile lib/tests/Makefile lib/tests/include/Makefile lib/tests/include/tests/Makefile unit/Makefile unit/unittest.sh"
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -21846,6 +21851,7 @@ do
|
|||||||
"bin/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/pkcs11/Makefile" ;;
|
"bin/pkcs11/Makefile") CONFIG_FILES="$CONFIG_FILES bin/pkcs11/Makefile" ;;
|
||||||
"bin/python/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/Makefile" ;;
|
"bin/python/Makefile") CONFIG_FILES="$CONFIG_FILES bin/python/Makefile" ;;
|
||||||
"bin/python/dnssec-checkds.py") CONFIG_FILES="$CONFIG_FILES bin/python/dnssec-checkds.py" ;;
|
"bin/python/dnssec-checkds.py") CONFIG_FILES="$CONFIG_FILES bin/python/dnssec-checkds.py" ;;
|
||||||
|
"bin/python/dnssec-coverage.py") CONFIG_FILES="$CONFIG_FILES bin/python/dnssec-coverage.py" ;;
|
||||||
"bin/rndc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/rndc/Makefile" ;;
|
"bin/rndc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/rndc/Makefile" ;;
|
||||||
"bin/tests/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/Makefile" ;;
|
"bin/tests/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/Makefile" ;;
|
||||||
"bin/tests/atomic/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/atomic/Makefile" ;;
|
"bin/tests/atomic/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/atomic/Makefile" ;;
|
||||||
|
@@ -179,6 +179,7 @@ except: exit(1)'
|
|||||||
unspec)
|
unspec)
|
||||||
PYTHON=""
|
PYTHON=""
|
||||||
AC_SUBST(CHECKDS)
|
AC_SUBST(CHECKDS)
|
||||||
|
AC_SUBST(COVERAGE)
|
||||||
AC_MSG_RESULT([not found, python disabled])
|
AC_MSG_RESULT([not found, python disabled])
|
||||||
;;
|
;;
|
||||||
yes)
|
yes)
|
||||||
@@ -192,11 +193,14 @@ esac
|
|||||||
|
|
||||||
PYTHON_TOOLS=''
|
PYTHON_TOOLS=''
|
||||||
CHECKDS=''
|
CHECKDS=''
|
||||||
|
COVERAGE=''
|
||||||
if test "X$PYTHON" != "X"; then
|
if test "X$PYTHON" != "X"; then
|
||||||
PYTHON_TOOLS=python
|
PYTHON_TOOLS=python
|
||||||
CHECKDS=checkds
|
CHECKDS=checkds
|
||||||
|
COVERAGE=coverage
|
||||||
fi
|
fi
|
||||||
AC_SUBST(CHECKDS)
|
AC_SUBST(CHECKDS)
|
||||||
|
AC_SUBST(COVERAGE)
|
||||||
AC_SUBST(PYTHON_TOOLS)
|
AC_SUBST(PYTHON_TOOLS)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -3778,6 +3782,7 @@ AC_CONFIG_FILES([
|
|||||||
bin/pkcs11/Makefile
|
bin/pkcs11/Makefile
|
||||||
bin/python/Makefile
|
bin/python/Makefile
|
||||||
bin/python/dnssec-checkds.py
|
bin/python/dnssec-checkds.py
|
||||||
|
bin/python/dnssec-coverage.py
|
||||||
bin/rndc/Makefile
|
bin/rndc/Makefile
|
||||||
bin/tests/Makefile
|
bin/tests/Makefile
|
||||||
bin/tests/atomic/Makefile
|
bin/tests/atomic/Makefile
|
||||||
|
@@ -17504,6 +17504,8 @@ zone "example.com" {
|
|||||||
<title>Manual pages</title>
|
<title>Manual pages</title>
|
||||||
<xi:include href="../../bin/dig/dig.docbook"/>
|
<xi:include href="../../bin/dig/dig.docbook"/>
|
||||||
<xi:include href="../../bin/dig/host.docbook"/>
|
<xi:include href="../../bin/dig/host.docbook"/>
|
||||||
|
<xi:include href="../../bin/python/dnssec-checkds.docbook"/>
|
||||||
|
<xi:include href="../../bin/python/dnssec-coverage.docbook"/>
|
||||||
<xi:include href="../../bin/dnssec/dnssec-dsfromkey.docbook"/>
|
<xi:include href="../../bin/dnssec/dnssec-dsfromkey.docbook"/>
|
||||||
<xi:include href="../../bin/dnssec/dnssec-keyfromlabel.docbook"/>
|
<xi:include href="../../bin/dnssec/dnssec-keyfromlabel.docbook"/>
|
||||||
<xi:include href="../../bin/dnssec/dnssec-keygen.docbook"/>
|
<xi:include href="../../bin/dnssec/dnssec-keygen.docbook"/>
|
||||||
|
Reference in New Issue
Block a user