Add duplicate RR detection to jdnssec-verifyzone, and a command line option to disable it.

This commit is contained in:
David Blacka 2012-05-26 23:14:12 -04:00
parent b5775a8fdf
commit d3e8c4c913
2 changed files with 60 additions and 13 deletions

View File

@ -48,6 +48,7 @@ public class VerifyZone extends CLBase
public int startfudge = 0; public int startfudge = 0;
public int expirefudge = 0; public int expirefudge = 0;
public boolean ignoreTime = false; public boolean ignoreTime = false;
public boolean ignoreDups = false;
public CLIState() public CLIState()
{ {
@ -71,6 +72,10 @@ public class VerifyZone extends CLBase
OptionBuilder.withLongOpt("ignore-time"); OptionBuilder.withLongOpt("ignore-time");
OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors."); OptionBuilder.withDescription("Ignore RRSIG inception and expiration time errors.");
opts.addOption(OptionBuilder.create()); opts.addOption(OptionBuilder.create());
OptionBuilder.withLongOpt("ignore-duplicate-rrs");
OptionBuilder.withDescription("Ignore duplicate record errors.");
opts.addOption(OptionBuilder.create());
} }
protected void processOptions(CommandLine cli) protected void processOptions(CommandLine cli)
@ -80,6 +85,11 @@ public class VerifyZone extends CLBase
ignoreTime = true; ignoreTime = true;
} }
if (cli.hasOption("ignore-duplicate-rrs"))
{
ignoreDups = true;
}
String optstr = null; String optstr = null;
if ((optstr = cli.getOptionValue('S')) != null) if ((optstr = cli.getOptionValue('S')) != null)
{ {
@ -126,6 +136,7 @@ public class VerifyZone extends CLBase
zoneverifier.getVerifier().setStartFudge(state.startfudge); zoneverifier.getVerifier().setStartFudge(state.startfudge);
zoneverifier.getVerifier().setExpireFudge(state.expirefudge); zoneverifier.getVerifier().setExpireFudge(state.expirefudge);
zoneverifier.getVerifier().setIgnoreTime(state.ignoreTime); zoneverifier.getVerifier().setIgnoreTime(state.ignoreTime);
zoneverifier.setIgnoreDuplicateRRs(state.ignoreDups);
List<Record> records = ZoneUtils.readZoneFile(state.zonefile, null); List<Record> records = ZoneUtils.readZoneFile(state.zonefile, null);

View File

@ -48,7 +48,7 @@ import org.xbill.DNS.utils.base32;
* A class for whole zone DNSSEC verification. Along with cryptographically * A class for whole zone DNSSEC verification. Along with cryptographically
* verifying signatures, this class will also detect invalid NSEC and NSEC3 * verifying signatures, this class will also detect invalid NSEC and NSEC3
* chains. * chains.
* *
* @author David Blacka (original) * @author David Blacka (original)
* @author $Author: davidb $ * @author $Author: davidb $
* @version $Revision: 172 $ * @version $Revision: 172 $
@ -63,6 +63,7 @@ public class ZoneVerifier
private Name mZoneName; private Name mZoneName;
private DNSSECType mDNSSECType; private DNSSECType mDNSSECType;
private NSEC3PARAMRecord mNSEC3params; private NSEC3PARAMRecord mNSEC3params;
private boolean mIgnoreDuplicateRRs;
private DnsSecVerifier mVerifier; private DnsSecVerifier mVerifier;
private base32 mBase32; private base32 mBase32;
@ -107,22 +108,48 @@ public class ZoneVerifier
mVerifier = new DnsSecVerifier(); mVerifier = new DnsSecVerifier();
mBase32 = new base32(base32.Alphabet.BASE32HEX, false, true); mBase32 = new base32(base32.Alphabet.BASE32HEX, false, true);
mBAcmp = new ByteArrayComparator(); mBAcmp = new ByteArrayComparator();
mIgnoreDuplicateRRs = false;
} }
/** @return the DnsSecVerifier object used to verify individual RRsets. */
public DnsSecVerifier getVerifier() public DnsSecVerifier getVerifier()
{ {
return mVerifier; return mVerifier;
} }
public void setIgnoreDuplicateRRs(boolean value)
{
mIgnoreDuplicateRRs = value;
}
private static String key(Name n, int type) private static String key(Name n, int type)
{ {
return n.toString() + ':' + type; return n.toString() + ':' + type;
} }
@SuppressWarnings("rawtypes")
private boolean addRRtoRRset(RRset rrset, Record rr)
{
if (mIgnoreDuplicateRRs)
{
rrset.addRR(rr);
return true;
}
for (Iterator i = rrset.rrs(); i.hasNext(); )
{
Record record = (Record) i.next();
if (rr.equals(record)) return false;
}
rrset.addRR(rr);
return true;
}
/** /**
* Add a record to the various maps. * Add a record to the various maps.
* @return TODO
*/ */
private void addRR(Record r) private boolean addRR(Record r)
{ {
Name r_name = r.getName(); Name r_name = r.getName();
int r_type = r.getType(); int r_type = r.getType();
@ -138,8 +165,8 @@ public class ZoneVerifier
rrset = new MarkRRset(); rrset = new MarkRRset();
mNSECMap.put(r_name, rrset); mNSECMap.put(r_name, rrset);
} }
rrset.addRR(r);
return; return addRRtoRRset(rrset, r);
} }
if (r_type == Type.NSEC3) if (r_type == Type.NSEC3)
@ -151,8 +178,8 @@ public class ZoneVerifier
rrset = new MarkRRset(); rrset = new MarkRRset();
mNSEC3Map.put(r_name, rrset); mNSEC3Map.put(r_name, rrset);
} }
rrset.addRR(r);
return; return addRRtoRRset(rrset, r);
} }
// Add the name and type to the node map // Add the name and type to the node map
@ -172,7 +199,7 @@ public class ZoneVerifier
rrset = new RRset(); rrset = new RRset();
mRRsetMap.put(k, rrset); mRRsetMap.put(k, rrset);
} }
rrset.addRR(r); return addRRtoRRset(rrset, r);
} }
/** /**
@ -198,10 +225,11 @@ public class ZoneVerifier
/** /**
* Given an unsorted list of records, load the node and rrset maps, as well as * Given an unsorted list of records, load the node and rrset maps, as well as
* determine the NSEC3 parameters and signing type. * determine the NSEC3 parameters and signing type.
* *
* @param records * @param records
* @return TODO
*/ */
private void calculateNodes(List<Record> records) private int calculateNodes(List<Record> records)
{ {
mNodeMap = new TreeMap<Name, Set<Integer>>(); mNodeMap = new TreeMap<Name, Set<Integer>>();
mRRsetMap = new HashMap<String, RRset>(); mRRsetMap = new HashMap<String, RRset>();
@ -209,13 +237,19 @@ public class ZoneVerifier
// The zone is unsigned until we get a clue otherwise. // The zone is unsigned until we get a clue otherwise.
mDNSSECType = DNSSECType.UNSIGNED; mDNSSECType = DNSSECType.UNSIGNED;
int errors = 0;
for (Record r : records) for (Record r : records)
{ {
Name r_name = r.getName(); Name r_name = r.getName();
int r_type = r.getType(); int r_type = r.getType();
// Add the record to the various maps. // Add the record to the various maps.
addRR(r); boolean res = addRR(r);
if (!res)
{
log.warning("Record '" + r + "' detected as a duplicate");
errors++;
}
// Learn some things about the zone as we do this pass. // Learn some things about the zone as we do this pass.
if (r_type == Type.SOA) mZoneName = r_name; if (r_type == Type.SOA) mZoneName = r_name;
@ -229,6 +263,8 @@ public class ZoneVerifier
if (mDNSSECType == DNSSECType.UNSIGNED) mDNSSECType = determineDNSSECType(r); if (mDNSSECType == DNSSECType.UNSIGNED) mDNSSECType = determineDNSSECType(r);
} }
return errors;
} }
/** /**
@ -290,7 +326,7 @@ public class ZoneVerifier
last_cut = n; last_cut = n;
} }
// check all of the RRset that should be signed // check all of the RRsets that should be signed
for (int type : typeset) for (int type : typeset)
{ {
if (type == Type.RRSIG) continue; if (type == Type.RRSIG) continue;
@ -709,9 +745,9 @@ public class ZoneVerifier
{ {
int errors = 0; int errors = 0;
calculateNodes(records); errors += calculateNodes(records);
errors = processNodes(); errors += processNodes();
if (mDNSSECType == DNSSECType.NSEC) if (mDNSSECType == DNSSECType.NSEC)
{ {