summaryrefslogtreecommitdiffstats
path: root/contrib/scripts
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 07:24:22 +0000
commit45d6379135504814ab723b57f0eb8be23393a51d (patch)
treed4f2ec4acca824a8446387a758b0ce4238a4dffa /contrib/scripts
parentInitial commit. (diff)
downloadbind9-upstream.tar.xz
bind9-upstream.zip
Adding upstream version 1:9.16.44.upstream/1%9.16.44upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--contrib/scripts/catzhash.py35
-rw-r--r--contrib/scripts/check-secure-delegation.pl.in116
-rw-r--r--contrib/scripts/check5011.pl210
-rw-r--r--contrib/scripts/dnssec-keyset.sh207
-rw-r--r--contrib/scripts/named-bootconf.sh301
-rw-r--r--contrib/scripts/nanny.pl49
-rw-r--r--contrib/scripts/zone-edit.sh.in153
7 files changed, 1071 insertions, 0 deletions
diff --git a/contrib/scripts/catzhash.py b/contrib/scripts/catzhash.py
new file mode 100644
index 0000000..98f6c9e
--- /dev/null
+++ b/contrib/scripts/catzhash.py
@@ -0,0 +1,35 @@
+#!/usr/bin/python
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# catzhash.py: generate the SHA-1 hash of a domain name in wire format.
+#
+# This can be used to determine the label to use in a catalog zone to
+# represent the specified zone. For example, the zone
+# "domain.example" can be represented in a catalog zone called
+# "catalog.example" by adding the following record:
+#
+# 5960775ba382e7a4e09263fc06e7c00569b6a05c.zones.catalog.example. \
+# IN PTR domain.example.
+#
+# The label "5960775ba382e7a4e09263fc06e7c00569b6a05c" is the output of
+# this script when run with the argument "domain.example".
+
+import sys
+import hashlib
+import dns.name
+
+if len(sys.argv) < 2:
+ print("Usage: %s name" % sys.argv[0])
+
+NAME = dns.name.from_text(sys.argv[1]).to_wire()
+print(hashlib.sha1(NAME).hexdigest())
diff --git a/contrib/scripts/check-secure-delegation.pl.in b/contrib/scripts/check-secure-delegation.pl.in
new file mode 100644
index 0000000..f2a3a19
--- /dev/null
+++ b/contrib/scripts/check-secure-delegation.pl.in
@@ -0,0 +1,116 @@
+#!@PERL@
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+use warnings;
+use FileHandle;
+use IPC::Open2;
+use POSIX qw/strftime/;
+
+#
+# We only compare keyid / DNSSEC algorithm pairs. If this succeeds then
+# the crypto will likely succeed. If it fails then the crypto will definitely
+# fail.
+#
+$prefix = "@prefix@";
+$dig = "$prefix/bin/dig +cd +dnssec +noall +answer";
+$dsfromkey = "$prefix/sbin/dnssec-dsfromkey -1 -A -f /dev/stdin";
+
+# Get "now" in a RRSIG datestamp format.
+$now = strftime "%Y%m%d%H%M%S", gmtime;
+
+foreach $zone (@ARGV) {
+ my %algorithms = ();
+ my %dnskeygood = ();
+ my %dnskeyalg = ();
+ my %dnskey = ();
+ my %dsgood = ();
+ my %ds = ();
+
+ # Read the DS records and extract the key id, algorithm pairs
+ open(DS, "$dig -t DS -q $zone|") || die("dig DS failed");
+ while(<DS>) {
+ @words = split;
+ if ($words[3] eq "RRSIG" && $words[4] eq "DS") {
+ next if ($words[8] >= $now && $words[9] <= $now);
+ print "BAD SIG DATES: $_";
+ }
+ next if ($words[3] ne "DS");
+ $ds{"$words[4] $words[5]"} = 1;
+ $algorithms{"$words[5]"} = 1;
+ }
+ close(DS);
+
+ # Read the RRSIG(DNSKEY) records and extract the key id,
+ # algorithm pairs. Set good if we have a match against the DS
+ # records. DNSKEY records should be before the RRSIG records.
+ open(DNSKEY, "$dig -t DNSKEY -q $zone|") || die("dig DNSKEY failed");
+ while (<DNSKEY>) {
+ @words = split;
+ if ($words[3] eq "DNSKEY") {
+ $dnskeyalg{"$words[6]"} = 1;
+ next if (! -e "/dev/stdin");
+ # get the key id ($dswords[3]).
+ $pid = open2(*Reader, *Writer, "$dsfromkey $zone");
+ die("dsfromkey failed") if ($pid == -1);
+ print Writer "$_";
+ close(Writer);
+ $line = <Reader>;
+ close(Reader);
+ @dswords = split /\s/, $line;
+ $dnskey{"$dswords[3] $dswords[4]"} = 1;
+ next;
+ }
+ next if ($words[3] ne "RRSIG" || $words[4] ne "DNSKEY");
+ if ($words[8] >= $now && $words[9] <= $now) {
+ # If we don't have /dev/stdin then just check for the
+ # RRSIG otherwise check for both the DNSKEY and
+ # RRSIG.
+ $dsgood{"$words[5]"} = 1
+ if (! -e "/dev/stdin" &&
+ exists($ds{"$words[10] $words[5]"}));
+ $dsgood{"$words[5]"} = 1
+ if (exists($ds{"$words[10] $words[5]"}) &&
+ exists($dnskey{"$words[10] $words[5]"}));
+ $dnskeygood{"$words[5]"} = 1
+ if (! -e "/dev/stdin");
+ $dnskeygood{"$words[5]"} = 1
+ if (exists($dnskey{"$words[10] $words[5]"}));
+ } else {
+ $dnskeygood{"$words[5]"} = 1;
+ print "BAD SIG DATES: $_";
+ }
+ }
+ close(DNSKEY);
+
+ # Do we have signatures for all DNSKEY algorithms?
+ foreach $alg ( keys %dnskeyalg ) {
+ print "Missing $zone DNSKEY RRSIG for algorithm $alg\n"
+ if (!exists($dnskeygood{$alg}));
+ }
+
+ # Do we have a matching self signed DNSKEY for all DNSSEC algorithms
+ # in the DS records.
+ $count = 0;
+ foreach $alg ( keys %algorithms ) {
+ if (exists($dsgood{$alg})) {
+ print "$zone algorithm $alg good " .
+ "(found DS / self signed DNSKEY pair)\n";
+ } else {
+ print "$zone algorithm $alg bad " .
+ "(no DS / self signed DNSKEY pair found)\n";
+ }
+ $count++;
+ }
+ print "$zone has no secure delegation records\n"
+ if (! $count);
+}
diff --git a/contrib/scripts/check5011.pl b/contrib/scripts/check5011.pl
new file mode 100644
index 0000000..814295a
--- /dev/null
+++ b/contrib/scripts/check5011.pl
@@ -0,0 +1,210 @@
+#!/usr/bin/perl
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+use warnings;
+use strict;
+
+use POSIX qw(strftime);
+my $now = strftime "%Y%m%d%H%M%S", gmtime;
+
+sub ext8601 ($) {
+ my $d = shift;
+ $d =~ s{(....)(..)(..)(..)(..)(..)}
+ {$1-$2-$3.$4:$5:$6+0000};
+ return $d;
+}
+
+sub getkey ($$) {
+ my $h = shift;
+ my $k = shift;
+ m{\s+(\d+)\s+(\d+)\s+(\d+)\s+[(]\s*$};
+ $k->{flags} = $1;
+ $k->{protocol} = $2;
+ $k->{algorithm} = $3;
+ my $data = "(";
+ while (<$h>) {
+ s{^\s+}{};
+ s{\s+$}{};
+ last if m{^[)]};
+ $data .= $_;
+ }
+ m{ alg = (\S+)\s*; key id = (\d+)};
+ $k->{alg} = $1;
+ $k->{id} = $2;
+ $k->{data} = $data;
+ return $k;
+}
+
+sub fmtkey ($) {
+ my $k = shift;
+ return sprintf "%16s tag %s", $k->{name}, $k->{id};
+}
+
+sub printstatus ($) {
+ my $a = shift;
+ if ($a->{removehd} ne "19700101000000") {
+ printf " untrusted and to be removed at %s\n", ext8601 $a->{removehd};
+ } elsif ($a->{addhd} le $now) {
+ printf " trusted\n";
+ } else {
+ printf " waiting for %s\n", ext8601 $a->{addhd};
+ }
+}
+
+sub digkeys ($) {
+ my $name = shift;
+ my $keys;
+ open my $d, "-|", qw{dig +multiline DNSKEY}, $name;
+ while (<$d>) {
+ next unless m{^([a-z0-9.-]*)\s+\d+\s+IN\s+DNSKEY\s+};
+ next unless $name eq $1;
+ push @$keys, getkey $d, { name => $name };
+ }
+ return $keys;
+}
+
+my $anchor;
+my $owner = ".";
+while (<>) {
+ next unless m{^([a-z0-9.-]*)\s+KEYDATA\s+(\d+)\s+(\d+)\s+(\d+)\s+};
+ my $k = getkey *ARGV, {
+ name => $1,
+ refresh => $2,
+ addhd => $3,
+ removehd => $4,
+ };
+ if ($k->{name} eq "") {
+ $k->{name} = $owner;
+ } else {
+ $owner = $k->{name};
+ }
+ $k->{name} =~ s{[.]*$}{.};
+ push @{$anchor->{$k->{name}}}, $k;
+}
+
+for my $name (keys %$anchor) {
+ my $keys = digkeys $name;
+ my $anchors = $anchor->{$name};
+ for my $k (@$keys) {
+ if ($k->{flags} & 1) {
+ printf "%s %s", fmtkey $k, $k->{alg};
+ } else {
+ # ZSK - skipping
+ next;
+ }
+ if ($k->{flags} & 512) {
+ print " revoked;";
+ }
+ my $a;
+ for my $t (@$anchors) {
+ if ($t->{data} eq $k->{data} and
+ $t->{protocol} eq $k->{protocol} and
+ $t->{algorithm} eq $k->{algorithm}) {
+ $t->{matched} = 1;
+ $a = $t;
+ last;
+ }
+ }
+ if (not defined $a) {
+ print " no trust anchor\n";
+ next;
+ }
+ printstatus $a;
+ }
+ for my $a (@$anchors) {
+ next if $a->{matched};
+ printf "%s %s missing;", fmtkey $a, $a->{alg};
+ printstatus $a;
+ }
+}
+
+exit;
+
+__END__
+
+=head1 NAME
+
+check5011 - summarize DNSSEC trust anchor status
+
+=head1 SYNOPSIS
+
+check5011 <I<managed-keys.bind>>
+
+=head1 DESCRIPTION
+
+The BIND managed-keys file contains DNSSEC trust anchors
+that can be automatically updated according to RFC 5011. The
+B<check5011> program reads this file and prints a summary of the
+status of the trust anchors. It fetches the corresponding
+DNSKEY records using B<dig> and compares them to the trust anchors.
+
+Each key is printed on a line with its name, its tag, and its
+algorithm, followed by a summary of its status.
+
+=over
+
+=item C<trusted>
+
+The key is currently trusted.
+
+=item C<waiting for ...>
+
+The key is new, and B<named> is waiting for the "add hold-down" period
+to pass before the key will be trusted.
+
+=item C<untrusted and to be removed at ...>
+
+The key was revoked and will be removed at the stated time.
+
+=item C<no trust anchor>
+
+The key is present in the DNS but not in the managed-keys file.
+
+=item C<revoked>
+
+The key has its revoked flag set. This is printed before the key's
+trust anchor status which should normally be C<untrusted...> if
+B<named> has observed the revocation.
+
+=item C<missing>
+
+There is no DNSKEY record for this trust anchor. This is printed
+before the key's trust anchor status.
+
+=back
+
+By default the managed keys are stored in a file called
+F<managed-keys.bind> in B<named>'s working directory. This location
+can be changed with B<named>'s B<managed-keys-directory> option. If
+you are using views the file may be named with the SHA256 hash of a
+view name with a F<.mkeys> extension added.
+
+=head1 AUTHOR
+
+=over
+
+=item Written by Tony Finch <fanf2@cam.ac.uk> <dot@dotat.at>
+
+=item at the University of Cambridge Computing Service.
+
+=item You may do anything with this. It has no warranty.
+
+=item L<http://creativecommons.org/publicdomain/zero/1.0/>
+
+=back
+
+=head1 SEE ALSO
+
+dig(1), named(8)
+
+=cut
diff --git a/contrib/scripts/dnssec-keyset.sh b/contrib/scripts/dnssec-keyset.sh
new file mode 100644
index 0000000..9bf02c6
--- /dev/null
+++ b/contrib/scripts/dnssec-keyset.sh
@@ -0,0 +1,207 @@
+#!/bin/sh
+
+# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+HELP="
+Generates a set of <count> successive DNSSEC keys for <zone>
+Key timings are based on a pre-publication rollover strategy
+
+ <life> (lifetime) is the key active lifetime in days [default 180]
+ <intro> (introduction time) is the number of days from publication
+ to activation of a key [default 30]
+ <ret> (retirement time) is the number of days from inactivation
+ to deletion of a key [default 30]
+
+Options:
+ -a <alg> Cryptographic algorithm. See man dnssec-keygen for defaults.
+ -b <bits> Number of bits in the key. See man dnssec-keygen for defaults.
+ -k if present, generate Key Signing Keys (KSKs). Otherwise,
+ generate Zone Signing Keys (ZSKs).
+ -3 If present and if -a is not specified, use an NSEC3-
+ capable algorithm. See man dnssec-keygen for defaults.
+ -i <date> Inception date of the set of keys, in 'mm/dd/yyyy' format.
+ The first two keys will be published by this date, and the
+ first one will be activated. Default is today.
+ -f <index> Index of first key generated. Defaults to 0.
+ -K <dir> Key repository: write keys to this directory. Defaults to CWD.
+ -d Dry run. No actual keys generated if present."
+
+USAGE="Usage:
+`basename $0` [-a <alg>] [-b <bits>] [-k] [-3] [-i <date>]
+ [-f <index>] [-d] <zone> <count> [<life>] [<intro>] [<ret>]"
+
+ALGFLAG=''
+BITSFLAG=''
+KSKFLAG=''
+NSEC3FLAG=''
+KEYREPO=''
+DRYRUN=false
+OPTKSK=false
+K=0
+INCEP=`date +%m/%d/%Y`
+
+# Parse command line options
+while getopts ":a:b:df:hkK:3i:" thisOpt
+do
+ case $thisOpt in
+ a)
+ ALGFLAG=" -a $OPTARG"
+ ;;
+ b)
+ BITSFLAG=" -b $OPTARG"
+ ;;
+ d)
+ DRYRUN=true
+ ;;
+ f)
+ OPTKSK=true
+ K=$OPTARG
+ ;;
+ h)
+ echo "$USAGE"
+ echo "$HELP"
+ exit 0
+ ;;
+ k)
+ KSKFLAG=" -f KSK"
+ ;;
+ K)
+ KEYREPO=$OPTARG
+ ;;
+ 3)
+ NSEC3FLAG=" -3"
+ ;;
+ i)
+ INCEP=$OPTARG
+ ;;
+ *)
+ echo 'Unrecognized option.'
+ echo "$USAGE"
+ exit 1
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+# Check that required arguments are present
+if [ $# -gt 5 -o $# -lt 2 ]; then
+ echo "$USAGE"
+ exit 1
+fi
+
+# Remaining arguments:
+# DNS zone name
+ZONE=$1
+shift
+
+# Number of keys to be generated
+COUNT=$1
+shift
+
+# Key active lifetime
+LIFE=${1:-180}
+[ $# -ne 0 ] && shift
+
+# Key introduction time (publication to activation)
+INTRO=${1:-30}
+[ $# -ne 0 ] && shift
+
+# Key retirement time (inactivation to deletion)
+RET=${1:-30}
+
+# Today's date in dnssec-keygen format (YYYYMMDD)
+TODAY=`date +%Y%m%d`
+
+# Key repository defaults to CWD
+if [ -z "$KEYREPO" ]; then
+ KEYREPO="."
+fi
+
+if $DRYRUN; then
+ echo 'Dry Run (no key files generated)'
+elif [ ! -d "$KEYREPO" ]; then
+ # Create the key repository if it does not currently exist
+ mkdir -p "$KEYREPO"
+fi
+
+# Iterate through the key set. K is the index, zero-based.
+KLAST=`expr $K + $COUNT`
+while [ $K -lt $KLAST ]; do
+ KEYLABEL="Key `printf \"%02d\" $K`:"
+ # Epoch of the current key
+ # (zero for the first key, increments of key lifetime)
+ # The epoch is in days relative to the inception date of the key set
+ EPOCH=`expr $LIFE \* $K`
+ # Activation date in days is the same as the epoch
+ ACTIVATE=$EPOCH
+ # Publication date in days relative to the key epoch
+ PUBLISH=`expr $EPOCH - $LIFE - $INTRO`
+ # Inactivation date in days relative to the key epoch
+ INACTIVE=`expr $EPOCH + $LIFE`
+ # Deletion date in days relative to the key epoch
+ DELETE=`expr $EPOCH + $LIFE + $RET`
+
+ # ... these values should not precede the key epoch
+ [ $ACTIVATE -lt 0 ] && ACTIVATE=0
+ [ $PUBLISH -lt 0 ] && PUBLISH=0
+ [ $INACTIVE -lt 0 ] && INACTIVE=0
+ [ $DELETE -lt 0 ] && DELETE=0
+
+ # Key timing dates in dnssec-keygen format (YYYYMMDD):
+ # publication, activation, inactivation, deletion
+ PDATE=`date -d "$INCEP +$PUBLISH day" +%Y%m%d`
+ ADATE=`date -d "$INCEP +$ACTIVATE day" +%Y%m%d`
+ IDATE=`date -d "$INCEP +$INACTIVE day" +%Y%m%d`
+ DDATE=`date -d "$INCEP +$DELETE day" +%Y%m%d`
+
+ # Construct the dnssec-keygen command including all the specified options.
+ # Suppress key generation progress information, and save the key in
+ # the $KEYREPO directory.
+ KEYGENCMD="dnssec-keygen -q$ALGFLAG$BITSFLAG$NSEC3FLAG$KSKFLAG -P $PDATE -A $ADATE -I $IDATE -D $DDATE -K $KEYREPO $ZONE"
+ echo "$KEYLABEL $KEYGENCMD"
+
+ # Generate the key and retrieve its name
+ if $DRYRUN; then
+ KEYNAME="DryRunKey-`printf \"%02d\" $K`"
+ else
+ KEYNAME=`$KEYGENCMD`
+ fi
+
+ # Indicate the key status based on key timing dates relative to today
+ if [ $TODAY -ge $DDATE ]; then
+ echo "$KEYLABEL $KEYNAME is obsolete post deletion date."
+ elif [ $TODAY -ge $IDATE ]; then
+ echo "$KEYLABEL $KEYNAME is published and inactive prior to deletion date."
+ elif [ $TODAY -ge $ADATE ]; then
+ echo "$KEYLABEL $KEYNAME is published and active."
+ elif [ $TODAY -ge $PDATE ]; then
+ echo "$KEYLABEL $KEYNAME is published prior to activation date."
+ else
+ echo "$KEYLABEL $KEYNAME is pending publication."
+ fi
+
+ # For published KSKs, generate the required DS records,
+ # saving them to the file $KEYREPO/DS-$KEYNAME
+ if $OPTKSK && [ $TODAY -ge $PDATE -a $TODAY -lt $DDATE ]; then
+ echo "$KEYLABEL $KEYNAME (KSK) requires the publication of DS records in the parent zone."
+ if $DRYRUN; then
+ echo "$KEYLABEL No DS-$KEYNAME file created."
+ else
+ dnssec-dsfromkey "$KEYREPO/$KEYNAME" > "$KEYREPO/DS-$KEYNAME"
+ echo "$KEYLABEL See $KEYREPO/DS-$KEYNAME."
+ fi
+ fi
+ K=`expr $K + 1`
+done
+
+exit 0
diff --git a/contrib/scripts/named-bootconf.sh b/contrib/scripts/named-bootconf.sh
new file mode 100644
index 0000000..273588d
--- /dev/null
+++ b/contrib/scripts/named-bootconf.sh
@@ -0,0 +1,301 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# $NetBSD: named-bootconf.sh,v 1.5 1998/12/15 01:00:53 tron Exp $
+#
+# Copyright (c) 1995, 1998 The NetBSD Foundation, Inc.
+# All rights reserved.
+#
+# This code is derived from software contributed to The NetBSD Foundation
+# by Matthias Scheler.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+
+if [ ${OPTIONFILE-X} = X ]; then
+ WORKDIR=/tmp/`date +%s`.$$
+ ( umask 077 ; mkdir $WORKDIR ) || {
+ echo "unable to create work directory '$WORKDIR'" >&2
+ exit 1
+ }
+ OPTIONFILE=$WORKDIR/options
+ ZONEFILE=$WORKDIR/zones
+ COMMENTFILE=$WORKDIR/comments
+ export OPTIONFILE ZONEFILE COMMENTFILE
+ touch $OPTIONFILE $ZONEFILE $COMMENTFILE
+ DUMP=1
+else
+ DUMP=0
+fi
+
+while read CMD ARGS; do
+ class=
+ CMD=`echo "${CMD}" | tr '[A-Z]' '[a-z]'`
+ case $CMD in
+ \; )
+ echo \# $ARGS >>$COMMENTFILE
+ ;;
+ cache )
+ set - X $ARGS
+ shift
+ if [ $# -eq 2 ]; then
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$1\" {"
+ echo " type hint;"
+ echo " file \"$2\";"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ directory )
+ set - X $ARGS
+ shift
+ if [ $# -eq 1 ]; then
+ (cat $COMMENTFILE
+ echo " directory \"$1\";") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+
+ DIRECTORY=$1
+ export DIRECTORY
+ fi
+ ;;
+ forwarders )
+ (cat $COMMENTFILE
+ echo " forwarders {"
+ for ARG in $ARGS; do
+ echo " $ARG;"
+ done
+ echo " };") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ include )
+ if [ "$ARGS" != "" ]; then
+ (cd ${DIRECTORY-.}; cat $ARGS) | $0
+ fi
+ ;;
+ limit )
+ ARGS=`echo "${ARGS}" | tr '[A-Z]' '[a-z]'`
+ set - X $ARGS
+ shift
+ if [ $# -eq 2 ]; then
+ cat $COMMENTFILE >>$OPTIONFILE
+ case $1 in
+ datasize | files | transfers-in | transfers-per-ns )
+ echo " $1 $2;" >>$OPTIONFILE
+ ;;
+ esac
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ options )
+ ARGS=`echo "${ARGS}" | tr '[A-Z]' '[a-z]'`
+ cat $COMMENTFILE >>$OPTIONFILE
+ for ARG in $ARGS; do
+ case $ARG in
+ fake-iquery )
+ echo " fake-iquery yes;" >>$OPTIONFILE
+ ;;
+ forward-only )
+ echo " forward only;" >>$OPTIONFILE
+ ;;
+ no-fetch-glue )
+ echo " fetch-glue no;" >>$OPTIONFILE
+ ;;
+ no-recursion )
+ echo " recursion no;" >>$OPTIONFILE
+ ;;
+ esac
+ done
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ primary|primary/* )
+ case $CMD in
+ primary/chaos )
+ class="chaos "
+ ;;
+ primary/hs )
+ class="hesiod "
+ ;;
+ esac
+ set - X $ARGS
+ shift
+ if [ $# -eq 2 ]; then
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$1\" ${class}{"
+ echo " type master;"
+ echo " file \"$2\";"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ secondary|secondary/* )
+ case $CMD in
+ secondary/chaos )
+ class="chaos "
+ ;;
+ secondary/hs )
+ class="hesiod "
+ ;;
+ esac
+ set - X $ARGS
+ shift
+ if [ $# -gt 2 ]; then
+ ZONE=$1
+ shift
+ PRIMARIES=$1
+ while [ $# -gt 2 ]; do
+ shift
+ PRIMARIES="$PRIMARIES $1"
+ done
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$ZONE\" ${class}{"
+ echo " type slave;"
+ echo " file \"$2\";"
+ echo " masters {"
+ for PRIMARY in $PRIMARIES; do
+ echo " $PRIMARY;"
+ done
+ echo " };"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ stub|stub/* )
+ case $CMD in
+ stub/chaos )
+ class="chaos "
+ ;;
+ stub/hs )
+ class="hesiod "
+ ;;
+ esac
+ set - X $ARGS
+ shift
+ if [ $# -gt 2 ]; then
+ ZONE=$1
+ shift
+ PRIMARIES=$1
+ while [ $# -gt 2 ]; do
+ shift
+ PRIMARIES="$PRIMARIES $1"
+ done
+ (echo ""
+ cat $COMMENTFILE
+ echo "zone \"$ZONE\" ${class}{"
+ echo " type stub;"
+ echo " file \"$2\";"
+ echo " masters {"
+ for PRIMARY in $PRIMARIES; do
+ echo " $PRIMARY;"
+ done
+ echo " };"
+ echo "};") >>$ZONEFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ fi
+ ;;
+ slave )
+ cat $COMMENTFILE >>$OPTIONFILE
+ echo " forward only;" >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ sortlist )
+ (cat $COMMENTFILE
+ echo " topology {"
+ for ARG in $ARGS; do
+ case $ARG in
+ *.0.0.0 )
+ echo " $ARG/8;"
+ ;;
+ *.0.0 )
+ echo " $ARG/16;"
+ ;;
+ *.0 )
+ echo " $ARG/24;"
+ ;;
+ * )
+ echo " $ARG;"
+ ;;
+ esac
+ done
+ echo " };") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ tcplist | xfrnets )
+ (cat $COMMENTFILE
+ echo " allow-transfer {"
+ for ARG in $ARGS; do
+ case $ARG in
+ *.0.0.0 )
+ echo " $ARG/8;"
+ ;;
+ *.0.0 )
+ echo " $ARG/16;"
+ ;;
+ *.0 )
+ echo " $ARG/24;"
+ ;;
+ * )
+ echo " $ARG;"
+ ;;
+ esac
+ done
+ echo " };") >>$OPTIONFILE
+ rm -f $COMMENTFILE
+ touch $COMMENTFILE
+ ;;
+ esac
+done
+
+if [ $DUMP -eq 1 ]; then
+ echo ""
+ echo "options {"
+ cat $OPTIONFILE
+ echo "};"
+ cat $ZONEFILE $COMMENTFILE
+
+ rm -f $OPTIONFILE $ZONEFILE $COMMENTFILE
+ rmdir $WORKDIR
+fi
+
+exit 0
diff --git a/contrib/scripts/nanny.pl b/contrib/scripts/nanny.pl
new file mode 100644
index 0000000..27a159e
--- /dev/null
+++ b/contrib/scripts/nanny.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+# A simple nanny to make sure named stays running.
+
+$pid_file_location = '/var/run/named.pid';
+$nameserver_location = 'localhost';
+$dig_program = 'dig';
+$named_program = 'named';
+
+fork() && exit();
+
+for (;;) {
+ $pid = 0;
+ open(FILE, $pid_file_location) || goto restart;
+ $pid = <FILE>;
+ close(FILE);
+ chomp($pid);
+
+ $res = kill 0, $pid;
+
+ goto restart if ($res == 0);
+
+ $dig_command =
+ "$dig_program +short . \@$nameserver_location > /dev/null";
+ $return = system($dig_command);
+ goto restart if ($return == 9);
+
+ sleep 30;
+ next;
+
+ restart:
+ if ($pid != 0) {
+ kill 15, $pid;
+ sleep 30;
+ }
+ system ($named_program);
+ sleep 120;
+}
diff --git a/contrib/scripts/zone-edit.sh.in b/contrib/scripts/zone-edit.sh.in
new file mode 100644
index 0000000..a4e076d
--- /dev/null
+++ b/contrib/scripts/zone-edit.sh.in
@@ -0,0 +1,153 @@
+#!/bin/sh
+
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+dir=/tmp/zone-edit.$$
+mkdir ${dir} || exit 1
+trap "/bin/rm -rf ${dir}" 0
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+sbindir=@sbindir@
+
+dig=${bindir}/dig
+checkzone=${sbindir}/named-checkzone
+nsupdate=${bindir}/nsupdate
+
+case $# in
+0) echo "Usage: zone-edit <zone> [dig options] [ -- nsupdate options ]"; exit 0 ;;
+esac
+
+# What kind of echo are we using?
+try=`echo -n ""`
+if test "X$try" = "X-n "
+then
+ echo_arg=""
+ bsc="\\c"
+else
+ echo_arg="-n"
+ bsc=""
+fi
+
+zone="${1}"
+shift
+digopts=
+while test $# -ne 0
+do
+ case "${1}" in
+ --)
+ shift
+ break
+ ;;
+ *)
+ digopts="$digopts $1"
+ shift
+ ;;
+ esac
+done
+
+${dig} axfr "$zone" $digopts |
+awk '$4 == "RRSIG" || $4 == "NSEC" || $4 == "NSEC3" || $4 == "NSEC3PARAM" { next; } { print; }' > ${dir}/old
+
+if test -s ${dir}/old
+then
+ ${checkzone} -q -D "$zone" ${dir}/old > ${dir}/ooo
+fi
+
+if test -s ${dir}/ooo
+then
+ cp ${dir}/ooo ${dir}/new
+ while :
+ do
+ if ${VISUAL:-${EDITOR:-/bin/ed}} ${dir}/new
+ then
+ if ${checkzone} -q -D "$zone" ${dir}/new > ${dir}/nnn
+ then
+ sort ${dir}/ooo > ${dir}/s1
+ sort ${dir}/nnn > ${dir}/s2
+ comm -23 ${dir}/s1 ${dir}/s2 |
+ sed 's/^/update delete /' > ${dir}/ccc
+ comm -13 ${dir}/s1 ${dir}/s2 |
+ sed 's/^/update add /' >> ${dir}/ccc
+ if test -s ${dir}/ccc
+ then
+ cat ${dir}/ccc | more
+ while :
+ do
+ echo ${echo_arg} "Update (u), Abort (a), Redo (r), Modify (m), Display (d) : $bsc"
+ read ans
+ case "$ans" in
+ u)
+ (
+ echo zone "$zone"
+ cat ${dir}/ccc
+ echo send
+ ) | ${nsupdate} "$@"
+ break 2
+ ;;
+ a)
+ break 2
+ ;;
+ d)
+ cat ${dir}/ccc | more
+ ;;
+ r)
+ cp ${dir}/ooo ${dir}/new
+ break
+ ;;
+ m)
+ break
+ ;;
+ esac
+ done
+ else
+ while :
+ do
+ echo ${echo_arg} "Abort (a), Redo (r), Modify (m) : $bsc"
+ read ans
+ case "$ans" in
+ a)
+ break 2
+ ;;
+ r)
+ cp ${dir}/ooo ${dir}/new
+ break
+ ;;
+ m)
+ break
+ ;;
+ esac
+ done
+ fi
+ else
+ while :
+ do
+ echo ${echo_arg} "Abort (a), Redo (r), Modify (m) : $bsc"
+ read ans
+ case "$ans" in
+ a)
+ break 2
+ ;;
+ r)
+ cp ${dir}/ooo ${dir}/new
+ break
+ ;;
+ m)
+ break
+ ;;
+ esac
+ done
+ fi
+ fi
+ done
+fi