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.core.filter.fastfail;
21  
22  import org.apache.avalon.framework.configuration.Configurable;
23  import org.apache.avalon.framework.configuration.Configuration;
24  import org.apache.avalon.framework.configuration.ConfigurationException;
25  import org.apache.avalon.framework.service.ServiceException;
26  import org.apache.avalon.framework.service.ServiceManager;
27  import org.apache.avalon.framework.service.Serviceable;
28  import org.apache.james.api.dnsservice.DNSService;
29  import org.apache.james.dsn.DSNStatus;
30  import org.apache.james.smtpserver.CommandHandler;
31  import org.apache.james.smtpserver.SMTPSession;
32  import org.apache.james.smtpserver.junkscore.JunkScore;
33  import org.apache.mailet.MailAddress;
34  
35  import java.net.UnknownHostException;
36  import java.util.ArrayList;
37  import java.util.Collection;
38  
39  /**
40   * This CommandHandler can be used to reject not resolvable EHLO/HELO
41   */
42  public class ResolvableEhloHeloHandler extends AbstractJunkHandler implements
43          CommandHandler, Configurable, Serviceable {
44  
45      public final static String BAD_EHLO_HELO = "BAD_EHLO_HELO";
46  
47      protected boolean checkAuthNetworks = false;
48  
49      private boolean checkAuthUsers = false;
50  
51      protected DNSService dnsServer = null;
52  
53      /**
54       * @see org.apache.avalon.framework.configuration.Configurable#configure(Configuration)
55       */
56      public void configure(Configuration handlerConfiguration)
57              throws ConfigurationException {
58          Configuration configRelay = handlerConfiguration.getChild(
59                  "checkAuthNetworks", false);
60          if (configRelay != null) {
61              setCheckAuthNetworks(configRelay.getValueAsBoolean(false));
62          }
63  
64          Configuration configAuthUser = handlerConfiguration.getChild(
65                  "checkAuthUsers", false);
66          if (configAuthUser != null) {
67              setCheckAuthUsers(configAuthUser.getValueAsBoolean(false));
68          }
69          
70          super.configure(handlerConfiguration);
71      }
72  
73      /**
74       * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
75       */
76      public void service(ServiceManager serviceMan) throws ServiceException {
77          setDnsServer((DNSService) serviceMan.lookup(DNSService.ROLE));
78      }
79  
80      /**
81       * Set to true if AuthNetworks should be included in the EHLO/HELO check
82       * 
83       * @param checkAuthNetworks
84       *            Set to true to enable
85       */
86      public void setCheckAuthNetworks(boolean checkAuthNetworks) {
87          this.checkAuthNetworks = checkAuthNetworks;
88      }
89  
90      /**
91       * Set to true if Auth users should be included in the EHLO/HELO check
92       * 
93       * @param checkAuthUsers
94       *            Set to true to enable
95       */
96      public void setCheckAuthUsers(boolean checkAuthUsers) {
97          this.checkAuthUsers = checkAuthUsers;
98      }
99  
100     /**
101      * Set the DNSService
102      * 
103      * @param dnsServer
104      *            The DNSService
105      */
106     public void setDnsServer(DNSService dnsServer) {
107         this.dnsServer = dnsServer;
108     }
109 
110     /**
111      * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
112      */
113     public void onCommand(SMTPSession session) {
114         String argument = session.getCommandArgument();
115         String command = session.getCommandName();
116         if (command.equals("HELO")
117                 || command.equals("EHLO")) {
118             checkEhloHelo(session, argument);
119         } else if (command.equals("RCPT")) {
120             doProcessing(session);
121         }
122     }
123 
124     /**
125      * Check if EHLO/HELO is resolvable
126      * 
127      * @param session
128      *            The SMTPSession
129      * @param argument
130      *            The argument
131      */
132     protected void checkEhloHelo(SMTPSession session, String argument) {
133         /**
134          * don't check if the ip address is allowed to relay. Only check if it
135          * is set in the config.
136          */
137         if (!session.isRelayingAllowed() || checkAuthNetworks) {
138             // try to resolv the provided helo. If it can not resolved do not
139             // accept it.
140             try {
141                 dnsServer.getByName(argument);
142             } catch (UnknownHostException e) {
143                 session.getState().put(BAD_EHLO_HELO, "true");
144             }
145         }
146     }
147 
148 
149     /**
150      * @see org.apache.james.smtpserver.CommandHandler#getImplCommands()
151      */
152     public Collection getImplCommands() {
153         Collection implCommands = new ArrayList();
154         implCommands.add("EHLO");
155         implCommands.add("HELO");
156         implCommands.add("RCPT");
157 
158         return implCommands;
159     }
160 
161     /**
162      * @see org.apache.james.smtpserver.core.filter.fastfail.AbstractJunkHandler#check(org.apache.james.smtpserver.SMTPSession)
163      */
164     protected boolean check(SMTPSession session) {
165     
166         MailAddress rcpt = (MailAddress) session.getState().get(
167                 SMTPSession.CURRENT_RECIPIENT);
168 
169         // not reject it
170         if (session.getState().get(BAD_EHLO_HELO) == null
171                 || rcpt.getUser().equalsIgnoreCase("postmaster")
172                 || rcpt.getUser().equalsIgnoreCase("abuse"))
173             return false;
174 
175         // Check if the client was authenticated
176         if (!(session.isAuthRequired() && session.getUser() != null && !checkAuthUsers)) {
177             return true;
178         }
179         return false;
180     }
181 
182 
183     /**
184      * @see org.apache.james.smtpserver.core.filter.fastfail.AbstractJunkHandler#getJunkScore(org.apache.james.smtpserver.SMTPSession)
185      */
186     protected JunkScore getJunkScore(SMTPSession session) {
187         return (JunkScore) session.getConnectionState().get(JunkScore.JUNK_SCORE_SESSION);
188     }
189     
190     /**
191      * @see org.apache.james.smtpserver.core.filter.fastfail.AbstractJunkHandler#getJunkHandlerData(org.apache.james.smtpserver.SMTPSession)
192      */
193     public JunkHandlerData getJunkHandlerData(SMTPSession session) {
194         JunkHandlerData data = new JunkHandlerData();
195         
196         data.setJunkScoreLogString("Provided EHLO/HELO " + session.getState().get(SMTPSession.CURRENT_HELO_NAME) + " can not resolved. Add junkScore: " + getScore());
197         data.setRejectLogString("501 " + DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_ARG)
198                 + " Provided EHLO/HELO " + session.getState().get(SMTPSession.CURRENT_HELO_NAME) + " can not resolved");
199     
200         
201         data.setRejectResponseString("501 " + DSNStatus.getStatus(DSNStatus.PERMANENT, DSNStatus.DELIVERY_INVALID_ARG)
202                 + " Provided EHLO/HELO " + session.getState().get(SMTPSession.CURRENT_HELO_NAME) + " can not resolved");
203 
204         data.setScoreName("ResolvableEhloHeloCheck");
205         return data;
206     }
207 
208 }