View Javadoc

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