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.smtpserver;
21  
22  import org.apache.avalon.framework.logger.AbstractLogEnabled;
23  import org.apache.avalon.framework.configuration.Configuration;
24  import org.apache.avalon.framework.configuration.Configurable;
25  import org.apache.avalon.framework.configuration.ConfigurationException;
26  import java.util.ArrayList;
27  import java.util.StringTokenizer;
28  
29  /***
30    * Connect handler for DNSRBL processing
31    */
32  public class DNSRBLHandler
33      extends AbstractLogEnabled
34      implements ConnectHandler, Configurable {
35      /***
36       * The lists of rbl servers to be checked to limit spam
37       */
38      private String[] whitelist;
39      private String[] blacklist;
40  
41      /***
42       * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
43       */
44      public void configure(Configuration handlerConfiguration) throws ConfigurationException {
45  
46          Configuration rblserverConfiguration = handlerConfiguration.getChild("rblservers", false);
47          if ( rblserverConfiguration != null ) {
48              ArrayList rblserverCollection = new ArrayList();
49              Configuration[] children = rblserverConfiguration.getChildren("whitelist");
50              if ( children != null ) {
51                  for ( int i = 0 ; i < children.length ; i++ ) {
52                      String rblServerName = children[i].getValue();
53                      rblserverCollection.add(rblServerName);
54                      if (getLogger().isInfoEnabled()) {
55                          getLogger().info("Adding RBL server to whitelist: " + rblServerName);
56                      }
57                  }
58                  if (rblserverCollection != null && rblserverCollection.size() > 0) {
59                      whitelist = (String[]) rblserverCollection.toArray(new String[rblserverCollection.size()]);
60                      rblserverCollection.clear();
61                  }
62              }
63              children = rblserverConfiguration.getChildren("blacklist");
64              if ( children != null ) {
65                  for ( int i = 0 ; i < children.length ; i++ ) {
66                      String rblServerName = children[i].getValue();
67                      rblserverCollection.add(rblServerName);
68                      if (getLogger().isInfoEnabled()) {
69                          getLogger().info("Adding RBL server to blacklist: " + rblServerName);
70                      }
71                  }
72                  if (rblserverCollection != null && rblserverCollection.size() > 0) {
73                      blacklist = (String[]) rblserverCollection.toArray(new String[rblserverCollection.size()]);
74                      rblserverCollection.clear();
75                  }
76              }
77          }
78  
79      }
80  
81      /*
82       * check if the remote Ip address is block listed
83       *
84       * @see org.apache.james.smtpserver.ConnectHandler#onConnect(SMTPSession)
85      **/
86      public void onConnect(SMTPSession session) {
87          boolean blocklisted = checkDNSRBL(session, session.getRemoteIPAddress());
88          session.setBlockListed(blocklisted);
89      }
90  
91  
92      /***
93       * @see org.apache.james.smtpserver.SMTPHandlerConfigurationData#checkDNSRBL(Socket)
94       */
95      /*
96       * This checks DNSRBL whitelists and blacklists.  If the remote IP is whitelisted
97       * it will be permitted to send e-mail, otherwise if the remote IP is blacklisted,
98       * the sender will only be permitted to send e-mail to postmaster (RFC 2821) or
99       * abuse (RFC 2142), unless authenticated.
100      */
101 
102     public boolean checkDNSRBL(SMTPSession session, String ipAddress) {
103         
104         /*
105          * don't check against rbllists if the client is allowed to relay..
106          * This whould make no sense.
107          */
108         if (session.isRelayingAllowed()) {
109             getLogger().info("Ipaddress " + session.getRemoteIPAddress() + " is allowed to relay. Don't check it");
110             return false;
111         }
112         
113         if (whitelist != null || blacklist != null) {
114             StringBuffer sb = new StringBuffer();
115             StringTokenizer st = new StringTokenizer(ipAddress, " .", false);
116             while (st.hasMoreTokens()) {
117                 sb.insert(0, st.nextToken() + ".");
118             }
119             String reversedOctets = sb.toString();
120 
121             if (whitelist != null) {
122                 String[] rblList = whitelist;
123                 for (int i = 0 ; i < rblList.length ; i++) try {
124                     java.net.InetAddress addr = org.apache.james.dnsserver.DNSServer.getByName(reversedOctets + rblList[i]);
125                     if (getLogger().isInfoEnabled()) {
126                         getLogger().info("Connection from " + ipAddress + " whitelisted by " + rblList[i]);
127                     }
128  
129                     /* Ihis code may be helpful if admins need to debug why they are getting weird
130                        behavior from the blocklists.  Also, it might help them to know what IP is
131                        returned, since zones often use that to indicate interesting information.
132 
133                        The next version of this code already handles the associated TXT record,
134                        so this code is just temporary for this release.
135                      */
136                     if (getLogger().isDebugEnabled()) {
137                         getLogger().debug("Whitelist addr = " + addr.toString());
138                     }
139 
140                     return false;
141                 } catch (java.net.UnknownHostException uhe) {
142                     if (getLogger().isDebugEnabled()) {
143                         getLogger().debug("unknown host exception thrown:" + reversedOctets + rblList[i]);
144                     }
145                 }
146             }
147 
148             if (blacklist != null) {
149                 String[] rblList = blacklist;
150                 for (int i = 0 ; i < rblList.length ; i++) try {
151                     java.net.InetAddress addr = org.apache.james.dnsserver.DNSServer.getByName(reversedOctets + rblList[i]);
152                     if (getLogger().isInfoEnabled()) {
153                         getLogger().info("Connection from " + ipAddress + " restricted by " + rblList[i] + " to SMTP AUTH/postmaster/abuse.");
154                     }
155 
156                     /* Ihis code may be helpful if admins need to debug why they are getting weird
157                        behavior from the blocklists.  Also, it might help them to know what IP is
158                        returned, since zones often use that to indicate interesting information.
159 
160                        The next version of this code already handles the associated TXT record,
161                        so this code is just temporary for this release.
162                      */
163                     if (getLogger().isDebugEnabled()) {
164                         getLogger().debug("Blacklist addr = " + addr.toString());
165                     }
166 
167                     return true;
168                 } catch (java.net.UnknownHostException uhe) {
169                     // if it is unknown, it isn't blocked
170                     if (getLogger().isDebugEnabled()) {
171                         getLogger().debug("unknown host exception thrown:" + reversedOctets + rblList[i]);
172                     }
173                 }
174             }
175         }
176         return false;
177     }
178 
179 }