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.IPAddr;
27  import org.apache.james.jspf.core.MacroExpand;
28  import org.apache.james.jspf.core.SPFChecker;
29  import org.apache.james.jspf.core.SPFCheckerDNSResponseListener;
30  import org.apache.james.jspf.core.SPFSession;
31  import org.apache.james.jspf.core.SPFTermsRegexps;
32  import org.apache.james.jspf.core.exceptions.NeutralException;
33  import org.apache.james.jspf.core.exceptions.NoneException;
34  import org.apache.james.jspf.core.exceptions.PermErrorException;
35  import org.apache.james.jspf.core.exceptions.TempErrorException;
36  import org.apache.james.jspf.core.exceptions.TimeoutException;
37  
38  import java.util.ArrayList;
39  import java.util.List;
40  
41  /**
42   * This class represent the mx mechanism
43   * 
44   */
45  public class MXMechanism extends AMechanism implements SPFCheckerDNSResponseListener {
46  
47      private final class ExpandedChecker implements SPFChecker {
48          
49          /**
50           * @see org.apache.james.jspf.core.SPFChecker#checkSPF(org.apache.james.jspf.core.SPFSession)
51           */
52          public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
53                  TempErrorException, NeutralException, NoneException {
54  
55              // Get the right host.
56              String host = expandHost(spfData);
57              
58              return new DNSLookupContinuation(new DNSRequest(host, DNSRequest.MX), MXMechanism.this);
59          }
60      }
61  
62      private static final String ATTRIBUTE_MX_RECORDS = "MXMechanism.mxRecords";
63      private static final String ATTRIBUTE_CHECK_RECORDS = "MXMechanism.checkRecords";
64      /**
65       * ABNF: MX = "mx" [ ":" domain-spec ] [ dual-cidr-length ]
66       */
67      public static final String REGEX = "[mM][xX]" + "(?:\\:"
68              + SPFTermsRegexps.DOMAIN_SPEC_REGEX + ")?" + "(?:"
69              + DUAL_CIDR_LENGTH_REGEX + ")?";
70      
71      private SPFChecker expandedChecker = new ExpandedChecker();
72      
73      /**
74       * @see org.apache.james.jspf.terms.AMechanism#checkSPF(org.apache.james.jspf.core.SPFSession)
75       */
76      public DNSLookupContinuation checkSPF(SPFSession spfData) throws PermErrorException,
77              TempErrorException, NeutralException, NoneException{
78  
79          // update currentDepth
80          spfData.increaseCurrentDepth();
81  
82          spfData.pushChecker(expandedChecker);
83          return macroExpand.checkExpand(getDomain(), spfData, MacroExpand.DOMAIN);
84      }
85  
86      /**
87       * @see org.apache.james.jspf.terms.AMechanism#onDNSResponse(org.apache.james.jspf.core.DNSResponse, org.apache.james.jspf.core.SPFSession)
88       */
89      public DNSLookupContinuation onDNSResponse(DNSResponse response, SPFSession spfSession)
90          throws PermErrorException, TempErrorException, NoneException, NeutralException {
91          try {
92              
93              List records = (List) spfSession.getAttribute(ATTRIBUTE_CHECK_RECORDS);
94              List mxR = (List) spfSession.getAttribute(ATTRIBUTE_MX_RECORDS);
95  
96              if (records == null) {
97              
98                  records = response.getResponse();
99  
100                 if (records == null) {
101                     // no mx record found
102                     spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.FALSE);
103                     return null;
104                 }
105                 
106                 spfSession.setAttribute(ATTRIBUTE_CHECK_RECORDS, records);
107                 
108             } else {
109                 
110                 List res = response.getResponse();
111 
112                 if (res != null) {
113                     if (mxR == null) {
114                         mxR = new ArrayList();
115                         spfSession.setAttribute(ATTRIBUTE_MX_RECORDS, mxR);
116                     }
117                     mxR.addAll(res);
118                 }
119                 
120             }
121 
122             // if the remote IP is an ipv6 we check ipv6 addresses, otherwise ip4
123             boolean isIPv6 = IPAddr.isIPV6(spfSession.getIpAddress());
124 
125             String mx;
126             while (records.size() > 0 && (mx = (String) records.remove(0)) != null && mx.length() > 0) {
127                 log.debug("Add MX-Record " + mx + " to list");
128 
129                 return new DNSLookupContinuation(new DNSRequest(mx, isIPv6 ? DNSRequest.AAAA : DNSRequest.A), MXMechanism.this);
130                 
131             }
132                 
133             // no mx record found
134             if (mxR == null || mxR.size() == 0) {
135                 spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.FALSE);
136                 return null;
137             }
138 
139             // get the ipAddress
140             IPAddr checkAddress;
141             checkAddress = IPAddr.getAddress(spfSession.getIpAddress(), isIPv6 ? getIp6cidr() : getIp4cidr());
142             
143             // clean up attributes
144             spfSession.removeAttribute(ATTRIBUTE_CHECK_RECORDS);
145             spfSession.removeAttribute(ATTRIBUTE_MX_RECORDS);
146             spfSession.setAttribute(Directive.ATTRIBUTE_MECHANISM_RESULT, Boolean.valueOf(checkAddressList(checkAddress, mxR, getIp4cidr())));
147             return null;
148             
149         } catch (TimeoutException e) {
150             spfSession.setAttribute(ATTRIBUTE_CHECK_RECORDS, null);
151             spfSession.setAttribute(ATTRIBUTE_MX_RECORDS, null);
152             throw new TempErrorException("Timeout querying the dns server");
153         }
154     }
155 
156     /**
157      * @see org.apache.james.jspf.terms.AMechanism#toString()
158      */
159     public String toString() {
160         return super.toString("mx");
161     }
162 
163 }