More progress, no idea if we are working yet

This commit is contained in:
David Blacka 2009-04-19 20:57:24 -04:00
parent 1f647e3c77
commit 0b91cbfb1f
5 changed files with 364 additions and 262 deletions

2
TODO Normal file
View File

@ -0,0 +1,2 @@
* Add way to report errors and validation failure conditions.

View File

@ -61,35 +61,18 @@ public class CaptiveValidator {
// ---------------- Module Initialization ------------------- // ---------------- Module Initialization -------------------
/** /**
* Initialize the module. * Add a set of trusted keys from a file. The file should be in DNS master
*/ * zone file format. Only DNSKEY records will be added.
public void init(Properties config) throws Exception {
mVerifier.init(config);
String s = config.getProperty("dns.trust_anchor_file");
if (s != null) {
try {
loadTrustAnchors(s);
} catch (IOException e) {
System.err.println("Error loading trust anchors: " + e);
}
}
}
/**
* Load the trust anchor file into the trust anchor store. The trust anchors
* are currently stored in a zone file format list of DNSKEY or DS records.
* *
* @param filename * @param filename
* The trust anchor file. * The file contains the trusted keys.
* @throws IOException * @throws IOException
*/ */
private void loadTrustAnchors(String filename) throws IOException { @SuppressWarnings("unchecked")
System.err.println("reading trust anchor file file: " + filename); public void addTrustedKeysFromFile(String filename) throws IOException {
// First read in the whole trust anchor file. // First read in the whole trust anchor file.
Master master = new Master(filename, Name.root, 0); Master master = new Master(filename, Name.root, 0);
ArrayList records = new ArrayList(); ArrayList<Record> records = new ArrayList<Record>();
Record r = null; Record r = null;
while ((r = master.nextRecord()) != null) { while ((r = master.nextRecord()) != null) {
@ -102,28 +85,28 @@ public class CaptiveValidator {
Collections.sort(records); Collections.sort(records);
SRRset cur_rrset = new SRRset(); SRRset cur_rrset = new SRRset();
for (Iterator i = records.iterator(); i.hasNext();) { for (Record rec : records) {
r = (Record) i.next(); // Skip RR types that cannot be used as trusted keys. I.e.,
// Skip RR types that cannot be used as trust anchors. // everything not a key :)
if (r.getType() != Type.DNSKEY && r.getType() != Type.DS) continue; if (rec.getType() != Type.DNSKEY) continue;
// If our cur_rrset is empty, we can just add it. // If our cur_rrset is empty, we can just add it.
if (cur_rrset.size() == 0) { if (cur_rrset.size() == 0) {
cur_rrset.addRR(r); cur_rrset.addRR(rec);
continue; continue;
} }
// If this record matches our current RRset, we can just add it. // If this record matches our current RRset, we can just add it.
if (cur_rrset.getName().equals(r.getName()) if (cur_rrset.getName().equals(rec.getName())
&& cur_rrset.getType() == r.getType() && cur_rrset.getType() == rec.getType()
&& cur_rrset.getDClass() == r.getDClass()) { && cur_rrset.getDClass() == rec.getDClass()) {
cur_rrset.addRR(r); cur_rrset.addRR(rec);
continue; continue;
} }
// Otherwise, we add the rrset to our set of trust anchors. // Otherwise, we add the rrset to our set of trust anchors.
mTrustedKeys.store(cur_rrset); mTrustedKeys.store(cur_rrset);
cur_rrset = new SRRset(); cur_rrset = new SRRset();
cur_rrset.addRR(r); cur_rrset.addRR(rec);
} }
// add the last rrset (if it was not empty) // add the last rrset (if it was not empty)
@ -132,14 +115,155 @@ public class CaptiveValidator {
} }
} }
public void addTrustedKeysFromResponse(Message m) {
RRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
for (int i = 0; i < rrsets.length; ++i) {
if (rrsets[i].getType() == Type.DNSKEY) {
SRRset srrset = new SRRset(rrsets[i]);
mTrustedKeys.store(srrset);
}
}
}
// ----------------- Validation Support ---------------------- // ----------------- Validation Support ----------------------
/**
* This routine normalizes a response. This includes removing "irrelevant"
* records from the answer and additional sections and (re)synthesizing
* CNAMEs from DNAMEs, if present.
*
* @param response
*/
private SMessage normalize(SMessage m) {
if (m == null) return m;
if (m.getRcode() != Rcode.NOERROR && m.getRcode() != Rcode.NXDOMAIN) {
return m;
}
Name qname = m.getQuestion().getName();
int qtype = m.getQuestion().getType();
Name sname = qname;
// For the ANSWER section, remove all "irrelevant" records and add
// synthesized CNAMEs from DNAMEs
// This will strip out-of-order CNAMEs as well.
List<SRRset> rrset_list = m.getSectionList(Section.ANSWER);
Set<Name> additional_names = new HashSet<Name>();
for (ListIterator<SRRset> i = rrset_list.listIterator(); i.hasNext();) {
SRRset rrset = i.next();
int type = rrset.getType();
Name n = rrset.getName();
// Handle DNAME synthesis; DNAME synthesis does not occur at the
// DNAME name itself.
if (type == Type.DNAME && ValUtils.strictSubdomain(sname, n)) {
if (rrset.size() > 1) {
// log.debug("Found DNAME rrset with size > 1: " + rrset);
// return Util.errorMessage(m, Rcode.SERVFAIL);
return null; // FIXME
}
DNAMERecord dname = (DNAMERecord) rrset.first();
try {
Name cname_alias = sname.fromDNAME(dname);
// Note that synthesized CNAMEs should have a TTL of zero.
CNAMERecord cname = new CNAMERecord(sname,
dname.getDClass(), 0, cname_alias);
SRRset cname_rrset = new SRRset();
cname_rrset.addRR(cname);
i.add(cname_rrset);
sname = cname_alias;
} catch (NameTooLongException e) {
// log.debug("not adding synthesized CNAME -- "
// + "generated name is too long", e);
}
continue;
}
// The only records in the ANSWER section not allowed to
if (!n.equals(sname)) {
// log.debug("normalize: removing irrelevant rrset: " + rrset);
i.remove();
continue;
}
// Follow the CNAME chain.
if (type == Type.CNAME) {
if (rrset.size() > 1) {
// log.debug("Found CNAME rrset with size > 1: " + rrset);
// return Util.errorMessage(m, Rcode.SERVFAIL);
return null; // FIXME
}
CNAMERecord cname = (CNAMERecord) rrset.first();
sname = cname.getAlias();
continue;
}
// Otherwise, make sure that the RRset matches the qtype.
if (qtype != Type.ANY && qtype != type) {
// log.debug("normalize: removing irrelevant rrset: " + rrset);
i.remove();
}
// Otherwise, fetch the additional names from the relevant rrset.
rrsetAdditionalNames(additional_names, rrset);
}
// Get additional names from AUTHORITY
rrset_list = m.getSectionList(Section.AUTHORITY);
for (SRRset rrset : rrset_list) {
rrsetAdditionalNames(additional_names, rrset);
}
// For each record in the additional section, remove it if it is an
// address record and not in the collection of additional names found in
// ANSWER and AUTHORITY.
rrset_list = m.getSectionList(Section.ADDITIONAL);
for (Iterator<SRRset> i = rrset_list.iterator(); i.hasNext();) {
SRRset rrset = i.next();
int type = rrset.getType();
if ((type == Type.A || type == Type.AAAA)
&& !additional_names.contains(rrset.getName())) {
i.remove();
}
// FIXME: what about other types?
}
return m;
}
/**
* Extract additional names from the records in an rrset.
*
* @param additional_names
* The set to add the additional names to, if any.
* @param rrset
* The rrset to extract from.
*/
private void rrsetAdditionalNames(Set<Name> additional_names, SRRset rrset) {
if (rrset == null) return;
for (Iterator<Record> i = rrset.rrs(); i.hasNext();) {
Record r = i.next();
Name add_name = r.getAdditionalName();
if (add_name != null) {
additional_names.add(add_name);
}
}
}
private SRRset findKeys(SMessage message) { private SRRset findKeys(SMessage message) {
Name qname = message.getQName(); Name qname = message.getQName();
int qclass = message.getQClass(); int qclass = message.getQClass();
return mTrustedKeys.find(qname, qclass); return mTrustedKeys.find(qname, qclass);
} }
/** /**
* Check to see if a given response needs to go through the validation * Check to see if a given response needs to go through the validation
* process. Typical reasons for this routine to return false are: CD bit was * process. Typical reasons for this routine to return false are: CD bit was
@ -156,10 +280,6 @@ public class CaptiveValidator {
* mean we can actually validate this response). * mean we can actually validate this response).
*/ */
private boolean needsValidation(SMessage message) { private boolean needsValidation(SMessage message) {
// FIXME: add check to see if message qname is at or below any of our
// configured trust anchors.
int rcode = message.getRcode(); int rcode = message.getRcode();
if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) { if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) {
@ -168,6 +288,9 @@ public class CaptiveValidator {
return false; return false;
} }
if (!mTrustedKeys.isBelowTrustAnchor(message.getQName(), message.getQClass())) {
return false;
}
return true; return true;
} }
@ -197,10 +320,10 @@ public class CaptiveValidator {
// validate the ANSWER section - this will be the answer itself // validate the ANSWER section - this will be the answer itself
SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER); SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
Name wc = null; Name wc = null;
boolean wcNSEC_ok = false; boolean wcNSEC_ok = false;
boolean dname = false; boolean dname = false;
List nsec3s = null; List<NSEC3Record> nsec3s = null;
for (int i = 0; i < rrsets.length; i++) { for (int i = 0; i < rrsets.length; i++) {
// Skip the CNAME following a (validated) DNAME. // Skip the CNAME following a (validated) DNAME.
@ -217,8 +340,8 @@ public class CaptiveValidator {
// If the (answer) rrset failed to validate, then this message is // If the (answer) rrset failed to validate, then this message is
// BAD. // BAD.
if (status != SecurityStatus.SECURE) { if (status != SecurityStatus.SECURE) {
// log.debug("Positive response has failed ANSWER rrset: " // log.debug("Positive response has failed ANSWER rrset: "
// + rrsets[i]); // + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
@ -242,8 +365,8 @@ public class CaptiveValidator {
// a // a
// bad message. // bad message.
if (status != SecurityStatus.SECURE) { if (status != SecurityStatus.SECURE) {
// log.debug("Positive response has failed AUTHORITY rrset: " // log.debug("Positive response has failed AUTHORITY rrset: "
// + rrsets[i]); // + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
@ -258,8 +381,8 @@ public class CaptiveValidator {
key_rrset.getName())) { key_rrset.getName())) {
Name nsec_wc = ValUtils.nsecWildcard(qname, nsec); Name nsec_wc = ValUtils.nsecWildcard(qname, nsec);
if (!wc.equals(nsec_wc)) { if (!wc.equals(nsec_wc)) {
// log.debug("Postive wildcard response wasn't generated " // log.debug("Positive wildcard response wasn't generated "
// + "by the correct wildcard"); // + "by the correct wildcard");
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
@ -270,8 +393,8 @@ public class CaptiveValidator {
// Otherwise, if this is a positive wildcard response and we have // Otherwise, if this is a positive wildcard response and we have
// NSEC3 records, collect them. // NSEC3 records, collect them.
if (wc != null && rrsets[i].getType() == Type.NSEC3) { if (wc != null && rrsets[i].getType() == Type.NSEC3) {
if (nsec3s == null) nsec3s = new ArrayList(); if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
nsec3s.add(rrsets[i].first()); nsec3s.add((NSEC3Record) rrsets[i].first());
} }
} }
@ -288,18 +411,113 @@ public class CaptiveValidator {
// If after all this, we still haven't proven the positive wildcard // If after all this, we still haven't proven the positive wildcard
// response, fail. // response, fail.
if (wc != null && !wcNSEC_ok) { if (wc != null && !wcNSEC_ok) {
// log.debug("positive response was wildcard expansion and " // log.debug("positive response was wildcard expansion and "
// + "did not prove original data did not exist"); // + "did not prove original data did not exist");
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
// log.trace("Successfully validated postive response"); // log.trace("Successfully validated positive response");
m.setStatus(SecurityStatus.SECURE); m.setStatus(SecurityStatus.SECURE);
} }
private void validateReferral(SMessage message, SRRset key_rrset) { private void validateReferral(SMessage message, SRRset key_rrset) {
SMessage m = message;
if (m.getCount(Section.ANSWER) > 0) {
// FIXME: fail somehow.
}
// validate the AUTHORITY section.
SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
boolean secure_delegation = false;
Name delegation = null;
Name nsec3zone = null;
NSECRecord nsec = null;
List<NSEC3Record> nsec3s = null;
// validate the AUTHORITY section as well - this will generally be the
// NS rrset, plus proof of a secure delegation or not
rrsets = m.getSectionRRsets(Section.AUTHORITY);
for (int i = 0; i < rrsets.length; i++) {
int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
// If anything in the authority section fails to be secure, we have
// a bad message.
if (status != SecurityStatus.SECURE) {
// log.debug("Positive response has failed AUTHORITY rrset: "
// + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS);
return;
}
int type = rrsets[i].getType();
switch (type) {
case Type.DS:
secure_delegation = true;
break;
case Type.NS:
delegation = rrsets[i].getName();
break;
case Type.NSEC:
nsec = (NSECRecord) rrsets[i].first();
break;
case Type.NSEC3:
if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
NSEC3Record nsec3 = (NSEC3Record) rrsets[i].first();
nsec3s.add(nsec3);
nsec3zone = rrsets[i].getSignerName(); // this is a hack of sorts.
break;
default:
// FIXME: should probably whine if we see something else.
break;
}
}
// At this point, all validatable RRsets have been validated.
// Now to check to see if we have a valid combination of things.
if (delegation == null) {
// somehow we have a referral without an NS rrset.
m.setStatus(SecurityStatus.BOGUS);
return;
}
if (secure_delegation) {
if (nsec != null || nsec3s.size() > 0) {
// we found both a DS rrset *and* NSEC/NSEC3 rrsets!
m.setStatus(SecurityStatus.BOGUS);
return;
}
// otherwise, we are done.
m.setStatus(SecurityStatus.SECURE);
return;
}
// Note: not going to care if both NSEC and NSEC3 rrsets were present.
if (nsec != null) {
byte status = ValUtils.nsecProvesNoDS(nsec, delegation);
if (status != SecurityStatus.SECURE) {
// The NSEC *must* prove that there was no DS record. The INSECURE state here is still bogus.
m.setStatus(SecurityStatus.BOGUS);
return;
}
m.setStatus(SecurityStatus.SECURE);
return;
}
if (nsec3s.size() > 0) {
byte status = NSEC3ValUtils.proveNoDS(nsec3s, delegation, nsec3zone);
if (status != SecurityStatus.SECURE) {
// the NSEC3 RRs MUST prove no DS, so the INDETERMINATE state is actually bogus
m.setStatus(SecurityStatus.BOGUS);
return;
}
m.setStatus(SecurityStatus.SECURE);
return;
}
// failed to find proof either way.
m.setStatus(SecurityStatus.BOGUS);
} }
private void validateCNAMEResponse(SMessage message, SRRset key_rrset) { private void validateCNAMEResponse(SMessage message, SRRset key_rrset) {
@ -345,8 +563,8 @@ public class CaptiveValidator {
// If the (answer) rrset failed to validate, then this message is // If the (answer) rrset failed to validate, then this message is
// BAD. // BAD.
if (status != SecurityStatus.SECURE) { if (status != SecurityStatus.SECURE) {
// log.debug("Postive response has failed ANSWER rrset: " // log.debug("Positive response has failed ANSWER rrset: "
// + rrsets[i]); // + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
@ -361,14 +579,14 @@ public class CaptiveValidator {
// a // a
// bad message. // bad message.
if (status != SecurityStatus.SECURE) { if (status != SecurityStatus.SECURE) {
// log.debug("Postive response has failed AUTHORITY rrset: " // log.debug("Positive response has failed AUTHORITY rrset: "
// + rrsets[i]); // + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
} }
// log.trace("Successfully validated postive ANY response"); // log.trace("Successfully validated positive ANY response");
m.setStatus(SecurityStatus.SECURE); m.setStatus(SecurityStatus.SECURE);
} }
@ -406,19 +624,19 @@ public class CaptiveValidator {
boolean hasValidNSEC = false; // If true, then the NODATA has been boolean hasValidNSEC = false; // If true, then the NODATA has been
// proven. // proven.
Name ce = null; // for wildcard nodata responses. This is the proven Name ce = null; // for wildcard NODATA responses. This is the proven
// closest encloser. // closest encloser.
NSECRecord wc = null; // for wildcard nodata responses. This is the NSECRecord wc = null; // for wildcard NODATA responses. This is the
// wildcard NSEC. // wildcard NSEC.
List nsec3s = null; // A collection of NSEC3 RRs found in the authority List<NSEC3Record> nsec3s = null; // A collection of NSEC3 RRs found in the authority
// section. // section.
Name nsec3Signer = null; // The RRSIG signer field for the NSEC3 RRs. Name nsec3Signer = null; // The RRSIG signer field for the NSEC3 RRs.
for (int i = 0; i < rrsets.length; i++) { for (int i = 0; i < rrsets.length; i++) {
int status = mValUtils.verifySRRset(rrsets[i], key_rrset); int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
if (status != SecurityStatus.SECURE) { if (status != SecurityStatus.SECURE) {
// log.debug("NODATA response has failed AUTHORITY rrset: " // log.debug("NODATA response has failed AUTHORITY rrset: "
// + rrsets[i]); // + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
@ -440,8 +658,8 @@ public class CaptiveValidator {
// Collect any NSEC3 records present. // Collect any NSEC3 records present.
if (rrsets[i].getType() == Type.NSEC3) { if (rrsets[i].getType() == Type.NSEC3) {
if (nsec3s == null) nsec3s = new ArrayList(); if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
nsec3s.add(rrsets[i].first()); nsec3s.add((NSEC3Record) rrsets[i].first());
nsec3Signer = rrsets[i].getSignerName(); nsec3Signer = rrsets[i].getSignerName();
} }
} }
@ -458,7 +676,7 @@ public class CaptiveValidator {
hasValidNSEC = false; hasValidNSEC = false;
} }
} catch (TextParseException e) { } catch (TextParseException e) {
// log.error(e); // log.error(e);
} }
} }
@ -471,13 +689,13 @@ public class CaptiveValidator {
} }
if (!hasValidNSEC) { if (!hasValidNSEC) {
// log.debug("NODATA response failed to prove NODATA " // log.debug("NODATA response failed to prove NODATA "
// + "status with NSEC/NSEC3"); // + "status with NSEC/NSEC3");
// log.trace("Failed NODATA:\n" + m); // log.trace("Failed NODATA:\n" + m);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
// log.trace("sucessfully validated NODATA response."); // log.trace("successfully validated NODATA response.");
m.setStatus(SecurityStatus.SECURE); m.setStatus(SecurityStatus.SECURE);
} }
@ -513,14 +731,14 @@ public class CaptiveValidator {
boolean hasValidNSEC = false; boolean hasValidNSEC = false;
boolean hasValidWCNSEC = false; boolean hasValidWCNSEC = false;
SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY); SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
List nsec3s = null; List<NSEC3Record> nsec3s = null;
Name nsec3Signer = null; Name nsec3Signer = null;
for (int i = 0; i < rrsets.length; i++) { for (int i = 0; i < rrsets.length; i++) {
int status = mValUtils.verifySRRset(rrsets[i], key_rrset); int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
if (status != SecurityStatus.SECURE) { if (status != SecurityStatus.SECURE) {
// log.debug("NameError response has failed AUTHORITY rrset: " // log.debug("NameError response has failed AUTHORITY rrset: "
// + rrsets[i]); // + rrsets[i]);
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
@ -537,8 +755,8 @@ public class CaptiveValidator {
} }
} }
if (rrsets[i].getType() == Type.NSEC3) { if (rrsets[i].getType() == Type.NSEC3) {
if (nsec3s == null) nsec3s = new ArrayList(); if (nsec3s == null) nsec3s = new ArrayList<NSEC3Record>();
nsec3s.add(rrsets[i].first()); nsec3s.add((NSEC3Record) rrsets[i].first());
nsec3Signer = rrsets[i].getSignerName(); nsec3Signer = rrsets[i].getSignerName();
} }
} }
@ -546,11 +764,11 @@ public class CaptiveValidator {
NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s); NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
if (nsec3s != null && nsec3s.size() > 0) { if (nsec3s != null && nsec3s.size() > 0) {
// log.debug("Validating nxdomain: using NSEC3 records"); // log.debug("Validating nxdomain: using NSEC3 records");
// Attempt to prove name error with nsec3 records. // Attempt to prove name error with nsec3 records.
if (NSEC3ValUtils.allNSEC3sIgnoreable(nsec3s, key_rrset, mVerifier)) { if (NSEC3ValUtils.allNSEC3sIgnoreable(nsec3s, key_rrset, mVerifier)) {
// log.debug("all NSEC3s were validated but ignored."); // log.debug("all NSEC3s were validated but ignored.");
m.setStatus(SecurityStatus.INSECURE); m.setStatus(SecurityStatus.INSECURE);
return; return;
} }
@ -565,126 +783,34 @@ public class CaptiveValidator {
// If the message fails to prove either condition, it is bogus. // If the message fails to prove either condition, it is bogus.
if (!hasValidNSEC) { if (!hasValidNSEC) {
// log.debug("NameError response has failed to prove: " // log.debug("NameError response has failed to prove: "
// + "qname does not exist"); // + "qname does not exist");
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
if (!hasValidWCNSEC) { if (!hasValidWCNSEC) {
// log.debug("NameError response has failed to prove: " // log.debug("NameError response has failed to prove: "
// + "covering wildcard does not exist"); // + "covering wildcard does not exist");
m.setStatus(SecurityStatus.BOGUS); m.setStatus(SecurityStatus.BOGUS);
return; return;
} }
// Otherwise, we consider the message secure. // Otherwise, we consider the message secure.
// log.trace("successfully validated NAME ERROR response."); // log.trace("successfully validated NAME ERROR response.");
m.setStatus(SecurityStatus.SECURE); m.setStatus(SecurityStatus.SECURE);
} }
// /**
// * This state is used for validating CNAME-type responses -- i.e., responses
// * that have CNAME chains.
// *
// * It primarily is responsible for breaking down the response into a series
// * of separately validated queries & responses.
// *
// * @param event
// * @param state
// * @return
// */
// private boolean processCNAME(DNSEvent event, ValEventState state) {
// Request req = event.getRequest();
//
// Name qname = req.getQName();
// int qtype = req.getQType();
// int qclass = req.getQClass();
//
// SMessage m = event.getResponse().getSMessage();
//
// if (state.cnameSname == null) state.cnameSname = qname;
//
// // We break the chain down by re-querying for the specific CNAME or
// // DNAME
// // (or final answer).
// SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
//
// while (state.cnameIndex < rrsets.length) {
// SRRset rrset = rrsets[state.cnameIndex++];
// Name rname = rrset.getName();
// int rtype = rrset.getType();
//
// // Skip DNAMEs -- prefer to query for the generated CNAME,
// if (rtype == Type.DNAME && qtype != Type.DNAME) continue;
//
// // Set the SNAME if we are dealing with a CNAME
// if (rtype == Type.CNAME) {
// CNAMERecord cname = (CNAMERecord) rrset.first();
// state.cnameSname = cname.getTarget();
// }
//
// // Note if the current rrset is the answer. In that case, we want to
// // set
// // the final state differently.
// // For non-answers, the response ultimately comes back here.
// int final_state = ValEventState.CNAME_RESP_STATE;
// if (isAnswerRRset(rrset.getName(), rtype, state.cnameSname, qtype,
// Section.ANSWER)) {
// // If this is an answer, however, break out of this loop.
// final_state = ValEventState.CNAME_ANS_RESP_STATE;
// }
//
// // Generate the sub-query.
// Request localRequest = generateLocalRequest(rname, rtype, qclass);
// DNSEvent localEvent = generateLocalEvent(event, localRequest,
// ValEventState.INIT_STATE,
// final_state);
//
// // ...and send it along.
// processLocalRequest(localEvent);
// return false;
// }
//
// // Something odd has happened if we get here.
// log.warn("processCNAME: encountered unknown issue handling a CNAME chain.");
// return false;
// }
//
// private boolean processCNAMEResponse(DNSEvent event, ValEventState state) {
// DNSEvent forEvent = event.forEvent();
// ValEventState forState = getModuleState(forEvent);
//
// SMessage resp = event.getResponse().getSMessage();
// if (resp.getStatus() != SecurityStatus.SECURE) {
// forEvent.getResponse().getSMessage().setStatus(resp.getStatus());
// forState.state = forState.finalState;
// handleResponse(forEvent, forState);
// return false;
// }
//
// forState.state = ValEventState.CNAME_STATE;
// handleResponse(forEvent, forState);
// return false;
// }
//
// private boolean processCNAMEAnswer(DNSEvent event, ValEventState state) {
// DNSEvent forEvent = event.forEvent();
// ValEventState forState = getModuleState(forEvent);
//
// SMessage resp = event.getResponse().getSMessage();
// SMessage forResp = forEvent.getResponse().getSMessage();
//
// forResp.setStatus(resp.getStatus());
//
// forState.state = forState.finalState;
// handleResponse(forEvent, forState);
// return false;
// }
public byte validateMessage(SMessage message, Name zone) { public byte validateMessage(SMessage message, Name zone) {
// FIXME: it is unclear if we should actually normalize our responses
// Instead, maybe we should just fail if they are not normal?
message = normalize(message);
if (! needsValidation(message)) {
return SecurityStatus.UNCHECKED;
}
SRRset key_rrset = findKeys(message); SRRset key_rrset = findKeys(message);
if (key_rrset == null) { if (key_rrset == null) {
return SecurityStatus.BOGUS; return SecurityStatus.BOGUS;
@ -701,21 +827,21 @@ public class CaptiveValidator {
validateReferral(message, key_rrset); validateReferral(message, key_rrset);
break; break;
case NODATA: case NODATA:
// log.trace("Validating a nodata response"); // log.trace("Validating a NODATA response");
validateNodataResponse(message, key_rrset); validateNodataResponse(message, key_rrset);
break; break;
case NAMEERROR: case NAMEERROR:
// log.trace("Validating a nxdomain response"); // log.trace("Validating a NXDOMAIN response");
validateNameErrorResponse(message, key_rrset); validateNameErrorResponse(message, key_rrset);
break; break;
case CNAME: case CNAME:
// log.trace("Validating a cname response"); // log.trace("Validating a CNAME response");
// forward on to the special CNAME state for this. // forward on to the special CNAME state for this.
// state.state = ValEventState.CNAME_STATE; // state.state = ValEventState.CNAME_STATE;
validateCNAMEResponse(message, key_rrset); validateCNAMEResponse(message, key_rrset);
break; break;
case ANY: case ANY:
// log.trace("Validating a postive ANY response"); // log.trace("Validating a positive ANY response");
validateAnyResponse(message, key_rrset); validateAnyResponse(message, key_rrset);
break; break;
default: default:

View File

@ -702,7 +702,7 @@ public class NSEC3ValUtils {
* delegation point, and SecurityStatus.BOGUS if the proofs don't * delegation point, and SecurityStatus.BOGUS if the proofs don't
* work out. * work out.
*/ */
public static int proveNoDS(List<NSEC3Record> nsec3s, Name qname, public static byte proveNoDS(List<NSEC3Record> nsec3s, Name qname,
Name zonename) { Name zonename) {
if (nsec3s == null || nsec3s.size() == 0) return SecurityStatus.BOGUS; if (nsec3s == null || nsec3s.size() == 0) return SecurityStatus.BOGUS;

View File

@ -36,52 +36,47 @@ import org.xbill.DNS.Name;
/** /**
* *
*/ */
public class TrustAnchorStore public class TrustAnchorStore {
{ private Map<String, SRRset> mMap;
private Map<String, SRRset> mMap;
public TrustAnchorStore() public TrustAnchorStore() {
{ mMap = null;
mMap = null;
}
private String key(Name n, int dclass)
{
return "T" + dclass + "/" + Util.nameToString(n);
}
public void store(SRRset rrset)
{
if (mMap == null)
{
mMap = new HashMap<String, SRRset>();
}
String k = key(rrset.getName(), rrset.getDClass());
rrset.setSecurityStatus(SecurityStatus.SECURE);
mMap.put(k, rrset);
}
private SRRset lookup(String key)
{
if (mMap == null) return null;
return mMap.get(key);
}
public SRRset find(Name n, int dclass)
{
if (mMap == null) return null;
while (n.labels() > 0)
{
String k = key(n, dclass);
SRRset r = lookup(k);
if (r != null) return r;
n = new Name(n, 1);
} }
return null; private String key(Name n, int dclass) {
} return "T" + dclass + "/" + Util.nameToString(n);
}
public void store(SRRset rrset) {
if (mMap == null) {
mMap = new HashMap<String, SRRset>();
}
String k = key(rrset.getName(), rrset.getDClass());
rrset.setSecurityStatus(SecurityStatus.SECURE);
mMap.put(k, rrset);
}
private SRRset lookup(String key) {
if (mMap == null) return null;
return mMap.get(key);
}
public SRRset find(Name n, int dclass) {
if (mMap == null) return null;
while (n.labels() > 0) {
String k = key(n, dclass);
SRRset r = lookup(k);
if (r != null) return r;
n = new Name(n, 1);
}
return null;
}
public boolean isBelowTrustAnchor(Name n, int dclass) {
return find(n, dclass) != null;
}
} }

View File

@ -59,27 +59,6 @@ public class ValUtils {
// a throwaway response (i.e., an error) // a throwaway response (i.e., an error)
} }
// /** Not subtyped yet. */
// public static final int UNTYPED = 0;
//
// /** Not a recognized subtype. */
// public static final int UNKNOWN = 1;
//
// /** A postive, direct, response. */
// public static final int POSITIVE = 2;
//
// /** A postive response, with a CNAME/DNAME chain. */
// public static final int CNAME = 3;
//
// /** A NOERROR/NODATA response. */
// public static final int NODATA = 4;
//
// /** A NXDOMAIN response. */
// public static final int NAMEERROR = 5;
//
// /** A response to a qtype=ANY query. */
// public static final int ANY = 6;
/** A local copy of the verifier object. */ /** A local copy of the verifier object. */
private DnsSecVerifier mVerifier; private DnsSecVerifier mVerifier;
@ -598,7 +577,7 @@ public class ValUtils {
return true; return true;
} }
public static int nsecProvesNoDS(NSECRecord nsec, Name qname) { public static byte nsecProvesNoDS(NSECRecord nsec, Name qname) {
// Could check to make sure the qname is a subdomain of nsec // Could check to make sure the qname is a subdomain of nsec
int[] types = nsec.getTypes(); int[] types = nsec.getTypes();
if (typeMapHasType(types, Type.SOA) || typeMapHasType(types, Type.DS)) { if (typeMapHasType(types, Type.SOA) || typeMapHasType(types, Type.DS)) {