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  package org.apache.james.jspf.impl;
21  
22  import org.apache.james.jspf.core.DNSRequest;
23  import org.apache.james.jspf.core.DNSService;
24  import org.apache.james.jspf.core.IPAddr;
25  import org.apache.james.jspf.core.Logger;
26  import org.apache.james.jspf.core.exceptions.TimeoutException;
27  import org.xbill.DNS.AAAARecord;
28  import org.xbill.DNS.ARecord;
29  import org.xbill.DNS.Lookup;
30  import org.xbill.DNS.MXRecord;
31  import org.xbill.DNS.PTRRecord;
32  import org.xbill.DNS.Record;
33  import org.xbill.DNS.Resolver;
34  import org.xbill.DNS.SPFRecord;
35  import org.xbill.DNS.TXTRecord;
36  import org.xbill.DNS.TextParseException;
37  import org.xbill.DNS.Type;
38  
39  import java.net.InetAddress;
40  import java.net.UnknownHostException;
41  import java.util.ArrayList;
42  import java.util.Iterator;
43  import java.util.List;
44  
45  /**
46   * This class contains helper to get all neccassary DNS infos that are needed
47   * for SPF
48   */
49  public class DNSServiceXBillImpl implements DNSService {
50  
51      // The logger
52      protected Logger log;
53      
54      // The record limit for lookups
55      protected int recordLimit;
56  
57      // The resolver used for the lookup
58      protected Resolver resolver;
59      
60      /**
61       * Default Constructor.
62       * Uses the DNSJava static DefaultResolver
63       */
64      public DNSServiceXBillImpl(Logger logger) {
65          this(logger, Lookup.getDefaultResolver());
66      }
67      
68      /**
69       * Constructor to specify a custom resolver.
70       */
71      public DNSServiceXBillImpl(Logger logger, Resolver resolver) {
72          this.log = logger;
73          this.resolver = resolver;
74          // Default record limit is 10
75          this.recordLimit = 10;
76      }
77  
78      /**
79       * NOTE if this class is created with the default constructor it
80       * will use the static DefaultResolver from DNSJava and this method
81       * will change it's timeout.
82       * Other tools using DNSJava in the same JVM could be affected by
83       * this timeout change.
84       * 
85       * @see org.apache.james.jspf.core.DNSService#setTimeOut(int)
86       */
87      public synchronized void setTimeOut(int timeOut) {
88          this.resolver.setTimeout(timeOut);
89      }
90  
91      /**
92       * @see org.apache.james.jspf.core.DNSService#getLocalDomainNames()
93       */
94      public List getLocalDomainNames() {
95          List names = new ArrayList();
96  
97          log.debug("Start Local ipaddress lookup");
98          try {
99              InetAddress ia[] = InetAddress.getAllByName(InetAddress
100                     .getLocalHost().getHostName());
101 
102             for (int i = 0; i < ia.length; i++) {
103                 String host = ia[i].getHostName();
104                 names.add(host);
105 
106                 log.debug("Add hostname " + host + " to list");
107             }
108         } catch (UnknownHostException e) {
109             // just ignore this..
110         }
111         return names;
112 
113     }
114 
115     /**
116      * @return the current record limit
117      */
118     public int getRecordLimit() {
119         return recordLimit;
120     }
121 
122     /**
123      * Set a new limit for the number of records for MX and PTR lookups.
124      * @param recordLimit
125      */
126     public void setRecordLimit(int recordLimit) {
127         this.recordLimit = recordLimit;
128     }
129     
130     /**
131      * @see org.apache.james.jspf.core.DNSService#getRecords(org.apache.james.jspf.core.DNSRequest)
132      */
133     public List getRecords(DNSRequest request)
134             throws TimeoutException {
135         String recordTypeDescription;
136         int dnsJavaType;
137         switch (request.getRecordType()) {
138             case DNSRequest.A: recordTypeDescription = "A"; dnsJavaType = Type.A; break;
139             case DNSRequest.AAAA: recordTypeDescription = "AAAA"; dnsJavaType = Type.AAAA; break;
140             case DNSRequest.MX: recordTypeDescription = "MX"; dnsJavaType = Type.MX; break;
141             case DNSRequest.PTR: recordTypeDescription = "PTR"; dnsJavaType = Type.PTR; break;
142             case DNSRequest.TXT: recordTypeDescription = "TXT"; dnsJavaType = Type.TXT; break;
143             case DNSRequest.SPF: recordTypeDescription= "SPF"; dnsJavaType = Type.SPF; break;
144             default: // TODO fail!
145                 return null;
146         }
147         try {
148 
149             log.debug("Start "+recordTypeDescription+"-Record lookup for : " + request.getHostname());
150 
151             Lookup query = new Lookup(request.getHostname(), dnsJavaType);
152             query.setResolver(resolver);
153 
154             Record[] rr = query.run();
155             int queryResult = query.getResult();
156             
157 
158             if (queryResult == Lookup.TRY_AGAIN) {
159                 throw new TimeoutException(query.getErrorString());
160             }
161             
162             List records = convertRecordsToList(rr);
163             
164             log.debug("Found " + (rr != null ? rr.length : 0) + " "+recordTypeDescription+"-Records");
165             return records;
166         } catch (TextParseException e) {
167             // i think this is the best we could do
168             log.debug("No "+recordTypeDescription+" Record found for host: " + request.getHostname());
169             return null;
170         }
171     }
172     
173     /**
174      * Convert the given Record array to a List
175      * 
176      * @param rr Record array
177      * @return list
178      */
179     public static List convertRecordsToList(Record[] rr) {
180         List records;
181         if (rr != null && rr.length > 0) {
182             records = new ArrayList();
183             for (int i = 0; i < rr.length; i++) {
184                 switch (rr[i].getType()) {
185                     case Type.A:
186                         ARecord a = (ARecord) rr[i];
187                         records.add(a.getAddress().getHostAddress());
188                         break;
189                     case Type.AAAA:
190                         AAAARecord aaaa = (AAAARecord) rr[i];
191                         records.add(aaaa.getAddress().getHostAddress());
192                         break;
193                     case Type.MX:
194                         MXRecord mx = (MXRecord) rr[i];
195                         records.add(mx.getTarget().toString());
196                         break;
197                     case Type.PTR:
198                         PTRRecord ptr = (PTRRecord) rr[i];
199                         records.add(IPAddr.stripDot(ptr.getTarget().toString()));
200                         break;
201                     case Type.TXT:
202                         TXTRecord txt = (TXTRecord) rr[i];
203                         if (txt.getStrings().size() == 1) {
204                             records.add(txt.getStrings().get(0));
205                         } else {
206                             StringBuffer sb = new StringBuffer();
207                             for (Iterator it = txt.getStrings().iterator(); it
208                                     .hasNext();) {
209                                 String k = (String) it.next();
210                                 sb.append(k);
211                             }
212                             records.add(sb.toString());
213                         }
214                         break;
215                     case Type.SPF:
216                         SPFRecord spf = (SPFRecord) rr[i];
217                         if (spf.getStrings().size() == 1) {
218                             records.add(spf.getStrings().get(0));
219                         } else {
220                             StringBuffer sb = new StringBuffer();
221                             for (Iterator it = spf.getStrings().iterator(); it
222                                     .hasNext();) {
223                                 String k = (String) it.next();
224                                 sb.append(k);
225                             }
226                             records.add(sb.toString());
227                         }
228                         break;
229                     default:
230                         return null;
231                 }
232             }
233         } else {
234             records = null;
235         }
236         return records;
237     }
238 }