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.mina.filter.firewall;
21
22 import java.net.InetSocketAddress;
23 import java.net.SocketAddress;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.Map;
27
28 import org.apache.mina.core.filterchain.IoFilter;
29 import org.apache.mina.core.filterchain.IoFilterAdapter;
30 import org.apache.mina.core.session.IoSession;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 /**
35 * A {@link IoFilter} which blocks connections from connecting
36 * at a rate faster than the specified interval.
37 *
38 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
39 */
40 public class ConnectionThrottleFilter extends IoFilterAdapter {
41 private static final long DEFAULT_TIME = 1000;
42
43 private long allowedInterval;
44
45 private final Map<String, Long> clients;
46
47 private final static Logger LOGGER = LoggerFactory.getLogger(ConnectionThrottleFilter.class);
48 /**
49 * Default constructor. Sets the wait time to 1 second
50 */
51 public ConnectionThrottleFilter() {
52 this(DEFAULT_TIME);
53 }
54
55 /**
56 * Constructor that takes in a specified wait time.
57 *
58 * @param allowedInterval
59 * The number of milliseconds a client is allowed to wait
60 * before making another successful connection
61 *
62 */
63 public ConnectionThrottleFilter(long allowedInterval) {
64 this.allowedInterval = allowedInterval;
65 clients = Collections.synchronizedMap(new HashMap<String, Long>());
66 }
67
68 /**
69 * Sets the interval between connections from a client.
70 * This value is measured in milliseconds.
71 *
72 * @param allowedInterval
73 * The number of milliseconds a client is allowed to wait
74 * before making another successful connection
75 */
76 public void setAllowedInterval(long allowedInterval) {
77 this.allowedInterval = allowedInterval;
78 }
79
80 /**
81 * Method responsible for deciding if a connection is OK
82 * to continue
83 *
84 * @param session
85 * The new session that will be verified
86 * @return
87 * True if the session meets the criteria, otherwise false
88 */
89 protected boolean isConnectionOk(IoSession session) {
90 SocketAddress remoteAddress = session.getRemoteAddress();
91 if (remoteAddress instanceof InetSocketAddress) {
92 InetSocketAddress addr = (InetSocketAddress) remoteAddress;
93 long now = System.currentTimeMillis();
94
95 if (clients.containsKey(addr.getAddress().getHostAddress())) {
96
97 LOGGER.debug("This is not a new client");
98 Long lastConnTime = clients.get(addr.getAddress()
99 .getHostAddress());
100
101 clients.put(addr.getAddress().getHostAddress(), now);
102
103 // if the interval between now and the last connection is
104 // less than the allowed interval, return false
105 if (now - lastConnTime < allowedInterval) {
106 LOGGER.warn("Session connection interval too short");
107 return false;
108 }
109
110 return true;
111 }
112
113 clients.put(addr.getAddress().getHostAddress(), now);
114 return true;
115 }
116
117 return false;
118 }
119
120 @Override
121 public void sessionCreated(NextFilter nextFilter, IoSession session)
122 throws Exception {
123 if (!isConnectionOk(session)) {
124 LOGGER.warn("Connections coming in too fast; closing.");
125 session.close(true);
126 }
127 nextFilter.sessionCreated(session);
128 }
129 }