CC: | "Tony Finch" <dot@dotat.at> |
Subject: | [PATCH] Alternative NSEC3 mode for nsec3hash |
Date: | Thu, 4 May 2017 16:57:28 +0100 |
To: | bind9-bugs@isc.org |
From: | "Tony Finch" <dot@dotat.at> |
When nsec3hash is invoked as NSEC3 it takes arguments in the same order
as the NSEC3 record presentation format. This makes it easy to invoke the
command by copy-and-paste from dig to sh without having to remember the
order of arguments.
---
bin/tests/system/conf.sh.in | 2 +
bin/tests/system/nsec3hash/clean.sh | 12 ++++++
bin/tests/system/nsec3hash/tests.sh | 76 +++++++++++++++++++++++++++++++++++++
bin/tools/.gitignore | 1 +
bin/tools/Makefile.in | 11 +++++-
bin/tools/nsec3hash.8 | 11 +++++-
bin/tools/nsec3hash.c | 70 ++++++++++++++++++++++++++--------
bin/tools/nsec3hash.docbook | 27 +++++++++++++
8 files changed, 192 insertions(+), 18 deletions(-)
create mode 100644 bin/tests/system/nsec3hash/clean.sh
create mode 100644 bin/tests/system/nsec3hash/tests.sh
diff --git a/bin/tests/system/conf.sh.in b/bin/tests/system/conf.sh.in
index 8e1bbd6..78ac6f4 100644
--- a/bin/tests/system/conf.sh.in
+++ b/bin/tests/system/conf.sh.in
@@ -49,6 +49,7 @@ ARPANAME=$TOP/bin/tools/arpaname
RESOLVE=$TOP/lib/samples/resolve
RRCHECKER=$TOP/bin/tools/named-rrchecker
GENRANDOM=$TOP/bin/tools/genrandom
+NSEC3HASH=$TOP/bin/tools/nsec3hash
NSLOOKUP=$TOP/bin/dig/nslookup
DNSTAPREAD=$TOP/bin/tools/dnstap-read
MDIG=$TOP/bin/tools/mdig
@@ -156,6 +157,7 @@ export LWTEST
export MAKEJOURNAL
export MDIG
export NAMED
+export NSEC3HASH
export NSLOOKUP
export NSUPDATE
export NZD2NZF
diff --git a/bin/tests/system/nsec3hash/clean.sh b/bin/tests/system/nsec3hash/clean.sh
new file mode 100644
index 0000000..52d57a6
--- /dev/null
+++ b/bin/tests/system/nsec3hash/clean.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+rm -f NSEC3
+rm -f nsec3hash
+rm -f nsec3param
+rm -f testcases
diff --git a/bin/tests/system/nsec3hash/tests.sh b/bin/tests/system/nsec3hash/tests.sh
new file mode 100644
index 0000000..8c22e79
--- /dev/null
+++ b/bin/tests/system/nsec3hash/tests.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2016 Internet Systems Consortium, Inc. ("ISC")
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+SYSTEMTESTTOP=..
+. $SYSTEMTESTTOP/conf.sh
+
+status=0
+
+# work around libtool breaking argv[0]
+ltbin=${NSEC3HASH%/*}/.libs/nsec3hash
+[ -x $ltbin ] && NSEC3HASH=$ltbin
+ln -sf $NSEC3HASH ./nsec3hash
+ln -sf $NSEC3HASH ./NSEC3
+
+# test cases from RFC 5155 appendix A
+rfc5155=../../../../doc/rfc/rfc5155.txt
+
+grep ' NSEC3PARAM ' $rfc5155 >nsec3param || {
+ echo "I:failed grep NSEC3PARAM"
+ exit 1
+}
+NSEC3PARAM() {
+ algo=$1
+ flags=$2
+ iters=$3
+ salt=$4
+}
+. ./nsec3param
+
+$PERL -e '
+ undef $/;
+ my $rfc = <>;
+ my %hash = $rfc =~
+ m{\n ; H\(([^)]+)\)[\s\n;]+= (\S+)}g;
+ printf "%s %s\n", $_, uc $hash{$_}
+ for sort keys %hash;
+' <$rfc5155 >testcases
+
+case $(wc -l <testcases) in
+(12) : ok ;;
+(*) echo "I:failed to find expected testcases"
+ exit 1
+esac
+
+while read name hash
+do
+ echo "I:checking nsec3hash $name"
+ for cmd in "./nsec3hash $salt $algo $iters $name" \
+ "./NSEC3 $algo $flags $iters $salt $name"
+ do
+ out="$($cmd)"
+ case $? in
+ (0) : ok ;;
+ (*) echo "I:failed $cmd"
+ status=$(expr $status + 1)
+ continue
+ ;;
+ esac
+ case $out in
+ (*$hash*) : ok ;;
+ (*) echo "I:Mismatch $cmd"
+ echo "I:expect $hash"
+ echo "I:output $out"
+ status=$(expr $status + 1)
+ ;;
+ esac
+ done
+done <testcases
+
+echo "I:exit status: $status"
+[ $status -eq 0 ] || exit 1
diff --git a/bin/tools/.gitignore b/bin/tools/.gitignore
index b760aa3..d92df6c 100644
--- a/bin/tools/.gitignore
+++ b/bin/tools/.gitignore
@@ -7,3 +7,4 @@ named-journalprint
named-nzd2nzf
named-rrchecker
nsec3hash
+NSEC3
diff --git a/bin/tools/Makefile.in b/bin/tools/Makefile.in
index 36d7b8d..0648ae1 100644
--- a/bin/tools/Makefile.in
+++ b/bin/tools/Makefile.in
@@ -40,7 +40,7 @@ SUBDIRS =
DNSTAPTARGETS = dnstap-read@EXEEXT@
NZDTARGETS = named-nzd2nzf@EXEEXT@
TARGETS = arpaname@EXEEXT@ named-journalprint@EXEEXT@ \
- named-rrchecker@EXEEXT@ nsec3hash@EXEEXT@ \
+ named-rrchecker@EXEEXT@ nsec3hash@EXEEXT@ NSEC3@EXEEXT@ \
genrandom@EXEEXT@ isc-hmac-fixup@EXEEXT@ mdig@EXEEXT@ \
@DNSTAPTARGETS@ @NZDTARGETS@
@@ -81,6 +81,10 @@ nsec3hash@EXEEXT@: nsec3hash.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
export LIBS0="${DNSLIBS}"; \
${FINALBUILDCMD}
+NSEC3@EXEEXT@: nsec3hash@EXEEXT@
+ rm -f NSEC3@EXEEXT@
+ @LN@ nsec3hash@EXEEXT@ NSEC3@EXEEXT@
+
isc-hmac-fixup@EXEEXT@: isc-hmac-fixup.@O@ ${ISCDEPLIBS}
export BASEOBJS="isc-hmac-fixup.@O@"; \
export LIBS0="${ISCLIBS}"; \
@@ -135,6 +139,7 @@ install:: ${TARGETS} installdirs @DNSTAP@ @NZD_TOOLS@
${DESTDIR}${bindir}
${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} nsec3hash@EXEEXT@ \
${DESTDIR}${sbindir}
+ (cd ${DESTDIR}${sbindir}; rm -f NSEC3@EXEEXT@; @LN@ nsec3hash@EXEEXT@ NSEC3@EXEEXT@)
${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} genrandom@EXEEXT@ \
${DESTDIR}${sbindir}
${LIBTOOL_MODE_INSTALL} ${INSTALL_PROGRAM} isc-hmac-fixup@EXEEXT@ \
@@ -148,11 +153,13 @@ install:: ${TARGETS} installdirs @DNSTAP@ @NZD_TOOLS@
${INSTALL_DATA} ${srcdir}/nsec3hash.8 ${DESTDIR}${mandir}/man8
${INSTALL_DATA} ${srcdir}/genrandom.8 ${DESTDIR}${mandir}/man8
${INSTALL_DATA} ${srcdir}/mdig.1 ${DESTDIR}${mandir}/man1
+ (cd ${DESTDIR}${mandir}/man8; rm -f NSEC3.8; @LN@ nsec3hash.8 NSEC3.8)
uninstall::
rm -f ${DESTDIR}${mandir}/man1/mdig.1
rm -f ${DESTDIR}${mandir}/man8/genrandom.8
rm -f ${DESTDIR}${mandir}/man8/nsec3hash.8
+ rm -f ${DESTDIR}${mandir}/man8/NSEC3.8
rm -f ${DESTDIR}${mandir}/man1/named-rrchecker.1
rm -f ${DESTDIR}${mandir}/man8/named-journalprint.8
rm -f ${DESTDIR}${mandir}/man8/isc-hmac-fixup.8
@@ -166,6 +173,8 @@ uninstall::
${LIBTOOL_MODE_UNINSTALL} rm -f \
${DESTDIR}${sbindir}/nsec3hash@EXEEXT@
${LIBTOOL_MODE_UNINSTALL} rm -f \
+ ${DESTDIR}${sbindir}/NSEC3@EXEEXT@
+ ${LIBTOOL_MODE_UNINSTALL} rm -f \
${DESTDIR}${bindir}/named-rrchecker@EXEEXT@
${LIBTOOL_MODE_UNINSTALL} rm -f \
${DESTDIR}${sbindir}/named-journalprint@EXEEXT@
diff --git a/bin/tools/nsec3hash.8 b/bin/tools/nsec3hash.8
index 78fd039..210e35d 100644
--- a/bin/tools/nsec3hash.8
+++ b/bin/tools/nsec3hash.8
@@ -36,14 +36,18 @@
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
-nsec3hash \- generate NSEC3 hash
+nsec3hash, NSEC3 \- generate NSEC3 hash
.SH "SYNOPSIS"
.HP \w'\fBnsec3hash\fR\ 'u
\fBnsec3hash\fR {\fIsalt\fR} {\fIalgorithm\fR} {\fIiterations\fR} {\fIdomain\fR}
+.HP \w'\fBNSEC3\fR\ 'u
+\fBNSEC3\fR {\fIalgorithm\fR} {\fIflags\fR} {\fIiterations\fR} {\fIsalt\fR} {\fIdomain\fR}
.SH "DESCRIPTION"
.PP
\fBnsec3hash\fR
generates an NSEC3 hash based on a set of NSEC3 parameters\&. This can be used to check the validity of NSEC3 records in a signed zone\&.
+.PP
+This command can also be invoked as \fBNSEC3\fR, in which case it takes arguments matching the first four fields of an NSEC3 record\&. This makes it convenient to copy and paste an NSEC3 or NSEC3PARAM record into a command line\&.
.SH "ARGUMENTS"
.PP
salt
@@ -56,6 +60,11 @@ algorithm
A number indicating the hash algorithm\&. Currently the only supported hash algorithm for NSEC3 is SHA\-1, which is indicated by the number 1; consequently "1" is the only useful value for this argument\&.
.RE
.PP
+flags
+.RS 4
+Provided for compatibility with NSEC3 record presentation format, but ignored since the flags do not affect the hash\&.
+.RE
+.PP
iterations
.RS 4
The number of additional times the hash should be performed\&.
diff --git a/bin/tools/nsec3hash.c b/bin/tools/nsec3hash.c
index a0af0d1..3293e0d 100644
--- a/bin/tools/nsec3hash.c
+++ b/bin/tools/nsec3hash.c
@@ -15,6 +15,7 @@
#include <isc/base32.h>
#include <isc/buffer.h>
+#include <isc/file.h>
#include <isc/hex.h>
#include <isc/iterated_hash.h>
#include <isc/print.h>
@@ -51,14 +52,18 @@ check_result(isc_result_t result, const char *message) {
}
static void
-usage(void) {
- fprintf(stderr, "Usage: %s salt algorithm iterations domain\n",
- program);
+usage(const char *args) {
+ fprintf(stderr, "Usage: %s %s\n", program, args);
exit(1);
}
-int
-main(int argc, char **argv) {
+typedef void nsec3printer(unsigned algo, unsigned flags, unsigned iters,
+ char *saltstr, char *domain, char *digest);
+
+static void
+nsec3hash(nsec3printer *nsec3print, char *algostr, char *flagstr,
+ char *iterstr, char *saltstr, char *domain)
+{
dns_fixedname_t fixed;
dns_name_t *name;
isc_buffer_t buffer;
@@ -68,35 +73,36 @@ main(int argc, char **argv) {
unsigned char salt[DNS_NSEC3_SALTSIZE];
unsigned char text[1024];
unsigned int hash_alg;
+ unsigned int flags;
unsigned int length;
unsigned int iterations;
unsigned int salt_length;
- if (argc != 5)
- usage();
-
- if (strcmp(argv[1], "-") == 0) {
+ if (strcmp(saltstr, "-") == 0) {
salt_length = 0;
salt[0] = 0;
} else {
isc_buffer_init(&buffer, salt, sizeof(salt));
- result = isc_hex_decodestring(argv[1], &buffer);
+ result = isc_hex_decodestring(saltstr, &buffer);
check_result(result, "isc_hex_decodestring(salt)");
salt_length = isc_buffer_usedlength(&buffer);
if (salt_length > DNS_NSEC3_SALTSIZE)
fatal("salt too long");
}
- hash_alg = atoi(argv[2]);
+ hash_alg = atoi(algostr);
if (hash_alg > 255U)
fatal("hash algorithm too large");
- iterations = atoi(argv[3]);
+ flags = flagstr == NULL ? 0 : atoi(flagstr);
+ if (flags > 255U)
+ fatal("flags too large");
+ iterations = atoi(iterstr);
if (iterations > 0xffffU)
fatal("iterations to large");
dns_fixedname_init(&fixed);
name = dns_fixedname_name(&fixed);
- isc_buffer_init(&buffer, argv[4], strlen(argv[4]));
- isc_buffer_add(&buffer, strlen(argv[4]));
+ isc_buffer_init(&buffer, domain, strlen(domain));
+ isc_buffer_add(&buffer, strlen(domain));
result = dns_name_fromtext(name, &buffer, dns_rootname, 0, NULL);
check_result(result, "dns_name_fromtext() failed");
@@ -109,7 +115,39 @@ main(int argc, char **argv) {
region.length = length;
isc_buffer_init(&buffer, text, sizeof(text));
isc_base32hexnp_totext(®ion, 1, "", &buffer);
- fprintf(stdout, "%.*s (salt=%s, hash=%u, iterations=%u)\n",
- (int)isc_buffer_usedlength(&buffer), text, argv[1], hash_alg, iterations);
+ isc_buffer_putuint8(&buffer, '\0');
+
+ nsec3print(hash_alg, flags, iterations, saltstr, domain, (char *)text);
+}
+
+static void
+nsec3hash_print(unsigned algo, unsigned flags, unsigned iters,
+ char *saltstr, char *domain, char *digest) {
+ (void)flags; (void)domain;
+ fprintf(stdout, "%s (salt=%s, hash=%u, iterations=%u)\n",
+ digest, saltstr, algo, iters);
+}
+
+static void
+NSEC3_print(unsigned algo, unsigned flags, unsigned iters,
+ char *saltstr, char *domain, char *digest) {
+ fprintf(stdout, "%s NSEC3 %u %u %u %s %s\n",
+ domain, algo, flags, iters, saltstr, digest);
+}
+
+int
+main(int argc, char *argv[]) {
+ if (strcmp(isc_file_basename(argv[0]), "NSEC3") == 0) {
+ program = "NSEC3";
+ if (argc != 6)
+ usage("algo flags iters salt domain");
+ nsec3hash(NSEC3_print,
+ argv[1], argv[2], argv[3], argv[4], argv[5]);
+ } else {
+ if (argc != 5)
+ usage("salt algorithm iterations domain");
+ nsec3hash(nsec3hash_print,
+ argv[2], NULL, argv[3], argv[1], argv[4]);
+ }
return(0);
}
diff --git a/bin/tools/nsec3hash.docbook b/bin/tools/nsec3hash.docbook
index ddc0342..5f19c71 100644
--- a/bin/tools/nsec3hash.docbook
+++ b/bin/tools/nsec3hash.docbook
@@ -24,6 +24,7 @@
<refnamediv>
<refname><application>nsec3hash</application></refname>
+ <refname><application>NSEC3</application></refname>
<refpurpose>generate NSEC3 hash</refpurpose>
</refnamediv>
@@ -45,6 +46,14 @@
<arg choice="req" rep="norepeat"><replaceable class="parameter">iterations</replaceable></arg>
<arg choice="req" rep="norepeat"><replaceable class="parameter">domain</replaceable></arg>
</cmdsynopsis>
+ <cmdsynopsis sepchar=" ">
+ <command>NSEC3</command>
+ <arg choice="req" rep="norepeat"><replaceable class="parameter">algorithm</replaceable></arg>
+ <arg choice="req" rep="norepeat"><replaceable class="parameter">flags</replaceable></arg>
+ <arg choice="req" rep="norepeat"><replaceable class="parameter">iterations</replaceable></arg>
+ <arg choice="req" rep="norepeat"><replaceable class="parameter">salt</replaceable></arg>
+ <arg choice="req" rep="norepeat"><replaceable class="parameter">domain</replaceable></arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsection><info><title>DESCRIPTION</title></info>
@@ -54,6 +63,14 @@
a set of NSEC3 parameters. This can be used to check the validity
of NSEC3 records in a signed zone.
</para>
+
+ <para>
+ This command can also be invoked as <command>NSEC3</command>, in
+ which case it takes arguments matching the first four fields of
+ an NSEC3 record. This makes it convenient to copy and paste an
+ NSEC3 or NSEC3PARAM record into a command line.
+ </para>
+
</refsection>
<refsection><info><title>ARGUMENTS</title></info>
@@ -81,6 +98,16 @@
</varlistentry>
<varlistentry>
+ <term>flags</term>
+ <listitem>
+ <para>
+ Provided for compatibility with NSEC3 record presentation
+ format, but ignored since the flags do not affect the hash.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>iterations</term>
<listitem>
<para>
--
2.10.1.445.g3cdd5d1