001    /****************************************************************
002     * Licensed to the Apache Software Foundation (ASF) under one   *
003     * or more contributor license agreements.  See the NOTICE file *
004     * distributed with this work for additional information        *
005     * regarding copyright ownership.  The ASF licenses this file   *
006     * to you under the Apache License, Version 2.0 (the            *
007     * "License"); you may not use this file except in compliance   *
008     * with the License.  You may obtain a copy of the License at   *
009     *                                                              *
010     *   http://www.apache.org/licenses/LICENSE-2.0                 *
011     *                                                              *
012     * Unless required by applicable law or agreed to in writing,   *
013     * software distributed under the License is distributed on an  *
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015     * KIND, either express or implied.  See the License for the    *
016     * specific language governing permissions and limitations      *
017     * under the License.                                           *
018     ****************************************************************/
019    
020    
021    package org.apache.james.protocols.smtp.core.fastfail;
022    
023    import java.util.ArrayList;
024    import java.util.Collection;
025    import java.util.HashMap;
026    import java.util.Map;
027    
028    import org.apache.james.protocols.smtp.SMTPSession;
029    import org.apache.james.protocols.smtp.hook.HookResult;
030    import org.apache.james.protocols.smtp.hook.HookReturnCode;
031    import org.apache.james.protocols.smtp.hook.RcptHook;
032    import org.apache.mailet.MailAddress;
033    
034    /**
035     * This handler can be used for providing a spam trap. IPAddresses which send emails to the configured
036     * recipients will get blacklisted for the configured time.
037     */
038    public class SpamTrapHandler implements RcptHook {
039    
040        /** Map which hold blockedIps and blockTime in memory */
041        private Map<String,Long> blockedIps = new HashMap<String,Long>();
042        
043        private Collection<String> spamTrapRecips = new ArrayList<String>();
044        
045        /** Default blocktime 12 hours */
046        protected long blockTime = 4320000; 
047        
048       
049        public void setSpamTrapRecipients(Collection<String> spamTrapRecips) {
050            this.spamTrapRecips = spamTrapRecips;
051        }
052        
053        public void setBlockTime(long blockTime) {
054            this.blockTime = blockTime;
055        }
056        
057        /**
058         * @see org.apache.james.protocols.smtp.hook.RcptHook#doRcpt(org.apache.james.protocols.smtp.SMTPSession, org.apache.mailet.MailAddress, org.apache.mailet.MailAddress)
059         */
060        public HookResult doRcpt(SMTPSession session, MailAddress sender, MailAddress rcpt) {
061            if (isBlocked(session.getRemoteIPAddress(), session)) {
062                return new HookResult(HookReturnCode.DENY);
063            } else {
064             
065                if (spamTrapRecips.contains(rcpt.toString().toLowerCase())){
066            
067                    addIp(session.getRemoteIPAddress(), session);
068                
069                    return new HookResult(HookReturnCode.DENY);
070                }
071            }
072            return new HookResult(HookReturnCode.DECLINED);
073        }
074        
075        
076        /**
077         * Check if ipAddress is in the blockList.
078         * 
079         * @param ip ipAddress to check
080         * @param session not null
081         * @return true or false
082         */
083        private boolean isBlocked(String ip, SMTPSession session) {
084            Long rawTime = blockedIps.get(ip);
085        
086            if (rawTime != null) {
087                long blockTime = rawTime.longValue();
088               
089                if (blockTime > System.currentTimeMillis()) {
090                    session.getLogger().debug("BlockList contain Ip " + ip);
091                    return true;
092                } else {
093                    session.getLogger().debug("Remove ip " + ip + " from blockList");
094                   
095                    synchronized(blockedIps) {
096                        blockedIps.remove(ip);
097                    }
098                }
099            }
100            return false;
101        }
102        
103        /**
104         * Add ipaddress to blockList
105         * 
106         * @param ip IpAddress to add
107         * @param session not null
108         */
109        private void addIp(String ip, SMTPSession session) {
110            long bTime = System.currentTimeMillis() + blockTime;
111            
112            session.getLogger().debug("Add ip " + ip + " for " + bTime + " to blockList");
113        
114            synchronized(blockedIps) {
115                blockedIps.put(ip, Long.valueOf(bTime));
116            }
117        
118        }
119    }