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.DNSLookupContinuation;
24  import org.apache.james.jspf.core.DNSRequest;
25  import org.apache.james.jspf.core.DNSResponse;
26  import org.apache.james.jspf.core.DNSService;
27  import org.apache.james.jspf.core.DNSServiceEnabled;
28  import org.apache.james.jspf.core.IPAddr;
29  import org.apache.james.jspf.core.MacroExpand;
30  import org.apache.james.jspf.core.SPFChecker;
31  import org.apache.james.jspf.core.SPFCheckerDNSResponseListener;
32  import org.apache.james.jspf.core.SPFSession;
33  import org.apache.james.jspf.core.SPFTermsRegexps;
34  import org.apache.james.jspf.core.exceptions.NeutralException;
35  import org.apache.james.jspf.core.exceptions.NoneException;
36  import org.apache.james.jspf.core.exceptions.PermErrorException;
37  import org.apache.james.jspf.core.exceptions.TempErrorException;
38  import org.apache.james.jspf.core.exceptions.TimeoutException;
39  
40  import java.util.List;
41  
42  /**
43   * This class represent the ptr mechanism
44   * 
45   */
46  public class PTRMechanism extends GenericMechanism implements DNSServiceEnabled, SPFCheckerDNSResponseListener {
47  
48      private final class ExpandedChecker implements SPFChecker {
49          private CleanupChecker cleanupChecker = new CleanupChecker();
50  
51          private final class CleanupChecker implements SPFChecker {
52  
53              /**
54               * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
55               */
56              public DNSLookupContinuation checkSPF(SPFSession spfData)
57                      throws PermErrorException, TempErrorException,
58                      NeutralException, NoneException {
59                  spfData.removeAttribute(ATTRIBUTE_DOMAIN_LIST);
60                  spfData.removeAttribute(ATTRIBUTE_CURRENT_DOMAIN);
61                  return null;
62              }
63          }
64  
65          /**
66           * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
67           */
68          public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
69                  TempErrorException, NeutralException, NoneException {
70  
71              // Get PTR Records for the ipAddress which is provided by SPF1Data
72              IPAddr ip = IPAddr.getAddress(spfData.getIpAddress());
73  
74              // Get the right host.
75              String host = expandHost(spfData);
76              
77              spfData.setAttribute(ATTRIBUTE_EXPANDED_HOST, host);
78              
79              spfData.pushChecker(cleanupChecker);
80  
81              return new DNSLookupContinuation(new DNSRequest(ip.getReverseIP(), DNSRequest.PTR), PTRMechanism.this);
82          }
83      }
84  
85      private static final String ATTRIBUTE_CURRENT_DOMAIN = "PTRMechanism.currentDomain";
86  
87      private static final String ATTRIBUTE_EXPANDED_HOST = "PTRMechanism.expandedHost";
88  
89      private static final String ATTRIBUTE_DOMAIN_LIST = "PTRMechanism.domainListCheck";
90  
91      /**
92       * ABNF: PTR = "ptr" [ ":" domain-spec ]
93       */
94      public static final String REGEX = "[pP][tT][rR]" + "(?:\\:"
95              + SPFTermsRegexps.DOMAIN_SPEC_REGEX + ")?";
96      
97      private DNSService dnsService;
98  
99      private SPFChecker expandedChecker = new ExpandedChecker();
100 
101     /**
102      * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
103      */
104     public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
105             TempErrorException, NeutralException, NoneException {
106         // update currentDepth
107         spfData.increaseCurrentDepth();
108 
109         spfData.pushChecker(expandedChecker);
110         return macroExpand.checkExpand(getDomain(), spfData, MacroExpand.DOMAIN);
111     }
112 
113     /**
114      * @see org.apache.james.jspf.core.DNSServiceEnabled#enableDNSService(org.apache.james.jspf.core.DNSService)
115      */
116     public void enableDNSService(DNSService service) {
117         this.dnsService = service;
118     }
119 
120     /**
121      * @see org.apache.james.jspf.core.SPFCheckerDNSResponseListener#onDNSResponse(org.apache.james.jspf.core.DNSResponse, org.apache.james.jspf.core.SPFSession)
122      */
123     public DNSLookupContinuation onDNSResponse(DNSResponse response, SPFSession spfSession)
124             throws PermErrorException, TempErrorException, NoneException, NeutralException {
125         
126         List domainList = (List) spfSession.getAttribute(ATTRIBUTE_DOMAIN_LIST);
127         try {
128             if (domainList == null) {
129             
130                 domainList = response.getResponse();
131                 
132                 // No PTR records found
133                 if (domainList == null) {
134                     spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.FALSE);
135                     return null;
136                 }
137         
138                 // check if the maximum lookup count is reached
139                 if (dnsService.getRecordLimit() > 0 && domainList.size() > dnsService.getRecordLimit()) {
140                     // Truncate the PTR list to getRecordLimit.
141                     // See #ptr-limit rfc4408 test
142                     domainList = domainList.subList(0, dnsService.getRecordLimit()-1);
143                     // throw new PermErrorException("Maximum PTR lookup count reached");
144                 }
145                 
146                 spfSession.setAttribute(ATTRIBUTE_DOMAIN_LIST, domainList);
147                 
148             } else {
149 
150                 String compareDomain = (String) spfSession.getAttribute(ATTRIBUTE_CURRENT_DOMAIN);
151                 String host = (String) spfSession.getAttribute(ATTRIBUTE_EXPANDED_HOST);
152     
153                 List aList = response.getResponse();
154     
155 
156                 if (aList != null) {
157                     for (int j = 0; j < aList.size(); j++) {
158                         // Added the IPAddr parsing/toString to have matching in IPV6 multiple ways to 
159                         if (IPAddr.getAddress((String) aList.get(j)).getIPAddress().equals(IPAddr.getAddress(spfSession.getIpAddress()).getIPAddress())) {
160                             
161                             if (compareDomain.equals(host)
162                                     || compareDomain.endsWith("." + host)) {
163                                 spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.TRUE);
164                                 return null;
165                             }
166                         }
167                     }
168                 }
169             
170             }
171         } catch (TimeoutException e) {
172             throw new TempErrorException("Timeout querying the dns server");
173         }
174         
175 
176         if (domainList.size() > 0) {
177             String currentDomain = (String) domainList.remove(0);
178     
179             DNSRequest dnsRequest;
180             // check if the connecting ip is ip6. If so lookup AAAA record
181             if (IPAddr.isIPV6(spfSession.getIpAddress())) {
182                 // Get aaaa record for this
183                 dnsRequest = new DNSRequest(currentDomain, DNSRequest.AAAA);
184             } else {
185                 // Get a record for this
186                 dnsRequest = new DNSRequest(currentDomain, DNSRequest.A);
187             }
188             
189             spfSession.setAttribute(ATTRIBUTE_CURRENT_DOMAIN, currentDomain);
190             
191             return new DNSLookupContinuation(dnsRequest, PTRMechanism.this);
192         } else {
193             spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.FALSE);
194             return null;
195         }
196 
197     }
198 
199 
200 }