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 /**
50 * Default constructor. Sets the wait time to 1 second
51 */
52 public ConnectionThrottleFilter() {
53 this(DEFAULT_TIME);
54 }
55
56 /**
57 * Constructor that takes in a specified wait time.
58 *
59 * @param allowedInterval
60 * The number of milliseconds a client is allowed to wait
61 * before making another successful connection
62 *
63 */
64 public ConnectionThrottleFilter(long allowedInterval) {
65 this.allowedInterval = allowedInterval;
66 clients = Collections.synchronizedMap(new HashMap<String, Long>());
67 }
68
69 /**
70 * Sets the interval between connections from a client.
71 * This value is measured in milliseconds.
72 *
73 * @param allowedInterval
74 * The number of milliseconds a client is allowed to wait
75 * before making another successful connection
76 */
77 public void setAllowedInterval(long allowedInterval) {
78 this.allowedInterval = allowedInterval;
79 }
80
81 /**
82 * Method responsible for deciding if a connection is OK
83 * to continue
84 *
85 * @param session
86 * The new session that will be verified
87 * @return
88 * True if the session meets the criteria, otherwise false
89 */
90 protected boolean isConnectionOk(IoSession session) {
91 SocketAddress remoteAddress = session.getRemoteAddress();
92 if (remoteAddress instanceof InetSocketAddress) {
93 InetSocketAddress addr = (InetSocketAddress) remoteAddress;
94 long now = System.currentTimeMillis();
95
96 if (clients.containsKey(addr.getAddress().getHostAddress())) {
97
98 LOGGER.debug("This is not a new client");
99 Long lastConnTime = clients.get(addr.getAddress().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) throws Exception {
122 if (!isConnectionOk(session)) {
123 LOGGER.warn("Connections coming in too fast; closing.");
124 session.close(true);
125 }
126 nextFilter.sessionCreated(session);
127 }
128 }