more progress -- still not compiling
[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     /**
302      * Given an "ANY" response -- a response that contains an answer to a
303      * qtype==ANY question, with answers. This consists of simply verifying all
304      * present answer/auth RRsets, with no checking that all types are present.
305      * 
306      * NOTE: it may be possible to get parent-side delegation point records
307      * here, which won't all be signed. Right now, this routine relies on the
308      * upstream iterative resolver to not return these responses -- instead
309      * treating them as referrals.
310      * 
311      * NOTE: RFC 4035 is silent on this issue, so this may change upon
312      * clarification.
313      * 
314      * Note that by the time this method is called, the process of finding the
315      * trusted DNSKEY rrset that signs this response must already have been
316      * completed.
317      * 
318      * @param message
319      *            The response to validate.
320      * @param key_rrset
321      *            The trusted DNSKEY rrset that matches the signer of the
322      *            answer.
323      */
324     private void validateAnyResponse(SMessage message, SRRset key_rrset) {
325         int qtype = message.getQType();
326
327         if (qtype != Type.ANY)
328             throw new IllegalArgumentException(
329                     "ANY validation called on non-ANY response.");
330
331         SMessage m = message;
332
333         // validate the ANSWER section.
334         SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
335         for (int i = 0; i < rrsets.length; i++) {
336             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
337             // If the (answer) rrset failed to validate, then this message is
338             // BAD.
339             if (status != SecurityStatus.SECURE) {
340 //                log.debug("Postive response has failed ANSWER rrset: "
341 //                          + rrsets[i]);
342                 m.setStatus(SecurityStatus.BOGUS);
343                 return;
344             }
345         }
346
347         // validate the AUTHORITY section as well - this will be the NS rrset
348         // (which could be missing, no problem)
349         rrsets = m.getSectionRRsets(Section.AUTHORITY);
350         for (int i = 0; i < rrsets.length; i++) {
351             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
352             // If anything in the authority section fails to be secure, we have
353             // a
354             // bad message.
355             if (status != SecurityStatus.SECURE) {
356 //                log.debug("Postive response has failed AUTHORITY rrset: "
357 //                          + rrsets[i]);
358                 m.setStatus(SecurityStatus.BOGUS);
359                 return;
360             }
361         }
362
363 //        log.trace("Successfully validated postive ANY response");
364         m.setStatus(SecurityStatus.SECURE);
365     }
366
367     /**
368      * Validate a NOERROR/NODATA signed response -- a response that has a
369      * NOERROR Rcode but no ANSWER section RRsets. This consists of verifying
370      * the authority section rrsets and making certain that the authority
371      * section NSEC/NSEC3s proves that the qname does exist and the qtype
372      * doesn't.
373      * 
374      * Note that by the time this method is called, the process of finding the
375      * trusted DNSKEY rrset that signs this response must already have been
376      * completed.
377      * 
378      * @param response
379      *            The response to validate.
380      * @param request
381      *            The request that generated this response.
382      * @param key_rrset
383      *            The trusted DNSKEY rrset that signs this response.
384      */
385     private void validateNodataResponse(SMessage message, SRRset key_rrset) {
386         Name qname = message.getQName();
387         int qtype = message.getQType();
388
389         SMessage m = message;
390
391         // Since we are here, there must be nothing in the ANSWER section to
392         // validate. (Note: CNAME/DNAME responses will not directly get here --
393         // instead they are broken down into individual CNAME/DNAME/final answer
394         // responses.)
395
396         // validate the AUTHORITY section
397         SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
398
399         boolean hasValidNSEC = false; // If true, then the NODATA has been
400         // proven.
401         Name ce = null; // for wildcard nodata responses. This is the proven
402         // closest encloser.
403         NSECRecord wc = null; // for wildcard nodata responses. This is the
404         // wildcard NSEC.
405         List nsec3s = null; // A collection of NSEC3 RRs found in the authority
406         // section.
407         Name nsec3Signer = null; // The RRSIG signer field for the NSEC3 RRs.
408
409         for (int i = 0; i < rrsets.length; i++) {
410             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
411             if (status != SecurityStatus.SECURE) {
412 //                log.debug("NODATA response has failed AUTHORITY rrset: "
413 //                          + rrsets[i]);
414                 m.setStatus(SecurityStatus.BOGUS);
415                 return;
416             }
417
418             // If we encounter an NSEC record, try to use it to prove NODATA.
419             // This needs to handle the ENT NODATA case.
420             if (rrsets[i].getType() == Type.NSEC) {
421                 NSECRecord nsec = (NSECRecord) rrsets[i].first();
422                 if (ValUtils.nsecProvesNodata(nsec, qname, qtype)) {
423                     hasValidNSEC = true;
424                     if (nsec.getName().isWild()) wc = nsec;
425                 } else if (ValUtils.nsecProvesNameError(
426                                                         nsec,
427                                                         qname,
428                                                         rrsets[i].getSignerName())) {
429                     ce = ValUtils.closestEncloser(qname, nsec);
430                 }
431             }
432
433             // Collect any NSEC3 records present.
434             if (rrsets[i].getType() == Type.NSEC3) {
435                 if (nsec3s == null) nsec3s = new ArrayList();
436                 nsec3s.add(rrsets[i].first());
437                 nsec3Signer = rrsets[i].getSignerName();
438             }
439         }
440
441         // check to see if we have a wildcard NODATA proof.
442
443         // The wildcard NODATA is 1 NSEC proving that qname does not exists (and
444         // also proving what the closest encloser is), and 1 NSEC showing the
445         // matching wildcard, which must be *.closest_encloser.
446         if (ce != null || wc != null) {
447             try {
448                 Name wc_name = new Name("*", ce);
449                 if (!wc_name.equals(wc.getName())) {
450                     hasValidNSEC = false;
451                 }
452             } catch (TextParseException e) {
453 //                log.error(e);
454             }
455         }
456
457         NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
458
459         if (!hasValidNSEC && nsec3s != null && nsec3s.size() > 0) {
460             // try to prove NODATA with our NSEC3 record(s)
461             hasValidNSEC = NSEC3ValUtils.proveNodata(nsec3s, qname, qtype,
462                                                      nsec3Signer);
463         }
464
465         if (!hasValidNSEC) {
466 //            log.debug("NODATA response failed to prove NODATA "
467 //                      + "status with NSEC/NSEC3");
468 //            log.trace("Failed NODATA:\n" + m);
469             m.setStatus(SecurityStatus.BOGUS);
470             return;
471         }
472 //        log.trace("sucessfully validated NODATA response.");
473         m.setStatus(SecurityStatus.SECURE);
474     }
475
476     /**
477      * Validate a NAMEERROR signed response -- a response that has a NXDOMAIN
478      * Rcode. This consists of verifying the authority section rrsets and making
479      * certain that the authority section NSEC proves that the qname doesn't
480      * exist and the covering wildcard also doesn't exist..
481      * 
482      * Note that by the time this method is called, the process of finding the
483      * trusted DNSKEY rrset that signs this response must already have been
484      * completed.
485      * 
486      * @param response
487      *            The response to validate.
488      * @param request
489      *            The request that generated this response.
490      * @param key_rrset
491      *            The trusted DNSKEY rrset that signs this response.
492      */
493     private void validateNameErrorResponse(SMessage message, SRRset key_rrset) {
494         Name qname = message.getQName();
495
496         SMessage m = message;
497
498         // FIXME: should we check to see if there is anything in the answer
499         // section? if so, what should the result be?
500
501         // Validate the authority section -- all RRsets in the authority section
502         // must be signed and valid.
503         // In addition, the NSEC record(s) must prove the NXDOMAIN condition.
504
505         boolean hasValidNSEC = false;
506         boolean hasValidWCNSEC = false;
507         SRRset[] rrsets = m.getSectionRRsets(Section.AUTHORITY);
508         List nsec3s = null;
509         Name nsec3Signer = null;
510
511         for (int i = 0; i < rrsets.length; i++) {
512             int status = mValUtils.verifySRRset(rrsets[i], key_rrset);
513             if (status != SecurityStatus.SECURE) {
514 //                log.debug("NameError response has failed AUTHORITY rrset: "
515 //                          + rrsets[i]);
516                 m.setStatus(SecurityStatus.BOGUS);
517                 return;
518             }
519             if (rrsets[i].getType() == Type.NSEC) {
520                 NSECRecord nsec = (NSECRecord) rrsets[i].first();
521
522                 if (ValUtils.nsecProvesNameError(nsec, qname,
523                                                  rrsets[i].getSignerName())) {
524                     hasValidNSEC = true;
525                 }
526                 if (ValUtils.nsecProvesNoWC(nsec, qname,
527                                             rrsets[i].getSignerName())) {
528                     hasValidWCNSEC = true;
529                 }
530             }
531             if (rrsets[i].getType() == Type.NSEC3) {
532                 if (nsec3s == null) nsec3s = new ArrayList();
533                 nsec3s.add(rrsets[i].first());
534                 nsec3Signer = rrsets[i].getSignerName();
535             }
536         }
537
538         NSEC3ValUtils.stripUnknownAlgNSEC3s(nsec3s);
539
540         if (nsec3s != null && nsec3s.size() > 0) {
541 //            log.debug("Validating nxdomain: using NSEC3 records");
542             // Attempt to prove name error with nsec3 records.
543
544             if (NSEC3ValUtils.allNSEC3sIgnoreable(nsec3s, key_rrset, mVerifier)) {
545 //                log.debug("all NSEC3s were validated but ignored.");
546                 m.setStatus(SecurityStatus.INSECURE);
547                 return;
548             }
549
550             hasValidNSEC = NSEC3ValUtils.proveNameError(nsec3s, qname,
551                                                         nsec3Signer);
552
553             // Note that we assume that the NSEC3ValUtils proofs encompass the
554             // wildcard part of the proof.
555             hasValidWCNSEC = hasValidNSEC;
556         }
557
558         // If the message fails to prove either condition, it is bogus.
559         if (!hasValidNSEC) {
560 //            log.debug("NameError response has failed to prove: "
561 //                      + "qname does not exist");
562             m.setStatus(SecurityStatus.BOGUS);
563             return;
564         }
565
566         if (!hasValidWCNSEC) {
567 //            log.debug("NameError response has failed to prove: "
568 //                      + "covering wildcard does not exist");
569             m.setStatus(SecurityStatus.BOGUS);
570             return;
571         }
572
573         // Otherwise, we consider the message secure.
574 //        log.trace("successfully validated NAME ERROR response.");
575         m.setStatus(SecurityStatus.SECURE);
576     }
577
578 //    /**
579 //     * This state is used for validating CNAME-type responses -- i.e., responses
580 //     * that have CNAME chains.
581 //     * 
582 //     * It primarily is responsible for breaking down the response into a series
583 //     * of separately validated queries & responses.
584 //     * 
585 //     * @param event
586 //     * @param state
587 //     * @return
588 //     */
589 //    private boolean processCNAME(DNSEvent event, ValEventState state) {
590 //        Request req = event.getRequest();
591 //
592 //        Name qname = req.getQName();
593 //        int qtype = req.getQType();
594 //        int qclass = req.getQClass();
595 //
596 //        SMessage m = event.getResponse().getSMessage();
597 //
598 //        if (state.cnameSname == null) state.cnameSname = qname;
599 //
600 //        // We break the chain down by re-querying for the specific CNAME or
601 //        // DNAME
602 //        // (or final answer).
603 //        SRRset[] rrsets = m.getSectionRRsets(Section.ANSWER);
604 //
605 //        while (state.cnameIndex < rrsets.length) {
606 //            SRRset rrset = rrsets[state.cnameIndex++];
607 //            Name rname = rrset.getName();
608 //            int rtype = rrset.getType();
609 //
610 //            // Skip DNAMEs -- prefer to query for the generated CNAME,
611 //            if (rtype == Type.DNAME && qtype != Type.DNAME) continue;
612 //
613 //            // Set the SNAME if we are dealing with a CNAME
614 //            if (rtype == Type.CNAME) {
615 //                CNAMERecord cname = (CNAMERecord) rrset.first();
616 //                state.cnameSname = cname.getTarget();
617 //            }
618 //
619 //            // Note if the current rrset is the answer. In that case, we want to
620 //            // set
621 //            // the final state differently.
622 //            // For non-answers, the response ultimately comes back here.
623 //            int final_state = ValEventState.CNAME_RESP_STATE;
624 //            if (isAnswerRRset(rrset.getName(), rtype, state.cnameSname, qtype,
625 //                              Section.ANSWER)) {
626 //                // If this is an answer, however, break out of this loop.
627 //                final_state = ValEventState.CNAME_ANS_RESP_STATE;
628 //            }
629 //
630 //            // Generate the sub-query.
631 //            Request localRequest = generateLocalRequest(rname, rtype, qclass);
632 //            DNSEvent localEvent = generateLocalEvent(event, localRequest,
633 //                                                     ValEventState.INIT_STATE,
634 //                                                     final_state);
635 //
636 //            // ...and send it along.
637 //            processLocalRequest(localEvent);
638 //            return false;
639 //        }
640 //
641 //        // Something odd has happened if we get here.
642 //        log.warn("processCNAME: encountered unknown issue handling a CNAME chain.");
643 //        return false;
644 //    }
645 //
646 //    private boolean processCNAMEResponse(DNSEvent event, ValEventState state) {
647 //        DNSEvent forEvent = event.forEvent();
648 //        ValEventState forState = getModuleState(forEvent);
649 //
650 //        SMessage resp = event.getResponse().getSMessage();
651 //        if (resp.getStatus() != SecurityStatus.SECURE) {
652 //            forEvent.getResponse().getSMessage().setStatus(resp.getStatus());
653 //            forState.state = forState.finalState;
654 //            handleResponse(forEvent, forState);
655 //            return false;
656 //        }
657 //
658 //        forState.state = ValEventState.CNAME_STATE;
659 //        handleResponse(forEvent, forState);
660 //        return false;
661 //    }
662 //
663 //    private boolean processCNAMEAnswer(DNSEvent event, ValEventState state) {
664 //        DNSEvent forEvent = event.forEvent();
665 //        ValEventState forState = getModuleState(forEvent);
666 //
667 //        SMessage resp = event.getResponse().getSMessage();
668 //        SMessage forResp = forEvent.getResponse().getSMessage();
669 //
670 //        forResp.setStatus(resp.getStatus());
671 //
672 //        forState.state = forState.finalState;
673 //        handleResponse(forEvent, forState);
674 //        return false;
675 //    }
676
677
678     public byte validateMessage(SMessage message) {
679
680         SRRset key_rrset = findKeys(message);
681         if (key_rrset == null) {
682             return SecurityStatus.BOGUS;
683         }
684         
685         int subtype = ValUtils.classifyResponse(message);
686
687         switch (subtype) {
688         case ValUtils.POSITIVE:
689             // log.trace("Validating a positive response");
690             validatePositiveResponse(message, key_rrset);
691             break;
692         case ValUtils.NODATA:
693             // log.trace("Validating a nodata response");
694             validateNodataResponse(message, key_rrset);
695             break;
696         case ValUtils.NAMEERROR:
697             // log.trace("Validating a nxdomain response");
698             validateNameErrorResponse(message, key_rrset);
699             break;
700         case ValUtils.CNAME:
701             // log.trace("Validating a cname response");
702             // forward on to the special CNAME state for this.
703 //            state.state = ValEventState.CNAME_STATE;
704             break;
705         case ValUtils.ANY:
706             // log.trace("Validating a postive ANY response");
707             validateAnyResponse(message, key_rrset);
708             break;
709         default:
710             // log.error("unhandled response subtype: " + subtype);
711         }
712         
713         return message.getSecurityStatus().getStatus();
714
715     }
716 }