2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 05:57:52 +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:
Evan Hunt 2013-03-20 14:31:10 -07:00
parent 027591e157
commit 831f59eb43
29 changed files with 1326 additions and 8 deletions

View File

@ -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
request a particular XML schema from the statistics
channel, returning 404 if not supported. [RT #32481]

View File

@ -1,2 +1,4 @@
dnssec-checkds
dnssec-checkds.py
dnssec-coverage
dnssec-coverage.py

View File

@ -22,17 +22,19 @@ top_srcdir = @top_srcdir@
PYTHON = @PYTHON@
TARGETS = dnssec-checkds
SRCS = dnssec-checkds.py
TARGETS = dnssec-checkds dnssec-coverage
SRCS = dnssec-checkds.py dnssec-coverage.py
MANPAGES = dnssec-checkds.8
HTMLPAGES = dnssec-checkds.html
MANPAGES = dnssec-checkds.8 dnssec-coverage.8
HTMLPAGES = dnssec-checkds.html dnssec-coverage.html
MANOBJS = ${MANPAGES} ${HTMLPAGES}
@BIND9_MAKE_RULES@
dnssec-checkds: dnssec-checkds.py
dnssec-coverage: dnssec-coverage.py
doc man:: ${MANOBJS}
docclean manclean maintainer-clean::
@ -44,10 +46,12 @@ installdirs:
install:: ${TARGETS} installdirs
${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-coverage.8 ${DESTDIR}${mandir}/man8
clean distclean::
rm -f ${TARGETS}
distclean::
rm -f dnssec-checkds.py
rm -f dnssec-checkds.py dnssec-coverage.py

View 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 "&#8212;">]>
<!--
- 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
View 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()

View File

@ -44,6 +44,7 @@ REVOKE=$TOP/bin/dnssec/dnssec-revoke
SETTIME=$TOP/bin/dnssec/dnssec-settime
DSFROMKEY=$TOP/bin/dnssec/dnssec-dsfromkey
CHECKDS=$TOP/bin/python/dnssec-checkds
COVERAGE=$TOP/bin/python/dnssec-coverage
CHECKZONE=$TOP/bin/check/named-checkzone
CHECKCONF=$TOP/bin/check/named-checkconf
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.
# v6synth
SUBDIRS="acl additional allow_query addzone autosign builtin
cacheclean checkconf @CHECKDS@ checknames checkzone database
dlv dlvauto dlz dlzexternal dlzredir dname dns64 dnssec
cacheclean checkconf @CHECKDS@ checknames checkzone @COVERAGE@
database dlv dlvauto dlz dlzexternal dlzredir dname dns64 dnssec
dsdigest ecdsa formerr forward glue gost ixfr inline limits
logfileconfig lwresd masterfile masterformat metadata
notify nsupdate pending pkcs11 redirect resolver rndc rpz

View 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

View File

@ -0,0 +1,6 @@
args="-d 1h -m 2h"
warn=0
error=1
ok=1
retcode=1
match="No KSK's are active"

View 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

View File

@ -0,0 +1,6 @@
args="-d 1h -m 2h"
warn=0
error=1
ok=1
retcode=1
match="No ZSK's are active"

View 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

View 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"

View 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

View 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"

View 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

View 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"

View 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

View 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"

View File

@ -0,0 +1,4 @@
This set includes a KSK rollover, with insufficient delay between
prepublication and rollover.
Expected tool output TBD.

View 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."

View File

@ -0,0 +1,4 @@
This set includes a KSK rollover, with insufficient delay between
prepublication and rollover.
Expected tool output TBD.

View 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."

View 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

View 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`

View 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

View File

@ -1236,6 +1236,18 @@ israw1 signer/signer.out.7 || ret=1
if [ $ret != 0 ]; then echo "I:failed"; fi
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)"
ret=0
$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
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"
exit $status

8
configure vendored
View File

@ -1339,6 +1339,7 @@ ISC_PLATFORM_NORETURN_PRE
ISC_PLATFORM_HAVELONGLONG
ISC_SOCKADDR_LEN_T
PYTHON_TOOLS
COVERAGE
CHECKDS
PYTHON
PERL
@ -12206,6 +12207,7 @@ $as_echo "found, using $PYTHON" >&6; }
unspec)
PYTHON=""
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: not found, python disabled" >&5
$as_echo "not found, python disabled" >&6; }
;;
@ -12221,13 +12223,16 @@ esac
PYTHON_TOOLS=''
CHECKDS=''
COVERAGE=''
if test "X$PYTHON" != "X"; then
PYTHON_TOOLS=python
CHECKDS=checkds
COVERAGE=coverage
fi
#
# Special processing of paths depending on whether --prefix,
# --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.
#
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/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-coverage.py") CONFIG_FILES="$CONFIG_FILES bin/python/dnssec-coverage.py" ;;
"bin/rndc/Makefile") CONFIG_FILES="$CONFIG_FILES bin/rndc/Makefile" ;;
"bin/tests/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/Makefile" ;;
"bin/tests/atomic/Makefile") CONFIG_FILES="$CONFIG_FILES bin/tests/atomic/Makefile" ;;

View File

@ -179,6 +179,7 @@ except: exit(1)'
unspec)
PYTHON=""
AC_SUBST(CHECKDS)
AC_SUBST(COVERAGE)
AC_MSG_RESULT([not found, python disabled])
;;
yes)
@ -192,11 +193,14 @@ esac
PYTHON_TOOLS=''
CHECKDS=''
COVERAGE=''
if test "X$PYTHON" != "X"; then
PYTHON_TOOLS=python
CHECKDS=checkds
COVERAGE=coverage
fi
AC_SUBST(CHECKDS)
AC_SUBST(COVERAGE)
AC_SUBST(PYTHON_TOOLS)
#
@ -3778,6 +3782,7 @@ AC_CONFIG_FILES([
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

View File

@ -17504,6 +17504,8 @@ zone "example.com" {
<title>Manual pages</title>
<xi:include href="../../bin/dig/dig.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-keyfromlabel.docbook"/>
<xi:include href="../../bin/dnssec/dnssec-keygen.docbook"/>