2 * Copyright 2008 ZXing authors
\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.Collections;
\r
31 import java.util.HashSet;
\r
32 import java.util.Set;
\r
33 import java.util.Timer;
\r
34 import java.util.TimerTask;
\r
37 * A {@link Filter} that rejects requests from hosts that are sending too many
\r
38 * requests in too short a time.
\r
42 public final class DoSFilter implements Filter {
\r
44 private static final int MAX_ACCESSES_PER_IP_PER_TIME = 10;
\r
45 private static final long MAX_ACCESS_INTERVAL_MSEC = 10L * 1000L;
\r
46 private static final long UNBAN_INTERVAL_MSEC = 60L * 60L * 1000L;
\r
48 private final IPTrie numRecentAccesses;
\r
49 private final Timer timer;
\r
50 private final Set<String> bannedIPAddresses;
\r
51 private ServletContext context;
\r
53 public DoSFilter() {
\r
54 numRecentAccesses = new IPTrie();
\r
55 timer = new Timer("DosFilter reset timer");
\r
56 bannedIPAddresses = Collections.synchronizedSet(new HashSet<String>());
\r
59 public void init(FilterConfig filterConfig) {
\r
60 context = filterConfig.getServletContext();
\r
61 timer.scheduleAtFixedRate(new ResetTask(), 0L, MAX_ACCESS_INTERVAL_MSEC);
\r
62 timer.scheduleAtFixedRate(new UnbanTask(), 0L, UNBAN_INTERVAL_MSEC);
\r
65 public void doFilter(ServletRequest request,
\r
66 ServletResponse response,
\r
67 FilterChain chain) throws IOException, ServletException {
\r
68 if (isBanned(request)) {
\r
69 HttpServletResponse servletResponse = (HttpServletResponse) response;
\r
70 servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
\r
72 chain.doFilter(request, response);
\r
76 private boolean isBanned(ServletRequest request) {
\r
77 String remoteIPAddressString = request.getRemoteAddr();
\r
78 if (bannedIPAddresses.contains(remoteIPAddressString)) {
\r
81 InetAddress remoteIPAddress;
\r
83 remoteIPAddress = InetAddress.getByName(remoteIPAddressString);
\r
84 } catch (UnknownHostException uhe) {
\r
85 context.log("Can't determine host from: " + remoteIPAddressString + "; assuming banned");
\r
88 if (numRecentAccesses.incrementAndGet(remoteIPAddress) > MAX_ACCESSES_PER_IP_PER_TIME) {
\r
89 context.log("Possible DoS attack from " + remoteIPAddressString);
\r
90 bannedIPAddresses.add(remoteIPAddressString);
\r
96 public void destroy() {
\r
98 numRecentAccesses.clear();
\r
99 bannedIPAddresses.clear();
\r
102 private final class ResetTask extends TimerTask {
\r
104 public void run() {
\r
105 numRecentAccesses.clear();
\r
109 private final class UnbanTask extends TimerTask {
\r
111 public void run() {
\r
112 bannedIPAddresses.clear();
\r