2 * Copyright 2008 Google Inc.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.google.zxing.web;
\r
19 import javax.servlet.Filter;
\r
20 import javax.servlet.FilterChain;
\r
21 import javax.servlet.FilterConfig;
\r
22 import javax.servlet.ServletContext;
\r
23 import javax.servlet.ServletException;
\r
24 import javax.servlet.ServletRequest;
\r
25 import javax.servlet.ServletResponse;
\r
26 import javax.servlet.http.HttpServletResponse;
\r
27 import java.io.IOException;
\r
28 import java.net.InetAddress;
\r
29 import java.net.UnknownHostException;
\r
30 import java.util.Collection;
\r
31 import java.util.Collections;
\r
32 import java.util.HashSet;
\r
33 import java.util.Set;
\r
34 import java.util.Timer;
\r
35 import java.util.TimerTask;
\r
38 * A {@link Filter} that rejects requests from hosts that are sending too many
\r
39 * requests in too short a time.
\r
41 * @author Sean Owen (srowen@google.com)
\r
43 public final class DoSFilter implements Filter {
\r
45 private static final int MAX_ACCESSES_PER_IP_PER_TIME = 10;
\r
46 private static final long MAX_ACCESS_INTERVAL_MSEC = 10L * 1000L;
\r
47 private static final long UNBAN_INTERVAL_MSEC = 60L * 60L * 1000L;
\r
49 private final IPTrie numRecentAccesses;
\r
50 private final Timer timer;
\r
51 private final Set<String> bannedIPAddresses;
\r
52 private final Collection<String> manuallyBannedIPAddresses;
\r
53 private ServletContext context;
\r
55 public DoSFilter() {
\r
56 numRecentAccesses = new IPTrie();
\r
57 timer = new Timer("DosFilter reset timer");
\r
58 bannedIPAddresses = Collections.synchronizedSet(new HashSet<String>());
\r
59 manuallyBannedIPAddresses = new HashSet<String>();
\r
62 public void init(FilterConfig filterConfig) {
\r
63 context = filterConfig.getServletContext();
\r
64 String bannedIPs = filterConfig.getInitParameter("bannedIPs");
\r
65 if (bannedIPs != null) {
\r
66 for (String ip : bannedIPs.split(",")) {
\r
67 manuallyBannedIPAddresses.add(ip.trim());
\r
70 timer.scheduleAtFixedRate(new ResetTask(), 0L, MAX_ACCESS_INTERVAL_MSEC);
\r
71 timer.scheduleAtFixedRate(new UnbanTask(), 0L, UNBAN_INTERVAL_MSEC);
\r
74 public void doFilter(ServletRequest request,
\r
75 ServletResponse response,
\r
76 FilterChain chain) throws IOException, ServletException {
\r
77 if (isBanned(request)) {
\r
78 HttpServletResponse servletResponse = (HttpServletResponse) response;
\r
79 servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
\r
81 chain.doFilter(request, response);
\r
85 private boolean isBanned(ServletRequest request) {
\r
86 String remoteIPAddressString = request.getRemoteAddr();
\r
87 if (bannedIPAddresses.contains(remoteIPAddressString) ||
\r
88 manuallyBannedIPAddresses.contains(remoteIPAddressString)) {
\r
91 InetAddress remoteIPAddress;
\r
93 remoteIPAddress = InetAddress.getByName(remoteIPAddressString);
\r
94 } catch (UnknownHostException uhe) {
\r
95 context.log("Can't determine host from: " + remoteIPAddressString + "; assuming banned");
\r
98 if (numRecentAccesses.incrementAndGet(remoteIPAddress) > MAX_ACCESSES_PER_IP_PER_TIME) {
\r
99 context.log("Possible DoS attack from " + remoteIPAddressString);
\r
100 bannedIPAddresses.add(remoteIPAddressString);
\r
106 public void destroy() {
\r
108 numRecentAccesses.clear();
\r
109 bannedIPAddresses.clear();
\r
112 private final class ResetTask extends TimerTask {
\r
114 public void run() {
\r
115 numRecentAccesses.clear();
\r
119 private final class UnbanTask extends TimerTask {
\r
121 public void run() {
\r
122 bannedIPAddresses.clear();
\r