View Javadoc

1   /*****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  
21  package org.apache.james.jspf.terms;
22  
23  import org.apache.james.jspf.core.DNSService;
24  import org.apache.james.jspf.core.SPF1Constants;
25  import org.apache.james.jspf.core.SPF1Data;
26  import org.apache.james.jspf.exceptions.PermErrorException;
27  import org.apache.james.jspf.exceptions.TempErrorException;
28  import org.apache.james.jspf.macro.MacroExpand;
29  import org.apache.james.jspf.util.SPFTermsRegexps;
30  import org.apache.james.jspf.wiring.DNSServiceEnabled;
31  import org.apache.james.jspf.wiring.MacroExpandEnabled;
32  
33  import java.util.List;
34  
35  /***
36   * This class represent the exp modifier
37   * 
38   */
39  public class ExpModifier extends GenericModifier implements DNSServiceEnabled, MacroExpandEnabled {
40  
41      /***
42       * ABNF: explanation = "exp" "=" domain-spec
43       * 
44       * NOTE: the last +"?" has been added to support RFC4408 ERRATA for the EXP modifier.
45       * An "exp=" should not result in a perm error but should be ignored.
46       * Errata: http://www.openspf.org/RFC_4408/Errata#empty-exp
47       */
48      public static final String REGEX = "[eE][xX][pP]" + "//="
49              + SPFTermsRegexps.DOMAIN_SPEC_REGEX+"?";
50  
51      private DNSService dnsService;
52      
53      private MacroExpand macroExpand;
54  
55      /***
56       * Generate the explanation and set it in SPF1Data so it can be accessed
57       * easy later if needed
58       * 
59       * @param spfData
60       *            The SPF1Data which should used
61       * @throws PermErrorException 
62       */
63      protected void checkSPFLogged(SPF1Data spfData) throws PermErrorException {
64          String exp = null;
65          String host = getHost();
66          
67          // RFC4408 Errata: http://www.openspf.org/RFC_4408/Errata#empty-exp
68          if (host == null) {
69              return;
70          }
71  
72          // If we should ignore the explanation we don't have to run this class
73          if (spfData.ignoreExplanation() == true)
74              return;
75          
76          // If the currentResult is not fail we have no need to run all these
77          // methods!
78          if (spfData.getCurrentResult()== null || !spfData.getCurrentResult().equals(SPF1Constants.FAIL))
79              return;
80  
81          host = macroExpand.expand(host, spfData, MacroExpand.DOMAIN);
82  
83          try {
84              try {
85                  exp = getTxtType(dnsService, host);
86              } catch (TempErrorException e) {
87                  // Nothing todo here.. just return null
88                  return;
89              }
90  
91              if ((exp != null) && (!exp.equals(""))) {
92                  String expandedExplanation = macroExpand.expand(exp, spfData, MacroExpand.EXPLANATION);
93                  spfData.setExplanation(expandedExplanation);
94              } 
95          } catch (PermErrorException e) {
96              // TODO add logging here!
97              // Only catch the error and return null
98              return;
99          }
100         return;
101     }
102 
103 
104     /***
105      * Get TXT records as a string
106      * 
107      * @param dns The DNSService to query
108      * @param strServer
109      *            The hostname for which we want to retrieve the TXT-Record
110      * @return String which reflect the TXT-Record
111      * @throws PermErrorException
112      *             if more then one TXT-Record for explanation was found
113      * @throws TempErrorException
114      *             if the lookup result was "TRY_AGAIN"
115      */
116     public String getTxtType(DNSService dns, String strServer) throws TempErrorException, PermErrorException {
117         try {
118             List records = dns.getRecords(strServer, DNSService.TXT);
119         
120             if (records == null) {
121                 return null;
122             }
123     
124             // See SPF-Spec 6.2
125             //
126             // If domain-spec is empty, or there are any DNS processing errors (any RCODE other than 0), 
127             // or if no records are returned, or if more than one record is returned, or if there are syntax 
128             // errors in the explanation string, then proceed as if no exp modifier was given.   
129             if (records.size() > 1) {
130                 log.debug("More then one TXT-Record found for explanation");
131                 throw new PermErrorException("More then one TXT-Record for explanation");
132             } else {
133                 return (String) records.get(0);
134             }
135         } catch (DNSService.TimeoutException e) {
136             throw new TempErrorException("Timeout querying dns server");
137         }
138     }
139     
140     /***
141      * @see java.lang.Object#toString()
142      */
143     public String toString() {
144        return "exp="+getHost();
145     }
146 
147     /***
148      * @see org.apache.james.jspf.wiring.DNSServiceEnabled#enableDNSService(org.apache.james.jspf.core.DNSService)
149      */
150     public void enableDNSService(DNSService service) {
151         this.dnsService = service;
152     }
153 
154 
155     /***
156      * @see org.apache.james.jspf.wiring.MacroExpandEnabled#enableMacroExpand(org.apache.james.jspf.macro.MacroExpand)
157      */
158     public void enableMacroExpand(MacroExpand macroExpand) {
159         this.macroExpand = macroExpand;
160     }
161 
162 }