Added source code to zxing.org
[zxing.git] / zxingorg / src / com / google / zxing / web / DoSFilter.java
diff --git a/zxingorg/src/com/google/zxing/web/DoSFilter.java b/zxingorg/src/com/google/zxing/web/DoSFilter.java
new file mode 100755 (executable)
index 0000000..8c6f388
--- /dev/null
@@ -0,0 +1,123 @@
+/*\r
+ * Copyright 2008 Google Inc.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *      http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.google.zxing.web;\r
+\r
+import javax.servlet.Filter;\r
+import javax.servlet.FilterChain;\r
+import javax.servlet.FilterConfig;\r
+import javax.servlet.ServletException;\r
+import javax.servlet.ServletRequest;\r
+import javax.servlet.ServletResponse;\r
+import javax.servlet.ServletContext;\r
+import javax.servlet.http.HttpServletResponse;\r
+import java.io.IOException;\r
+import java.net.InetAddress;\r
+import java.net.UnknownHostException;\r
+import java.util.Collections;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+import java.util.Timer;\r
+import java.util.TimerTask;\r
+import java.util.Collection;\r
+\r
+/**\r
+ * @author Sean Owen\r
+ */\r
+public final class DoSFilter implements Filter {\r
+\r
+       private static final int MAX_ACCESSES_PER_IP_PER_TIME = 10;\r
+       private static final long MAX_ACCESS_INTERVAL_MSEC = 10L * 1000L;\r
+       private static final long UNBAN_INTERVAL_MSEC = 60L * 60L * 1000L;\r
+\r
+       private final IPTrie numRecentAccesses;\r
+       private final Timer timer;\r
+       private final Set<String> bannedIPAddresses;\r
+       private final Collection<String> manuallyBannedIPAddresses;\r
+    private ServletContext context;\r
+\r
+    public DoSFilter() {\r
+               numRecentAccesses = new IPTrie();\r
+               timer = new Timer("DosFilter reset timer");\r
+               bannedIPAddresses = Collections.synchronizedSet(new HashSet<String>());\r
+               manuallyBannedIPAddresses = new HashSet<String>();\r
+       }\r
+\r
+    public void init(FilterConfig filterConfig) {\r
+        context = filterConfig.getServletContext();\r
+        String bannedIPs = filterConfig.getInitParameter("bannedIPs");\r
+           if (bannedIPs != null) {\r
+                   for (String ip : bannedIPs.split(",")) {\r
+                           manuallyBannedIPAddresses.add(ip.trim());\r
+                   }\r
+           }\r
+               timer.scheduleAtFixedRate(new ResetTask(), 0L, MAX_ACCESS_INTERVAL_MSEC);\r
+           timer.scheduleAtFixedRate(new UnbanTask(), 0L, UNBAN_INTERVAL_MSEC);\r
+    }\r
+\r
+    public void doFilter(ServletRequest request,\r
+                         ServletResponse response,\r
+                         FilterChain chain) throws IOException, ServletException {\r
+           if (isBanned(request)) {\r
+                   HttpServletResponse servletResponse = (HttpServletResponse) response;\r
+                   servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);\r
+           } else {\r
+                   chain.doFilter(request, response);\r
+           }\r
+    }\r
+\r
+       private boolean isBanned(ServletRequest request) {\r
+               String remoteIPAddressString = request.getRemoteAddr();\r
+               if (bannedIPAddresses.contains(remoteIPAddressString) ||\r
+                   manuallyBannedIPAddresses.contains(remoteIPAddressString)) {\r
+                       return true;\r
+               }\r
+               InetAddress remoteIPAddress;\r
+               try {\r
+                       remoteIPAddress = InetAddress.getByName(remoteIPAddressString);\r
+               } catch (UnknownHostException uhe) {\r
+                       context.log("Can't determine host from: " + remoteIPAddressString + "; assuming banned");\r
+                       return true;\r
+               }\r
+               if (numRecentAccesses.incrementAndGet(remoteIPAddress) > MAX_ACCESSES_PER_IP_PER_TIME) {\r
+                       context.log("Possible DoS attack from " + remoteIPAddressString);\r
+                       bannedIPAddresses.add(remoteIPAddressString);\r
+                       return true;\r
+               }\r
+               return false;\r
+       }\r
+\r
+       public void destroy() {\r
+           timer.cancel();\r
+        numRecentAccesses.clear();\r
+           bannedIPAddresses.clear();\r
+    }\r
+\r
+       private final class ResetTask extends TimerTask {\r
+               @Override\r
+               public void run() {\r
+                       numRecentAccesses.clear();\r
+               }\r
+       }\r
+\r
+       private final class UnbanTask extends TimerTask {\r
+               @Override\r
+               public void run() {\r
+                       bannedIPAddresses.clear();\r
+               }\r
+       }\r
+\r
+}
\ No newline at end of file