diff --git a/README b/README
index eb7d2b5..40ad66b 100644
--- a/README
+++ b/README
@@ -12,7 +12,8 @@ These tools depend upon DNSjava (http://www.xbill.org/dnsjava), the
Jakarta Commons CLI and Logging libraries (http://jakarta.apache.org),
and Sun's Java Cryptography extensions. A copy of each of these
libraries is included in the distribution. Currently, these tools use
-a custom version of the DNSjava library (for NSEC3 support)
+a custom version of the DNSjava library (for NSEC3 support), which is
+provided.
See the "licenses" directory for the licensing information of this
package and the other packages that are distributed with it.
@@ -47,6 +48,12 @@ build tool).
run the tools directly from the build area by using the
./bin/_jdnssec_* wrappers.
+
+The source for this project is available in subversion, at
+http://svn.verisignlabs.com/main/dnssec/sectools/trunk. Source for
+the modified DNSjava library can be found in subversion at
+http://svn.verisignlabs.com/main/dnssec/dnsjava/trunk.
+
---
Questions or comments may be directed to the author
diff --git a/bin/_jdnssec-zoneformat b/bin/_jdnssec-zoneformat
new file mode 100755
index 0000000..f81fb60
--- /dev/null
+++ b/bin/_jdnssec-zoneformat
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+thisdir=`dirname $0`
+basedir=`cd $thisdir/..; pwd`
+
+ulimit -n `ulimit -H -n`
+
+# set the classpath
+CLASSPATH=$CLASSPATH:$basedir/build/classes
+
+for i in $basedir/lib/*.jar $basedir/lib/*.zip; do
+ CLASSPATH="$CLASSPATH":"$i"
+done
+export CLASSPATH
+
+exec java com.verisignlabs.dnssec.cl.ZoneFormat "$@"
diff --git a/bin/jdnssec-zoneformat b/bin/jdnssec-zoneformat
new file mode 100755
index 0000000..8499d81
--- /dev/null
+++ b/bin/jdnssec-zoneformat
@@ -0,0 +1,14 @@
+#! /bin/sh
+
+thisdir=`dirname $0`
+basedir=`cd $thisdir/..; pwd`
+
+ulimit -n `ulimit -H -n`
+
+# set the classpath
+for i in $basedir/lib/*.jar $basedir/lib/*.zip; do
+ CLASSPATH="$CLASSPATH":"$i"
+done
+export CLASSPATH
+
+exec java com.verisignlabs.dnssec.cl.ZoneFormat "$@"
diff --git a/build.xml b/build.xml
index 9ccc2c5..0fece34 100644
--- a/build.xml
+++ b/build.xml
@@ -23,7 +23,7 @@
-
+
diff --git a/src/com/verisignlabs/dnssec/cl/ZoneFormat.java b/src/com/verisignlabs/dnssec/cl/ZoneFormat.java
new file mode 100644
index 0000000..ee15eca
--- /dev/null
+++ b/src/com/verisignlabs/dnssec/cl/ZoneFormat.java
@@ -0,0 +1,244 @@
+/*
+ * $Id$
+ *
+ * Copyright (c) 2005 VeriSign. All rights reserved.
+ *
+ * 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. 3. The name of the author may not
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ *
+ */
+
+package com.verisignlabs.dnssec.cl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.commons.cli.*;
+import org.xbill.DNS.Master;
+import org.xbill.DNS.Record;
+
+import com.verisignlabs.dnssec.security.RecordComparator;
+
+public class ZoneFormat
+{
+ // private static Logger log;
+
+ /**
+ * This is a small inner class used to hold all of the command line option
+ * state.
+ */
+ private static class CLIState
+ {
+ private org.apache.commons.cli.Options opts;
+ public String file;
+
+ public CLIState()
+ {
+ setupCLI();
+ }
+
+ public void parseCommandLine(String[] args)
+ throws org.apache.commons.cli.ParseException
+ {
+ CommandLineParser cli_parser = new PosixParser();
+ CommandLine cli = cli_parser.parse(opts, args);
+
+ // String optstr = null;
+
+ if (cli.hasOption('h')) usage();
+
+ if (cli.hasOption('v'))
+ {
+ int value = parseInt(cli.getOptionValue('v'), 5);
+ Logger rootLogger = Logger.getLogger("");
+ switch (value)
+ {
+ case 0 :
+ rootLogger.setLevel(Level.OFF);
+ break;
+ case 5 :
+ default :
+ rootLogger.setLevel(Level.FINE);
+ break;
+ case 6 :
+ rootLogger.setLevel(Level.ALL);
+ break;
+ }
+ }
+
+ String[] cl_args = cli.getArgs();
+
+ if (cl_args.length < 1)
+ {
+ System.err.println("error: must specify a zone file");
+ usage();
+ }
+
+ file = cl_args[0];
+ }
+
+ /**
+ * Set up the command line options.
+ *
+ * @return a set of command line options.
+ */
+ private void setupCLI()
+ {
+ opts = new org.apache.commons.cli.Options();
+
+ // boolean options
+ opts.addOption("h", "help", false, "Print this message.");
+
+ // Argument options
+ OptionBuilder.hasOptionalArg();
+ OptionBuilder.withLongOpt("verbose");
+ OptionBuilder.withArgName("level");
+ OptionBuilder.withDescription("verbosity level -- 0 is silence, "
+ + "5 is debug information, 6 is trace information.\n"
+ + "default is level 5.");
+ opts.addOption(OptionBuilder.create('v'));
+ }
+
+ /** Print out the usage and help statements, then quit. */
+ public void usage()
+ {
+ HelpFormatter f = new HelpFormatter();
+
+ PrintWriter out = new PrintWriter(System.err);
+
+ // print our own usage statement:
+ f.printHelp(out,
+ 75,
+ "jdnssec-zoneformat [..options..] zonefile",
+ null,
+ opts,
+ HelpFormatter.DEFAULT_LEFT_PAD,
+ HelpFormatter.DEFAULT_DESC_PAD,
+ null);
+
+ out.flush();
+ System.exit(64);
+
+ }
+
+ /**
+ * This is just a convenience method for parsing integers from strings.
+ *
+ * @param s the string to parse.
+ * @param def the default value, if the string doesn't parse.
+ * @return the parsed integer, or the default.
+ */
+ private static int parseInt(String s, int def)
+ {
+ try
+ {
+ int v = Integer.parseInt(s);
+ return v;
+ }
+ catch (NumberFormatException e)
+ {
+ return def;
+ }
+ }
+
+ }
+
+ private static List readZoneFile(String filename) throws IOException
+ {
+ Master master = new Master(filename);
+
+ List res = new ArrayList();
+ Record r = null;
+
+ while ((r = master.nextRecord()) != null)
+ {
+ res.add(r);
+ }
+
+ return res;
+ }
+
+ private static void formatZone(List zone)
+ {
+ // Sort both zones.
+ RecordComparator cmp = new RecordComparator();
+
+ Collections.sort(zone, cmp);
+
+ for (Iterator i = zone.iterator(); i.hasNext(); )
+ {
+ Record r = (Record) i.next();
+ System.out.println(r.toString());
+ }
+ }
+ private static void execute(CLIState state) throws IOException
+ {
+ List z = readZoneFile(state.file);
+ formatZone(z);
+ }
+
+ public static void main(String[] args)
+ {
+ CLIState state = new CLIState();
+
+ try
+ {
+ state.parseCommandLine(args);
+ }
+ catch (UnrecognizedOptionException e)
+ {
+ System.err.println("error: unknown option encountered: "
+ + e.getMessage());
+ state.usage();
+ }
+ catch (AlreadySelectedException e)
+ {
+ System.err.println("error: mutually exclusive options have "
+ + "been selected:\n " + e.getMessage());
+ state.usage();
+ }
+ catch (Exception e)
+ {
+ System.err.println("error: unknown command line parsing exception:");
+ e.printStackTrace();
+ state.usage();
+ }
+
+ // log = Logger.getLogger(VerifyZone.class.toString());
+
+ try
+ {
+ execute(state);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/src/com/verisignlabs/dnssec/security/SignUtils.java b/src/com/verisignlabs/dnssec/security/SignUtils.java
index 737ec5e..376cdd9 100644
--- a/src/com/verisignlabs/dnssec/security/SignUtils.java
+++ b/src/com/verisignlabs/dnssec/security/SignUtils.java
@@ -29,6 +29,7 @@ import java.util.*;
import java.util.logging.Logger;
import org.xbill.DNS.*;
+import org.xbill.DNS.utils.base16;
import org.xbill.DNS.utils.base64;
/**
@@ -718,6 +719,13 @@ public class SignUtils
proto_nsec3s);
List nsec3s = finishNSEC3s(proto_nsec3s);
+ // DEBUG
+// for (Iterator i = nsec3s.iterator(); i.hasNext();)
+// {
+// NSEC3Record nsec3 = (NSEC3Record) i.next();
+// log.fine("NSEC3: " + nsec3 + "\nRDATA: "
+// + base16.toString(nsec3.rdataToWireCanonical()));
+// }
records.addAll(nsec3s);
}
@@ -909,8 +917,19 @@ public class SignUtils
}
// Handle last NSEC3.
- cur_nsec3.setNext(first_nsec3_hash);
+ if (prev_nsec3.getNext() == null)
+ {
+ // if prev_nsec3's next field hasn't been set, then it is the last
+ // record (i.e., all remaining records were duplicates.)
+ prev_nsec3.setNext(first_nsec3_hash);
+ }
+ else
+ {
+ // otherwise, cur_nsec3 is the last record.
+ cur_nsec3.setNext(first_nsec3_hash);
+ }
+ // Convert our ProtoNSEC3s to actual (immutable) NSEC3Record objects.
List res = new ArrayList(nsec3s.size());
for (Iterator i = nsec3s.iterator(); i.hasNext();)
{