From 2c8136786124afffa2159064f1bda14a83e0ecfc Mon Sep 17 00:00:00 2001 From: davidb Date: Wed, 9 Jun 2010 18:25:26 -0400 Subject: [PATCH] now basically works, although not tested --- build.xml | 92 +++++++++ src/com/verisign/cl/DNSSECReconciler.java | 174 ++++++++++++++++-- .../verisign/tat/dnssec/CaptiveValidator.java | 3 +- 3 files changed, 248 insertions(+), 21 deletions(-) create mode 100644 build.xml diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..c403b78 --- /dev/null +++ b/build.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/com/verisign/cl/DNSSECReconciler.java b/src/com/verisign/cl/DNSSECReconciler.java index 49c0777..20765ce 100644 --- a/src/com/verisign/cl/DNSSECReconciler.java +++ b/src/com/verisign/cl/DNSSECReconciler.java @@ -1,10 +1,14 @@ package com.verisign.cl; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; import java.util.*; import org.xbill.DNS.*; import com.verisign.tat.dnssec.CaptiveValidator; +import com.verisign.tat.dnssec.SecurityStatus; public class DNSSECReconciler { @@ -13,6 +17,10 @@ public class DNSSECReconciler { * query_file=queries.txt dnskey_query=net dnskey_query=edu */ private CaptiveValidator validator; + private SimpleResolver resolver; + + private BufferedReader queryStream; + private Set zoneNames; // Options public String server; @@ -28,7 +36,7 @@ public class DNSSECReconciler { /** * Convert a query line of the form: to a request * message. - * + * * @param query_line * @return A query message * @throws TextParseException @@ -74,24 +82,150 @@ public class DNSSECReconciler { qclass = DClass.IN; } - Message query = Message.newQuery(Record.newRecord(qname, qtype, qclass)); + Message query = Message + .newQuery(Record.newRecord(qname, qtype, qclass)); return query; } - public void execute() { + /** + * Fetch the next query from either the command line or the query file + * + * @return a query Message, or null if the query list is exhausted + * @throws IOException + */ + private Message nextQuery() throws IOException { + if (query != null) { + Message res = queryFromString(query); + query = null; + return res; + } + + if (queryStream == null && queryFile != null) { + queryStream = new BufferedReader(new FileReader(queryFile)); + } + + if (queryStream != null) { + String line = queryStream.readLine(); + + if (line == null) + return null; + + return queryFromString(line); + } + + return null; + + } + + /** + * Figure out the correct zone from the query by comparing the qname to the + * list of trusted DNSKEY owner names. + * + * @param query + * @return a zone name + * @throws IOException + */ + private Name zoneFromQuery(Message query) throws IOException { + + if (zoneNames == null) { + zoneNames = new HashSet(); + for (String key : validator.listTrustedKeys()) { + String[] components = key.split("/"); + Name keyname = Name.fromString(components[0]); + if (! keyname.isAbsolute()) { + keyname = Name.concatenate(keyname, Name.root); + } + zoneNames.add(keyname); + } + } + + Name qname = query.getQuestion().getName(); + for (Name n : zoneNames) { + if (qname.subdomain(n)) { + return n; + } + } + + return null; + } + + public void execute() throws IOException { + // Configure our resolver + resolver = new SimpleResolver(server); + resolver.setEDNS(0, 4096, Flags.DO, null); + + // Prime the validator + if (dnskeyFile != null) { + validator.addTrustedKeysFromFile(dnskeyFile); + } else { + for (String name : dnskeyNames) { + Message query = queryFromString(name + " DNSKEY"); + Message response = resolver.send(query); + validator.addTrustedKeysFromResponse(response); + } + } + + // Log our set of trusted keys + for (String key : validator.listTrustedKeys()) { + System.out.println("Trusted Key: " + key); + } + + // Iterate over all queries + Message query = nextQuery(); + + while (query != null) { + Message response = resolver.send(query); + if (response == null) { + continue; + } + + Name zone = zoneFromQuery(query); + byte result = validator.validateMessage(response, zone.toString()); + + switch (result) { + case SecurityStatus.BOGUS: + case SecurityStatus.INVALID: + System.out.println("BOGUS Answer:"); + System.out.println("Query: " + query.getQuestion()); + System.out.println("Response:\n" + response); + for (String err : validator.getErrorList()) { + System.out.println("Error: " + err); + } + System.out.println(""); + break; + case SecurityStatus.INSECURE: + case SecurityStatus.INDETERMINATE: + case SecurityStatus.UNCHECKED: + System.out.println("Insecure Answer:"); + System.out.println("Query: " + query.getQuestion()); + System.out.println("Response:\n" + response); + for (String err : validator.getErrorList()) { + System.out.println("Error: " + err); + } + break; + case SecurityStatus.SECURE: + break; + } + + query = nextQuery(); + } } private static void usage() { - System.err.println("usage: java -jar dnssecreconiler.jar [..options..]"); + System.err + .println("usage: java -jar dnssecreconiler.jar [..options..]"); System.err.println(" server: the DNS server to query."); System.err.println(" query: a name [type [flags]] string."); - System.err.println(" query_file: a list of queries, one query per line."); - System.err.println(" dnskey_file: a file containing DNSKEY RRs to trust."); - System.err.println(" dnskey_query: query 'server' for DNSKEY at given name to trust, may repeat"); + System.err + .println(" query_file: a list of queries, one query per line."); + System.err + .println(" dnskey_file: a file containing DNSKEY RRs to trust."); + System.err + .println(" dnskey_query: query 'server' for DNSKEY at given name to trust, may repeat"); } - public static int main(String[] argv) { + public static void main(String[] argv) { DNSSECReconciler dr = new DNSSECReconciler(); @@ -102,15 +236,17 @@ public class DNSSECReconciler { if (arg.indexOf('=') < 0) { System.err.println("Unrecognized option: " + arg); usage(); - return 1; + System.exit(1); } - String[] split_arg = arg.split("[ \t]*=[ \t]*", 2); + String[] split_arg = arg.split("=", 2); String opt = split_arg[0]; String optarg = split_arg[1]; if (opt.equals("server")) { dr.server = optarg; + } else if (opt.equals("query")) { + dr.query = optarg; } else if (opt.equals("query_file")) { dr.queryFile = optarg; } else if (opt.equals("dnskey_file")) { @@ -123,7 +259,7 @@ public class DNSSECReconciler { } else { System.err.println("Unrecognized option: " + opt); usage(); - return 1; + System.exit(1); } } @@ -131,17 +267,19 @@ public class DNSSECReconciler { if (dr.server == null) { System.err.println("'server' must be specified"); usage(); - return 1; + System.exit(1); } if (dr.query == null && dr.queryFile == null) { - System.err.println("Either 'query' or 'query_file' must be specified"); + System.err + .println("Either 'query' or 'query_file' must be specified"); usage(); - return 1; + System.exit(1); } if (dr.dnskeyFile == null && dr.dnskeyNames == null) { - System.err.println("Either 'dnskey_file' or 'dnskey_query' must be specified"); + System.err + .println("Either 'dnskey_file' or 'dnskey_query' must be specified"); usage(); - return 1; + System.exit(1); } // Execute the job @@ -149,9 +287,7 @@ public class DNSSECReconciler { } catch (Exception e) { e.printStackTrace(); - return 1; + System.exit(1); } - - return 0; } } diff --git a/src/com/verisign/tat/dnssec/CaptiveValidator.java b/src/com/verisign/tat/dnssec/CaptiveValidator.java index 07311ce..74853de 100644 --- a/src/com/verisign/tat/dnssec/CaptiveValidator.java +++ b/src/com/verisign/tat/dnssec/CaptiveValidator.java @@ -943,8 +943,7 @@ public class CaptiveValidator { return SecurityStatus.BOGUS; } - ValUtils.ResponseType subtype = ValUtils - .classifyResponse(message, zone); + ValUtils.ResponseType subtype = ValUtils.classifyResponse(message, zone); switch (subtype) { case POSITIVE: