ASF Bugzilla – Attachment 27782 Details for
Bug 51953
Proposal: netmask filtering valve and filter [PATCH]
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Version "0.1" of the patch
all.patch (text/plain), 30.64 KB, created by
Francis Galiegue
on 2011-10-14 23:03:25 UTC
(
hide
)
Description:
Version "0.1" of the patch
Filename:
MIME Type:
Creator:
Francis Galiegue
Created:
2011-10-14 23:03:25 UTC
Size:
30.64 KB
patch
obsolete
>diff --git a/java/org/apache/catalina/filters/RemoteCIDRFilter.java b/java/org/apache/catalina/filters/RemoteCIDRFilter.java >new file mode 100644 >index 0000000..542fe0d >--- /dev/null >+++ b/java/org/apache/catalina/filters/RemoteCIDRFilter.java >@@ -0,0 +1,241 @@ >+package org.apache.catalina.filters; >+ >+import org.apache.catalina.comet.CometEvent; >+import org.apache.catalina.comet.CometFilter; >+import org.apache.catalina.comet.CometFilterChain; >+import org.apache.catalina.util.NetMask; >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+ >+import javax.servlet.FilterChain; >+import javax.servlet.ServletException; >+import javax.servlet.ServletRequest; >+import javax.servlet.ServletResponse; >+import javax.servlet.http.HttpServletResponse; >+import java.io.IOException; >+import java.io.PrintWriter; >+import java.net.InetAddress; >+import java.net.UnknownHostException; >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.LinkedList; >+import java.util.List; >+ >+public final class RemoteCIDRFilter >+ extends FilterBase >+ implements CometFilter { >+ >+ /** >+ * text/plain MIME type: this is the MIME type we return when a >+ * {@link ServletResponse} is not an {@link HttpServletResponse} >+ */ >+ >+ private static final String PLAIN_TEXT_MIME_TYPE = "text/plain"; >+ >+ /** >+ * Our logger >+ */ >+ >+ private static final Log log = LogFactory.getLog(RemoteCIDRFilter.class); >+ >+ /** >+ * The list of allowed {@link NetMask}s >+ */ >+ >+ private final List<NetMask> allow = new ArrayList<NetMask>(); >+ >+ /** >+ * The list of denied {@link NetMask}s >+ */ >+ >+ private final List<NetMask> deny = new ArrayList<NetMask>(); >+ >+ /** >+ * Return a string representation of the {@link NetMask} list in #allow. >+ * >+ * @return the #allow list as a string, without the leading '[' and >+ * trailing ']' >+ */ >+ >+ public String getAllow() { >+ return allow.toString().replace("[", "").replace("]", ""); >+ } >+ >+ >+ /** >+ * Fill the #allow list with the list of netmasks provided as an argument, >+ * if any. Calls #fillFromInput. >+ * >+ * @param input The list of netmasks, as a comma separated string >+ * @throws IllegalArgumentException One or more netmasks are invalid >+ */ >+ >+ public void setAllow(final String input) { >+ final List<String> messages = fillFromInput(input, allow); >+ >+ if (messages.isEmpty()) >+ return; >+ >+ for (final String message:messages) >+ log.error(message); >+ >+ throw new IllegalArgumentException("Filter error, see messages above"); >+ } >+ >+ >+ /** >+ * Return a string representation of the {@link NetMask} list in #deny. >+ * >+ * @return the #deny list as string, without the leading '[' and trailing >+ * ']' >+ */ >+ >+ public String getDeny() { >+ return deny.toString().replace("[", "").replace("]", ""); >+ } >+ >+ >+ /** >+ * Fill the #deny list with the list of netmasks provided as an argument, >+ * if any. Calls #fillFromInput. >+ * >+ * @param input The list of netmasks, as a comma separated string >+ * @throws IllegalArgumentException One or more netmasks are invalid >+ */ >+ >+ public void setDeny(final String input) { >+ final List<String> messages = fillFromInput(input, deny); >+ >+ if (messages.isEmpty()) >+ return; >+ >+ for (final String message: messages) >+ log.error(message); >+ >+ throw new IllegalArgumentException("Filter error: illegal netmask(s) " + >+ "in allow, see messages above"); >+ } >+ >+ @Override >+ public void doFilterEvent(CometEvent event, CometFilterChain chain) >+ throws IOException, ServletException { >+ processCometEvent(event.getHttpServletRequest().getRemoteHost(), >+ event, chain); >+ } >+ >+ @Override >+ public void doFilter(final ServletRequest request, >+ final ServletResponse response, final FilterChain chain) >+ throws IOException, ServletException { >+ process(request.getRemoteAddr(), request, response, chain); >+ } >+ >+ public void processCometEvent(final String property, final CometEvent event, >+ final CometFilterChain chain) >+ throws IOException, ServletException { >+ HttpServletResponse response = event.getHttpServletResponse(); >+ >+ if (isAllowed(property)) { >+ chain.doFilterEvent(event); >+ return; >+ } >+ >+ response.sendError(HttpServletResponse.SC_FORBIDDEN); >+ event.close(); >+ } >+ >+ public void process(final String property, final ServletRequest request, >+ final ServletResponse response, final FilterChain chain) >+ throws IOException, ServletException { >+ >+ if (isAllowed(property)) { >+ chain.doFilter(request, response); >+ return; >+ } >+ >+ if (!(response instanceof HttpServletResponse)) { >+ sendErrorWhenNotHttp(response); >+ return; >+ } >+ >+ ((HttpServletResponse) response) >+ .sendError(HttpServletResponse.SC_FORBIDDEN); >+ } >+ >+ @Override >+ public Log getLogger() { >+ return log; >+ } >+ >+ /** >+ * Test if a remote's IP address is allowed to proceed. >+ * >+ * @param property The remote's IP address, as a string >+ * @return true if allowed >+ */ >+ >+ private boolean isAllowed(final String property) { >+ final InetAddress addr; >+ >+ try { >+ addr = InetAddress.getByName(property); >+ } catch (UnknownHostException e) { >+ //Eh? >+ log.error("Eh? Our remote doesn't even have a valid IP address? ", >+ e); >+ return false; >+ } >+ >+ for (final NetMask nm: deny) >+ if (nm.matches(addr)) >+ return false; >+ >+ for (final NetMask nm: allow) >+ if (nm.matches(addr)) >+ return true; >+ >+ // Allow if deny is specified but allow isn't >+ if (!deny.isEmpty() && allow.isEmpty()) >+ return true; >+ >+ // Deny this request >+ return false; >+ } >+ >+ private void sendErrorWhenNotHttp(ServletResponse response) >+ throws IOException { >+ final PrintWriter writer = response.getWriter(); >+ response.setContentType(PLAIN_TEXT_MIME_TYPE); >+ writer.write(sm.getString("http.403")); >+ writer.flush(); >+ } >+ >+ /** >+ * Fill a {@link NetMask} list from a string input containing a >+ * comma-separated list of (hopefully valid) {@link NetMask}s. >+ * >+ * @param input The input string >+ * @param victim The list to fill >+ * @return a string list of processing errors (empty when no errors) >+ */ >+ >+ private List<String> fillFromInput(final String input, >+ final List<NetMask> victim) { >+ victim.clear(); >+ if (input == null || input.isEmpty()) >+ return Collections.emptyList(); >+ >+ final List<String> messages = new LinkedList<String>(); >+ NetMask nm; >+ >+ for (final String s: input.split("\\s*,\\s*")) >+ try { >+ nm = new NetMask(s); >+ victim.add(nm); >+ } catch (IllegalArgumentException e) { >+ messages.add(s + ": " + e.getMessage()); >+ } >+ >+ return Collections.unmodifiableList(messages); >+ } >+} >diff --git a/java/org/apache/catalina/util/NetMask.java b/java/org/apache/catalina/util/NetMask.java >new file mode 100644 >index 0000000..27d1602 >--- /dev/null >+++ b/java/org/apache/catalina/util/NetMask.java >@@ -0,0 +1,213 @@ >+package org.apache.catalina.util; >+ >+import java.net.InetAddress; >+import java.net.UnknownHostException; >+ >+/** >+ * A class representing a CIDR netmask. >+ * >+ * <p>The constructor takes a string as an argument which represents a >+ * netmask, as per the CIDR notation -- whether this netmask be IPv4 or >+ * IPv6. It then extracts the network address (before the /) and the CIDR >+ * prefix (after the /), and tells through the #matches() method whether a >+ * candidate {@link InetAddress} object fits in the recorded range.</p> >+ * >+ * <p>As byte arrays as returned by <code>InetAddress.getByName()</code> are >+ * always in network byte order, finding a match is therefore as simple as >+ * testing whether the n first bits (where n is the CIDR) are the same in both >+ * byte arrays (the one of the network address and the one of the candidate >+ * address). We do that by first doing byte comparisons, then testing the last >+ * bits if any (that is, if the remainder of the integer division of the CIDR >+ * by 8 is not 0).</p> >+ * >+ * <p>As a bonus, if no / is found in the input, it is assumed that an exact >+ * address match is required.</p> >+ */ >+ >+public final class NetMask { >+ /** >+ * The argument to the constructor, used for .toString() >+ */ >+ private final String expression; >+ >+ /** >+ * The byte array representing the address extracted from the expression >+ */ >+ private final byte[] netaddr; >+ >+ /** >+ * The number of bytes to test for equality (CIDR / 8) >+ */ >+ private final int nrBytes; >+ >+ /** >+ * The right shift to apply to the last byte if CIDR % 8 is not 0; if it is >+ * 0, this variable is set to 0 >+ */ >+ private final int lastByteShift; >+ >+ /** >+ * Constructor >+ * >+ * @param input the CIDR netmask >+ * @throws IllegalArgumentException if the netmask is not correct >+ * (invalid address specification, malformed CIDR prefix, etc) >+ */ >+ >+ public NetMask(final String input) { >+ >+ expression = input; >+ >+ final int idx = input.indexOf("/"); >+ >+ /* >+ * Handle the "IP only" case first >+ */ >+ if (idx == -1) { >+ try { >+ netaddr = InetAddress.getByName(input).getAddress(); >+ } catch (UnknownHostException e) { >+ throw new IllegalArgumentException("invalid address " >+ + "specification"); >+ } >+ nrBytes = netaddr.length; >+ lastByteShift = 0; >+ return; >+ } >+ >+ /* >+ * OK, we do have a netmask specified, so let's extract both the >+ * address and the CIDR. >+ */ >+ >+ final String addressPart = input.substring(0, idx), >+ cidrPart = input.substring(idx + 1); >+ >+ try { >+ /* >+ * The address first... >+ */ >+ netaddr = InetAddress.getByName(addressPart).getAddress(); >+ } catch (UnknownHostException e) { >+ throw new IllegalArgumentException("invalid address " >+ + "specification"); >+ } >+ >+ final int addrlen = netaddr.length * 8; >+ final int cidr; >+ >+ try { >+ /* >+ * And then the CIDR. >+ */ >+ cidr = Integer.parseInt(cidrPart); >+ } catch (NumberFormatException e) { >+ throw new IllegalArgumentException("CIDR is not a number"); >+ } >+ >+ /* >+ * We don't want a negative CIDR, nor do we want a CIDR which is >+ * greater than the address length (consider 0.0.0.0/33, or ::/129) >+ */ >+ if (cidr < 0) >+ throw new IllegalArgumentException("CIDR is negative"); >+ if (cidr > addrlen) >+ throw new IllegalArgumentException("CIDR is greater than address " >+ + "length"); >+ >+ nrBytes = cidr / 8; >+ >+ /* >+ * These last two lines could be shortened to: >+ * >+ * lastByteShift = (8 - (cidr % 8)) & 7; >+ * >+ * But... It's not worth it. In fact, explaining why it could work >+ * would be too long to be worth the trouble, so let's do it the simple >+ * way... >+ */ >+ >+ final int remainder = cidr % 8; >+ >+ lastByteShift = (remainder == 0) ? 0 : 8 - remainder; >+ } >+ >+ /** >+ * 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 byte[] candidate = addr.getAddress(); >+ >+ /* >+ * OK, remember that a CIDR prefix tells the number of BITS which >+ * should be equal between this NetMask's recorded address (netaddr) >+ * and the candidate address. One byte is 8 bits, no matter what, >+ * and IP addresses, whether they be IPv4 or IPv6, are big endian, >+ * aka MSB, Most Significant Byte (first). >+ * >+ * We therefore need to get the byte array of the candidate address, >+ * compare as many bytes of the candidate address with the recorded >+ * address as the CIDR prefix tells us to (that is, CIDR / 8), >+ * and then deal with the remaining bits -- if any. >+ * >+ * But prior to that, a simple test can be done: we deal with IP >+ * addresses here, which means IPv4 and IPv6. IPv4 addresses are >+ * encoded on 4 bytes, IPv6 addresses are encoded on 16 bytes. If the >+ * candidate address length is different than this NetMask's >+ * address, we don't have a match. >+ */ >+ if (candidate.length != netaddr.length) >+ return false; >+ >+ int i; >+ >+ /* >+ * Now do the byte-compare. The constructor has recorded the number >+ * of bytes to compare in nrBytes, use that. If any of the byte we have >+ * to compare is different than what we expect, we don't have a match. >+ * >+ * If, on the opposite, after this loop, all bytes have been deemed >+ * equal, then the loop variable i will point to the byte right after >+ * that -- which we will need... >+ */ >+ for (i = 0; i < nrBytes; i++) >+ if (netaddr[i] != candidate[i]) >+ return false; >+ >+ /* >+ * ... if there are bits left to test. There aren't any if >+ * lastByteShift is set to 0. >+ */ >+ if (lastByteShift == 0) >+ return true; >+ >+ /* >+ * If it is not 0, however, we must test for the relevant bits in the >+ * next byte (whatever is in the bytes after that doesn't matter). We >+ * do it this way (remember that lastByteShift contains the amount of >+ * bits we should _right_ shift the last byte): >+ * >+ * - grab both bytes at index i, both from the netmask address and >+ * the candidate address; >+ * - xor them both. >+ * >+ * After the xor, it means that all the remaining bits of the CIDR >+ * should be set to 0... >+ */ >+ final int lastByte = netaddr[i] ^ candidate[i]; >+ >+ /* >+ * ... Which means that right shifting by lastByteShift should be 0. >+ */ >+ return (lastByte >> lastByteShift == 0); >+ } >+ >+ @Override >+ public String toString() { >+ return expression; >+ } >+} >diff --git a/java/org/apache/catalina/valves/RemoteCIDRValve.java b/java/org/apache/catalina/valves/RemoteCIDRValve.java >new file mode 100644 >index 0000000..b3f236d >--- /dev/null >+++ b/java/org/apache/catalina/valves/RemoteCIDRValve.java >@@ -0,0 +1,184 @@ >+package org.apache.catalina.valves; >+ >+import org.apache.catalina.connector.Request; >+import org.apache.catalina.connector.Response; >+import org.apache.catalina.util.NetMask; >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+ >+import javax.servlet.ServletException; >+import javax.servlet.http.HttpServletResponse; >+import java.io.IOException; >+import java.net.InetAddress; >+import java.util.ArrayList; >+import java.util.Collections; >+import java.util.LinkedList; >+import java.util.List; >+ >+public final class RemoteCIDRValve >+ extends ValveBase { >+ >+ /** >+ * What this Valve is to the administrator >+ */ >+ >+ private static final String info >+ = "org.apache.catalina.valves.RemoteCIDRValve/1.0"; >+ >+ /** >+ * Our logger >+ */ >+ >+ private static final Log log = LogFactory.getLog(RemoteCIDRValve.class); >+ >+ /** >+ * The list of allowed {@link NetMask}s >+ */ >+ >+ private final List<NetMask> allow = new ArrayList<NetMask>(); >+ >+ /** >+ * The list of denied {@link NetMask}s >+ */ >+ >+ private final List<NetMask> deny = new ArrayList<NetMask>(); >+ >+ public RemoteCIDRValve() { >+ super(true); >+ } >+ >+ /** >+ * Return a string representation of the {@link NetMask} list in #allow. >+ * >+ * @return the #allow list as a string, without the leading '[' and >+ * trailing ']' >+ */ >+ >+ public String getAllow() { >+ return allow.toString().replace("[", "").replace("]", ""); >+ } >+ >+ /** >+ * Fill the #allow list with the list of netmasks provided as an argument, >+ * if any. Calls #fillFromInput. >+ * >+ * @param input The list of netmasks, as a comma separated string >+ * @throws IllegalArgumentException One or more netmasks are invalid >+ */ >+ >+ public void setAllow(final String input) { >+ final List<String> messages = fillFromInput(input, allow); >+ >+ if (messages.isEmpty()) >+ return; >+ >+ for (final String message: messages) >+ log.error(message); >+ >+ throw new IllegalArgumentException("Valve error: illegal netmask(s) " + >+ "in allow, see messages above"); >+ } >+ >+ /** >+ * Return a string representation of the {@link NetMask} list in #deny. >+ * >+ * @return the #deny list as a string, without the leading '[' and >+ * trailing ']' >+ */ >+ >+ public String getDeny() { >+ return deny.toString().replace("[", "").replace("]", ""); >+ } >+ >+ /** >+ * Fill the #deny list with the list of netmasks provided as an argument, >+ * if any. Calls #fillFromInput. >+ * >+ * @param input The list of netmasks, as a comma separated string >+ * @throws IllegalArgumentException One or more netmasks are invalid >+ */ >+ >+ public void setDeny(final String input) { >+ final List<String> messages = fillFromInput(input, deny); >+ >+ if (messages.isEmpty()) >+ return; >+ >+ for (final String message: messages) >+ log.error(message); >+ >+ throw new IllegalArgumentException("Valve error: illegal netmask(s) " + >+ "in deny, see messages above"); >+ } >+ >+ >+ /** >+ * Return descriptive information about this Valve implementation. >+ */ >+ >+ @Override >+ public String getInfo() { >+ return info; >+ } >+ >+ @Override >+ public void invoke(final Request request, final Response response) >+ throws IOException, ServletException { >+ process(request.getRequest().getRemoteAddr(), request, response); >+ } >+ >+ private void process(final String property, final Request request, >+ final Response response) >+ throws IOException, ServletException { >+ >+ final InetAddress addr = InetAddress.getByName(property); >+ >+ for (final NetMask nm : deny) >+ if (nm.matches(addr)) { >+ response.sendError(HttpServletResponse.SC_FORBIDDEN); >+ return; >+ } >+ >+ if (allow.isEmpty()) { >+ getNext().invoke(request, response); >+ return; >+ } >+ >+ for (final NetMask nm : allow) >+ if (nm.matches(addr)) { >+ getNext().invoke(request, response); >+ return; >+ } >+ >+ response.sendError(HttpServletResponse.SC_FORBIDDEN); >+ } >+ >+ /** >+ * Fill a {@link NetMask} list from a string input containing a >+ * comma-separated list of (hopefully valid) {@link NetMask}s. >+ * >+ * @param input The input string >+ * @param victim The list to fill >+ * @return a string list of processing errors (empty when no errors) >+ */ >+ >+ private List<String> fillFromInput(final String input, >+ final List<NetMask> victim) { >+ victim.clear(); >+ if (input == null || input.isEmpty()) >+ return Collections.emptyList(); >+ >+ final List<String> messages = new LinkedList<String>(); >+ NetMask nm; >+ >+ for (final String s: input.split("\\s*,\\s*")) >+ try { >+ nm = new NetMask(s); >+ victim.add(nm); >+ } catch (IllegalArgumentException e) { >+ messages.add(s + ": " + e.getMessage()); >+ } >+ >+ return Collections.unmodifiableList(messages); >+ } >+} >diff --git a/test/org/apache/catalina/util/TestNetMask.java b/test/org/apache/catalina/util/TestNetMask.java >new file mode 100644 >index 0000000..ab3d92a >--- /dev/null >+++ b/test/org/apache/catalina/util/TestNetMask.java >@@ -0,0 +1,72 @@ >+package org.apache.catalina.util; >+ >+import org.junit.Test; >+ >+import static org.junit.Assert.assertEquals; >+import static org.junit.Assert.fail; >+ >+public final class TestNetMask >+{ >+ >+ @Test >+ public void testIPV4InitErrors() { >+ try { >+ new NetMask("260.1.1.1"); >+ fail("NetMask succeeded with an invalid address!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "invalid address specification"); >+ } >+ >+ try { >+ new NetMask("1.2.3.4/foo"); >+ fail("NetMask succeeded with a non numeric CIDR!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "CIDR is not a number"); >+ } >+ >+ try { >+ new NetMask("1.2.3.4/-1"); >+ fail("NetMask succeeded with a negative CIDR!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "CIDR is negative"); >+ } >+ >+ try { >+ new NetMask("1.2.3.4/33"); >+ fail("NetMask succeeded with CIDR greater than address length!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "CIDR is greater than address length"); >+ } >+ } >+ >+ @Test >+ public void testIPV6InitErrors() { >+ try { >+ new NetMask("fffff::/71"); >+ fail("NetMask succeeded with an invalid address!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "invalid address specification"); >+ } >+ >+ try { >+ new NetMask("ae31::27:ef2:1/foo"); >+ fail("NetMask succeeded with a non numeric CIDR!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "CIDR is not a number"); >+ } >+ >+ try { >+ new NetMask("ae31::27:ef2:1/-1"); >+ fail("NetMask succeeded with a negative CIDR!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "CIDR is negative"); >+ } >+ >+ try { >+ new NetMask("ae31::27:ef2:1/129"); >+ fail("NetMask succeeded with CIDR greater than address length!"); >+ } catch (IllegalArgumentException e) { >+ assertEquals(e.getMessage(), "CIDR is greater than address length"); >+ } >+ } >+} >diff --git a/webapps/docs/config/filter.xml b/webapps/docs/config/filter.xml >index 707c667..335a81d 100644 >--- a/webapps/docs/config/filter.xml >+++ b/webapps/docs/config/filter.xml >@@ -654,6 +654,109 @@ FINE: Request "/docs/config/manager.html" with response status "200" content-typ > > </section> > >+<section name="Remote CIDR Filter"> >+ >+ <subsection name="Introduction"> >+ >+ <p>The <strong>Remote CIDR Filter</strong> allows you to compare the >+ IP address of the client that submitted this request against one or more >+ netmasks following the CIDR notation, and either allow the request to >+ continue or refuse to process the request from this client. IPv4 and >+ IPv6 are both fully supported. >+ </p> >+ >+ <p>This filter mimicks Apache's <code>Order</code>, >+ <code>Allow from</code> and <code>Deny from</code> directives, >+ with the following limitations: >+ </p> >+ >+ <ul> >+ <li><code>Order</code> will always be <code>allow, deny</code>;</li> >+ <li>dotted quad notations for netmasks are not supported (that is, you >+ cannot write <code>192.168.1.0/255.255.255.0</code>, you must write >+ <code>192.168.1.0/24</code>; >+ </li> >+ <li>shortcuts, like <code>10.10.</code>, which is equivalent to >+ <code>10.10.0.0/16</code>, are not supported; >+ </li> >+ <li>as the filter name says, this is a CIDR only filter, >+ therefore subdomain notations like <code>.mydomain.com</code> are not >+ supported either. >+ </li> >+ </ul> >+ >+ <p>Some more features of this filter are: >+ </p> >+ >+ <ul> >+ <li>if you omit the CIDR prefix, this filter becomes a single IP >+ filter;</li> >+ <li>unlike the <a href="#Remote_Host_Filter">Remote Host Filter</a>, >+ it will do the correct thing with IPv6 in every case, which means you can >+ write IPv6 addresses in condensed form (<code>::1</code>, >+ <code>fe80::/71</code>, etc).</li> >+ </ul> >+ >+ </subsection> >+ >+ <subsection name="Filter Class Name"> >+ >+ <p>The filter class name for the Remote Address Filter is >+ <strong><code>org.apache.catalina.filters.RemoteCIDRFilter</code> >+ </strong>.</p> >+ >+ </subsection> >+ >+ <subsection name="Initialisation parameters"> >+ >+ <p>The <strong>Remote CIDR Filter</strong> supports the following >+ initialisation parameters:</p> >+ >+ <attributes> >+ >+ <attribute name="allow" required="false"> >+ <p>A comma-separated list of IPv4 or IPv6 netmasks or addresses >+ that the remote client's IP address is matched against. >+ If this attribute is specified, the remote address MUST match >+ for this request to be accepted. If this attribute is not specified, >+ all requests will be accepted UNLESS the remote IP is matched by a >+ netmask in the <code>deny</code> attribute. >+ </p> >+ </attribute> >+ >+ <attribute name="deny" required="false"> >+ <p>A comma-separated list of IPv4 or IPv6 netmasks or addresses >+ that the remote client's IP address is matched against. >+ If this attribute is specified, the remote address MUST NOT match >+ for this request to be accepted. If this attribute is not specified, >+ request acceptance is governed solely by the <code>accept</code> >+ attribute. >+ </p> >+ </attribute> >+ >+ </attributes> >+ >+ </subsection> >+ >+ <subsection name="Example"> >+ <p>To allow access only for the clients connecting from localhost:</p> >+ <pre> >+ <filter> >+ <filter-name>Remote CIDR Filter</filter-name> >+ <filter-class>org.apache.catalina.filters.RemoteCIDRFilter</filter-class> >+ <init-param> >+ <param-name>allow</param-name> >+ <param-value>127.0.0.0/8, ::1</param-value> >+ </init-param> >+ </filter> >+ <filter-mapping> >+ <filter-name>Remote CIDR Filter</filter-name> >+ <url-pattern>/*</url-pattern> >+ </filter-mapping> >+ </pre> >+ </subsection> >+ >+</section> > > <section name="Remote IP Filter"> > >diff --git a/webapps/docs/config/valve.xml b/webapps/docs/config/valve.xml >index 9572e6a..f187fd5 100644 >--- a/webapps/docs/config/valve.xml >+++ b/webapps/docs/config/valve.xml >@@ -621,6 +621,100 @@ > > </section> > >+<section name="Remote CIDR Filter"> >+ >+ <subsection name="Introduction"> >+ >+ <p>The <strong>Remote CIDR Filter</strong> allows you to compare the >+ IP address of the client that submitted this request against one or more >+ netmasks following the CIDR notation, and either allow the request to >+ continue or refuse to process the request from this client. IPv4 and >+ IPv6 are both fully supported. A Remote CIDR Filter can be associated >+ with any Catalina container (<a href="engine.html">Engine</a>, >+ <a href="host.html">Host</a>, or <a href="context.html">Context</a>), and >+ must accept any request presented to this container for processing before >+ it will be passed on. >+ </p> >+ >+ <p>This filter mimicks Apache's <code>Order</code>, >+ <code>Allow from</code> and <code>Deny from</code> directives, >+ with the following limitations: >+ </p> >+ >+ <ul> >+ <li><code>Order</code> will always be <code>allow, deny</code>;</li> >+ <li>dotted quad notations for netmasks are not supported (that is, you >+ cannot write <code>192.168.1.0/255.255.255.0</code>, you must write >+ <code>192.168.1.0/24</code>; >+ </li> >+ <li>shortcuts, like <code>10.10.</code>, which is equivalent to >+ <code>10.10.0.0/16</code>, are not supported; >+ </li> >+ <li>as the filter name says, this is a CIDR only filter, >+ therefore subdomain notations like <code>.mydomain.com</code> are not >+ supported either. >+ </li> >+ </ul> >+ >+ <p>Some more features of this filter are: >+ </p> >+ >+ <ul> >+ <li>if you omit the CIDR prefix, this filter becomes a single IP >+ filter;</li> >+ <li>unlike the <a href="#Remote_Host_Filter">Remote Host Filter</a>, >+ it will do the correct thing with IPv6 in every case, which means you can >+ write IPv6 addresses in condensed form (<code>::1</code>, >+ <code>fe80::/71</code>, etc).</li> >+ </ul> >+ >+ </subsection> >+ >+ <subsection name="Attributes"> >+ >+ <p>The <strong>Remote CIDR Filter</strong> supports the following >+ configuration attributes:</p> >+ >+ <attributes> >+ >+ <attribute name="className" required="true"> >+ <p>Java class name of the implementation to use. This MUST be set to >+ <strong>org.apache.catalina.valves.RemoteCIDRValve</strong>.</p> >+ </attribute> >+ >+ <attribute name="allow" required="false"> >+ <p>A comma-separated list of IPv4 or IPv6 netmasks or addresses >+ that the remote client's IP address is matched against. >+ If this attribute is specified, the remote address MUST match >+ for this request to be accepted. If this attribute is not specified, >+ all requests will be accepted UNLESS the remote IP is matched by a >+ netmask in the <code>deny</code> attribute. >+ </p> >+ </attribute> >+ >+ <attribute name="deny" required="false"> >+ <p>A comma-separated list of IPv4 or IPv6 netmasks or addresses >+ that the remote client's IP address is matched against. >+ If this attribute is specified, the remote address MUST NOT match >+ for this request to be accepted. If this attribute is not specified, >+ request acceptance is governed solely by the <code>accept</code> >+ attribute. >+ </p> >+ </attribute> >+ >+ </attributes> >+ >+ </subsection> >+ >+ <subsection name="Example"> >+ <p>To allow access only for the clients connecting from localhost:</p> >+ <pre> >+ <Valve className="org.apache.catalina.valves.RemoteCIDRValve" >+ allow="127.0.0.1, ::1"/> >+ </pre> >+ </subsection> >+ >+</section> > > <section name="Single Sign On Valve"> >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 51953
:
27686
|
27687
|
27688
|
27689
|
27691
|
27694
|
27726
| 27782