Index: java/org/apache/catalina/filters/RequestFilter.java
===================================================================
--- java/org/apache/catalina/filters/RequestFilter.java (revision 1178969)
+++ java/org/apache/catalina/filters/RequestFilter.java (working copy)
@@ -218,7 +218,7 @@
* @return true
if this request should be allowed,
* false
otherwise
*/
- private boolean isAllowed(String property) {
+ protected boolean isAllowed(String property) {
if (deny != null && deny.matcher(property).matches()) {
return false;
}
Index: java/org/apache/catalina/filters/RemoteAddrNetmaskFilter.java
===================================================================
--- java/org/apache/catalina/filters/RemoteAddrNetmaskFilter.java (revision 0)
+++ java/org/apache/catalina/filters/RemoteAddrNetmaskFilter.java (revision 0)
@@ -0,0 +1,284 @@
+package org.apache.catalina.filters;
+
+import java.math.BigInteger;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+
+import org.apache.catalina.comet.CometEvent;
+import org.apache.catalina.comet.CometFilter;
+import org.apache.catalina.comet.CometFilterChain;
+
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+
+/**
+ * Implementation of a Filter that performs filtering based on comparing the
+ * appropriate request property (selected based on which subclass you choose
+ * to configure into your Container's pipeline) against the regular expressions
+ * configured for this Filter.
+ *
+ * This filter is configured by setting the allow
and/or
+ * deny
properties to a regular expressions (in the syntax
+ * supported by {@link java.util.regex.Pattern}) to which the appropriate request property will
+ * be compared. Evaluation proceeds as follows:
+ *
process()
method.
+ * process()
method
+ * to perform the actual filtering.
+ *
+ * @param event The comet event to be processed
+ * @param chain The filter chain for this event
+ *
+ * @exception IOException if an input/output error occurs
+ * @exception ServletException if a servlet error occurs
+ */
+ @Override
+ public void doFilterEvent(CometEvent event, CometFilterChain chain)
+ throws IOException, ServletException {
+ processCometEvent(event.getHttpServletRequest().getRemoteAddr(),
+ event, chain);
+ }
+
+ // ------------------------------------------------------ Protected Methods
+
+ @Override
+ protected boolean isAllowed(String property) {
+ final InetAddress addr;
+
+ try {
+ addr = InetAddress.getByName(property);
+ } catch (UnknownHostException e) {
+ // FIXME: log
+ return false;
+ }
+
+ for (final IPMatcher m: deny)
+ if (m.matches(addr))
+ return false;
+
+ for (final IPMatcher m: allow)
+ if (m.matches(addr))
+ return true;
+
+ // Allow if denies specified but not allows
+ if (!deny.isEmpty() && allow.isEmpty())
+ return true;
+
+ // Deny this request
+ return false;
+ }
+
+ @Override
+ protected Log getLogger() {
+ return log;
+ }
+
+ private interface IPMatcher
+ {
+ boolean matches(InetAddress address);
+ }
+
+ static class StringIPMatcher
+ implements IPMatcher
+ {
+ private String address;
+
+ public StringIPMatcher(final String address)
+ {
+ this.address = address;
+ }
+
+ public boolean matches(final InetAddress address)
+ {
+ return address.getHostAddress().equals(this.address);
+ }
+ }
+
+
+ /**
+ * A class representing a netmask, which is at the core of this valve.
+ *
+ * The constructor takes a {@link java.lang.String} representing a + * CIDR netmask as an argument and extracts two informations from it: the + * network address and the CIDR. It then turns the address into a + * {@link java.math.BigInteger}, calculates the right shift and shifts that + * BigInteger by it.
+ *The process to verify whether an IP address falls within the mask + * is to also convert it to a BigInteger, shifting it right and comparing + * it to the stored BigInteger. + *
+ */ + static class NetMaskIPMatcher + implements IPMatcher + { + /** + * The argument to the constructor, used for .toString() + */ + private final String expression; + + /** + * The number of bits a matching candidate needs to be shifted right + * in order to see if it matches + */ + private final int shift; + + /** + * The network address, already shifted right + */ + private final BigInteger mask; + + /** + * Constructor. + * + * @param expression the CIDR netmask + * @throws IllegalArgumentException if the netmask is not correct + * (invalid address specification, malformed CIDR prefix, etc) + */ + public NetMaskIPMatcher(final String expression) { + final int idx = expression.indexOf("/"); + final int cidr, addrlen; + final String addressPart; + final InetAddress addr; + final byte[] bytes; + + if (idx == -1) { + cidr = -1; + addressPart = expression; + } else { + final String substring = expression.substring(idx + 1); + try { + cidr = Integer.parseInt(substring); + if (cidr < 0) + throw new NumberFormatException("CIDR is negative"); + } catch (NumberFormatException ignored) { + throw new IllegalArgumentException("provided CIDR mask (" + + substring + ") is invalid"); + } + addressPart = expression.substring(0, idx); + } + + try { + addr = InetAddress.getByName(addressPart); + } catch (UnknownHostException e) { + throw new IllegalArgumentException("provided address (" + + addressPart + ") is invalid"); + } + + bytes = addr.getAddress(); + addrlen = bytes.length * 8; + shift = cidr == -1 ? 0 : addrlen - cidr; + + if (shift < 0) + throw new IllegalArgumentException("CIDR prefix (" + cidr + + ") is greater than address length (" + addrlen + ")"); + mask = new BigInteger(bytes).shiftRight(shift); + this.expression = expression; + } + + /** + * Test if a given address matches this netmask + * + * @param addr The {@link java.net.InetAddress} to test + * @return true on match, false otherwise + */ + public boolean matches (final InetAddress addr) { + final BigInteger provided = new BigInteger(addr.getAddress()) + .shiftRight(shift); + + return mask.equals(provided); + } + + @Override + public String toString() { + return expression; + } + } +}