remove some warnings by using java 5 features
[captive-validator.git] / src / com / versign / tat / dnssec / CaptiveValidator.java
1 /*
2  * Copyright (c) 2009 VeriSign, Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28
29 package com.versign.tat.dnssec;
30
31 import java.io.IOException;
32 import java.util.*;
33
34 import org.xbill.DNS.*;
35
36 /**
37  * This resolver module implements a "captive" DNSSEC validator. The captive
38  * validator does not have direct access to the Internet and DNS system --
39  * instead it attempts to validate DNS messages using only configured context.
40  * This is useful for determining if responses coming from a given authoritative
41  * server will validate independent of the normal chain of trust.
42  */
43
44 public class CaptiveValidator {
45
46     // A data structure holding all all of our trusted keys.
47     private TrustAnchorStore mTrustedKeys;
48     
49     // The local validation utilities.
50     private ValUtils         mValUtils;
51
52     // The local verification utility.
53     private DnsSecVerifier   mVerifier;
54
55     public CaptiveValidator() {
56         mVerifier = new DnsSecVerifier();
57         mValUtils = new ValUtils(mVerifier);
58         mTrustedKeys = new TrustAnchorStore();
59     }
60
61     // ---------------- Module Initialization -------------------
62
63     /**
64      * Initialize the module.
65      */
66     public void init(Properties config) throws Exception {
67         mVerifier.init(config);
68
69         String s = config.getProperty("dns.trust_anchor_file");
70         if (s != null) {
71             try {
72                 loadTrustAnchors(s);
73             } catch (IOException e) {
74                 System.err.println("Error loading trust anchors: " + e);
75             }
76         }
77     }
78
79     /**
80      * Load the trust anchor file into the trust anchor store. The trust anchors
81      * are currently stored in a zone file format list of DNSKEY or DS records.
82      * 
83      * @param filename
84      *            The trust anchor file.
85      * @throws IOException
86      */
87     private void loadTrustAnchors(String filename) throws IOException {
88         System.err.println("reading trust anchor file file: " + filename);
89
90         // First read in the whole trust anchor file.
91         Master master = new Master(filename, Name.root, 0);
92         ArrayList records = new ArrayList();
93         Record r = null;
94
95         while ((r = master.nextRecord()) != null) {
96             records.add(r);
97         }
98
99         // Record.compareTo() should sort them into DNSSEC canonical order.
100         // Don't care about canonical order per se, but do want them to be
101         // formable into RRsets.
102         Collections.sort(records);
103
104         SRRset cur_rrset = new SRRset();
105         for (Iterator i = records.iterator(); i.hasNext();) {
106             r = (Record) i.next();
107             // Skip RR types that cannot be used as trust anchors.
108             if (r.getType() != Type.DNSKEY && r.getType() != Type.DS) continue;
109
110             // If our cur_rrset is empty, we can just add it.
111             if (cur_rrset.size() == 0) {
112                 cur_rrset.addRR(r);
113                 continue;
114             }
115             // If this record matches our current RRset, we can just add it.
116             if (cur_rrset.getName().equals(r.getName())
117                 && cur_rrset.getType() == r.getType()
118                 && cur_rrset.getDClass() == r.getDClass()) {
119                 cur_rrset.addRR(r);
120                 continue;
121             }
122
123             // Otherwise, we add the rrset to our set of trust anchors.
124             mTrustedKeys.store(cur_rrset);
125             cur_rrset = new SRRset();
126             cur_rrset.addRR(r);
127         }
128
129         // add the last rrset (if it was not empty)
130         if (cur_rrset.size() > 0) {
131             mTrustedKeys.store(cur_rrset);
132         }
133     }
134
135     // ----------------- Validation Support ----------------------
136
137     private SRRset findKeys(SMessage message) {
138         Name qname = message.getQName();
139         int qclass = message.getQClass();
140         
141         return mTrustedKeys.find(qname, qclass);
142     }
143     /**
144      * Check to see if a given response needs to go through the validation
145      * process. Typical reasons for this routine to return false are: CD bit was
146      * on in the original request, the response was already validated, or the
147      * response is a kind of message that is unvalidatable (i.e., SERVFAIL,
148      * REFUSED, etc.)
149      * 
150      * @param message
151      *            The message to check.
152      * @param origRequest
153      *            The original request received from the client.
154      * 
155      * @return true if the response could use validation (although this does not
156      *         mean we can actually validate this response).
157      */
158     private boolean needsValidation(SMessage message) {
159
160         // FIXME: add check to see if message qname is at or below any of our
161         // configured trust anchors.
162         
163         int rcode = message.getRcode();
164         
165         if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) {
166             // log.debug("cannot validate non-answer.");
167             // log.trace("non-answer: " + response);
168             return false;
169         }
170
171         return true;
172     }
173
174     /**
175      * Given a "positive" response -- a response that contains an answer to the
176      * question, and no CNAME chain, validate this response. This generally
177      * consists of verifying the answer RRset and the authority RRsets.
178      * 
179      * Note that by the time this method is called, the process of finding the
180      * trusted DNSKEY rrset that signs this response must already have been
181      * completed.
182      * 
183      * @param response
184      *            The response to validate.
185      * @param request
186      *            The request that generated this response.
187      * @param key_rrset
188      *            The trusted DNSKEY rrset that matches the signer of the
189      *            answer.
190      */
191     private void validatePositiveResponse(SMessage message, SRRset key_rrset) {
192         Name qname = message.getQName();
193         int qtype = message.getQType();
194
195         SMessage m = message;
196
197         // validate the ANSWER section - this will be the answer itself
198         SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
199
200         Name wc           = null;
201         boolean wcNSEC_ok = false;
202         boolean dname     = false;
203         List nsec3s       = null;
204
205         for (int i = 0; i < rrsets.length; i++) {
206             // Skip the CNAME following a (validated) DNAME.
207             // Because of the normalization routines in NameserverClient, there
208             // will always be an unsigned CNAME following a DNAME (unless
209             // qtype=DNAME).
210             if (dname && rrsets[i].getType() == Type.CNAME) {
211                 dname = false;
212                 continue;
213             }
214
215             // Verify the answer rrset.
216             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
217             // If the (answer) rrset failed to validate, then this message is
218             // BAD.
219             if (status != SecurityStatus.SECURE) {
220 //                log.debug("Positive response has failed ANSWER rrset: "
221 //                          + rrsets[i]);
222                 m.setStatus(SecurityStatus.BOGUS);
223                 return;
224             }
225             // Check to see if the rrset is the result of a wildcard expansion.
226             // If so, an additional check will need to be made in the authority
227             // section.
228             wc = ValUtils.rrsetWildcard(rrsets[i]);
229
230             // Notice a DNAME that should be followed by an unsigned CNAME.
231             if (qtype != Type.DNAME && rrsets[i].getType() == Type.DNAME) {
232                 dname = true;
233             }
234         }
235
236         // validate the AUTHORITY section as well - this will generally be the
237         // NS rrset (which could be missing, no problem)
238         rrsets = m.getSectionRRsets(Section.AUTHORITY);
239         for (int i = 0; i < rrsets.length; i++) {
240             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
241             // If anything in the authority section fails to be secure, we have
242             // a
243             // bad message.
244             if (status != SecurityStatus.SECURE) {
245 //                log.debug("Positive response has failed AUTHORITY rrset: "
246 //                          + rrsets[i]);
247                 m.setStatus(SecurityStatus.BOGUS);
248                 return;
249             }
250
251             // If this is a positive wildcard response, and we have a (just
252             // verified) NSEC record, try to use it to 1) prove that qname
253             // doesn't exist and 2) that the correct wildcard was used.
254             if (wc != null && rrsets[i].getType() == Type.NSEC) {
255                 NSECRecord nsec = (NSECRecord) rrsets[i].first();
256
257                 if (ValUtils.nsecProvesNameError(nsec, qname,
258                                                  key_rrset.getName())) {
259                     Name nsec_wc = ValUtils.nsecWildcard(qname, nsec);
260                     if (!wc.equals(nsec_wc)) {
261 //                        log.debug("Postive wildcard response wasn't generated "
262 //                                  + "by the correct wildcard");
263                         m.setStatus(SecurityStatus.BOGUS);
264                         return;
265                     }
266                     wcNSEC_ok = true;
267                 }
268             }
269
270             // Otherwise, if this is a positive wildcard response and we have
271             // NSEC3 records, collect them.
272             if (wc != null && rrsets[i].getType() == Type.NSEC3) {
273                 if (nsec3s == null) nsec3s = new ArrayList();
274                 nsec3s.add(rrsets[i].first());
275             }
276         }
277
278         // If this was a positive wildcard response that we haven't already
279         // proven, and we have NSEC3 records, try to prove it using the NSEC3
280         // records.
281         if (wc != null && !wcNSEC_ok && nsec3s != null) {
282             if (NSEC3ValUtils.proveWildcard(nsec3s, qname, key_rrset.getName(),
283                                             wc)) {
284                 wcNSEC_ok = true;
285             }
286         }
287
288         // If after all this, we still haven't proven the positive wildcard
289         // response, fail.
290         if (wc != null && !wcNSEC_ok) {
291 //            log.debug("positive response was wildcard expansion and "
292 //                      + "did not prove original data did not exist");
293             m.setStatus(SecurityStatus.BOGUS);
294             return;
295         }
296
297 //        log.trace("Successfully validated postive response");
298         m.setStatus(SecurityStatus.SECURE);
299     }
300
301     private void validateReferral(SMessage message, SRRset key_rrset) {
302         
303     }
304     
305     private void validateCNAMEResponse(SMessage message, SRRset key_rrset) {
306         
307     }
308     
309     /**
310      * Given an "ANY" response -- a response that contains an answer to a
311      * qtype==ANY question, with answers. This consists of simply verifying all
312      * present answer/auth RRsets, with no checking that all types are present.
313      * 
314      * NOTE: it may be possible to get parent-side delegation point records
315      * here, which won't all be signed. Right now, this routine relies on the
316      * upstream iterative resolver to not return these responses -- instead
317      * treating them as referrals.
318      * 
319      * NOTE: RFC 4035 is silent on this issue, so this may change upon
320      * clarification.
321      * 
322      * Note that by the time this method is called, the process of finding the
323      * trusted DNSKEY rrset that signs this response must already have been
324      * completed.
325      * 
326      * @param message
327      *            The response to validate.
328      * @param key_rrset
329      *            The trusted DNSKEY rrset that matches the signer of the
330      *            answer.
331      */
332     private void validateAnyResponse(SMessage message, SRRset key_rrset) {
333         int qtype = message.getQType();
334
335         if (qtype != Type.ANY)
336             throw new IllegalArgumentException(
337                     "ANY validation called on non-ANY response.");
338
339         SMessage m = message;
340
341         // validate the ANSWER section.
342         SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
343         for (int i = 0; i < rrsets.length; i++) {
344             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
345             // If the (answer) rrset failed to validate, then this message is
346             // BAD.
347             if (status != SecurityStatus.SECURE) {
348 //                log.debug("Postive response has failed ANSWER rrset: "
349 //                          + rrsets[i]);
350                 m.setStatus(SecurityStatus.BOGUS);
351                 return;
352             }
353         }
354
355         // validate the AUTHORITY section as well - this will be the NS rrset
356         // (which could be missing, no problem)
357         rrsets = m.getSectionRRsets(Section.AUTHORITY);
358         for (int i = 0; i < rrsets.length; i++) {
359             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
360             // If anything in the authority section fails to be secure, we have
361             // a
362             // bad message.
363             if (status != SecurityStatus.SECURE) {
364 //                log.debug("Postive response has failed AUTHORITY rrset: "
365 //                          + rrsets[i]);
366                 m.setStatus(SecurityStatus.BOGUS);
367                 return;
368             }
369         }
370
371 //        log.trace("Successfully validated postive ANY response");
372         m.setStatus(SecurityStatus.SECURE);
373     }
374
375     /**
376      * Validate a NOERROR/NODATA signed response -- a response that has a
377      * NOERROR Rcode but no ANSWER section RRsets. This consists of verifying
378      * the authority section rrsets and making certain that the authority
379      * section NSEC/NSEC3s proves that the qname does exist and the qtype
380      * doesn't.
381      * 
382      * Note that by the time this method is called, the process of finding the
383      * trusted DNSKEY rrset that signs this response must already have been
384      * completed.
385      * 
386      * @param response
387      *            The response to validate.
388      * @param request
389      *            The request that generated this response.
390      * @param key_rrset
391      *            The trusted DNSKEY rrset that signs this response.
392      */
393     private void validateNodataResponse(SMessage message, SRRset key_rrset) {
394         Name qname = message.getQName();
395         int qtype = message.getQType();
396
397         SMessage m = message;
398
399         // Since we are here, there must be nothing in the ANSWER section to
400         // validate. (Note: CNAME/DNAME responses will not directly get here --
401         // instead they are broken down into individual CNAME/DNAME/final answer
402         // responses.)
403
404         // validate the AUTHORITY section
405         SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
406
407         boolean hasValidNSEC = false; // If true, then the NODATA has been
408         // proven.
409         Name ce = null; // for wildcard nodata responses. This is the proven
410         // closest encloser.
411         NSECRecord wc = null; // for wildcard nodata responses. This is the
412         // wildcard NSEC.
413         List nsec3s = null; // A collection of NSEC3 RRs found in the authority
414         // section.
415         Name nsec3Signer = null; // The RRSIG signer field for the NSEC3 RRs.
416
417         for (int i = 0; i < rrsets.length; i++) {
418             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
419             if (status != SecurityStatus.SECURE) {
420 //                log.debug("NODATA response has failed AUTHORITY rrset: "
421 //                          + rrsets[i]);
422                 m.setStatus(SecurityStatus.BOGUS);
423                 return;
424             }
425
426             // If we encounter an NSEC record, try to use it to prove NODATA.
427             // This needs to handle the ENT NODATA case.
428             if (rrsets[i].getType() == Type.NSEC) {
429                 NSECRecord nsec = (NSECRecord) rrsets[i].first();
430                 if (ValUtils.nsecProvesNodata(nsec, qname, qtype)) {
431                     hasValidNSEC = true;
432                     if (nsec.getName().isWild()) wc = nsec;
433                 } else if (ValUtils.nsecProvesNameError(
434                                                         nsec,
435                                                         qname,
436                                                         rrsets[i].getSignerName())) {
437                     ce = ValUtils.closestEncloser(qname, nsec);
438                 }
439             }
440
441             // Collect any NSEC3 records present.
442             if (rrsets[i].getType() == Type.NSEC3) {
443                 if (nsec3s == null) nsec3s = new ArrayList();
444                 nsec3s.add(rrsets[i].first());
445                 nsec3Signer = rrsets[i].getSignerName();
446             }
447         }
448
449         // check to see if we have a wildcard NODATA proof.
450
451         // The wildcard NODATA is 1 NSEC proving that qname does not exists (and
452         // also proving what the closest encloser is), and 1 NSEC showing the
453         // matching wildcard, which must be *.closest_encloser.
454         if (ce != null || wc != null) {
455             try {
456                 Name wc_name = new Name("*", ce);
457                 if (!wc_name.equals(wc.getName())) {
458                     hasValidNSEC = false;
459                 }
460             } catch (TextParseException e) {
461 //                log.error(e);
462             }
463         }
464
465         NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
466
467         if (!hasValidNSEC && nsec3s != null && nsec3s.size() > 0) {
468             // try to prove NODATA with our NSEC3 record(s)
469             hasValidNSEC = NSEC3ValUtils.proveNodata(nsec3s, qname, qtype,
470                                                      nsec3Signer);
471         }
472
473         if (!hasValidNSEC) {
474 //            log.debug("NODATA response failed to prove NODATA "
475 //                      + "status with NSEC/NSEC3");
476 //            log.trace("Failed NODATA:\n" + m);
477             m.setStatus(SecurityStatus.BOGUS);
478             return;
479         }
480 //        log.trace("sucessfully validated NODATA response.");
481         m.setStatus(SecurityStatus.SECURE);
482     }
483
484     /**
485      * Validate a NAMEERROR signed response -- a response that has a NXDOMAIN
486      * Rcode. This consists of verifying the authority section rrsets and making
487      * certain that the authority section NSEC proves that the qname doesn't
488      * exist and the covering wildcard also doesn't exist..
489      * 
490      * Note that by the time this method is called, the process of finding the
491      * trusted DNSKEY rrset that signs this response must already have been
492      * completed.
493      * 
494      * @param response
495      *            The response to validate.
496      * @param request
497      *            The request that generated this response.
498      * @param key_rrset
499      *            The trusted DNSKEY rrset that signs this response.
500      */
501     private void validateNameErrorResponse(SMessage message, SRRset key_rrset) {
502         Name qname = message.getQName();
503
504         SMessage m = message;
505
506         // FIXME: should we check to see if there is anything in the answer
507         // section? if so, what should the result be?
508
509         // Validate the authority section -- all RRsets in the authority section
510         // must be signed and valid.
511         // In addition, the NSEC record(s) must prove the NXDOMAIN condition.
512
513         boolean hasValidNSEC = false;
514         boolean hasValidWCNSEC = false;
515         SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
516         List nsec3s = null;
517         Name nsec3Signer = null;
518
519         for (int i = 0; i < rrsets.length; i++) {
520             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
521             if (status != SecurityStatus.SECURE) {
522 //                log.debug("NameError response has failed AUTHORITY rrset: "
523 //                          + rrsets[i]);
524                 m.setStatus(SecurityStatus.BOGUS);
525                 return;
526             }
527             if (rrsets[i].getType() == Type.NSEC) {
528                 NSECRecord nsec = (NSECRecord) rrsets[i].first();
529
530                 if (ValUtils.nsecProvesNameError(nsec, qname,
531                                                  rrsets[i].getSignerName())) {
532                     hasValidNSEC = true;
533                 }
534                 if (ValUtils.nsecProvesNoWC(nsec, qname,
535                                             rrsets[i].getSignerName())) {
536                     hasValidWCNSEC = true;
537                 }
538             }
539             if (rrsets[i].getType() == Type.NSEC3) {
540                 if (nsec3s == null) nsec3s = new ArrayList();
541                 nsec3s.add(rrsets[i].first());
542                 nsec3Signer = rrsets[i].getSignerName();
543             }
544         }
545
546         NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
547
548         if (nsec3s != null && nsec3s.size() > 0) {
549 //            log.debug("Validating nxdomain: using NSEC3 records");
550             // Attempt to prove name error with nsec3 records.
551
552             if (NSEC3ValUtils.allNSEC3sIgnoreable(nsec3s, key_rrset, mVerifier)) {
553 //                log.debug("all NSEC3s were validated but ignored.");
554                 m.setStatus(SecurityStatus.INSECURE);
555                 return;
556             }
557
558             hasValidNSEC = NSEC3ValUtils.proveNameError(nsec3s, qname,
559                                                         nsec3Signer);
560
561             // Note that we assume that the NSEC3ValUtils proofs encompass the
562             // wildcard part of the proof.
563             hasValidWCNSEC = hasValidNSEC;
564         }
565
566         // If the message fails to prove either condition, it is bogus.
567         if (!hasValidNSEC) {
568 //            log.debug("NameError response has failed to prove: "
569 //                      + "qname does not exist");
570             m.setStatus(SecurityStatus.BOGUS);
571             return;
572         }
573
574         if (!hasValidWCNSEC) {
575 //            log.debug("NameError response has failed to prove: "
576 //                      + "covering wildcard does not exist");
577             m.setStatus(SecurityStatus.BOGUS);
578             return;
579         }
580
581         // Otherwise, we consider the message secure.
582 //        log.trace("successfully validated NAME ERROR response.");
583         m.setStatus(SecurityStatus.SECURE);
584     }
585
586 //    /**
587 //     * This state is used for validating CNAME-type responses -- i.e., responses
588 //     * that have CNAME chains.
589 //     * 
590 //     * It primarily is responsible for breaking down the response into a series
591 //     * of separately validated queries & responses.
592 //     * 
593 //     * @param event
594 //     * @param state
595 //     * @return
596 //     */
597 //    private boolean processCNAME(DNSEvent event, ValEventState state) {
598 //        Request req = event.getRequest();
599 //
600 //        Name qname = req.getQName();
601 //        int qtype = req.getQType();
602 //        int qclass = req.getQClass();
603 //
604 //        SMessage m = event.getResponse().getSMessage();
605 //
606 //        if (state.cnameSname == null) state.cnameSname = qname;
607 //
608 //        // We break the chain down by re-querying for the specific CNAME or
609 //        // DNAME
610 //        // (or final answer).
611 //        SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
612 //
613 //        while (state.cnameIndex < rrsets.length) {
614 //            SRRset rrset = rrsets[state.cnameIndex++];
615 //            Name rname = rrset.getName();
616 //            int rtype = rrset.getType();
617 //
618 //            // Skip DNAMEs -- prefer to query for the generated CNAME,
619 //            if (rtype == Type.DNAME && qtype != Type.DNAME) continue;
620 //
621 //            // Set the SNAME if we are dealing with a CNAME
622 //            if (rtype == Type.CNAME) {
623 //                CNAMERecord cname = (CNAMERecord) rrset.first();
624 //                state.cnameSname = cname.getTarget();
625 //            }
626 //
627 //            // Note if the current rrset is the answer. In that case, we want to
628 //            // set
629 //            // the final state differently.
630 //            // For non-answers, the response ultimately comes back here.
631 //            int final_state = ValEventState.CNAME_RESP_STATE;
632 //            if (isAnswerRRset(rrset.getName(), rtype, state.cnameSname, qtype,
633 //                              Section.ANSWER)) {
634 //                // If this is an answer, however, break out of this loop.
635 //                final_state = ValEventState.CNAME_ANS_RESP_STATE;
636 //            }
637 //
638 //            // Generate the sub-query.
639 //            Request localRequest = generateLocalRequest(rname, rtype, qclass);
640 //            DNSEvent localEvent = generateLocalEvent(event, localRequest,
641 //                                                     ValEventState.INIT_STATE,
642 //                                                     final_state);
643 //
644 //            // ...and send it along.
645 //            processLocalRequest(localEvent);
646 //            return false;
647 //        }
648 //
649 //        // Something odd has happened if we get here.
650 //        log.warn("processCNAME: encountered unknown issue handling a CNAME chain.");
651 //        return false;
652 //    }
653 //
654 //    private boolean processCNAMEResponse(DNSEvent event, ValEventState state) {
655 //        DNSEvent forEvent = event.forEvent();
656 //        ValEventState forState = getModuleState(forEvent);
657 //
658 //        SMessage resp = event.getResponse().getSMessage();
659 //        if (resp.getStatus() != SecurityStatus.SECURE) {
660 //            forEvent.getResponse().getSMessage().setStatus(resp.getStatus());
661 //            forState.state = forState.finalState;
662 //            handleResponse(forEvent, forState);
663 //            return false;
664 //        }
665 //
666 //        forState.state = ValEventState.CNAME_STATE;
667 //        handleResponse(forEvent, forState);
668 //        return false;
669 //    }
670 //
671 //    private boolean processCNAMEAnswer(DNSEvent event, ValEventState state) {
672 //        DNSEvent forEvent = event.forEvent();
673 //        ValEventState forState = getModuleState(forEvent);
674 //
675 //        SMessage resp = event.getResponse().getSMessage();
676 //        SMessage forResp = forEvent.getResponse().getSMessage();
677 //
678 //        forResp.setStatus(resp.getStatus());
679 //
680 //        forState.state = forState.finalState;
681 //        handleResponse(forEvent, forState);
682 //        return false;
683 //    }
684
685
686     public byte validateMessage(SMessage message, Name zone) {
687
688         SRRset key_rrset = findKeys(message);
689         if (key_rrset == null) {
690             return SecurityStatus.BOGUS;
691         }
692         
693         ValUtils.ResponseType subtype = ValUtils.classifyResponse(message, zone);
694
695         switch (subtype) {
696         case POSITIVE:
697             // log.trace("Validating a positive response");
698             validatePositiveResponse(message, key_rrset);
699             break;
700         case REFERRAL:
701             validateReferral(message, key_rrset);
702             break;
703         case NODATA:
704             // log.trace("Validating a nodata response");
705             validateNodataResponse(message, key_rrset);
706             break;
707         case NAMEERROR:
708             // log.trace("Validating a nxdomain response");
709             validateNameErrorResponse(message, key_rrset);
710             break;
711         case CNAME:
712             // log.trace("Validating a cname response");
713             // forward on to the special CNAME state for this.
714 //            state.state = ValEventState.CNAME_STATE;
715             validateCNAMEResponse(message, key_rrset);
716             break;
717         case ANY:
718             // log.trace("Validating a postive ANY response");
719             validateAnyResponse(message, key_rrset);
720             break;
721         default:
722             // log.error("unhandled response subtype: " + subtype);
723         }
724         
725         return message.getSecurityStatus().getStatus();
726
727     }
728 }