Merge pull request #4615 from eclipse/jetty-10.0.x-4598-InetAccessHandler
Issue #4598 - rework InetAccessHandler to use path mappings
This commit is contained in:
commit
6151fc0c36
|
@ -26,16 +26,20 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.HttpChannel;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.util.IncludeExclude;
|
||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||
import org.eclipse.jetty.util.InetAddressPattern;
|
||||
import org.eclipse.jetty.util.InetAddressSet;
|
||||
import org.eclipse.jetty.util.component.DumpableCollection;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
import static org.eclipse.jetty.server.handler.InetAccessSet.AccessTuple;
|
||||
import static org.eclipse.jetty.server.handler.InetAccessSet.PatternTuple;
|
||||
|
||||
/**
|
||||
* InetAddress Access Handler
|
||||
* <p>
|
||||
|
@ -43,18 +47,13 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* provided by and {@link IncludeExcludeSet} over a {@link InetAddressSet}. This
|
||||
* handler uses the real internet address of the connection, not one reported in
|
||||
* the forwarded for headers, as this cannot be as easily forged.
|
||||
* <p>
|
||||
* Additionally, there may be times when you want to only apply this handler to
|
||||
* a subset of your connectors. In this situation you can use
|
||||
* <b>connectorNames</b> to specify the connector names that you want this IP
|
||||
* access filter to apply to.
|
||||
* </p>
|
||||
*/
|
||||
public class InetAccessHandler extends HandlerWrapper
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(InetAccessHandler.class);
|
||||
|
||||
private final IncludeExcludeSet<String, InetAddress> _addrs = new IncludeExcludeSet<>(InetAddressSet.class);
|
||||
private final IncludeExclude<String> _names = new IncludeExclude<>();
|
||||
private final IncludeExcludeSet<PatternTuple, AccessTuple> _set = new IncludeExcludeSet<>(InetAccessSet.class);
|
||||
|
||||
/**
|
||||
* Clears all the includes, excludes, included connector names and excluded
|
||||
|
@ -62,92 +61,150 @@ public class InetAccessHandler extends HandlerWrapper
|
|||
*/
|
||||
public void clear()
|
||||
{
|
||||
_addrs.clear();
|
||||
_names.clear();
|
||||
_set.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes an InetAddress pattern
|
||||
* Includes an InetAccess pattern with an optional connector name, address and URI mapping.
|
||||
*
|
||||
* @param pattern InetAddress pattern to include
|
||||
* <p>The connector name is separated from the InetAddress pattern with an '@' character,
|
||||
* and the InetAddress pattern is separated from the URI pattern using the "|" (pipe)
|
||||
* character. URI patterns follow the servlet specification for simple * prefix and
|
||||
* suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz).</p>
|
||||
*
|
||||
* <br>Examples:
|
||||
* <ul>
|
||||
* <li>"connector1@127.0.0.1|/foo"</li>
|
||||
* <li>"127.0.0.1|/foo"</li>
|
||||
* <li>"connector1@127.0.0.1"</li>
|
||||
* <li>"127.0.0.1"</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param pattern InetAccess pattern to include
|
||||
* @see InetAddressSet
|
||||
*/
|
||||
public void include(String pattern)
|
||||
{
|
||||
_addrs.include(pattern);
|
||||
_set.include(PatternTuple.from(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes InetAddress patterns
|
||||
* Includes InetAccess patterns
|
||||
*
|
||||
* @param patterns InetAddress patterns to include
|
||||
* @see InetAddressSet
|
||||
*/
|
||||
public void include(String... patterns)
|
||||
{
|
||||
_addrs.include(patterns);
|
||||
for (String pattern : patterns)
|
||||
include(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes an InetAddress pattern
|
||||
* Includes an InetAccess entry.
|
||||
* @param connectorName optional name of a connector to include.
|
||||
* @param addressPattern optional InetAddress pattern to include.
|
||||
* @param pathSpec optional pathSpec to include.
|
||||
*/
|
||||
public void include(String connectorName, String addressPattern, PathSpec pathSpec)
|
||||
{
|
||||
_set.include(new PatternTuple(connectorName, InetAddressPattern.from(addressPattern), pathSpec));
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes an InetAccess entry pattern with an optional connector name, address and URI mapping.
|
||||
*
|
||||
* <p>The connector name is separated from the InetAddress pattern with an '@' character,
|
||||
* and the InetAddress pattern is separated from the URI pattern using the "|" (pipe)
|
||||
* character. URI patterns follow the servlet specification for simple * prefix and
|
||||
* suffix wild cards (e.g. /, /foo, /foo/bar, /foo/bar/*, *.baz).</p>
|
||||
*
|
||||
* <br>Examples:
|
||||
* <ul>
|
||||
* <li>"connector1@127.0.0.1|/foo"</li>
|
||||
* <li>"127.0.0.1|/foo"</li>
|
||||
* <li>"connector1@127.0.0.1"</li>
|
||||
* <li>"127.0.0.1"</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param pattern InetAddress pattern to exclude
|
||||
* @see InetAddressSet
|
||||
*/
|
||||
public void exclude(String pattern)
|
||||
{
|
||||
_addrs.exclude(pattern);
|
||||
_set.exclude(PatternTuple.from(pattern));
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes InetAddress patterns
|
||||
* Excludes InetAccess patterns
|
||||
*
|
||||
* @param patterns InetAddress patterns to exclude
|
||||
* @see InetAddressSet
|
||||
*/
|
||||
public void exclude(String... patterns)
|
||||
{
|
||||
_addrs.exclude(patterns);
|
||||
for (String pattern : patterns)
|
||||
exclude(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes an InetAccess entry.
|
||||
* @param connectorName optional name of a connector to exclude.
|
||||
* @param addressPattern optional InetAddress pattern to exclude.
|
||||
* @param pathSpec optional pathSpec to exclude.
|
||||
*/
|
||||
public void exclude(String connectorName, String addressPattern, PathSpec pathSpec)
|
||||
{
|
||||
_set.exclude(new PatternTuple(connectorName, InetAddressPattern.from(addressPattern), pathSpec));
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes a connector name.
|
||||
*
|
||||
* @param name Connector name to include in this handler.
|
||||
* @deprecated use {@link InetAccessHandler#include(String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void includeConnector(String name)
|
||||
{
|
||||
_names.include(name);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes a connector name.
|
||||
*
|
||||
* @param name Connector name to exclude in this handler.
|
||||
* @deprecated use {@link InetAccessHandler#include(String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void excludeConnector(String name)
|
||||
{
|
||||
_names.exclude(name);
|
||||
_set.exclude(new PatternTuple(name, null, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes connector names.
|
||||
*
|
||||
* @param names Connector names to include in this handler.
|
||||
* @deprecated use {@link InetAccessHandler#include(String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void includeConnectors(String... names)
|
||||
{
|
||||
_names.include(names);
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Excludes connector names.
|
||||
*
|
||||
* @param names Connector names to exclude in this handler.
|
||||
* @deprecated use {@link InetAccessHandler#include(String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public void excludeConnectors(String... names)
|
||||
{
|
||||
_names.exclude(names);
|
||||
for (String name : names)
|
||||
excludeConnector(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -187,26 +244,15 @@ public class InetAccessHandler extends HandlerWrapper
|
|||
*/
|
||||
protected boolean isAllowed(InetAddress addr, Request baseRequest, HttpServletRequest request)
|
||||
{
|
||||
String name = baseRequest.getHttpChannel().getConnector().getName();
|
||||
boolean filterAppliesToConnector = _names.test(name);
|
||||
boolean allowedByAddr = _addrs.test(addr);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("name = {}/{} addr={}/{} appliesToConnector={} allowedByAddr={}",
|
||||
name, _names, addr, _addrs, filterAppliesToConnector, allowedByAddr);
|
||||
}
|
||||
if (!filterAppliesToConnector)
|
||||
return true;
|
||||
return allowedByAddr;
|
||||
String connectorName = baseRequest.getHttpChannel().getConnector().getName();
|
||||
return _set.test(new AccessTuple(connectorName, addr, baseRequest.getPathInfo()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dump(Appendable out, String indent) throws IOException
|
||||
{
|
||||
dumpObjects(out, indent,
|
||||
new DumpableCollection("included", _addrs.getIncluded()),
|
||||
new DumpableCollection("excluded", _addrs.getExcluded()),
|
||||
new DumpableCollection("includedConnector", _names.getIncluded()),
|
||||
new DumpableCollection("excludedConnector", _names.getExcluded()));
|
||||
new DumpableCollection("included", _set.getIncluded()),
|
||||
new DumpableCollection("excluded", _set.getExcluded()));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.server.handler;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.http.pathmap.ServletPathSpec;
|
||||
import org.eclipse.jetty.util.InetAddressPattern;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
||||
public class InetAccessSet extends AbstractSet<InetAccessSet.PatternTuple> implements Set<InetAccessSet.PatternTuple>, Predicate<InetAccessSet.AccessTuple>
|
||||
{
|
||||
private ArrayList<PatternTuple> tuples = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public boolean add(PatternTuple storageTuple)
|
||||
{
|
||||
return tuples.add(storageTuple);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
return tuples.remove(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<PatternTuple> iterator()
|
||||
{
|
||||
return tuples.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return tuples.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(AccessTuple entry)
|
||||
{
|
||||
if (entry == null)
|
||||
return false;
|
||||
|
||||
for (PatternTuple tuple : tuples)
|
||||
{
|
||||
if (tuple.test(entry))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static class PatternTuple implements Predicate<AccessTuple>
|
||||
{
|
||||
private final String connector;
|
||||
private final InetAddressPattern address;
|
||||
private final PathSpec pathSpec;
|
||||
|
||||
public static PatternTuple from(String pattern)
|
||||
{
|
||||
|
||||
String path = null;
|
||||
int pathIndex = pattern.indexOf('|');
|
||||
if (pathIndex >= 0)
|
||||
path = pattern.substring(pathIndex + 1);
|
||||
|
||||
String connector = null;
|
||||
int connectorIndex = pattern.indexOf('@');
|
||||
if (connectorIndex >= 0)
|
||||
connector = pattern.substring(0, connectorIndex);
|
||||
|
||||
String addr = null;
|
||||
int addrStart = (connectorIndex < 0) ? 0 : connectorIndex + 1;
|
||||
int addrEnd = (pathIndex < 0) ? pattern.length() : pathIndex;
|
||||
if (addrStart != addrEnd)
|
||||
addr = pattern.substring(addrStart, addrEnd);
|
||||
|
||||
return new PatternTuple(connector, InetAddressPattern.from(addr),
|
||||
StringUtil.isEmpty(path) ? null : new ServletPathSpec(path));
|
||||
}
|
||||
|
||||
public PatternTuple(String connector, InetAddressPattern address, PathSpec pathSpec)
|
||||
{
|
||||
this.connector = connector;
|
||||
this.address = address;
|
||||
this.pathSpec = pathSpec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(AccessTuple entry)
|
||||
{
|
||||
// Match for connector.
|
||||
if ((connector != null) && !connector.equals(entry.getConnector()))
|
||||
return false;
|
||||
|
||||
// If we have a path we must must be at this path to match for an address.
|
||||
if ((pathSpec != null) && !pathSpec.matches(entry.getPath()))
|
||||
return false;
|
||||
|
||||
// Match for InetAddress.
|
||||
if ((address != null) && !address.test(entry.getAddress()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class AccessTuple
|
||||
{
|
||||
private final String connector;
|
||||
private final InetAddress address;
|
||||
private final String path;
|
||||
|
||||
public AccessTuple(String connector, InetAddress address, String path)
|
||||
{
|
||||
this.connector = connector;
|
||||
this.address = address;
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getConnector()
|
||||
{
|
||||
return connector;
|
||||
}
|
||||
|
||||
public InetAddress getAddress()
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -36,6 +35,7 @@ import org.eclipse.jetty.server.Connector;
|
|||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
|
@ -67,7 +67,6 @@ public class InetAccessHandlerTest
|
|||
{
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
response.setStatus(HttpStatus.OK_200);
|
||||
|
@ -85,7 +84,7 @@ public class InetAccessHandlerTest
|
|||
|
||||
@ParameterizedTest
|
||||
@MethodSource("data")
|
||||
public void testHandler(String include, String exclude, String includeConnectors, String excludeConnectors, String code)
|
||||
public void testHandler(String path, String include, String exclude, String includeConnectors, String excludeConnectors, String code)
|
||||
throws Exception
|
||||
{
|
||||
_handler.clear();
|
||||
|
@ -107,14 +106,14 @@ public class InetAccessHandlerTest
|
|||
{
|
||||
if (inc.length() > 0)
|
||||
{
|
||||
_handler.includeConnector(inc);
|
||||
_handler.include(inc + "@");
|
||||
}
|
||||
}
|
||||
for (String exc : excludeConnectors.split(";", -1))
|
||||
{
|
||||
if (exc.length() > 0)
|
||||
{
|
||||
_handler.excludeConnector(exc);
|
||||
_handler.exclude(exc + "@");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,11 +126,11 @@ public class InetAccessHandlerTest
|
|||
}
|
||||
}
|
||||
|
||||
testConnector(_connector1.getLocalPort(), include, exclude, includeConnectors, excludeConnectors, codePerConnector.get(0));
|
||||
testConnector(_connector2.getLocalPort(), include, exclude, includeConnectors, excludeConnectors, codePerConnector.get(1));
|
||||
testConnector(_connector1.getLocalPort(), path, include, exclude, includeConnectors, excludeConnectors, codePerConnector.get(0));
|
||||
testConnector(_connector2.getLocalPort(), path, include, exclude, includeConnectors, excludeConnectors, codePerConnector.get(1));
|
||||
}
|
||||
|
||||
private void testConnector(int port, String include, String exclude, String includeConnectors, String excludeConnectors, String code) throws IOException
|
||||
private void testConnector(int port, String path, String include, String exclude, String includeConnectors, String excludeConnectors, String code) throws IOException
|
||||
{
|
||||
try (Socket socket = new Socket("127.0.0.1", port);)
|
||||
{
|
||||
|
@ -139,7 +138,7 @@ public class InetAccessHandlerTest
|
|||
|
||||
HttpTester.Request request = HttpTester.newRequest();
|
||||
request.setMethod("GET");
|
||||
request.setURI("/path");
|
||||
request.setURI(StringUtil.isEmpty(path) ? "/" : path);
|
||||
request.setHeader("Host", "127.0.0.1");
|
||||
request.setVersion(HttpVersion.HTTP_1_0);
|
||||
|
||||
|
@ -164,62 +163,83 @@ public class InetAccessHandlerTest
|
|||
public static Stream<Arguments> data()
|
||||
{
|
||||
Object[][] data = new Object[][]
|
||||
{
|
||||
// Empty lists 1
|
||||
{"", "", "", "", "200;200"},
|
||||
{
|
||||
// Empty lists 1
|
||||
{"", "", "", "", "", "200;200"},
|
||||
|
||||
// test simple filters
|
||||
{"127.0.0.1", "", "", "", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "", "", "200;200"},
|
||||
{"192.0.0.1", "", "", "", "403;403"},
|
||||
{"192.0.0.1-192.0.0.254", "", "", "", "403;403"},
|
||||
// test simple filters
|
||||
{"", "127.0.0.1", "", "", "", "200;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "", "", "200;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "", "", "200;200"},
|
||||
{"", "192.0.0.1", "", "", "", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "", "", "403;403"},
|
||||
|
||||
// test includeConnector
|
||||
{"127.0.0.1", "", "http_connector1", "", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "http_connector1", "", "200;200"},
|
||||
{"192.0.0.1", "", "http_connector1", "", "403;200"},
|
||||
{"192.0.0.1-192.0.0.254", "", "http_connector1", "", "403;200"},
|
||||
{"192.0.0.1", "", "http_connector2", "", "200;403"},
|
||||
{"192.0.0.1-192.0.0.254", "", "http_connector2", "", "200;403"},
|
||||
// test includeConnector
|
||||
{"", "127.0.0.1", "", "http_connector1", "", "200;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "http_connector1", "", "200;200"},
|
||||
{"", "192.0.0.1", "", "http_connector1", "", "200;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "http_connector1", "", "200;403"},
|
||||
{"", "192.0.0.1", "", "http_connector2", "", "403;200"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "http_connector2", "", "403;200"},
|
||||
|
||||
// test includeConnector names where none of them match
|
||||
{"127.0.0.1", "", "nothttp", "", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "nothttp", "", "200;200"},
|
||||
{"192.0.0.1", "", "nothttp", "", "200;200"},
|
||||
{"192.0.0.1-192.0.0.254", "", "nothttp", "", "200;200"},
|
||||
// test includeConnector names where none of them match
|
||||
{"", "127.0.0.1", "", "nothttp", "", "200;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "nothttp", "", "200;200"},
|
||||
{"", "192.0.0.1", "", "nothttp", "", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "nothttp", "", "403;403"},
|
||||
|
||||
// text excludeConnector
|
||||
{"127.0.0.1", "", "", "http_connector1", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "", "http_connector1", "200;200"},
|
||||
{"192.0.0.1", "", "", "http_connector1", "200;403"},
|
||||
{"192.0.0.1-192.0.0.254", "", "", "http_connector1", "200;403"},
|
||||
{"192.0.0.1", "", "", "http_connector2", "403;200"},
|
||||
{"192.0.0.1-192.0.0.254", "", "", "http_connector2", "403;200"},
|
||||
// text excludeConnector
|
||||
{"", "127.0.0.1", "", "", "http_connector1", "403;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "", "http_connector1", "403;200"},
|
||||
{"", "192.0.0.1", "", "", "http_connector1", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "", "http_connector1", "403;403"},
|
||||
{"", "192.0.0.1", "", "", "http_connector2", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "", "http_connector2", "403;403"},
|
||||
|
||||
// test excludeConnector where none of them match.
|
||||
{"127.0.0.1", "", "", "nothttp", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "", "nothttp", "200;200"},
|
||||
{"192.0.0.1", "", "", "nothttp", "403;403"},
|
||||
{"192.0.0.1-192.0.0.254", "", "", "nothttp", "403;403"},
|
||||
// test excludeConnector where none of them match.
|
||||
{"", "127.0.0.1", "", "", "nothttp", "200;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "", "nothttp", "200;200"},
|
||||
{"", "192.0.0.1", "", "", "nothttp", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "", "nothttp", "403;403"},
|
||||
|
||||
// both connectors are excluded
|
||||
{"127.0.0.1", "", "", "http_connector1;http_connector2", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "", "http_connector1;http_connector2", "200;200"},
|
||||
{"192.0.0.1", "", "", "http_connector1;http_connector2", "200;200"},
|
||||
{"192.0.0.1-192.0.0.254", "", "", "http_connector1;http_connector2", "200;200"},
|
||||
// both connectors are excluded
|
||||
{"", "127.0.0.1", "", "", "http_connector1;http_connector2", "403;403"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "", "http_connector1;http_connector2", "403;403"},
|
||||
{"", "192.0.0.1", "", "", "http_connector1;http_connector2", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "", "http_connector1;http_connector2", "403;403"},
|
||||
|
||||
// both connectors are included
|
||||
{"127.0.0.1", "", "http_connector1;http_connector2", "", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "http_connector1;http_connector2", "", "200;200"},
|
||||
{"192.0.0.1", "", "http_connector1;http_connector2", "", "403;403"},
|
||||
{"192.0.0.1-192.0.0.254", "", "http_connector1;http_connector2", "", "403;403"},
|
||||
// both connectors are included
|
||||
{"", "127.0.0.1", "", "http_connector1;http_connector2", "", "200;200"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "http_connector1;http_connector2", "", "200;200"},
|
||||
{"", "192.0.0.1", "", "http_connector1;http_connector2", "", "200;200"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "http_connector1;http_connector2", "", "200;200"},
|
||||
{"", "", "127.0.0.1", "http_connector1;http_connector2", "", "403;403"},
|
||||
|
||||
// exclude takes precedence over include
|
||||
{"127.0.0.1", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "200;200"},
|
||||
{"127.0.0.1-127.0.0.254", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "200;200"},
|
||||
{"192.0.0.1", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "200;200"},
|
||||
{"192.0.0.1-192.0.0.254", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "200;200"}
|
||||
};
|
||||
return Arrays.asList(data).stream().map(Arguments::of);
|
||||
// exclude takes precedence over include
|
||||
{"", "127.0.0.1", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "403;403"},
|
||||
{"", "127.0.0.1-127.0.0.254", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "403;403"},
|
||||
{"", "192.0.0.1", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "403;403"},
|
||||
{"", "192.0.0.1-192.0.0.254", "", "http_connector1;http_connector2", "http_connector1;http_connector2", "403;403"},
|
||||
|
||||
// Test path specific include/exclude.
|
||||
{"/testPath", "", "", "http_connector1", "", "200;403"},
|
||||
{"/", "127.0.0.1", "127.0.0.1|/testPath", "http_connector1", "", "200;200"},
|
||||
{"/testPath", "127.0.0.1", "127.0.0.1|/testPath", "http_connector1", "", "403;403"},
|
||||
{"/notTestPath", "127.0.1.11|/testPath", "", "http_connector1", "", "200;403"},
|
||||
{"/testPath", "127.0.1.11|/testPath", "", "http_connector1", "", "200;403"},
|
||||
{"/testPath", "127.0.0.13|/testPath;127.0.0.1|/testPath", "", "http_connector1", "", "200;200"},
|
||||
{"/testPath", "127.0.0.1", "127.0.0.1|/testPath", "http_connector1", "", "403;403"},
|
||||
{"/", "127.0.0.1", "127.0.0.1|/testPath", "http_connector1", "", "200;200"},
|
||||
{"/a/b", "", "127.0.0.1|/a/*", "", "", "403;403"},
|
||||
{"/b/a", "", "127.0.0.1|/a/*", "", "", "200;200"},
|
||||
{"/org/eclipse/jetty/test.html", "127.0.0.1|*.html", "127.0.0.1|*.xml", "", "", "200;200"},
|
||||
{"/org/eclipse/jetty/test.xml", "127.0.0.1|*.html", "127.0.0.1|*.xml", "", "", "403;403"},
|
||||
{"/org/eclipse/jetty/test.pdf", "127.0.0.1|*.html", "127.0.0.1|*.xml", "", "", "403;403"},
|
||||
{"/a/test.html", "", "127.0.0.1|*.html;127.0.0.10|/a/*", "", "", "403;403"},
|
||||
{"/foo/bar/test.xml", "127.0.0.1|/foo/*", "127.0.0.0-127.0.0.2|*.html", "", "", "200;200"},
|
||||
{"/foo/bar/test.html", "127.0.0.1|/foo/*", "127.0.0.0-127.0.0.2|*.html", "", "", "403;403"},
|
||||
{"/foo/bar/test.xml", "127.0.0.1|/foo/bar/*", "127.0.0.1|/foo/*", "", "", "403;403"},
|
||||
};
|
||||
return Arrays.stream(data).map(Arguments::of);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
@ -145,10 +146,7 @@ public class IncludeExcludeSet<T, P> implements Predicate<P>
|
|||
|
||||
public void include(T... element)
|
||||
{
|
||||
for (T e : element)
|
||||
{
|
||||
_includes.add(e);
|
||||
}
|
||||
_includes.addAll(Arrays.asList(element));
|
||||
}
|
||||
|
||||
public void exclude(T element)
|
||||
|
@ -158,10 +156,7 @@ public class IncludeExcludeSet<T, P> implements Predicate<P>
|
|||
|
||||
public void exclude(T... element)
|
||||
{
|
||||
for (T e : element)
|
||||
{
|
||||
_excludes.add(e);
|
||||
}
|
||||
_excludes.addAll(Arrays.asList(element));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -233,34 +228,4 @@ public class IncludeExcludeSet<T, P> implements Predicate<P>
|
|||
{
|
||||
return _includes.isEmpty() && _excludes.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Match items in combined IncludeExcludeSets.
|
||||
* @param item1 The item to match against set1
|
||||
* @param set1 A IncludeExcludeSet to match item1 against
|
||||
* @param item2 The item to match against set2
|
||||
* @param set2 A IncludeExcludeSet to match item2 against
|
||||
* @param <T1> The type of item1
|
||||
* @param <T2> The type of item2
|
||||
* @return True IFF <ul>
|
||||
* <li>Neither item is excluded from their respective sets</li>
|
||||
* <li>Both sets have no includes OR at least one of the items is included in its respective set</li>
|
||||
* </ul>
|
||||
*/
|
||||
public static <T1,T2> boolean matchCombined(T1 item1, IncludeExcludeSet<?,T1> set1, T2 item2, IncludeExcludeSet<?,T2> set2)
|
||||
{
|
||||
Boolean match1 = set1.isIncludedAndNotExcluded(item1);
|
||||
Boolean match2 = set2.isIncludedAndNotExcluded(item2);
|
||||
|
||||
// if we are excluded from either set, then we do not match
|
||||
if (match1 == Boolean.FALSE || match2 == Boolean.FALSE)
|
||||
return false;
|
||||
|
||||
// If either set has any includes, then we must be included by one of them
|
||||
if (set1.hasIncludes() || set2.hasIncludes())
|
||||
return match1 == Boolean.TRUE || match2 == Boolean.TRUE;
|
||||
|
||||
// If not excluded and no includes, then we match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,282 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* A pattern representing a single or range of {@link InetAddress}. To create a pattern use
|
||||
* the {@link InetAddressPattern#from(String)} method, which will create a pattern given a
|
||||
* string conforming to one of the following formats.
|
||||
*
|
||||
* <dl>
|
||||
* <dt>InetAddress</dt>
|
||||
* <dd>A single InetAddress either in hostname or address format.
|
||||
* All formats supported by {@link InetAddress} are accepted. Not ethat using hostname
|
||||
* matches may force domain lookups. eg. "[::1]", "1.2.3.4", "::ffff:127.0.0.1"</dd>
|
||||
* <dt>InetAddress/CIDR</dt>
|
||||
* <dd>An InetAddress with a integer number of bits to indicate
|
||||
* the significant prefix. eg. "192.168.0.0/16" will match from "192.168.0.0" to
|
||||
* "192.168.255.255" </dd>
|
||||
* <dt>InetAddress-InetAddress</dt>
|
||||
* <dd>An inclusive range of InetAddresses.
|
||||
* eg. "[a000::1]-[afff::]", "192.168.128.0-192.168.128.255"</dd>
|
||||
* <dt>Legacy format</dt>
|
||||
* <dd>The legacy format used for IPv4 only.
|
||||
* eg. "10.10.10-14.0-128"</dd>
|
||||
* </dl>
|
||||
*/
|
||||
public abstract class InetAddressPattern implements Predicate<InetAddress>
|
||||
{
|
||||
protected final String _pattern;
|
||||
|
||||
public static InetAddressPattern from(String pattern)
|
||||
{
|
||||
if (pattern == null)
|
||||
return null;
|
||||
|
||||
int slash = pattern.lastIndexOf('/');
|
||||
int dash = pattern.lastIndexOf('-');
|
||||
try
|
||||
{
|
||||
if (slash >= 0)
|
||||
return new CidrInetAddressRange(pattern, InetAddress.getByName(pattern.substring(0, slash).trim()), StringUtil.toInt(pattern, slash + 1));
|
||||
|
||||
if (dash >= 0)
|
||||
return new MinMaxInetAddressRange(pattern, InetAddress.getByName(pattern.substring(0, dash).trim()), InetAddress.getByName(pattern.substring(dash + 1).trim()));
|
||||
|
||||
return new SingletonInetAddressRange(pattern, InetAddress.getByName(pattern));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (slash < 0 && dash > 0)
|
||||
return new LegacyInetAddressRange(pattern);
|
||||
}
|
||||
catch (Exception ex2)
|
||||
{
|
||||
e.addSuppressed(ex2);
|
||||
}
|
||||
throw new IllegalArgumentException("Bad pattern: " + pattern, e);
|
||||
}
|
||||
}
|
||||
|
||||
public InetAddressPattern(String pattern)
|
||||
{
|
||||
_pattern = pattern;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
|
||||
static class SingletonInetAddressRange extends InetAddressPattern
|
||||
{
|
||||
final InetAddress _address;
|
||||
|
||||
public SingletonInetAddressRange(String pattern, InetAddress address)
|
||||
{
|
||||
super(pattern);
|
||||
_address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress address)
|
||||
{
|
||||
return _address.equals(address);
|
||||
}
|
||||
}
|
||||
|
||||
static class MinMaxInetAddressRange extends InetAddressPattern
|
||||
{
|
||||
final int[] _min;
|
||||
final int[] _max;
|
||||
|
||||
public MinMaxInetAddressRange(String pattern, InetAddress min, InetAddress max)
|
||||
{
|
||||
super(pattern);
|
||||
|
||||
byte[] rawMin = min.getAddress();
|
||||
byte[] rawMax = max.getAddress();
|
||||
if (rawMin.length != rawMax.length)
|
||||
throw new IllegalArgumentException("Cannot mix IPv4 and IPv6: " + pattern);
|
||||
|
||||
if (rawMin.length == 4)
|
||||
{
|
||||
// there must be 6 '.' or this is likely to be a legacy pattern
|
||||
int count = 0;
|
||||
for (char c : pattern.toCharArray())
|
||||
{
|
||||
if (c == '.')
|
||||
count++;
|
||||
}
|
||||
if (count != 6)
|
||||
throw new IllegalArgumentException("Legacy pattern: " + pattern);
|
||||
}
|
||||
|
||||
_min = new int[rawMin.length];
|
||||
_max = new int[rawMin.length];
|
||||
|
||||
for (int i = 0; i < _min.length; i++)
|
||||
{
|
||||
_min[i] = 0xff & rawMin[i];
|
||||
_max[i] = 0xff & rawMax[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < _min.length; i++)
|
||||
{
|
||||
if (_min[i] > _max[i])
|
||||
throw new IllegalArgumentException("min is greater than max: " + pattern);
|
||||
if (_min[i] < _max[i])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress address)
|
||||
{
|
||||
byte[] raw = address.getAddress();
|
||||
if (raw.length != _min.length)
|
||||
return false;
|
||||
|
||||
boolean minOk = false;
|
||||
boolean maxOk = false;
|
||||
|
||||
for (int i = 0; i < _min.length; i++)
|
||||
{
|
||||
int r = 0xff & raw[i];
|
||||
if (!minOk)
|
||||
{
|
||||
if (r < _min[i])
|
||||
return false;
|
||||
if (r > _min[i])
|
||||
minOk = true;
|
||||
}
|
||||
if (!maxOk)
|
||||
{
|
||||
if (r > _max[i])
|
||||
return false;
|
||||
if (r < _max[i])
|
||||
maxOk = true;
|
||||
}
|
||||
|
||||
if (minOk && maxOk)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class CidrInetAddressRange extends InetAddressPattern
|
||||
{
|
||||
final byte[] _raw;
|
||||
final int _octets;
|
||||
final int _mask;
|
||||
final int _masked;
|
||||
|
||||
public CidrInetAddressRange(String pattern, InetAddress address, int cidr)
|
||||
{
|
||||
super(pattern);
|
||||
_raw = address.getAddress();
|
||||
_octets = cidr / 8;
|
||||
_mask = 0xff & (0xff << (8 - cidr % 8));
|
||||
_masked = _mask == 0 ? 0 : _raw[_octets] & _mask;
|
||||
|
||||
if (cidr > (_raw.length * 8))
|
||||
throw new IllegalArgumentException("CIDR too large: " + pattern);
|
||||
|
||||
if (_mask != 0 && (0xff & _raw[_octets]) != _masked)
|
||||
throw new IllegalArgumentException("CIDR bits non zero: " + pattern);
|
||||
|
||||
for (int o = _octets + (_mask == 0 ? 0 : 1); o < _raw.length; o++)
|
||||
{
|
||||
if (_raw[o] != 0)
|
||||
throw new IllegalArgumentException("CIDR bits non zero: " + pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress address)
|
||||
{
|
||||
byte[] raw = address.getAddress();
|
||||
if (raw.length != _raw.length)
|
||||
return false;
|
||||
|
||||
for (int o = 0; o < _octets; o++)
|
||||
{
|
||||
if (_raw[o] != raw[o])
|
||||
return false;
|
||||
}
|
||||
|
||||
return _mask == 0 || (raw[_octets] & _mask) == _masked;
|
||||
}
|
||||
}
|
||||
|
||||
static class LegacyInetAddressRange extends InetAddressPattern
|
||||
{
|
||||
int[] _min = new int[4];
|
||||
int[] _max = new int[4];
|
||||
|
||||
public LegacyInetAddressRange(String pattern)
|
||||
{
|
||||
super(pattern);
|
||||
|
||||
String[] parts = pattern.split("\\.");
|
||||
if (parts.length != 4)
|
||||
throw new IllegalArgumentException("Bad legacy pattern: " + pattern);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
String part = parts[i].trim();
|
||||
int dash = part.indexOf('-');
|
||||
if (dash < 0)
|
||||
_min[i] = _max[i] = Integer.parseInt(part);
|
||||
else
|
||||
{
|
||||
_min[i] = (dash == 0) ? 0 : StringUtil.toInt(part, 0);
|
||||
_max[i] = (dash == part.length() - 1) ? 255 : StringUtil.toInt(part, dash + 1);
|
||||
}
|
||||
|
||||
if (_min[i] < 0 || _min[i] > _max[i] || _max[i] > 255)
|
||||
throw new IllegalArgumentException("Bad legacy pattern: " + pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress address)
|
||||
{
|
||||
byte[] raw = address.getAddress();
|
||||
if (raw.length != 4)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if ((0xff & raw[i]) < _min[i] || (0xff & raw[i]) > _max[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,62 +30,20 @@ import java.util.function.Predicate;
|
|||
* A set of InetAddress patterns.
|
||||
* <p>This is a {@link Set} of String patterns that are used to match
|
||||
* a {@link Predicate} over InetAddress for containment semantics.
|
||||
* The patterns that may be set are:
|
||||
* The patterns that may be set are defined in {@link InetAddressPattern}.
|
||||
* </p>
|
||||
* <dl>
|
||||
* <dt>InetAddress</dt><dd>A single InetAddress either in hostname or address format.
|
||||
* All formats supported by {@link InetAddress} are accepted. Not ethat using hostname
|
||||
* matches may force domain lookups. eg. "[::1]", "1.2.3.4", "::ffff:127.0.0.1"</dd>
|
||||
* <dt>InetAddress/CIDR</dt><dd>An InetAddress with a integer number of bits to indicate
|
||||
* the significant prefix. eg. "192.168.0.0/16" will match from "192.168.0.0" to
|
||||
* "192.168.255.255" </dd>
|
||||
* <dt>InetAddress-InetAddress</dt><dd>An inclusive range of InetAddresses.
|
||||
* eg. "[a000::1]-[afff::]", "192.168.128.0-192.168.128.255"</dd>
|
||||
* </dl>
|
||||
* <p>This class is designed to work with {@link IncludeExcludeSet}</p>
|
||||
*
|
||||
* @see IncludeExcludeSet
|
||||
*/
|
||||
public class InetAddressSet extends AbstractSet<String> implements Set<String>, Predicate<InetAddress>
|
||||
{
|
||||
private Map<String, InetPattern> _patterns = new HashMap<>();
|
||||
private Map<String, InetAddressPattern> _patterns = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean add(String pattern)
|
||||
{
|
||||
return _patterns.put(pattern, newInetRange(pattern)) == null;
|
||||
}
|
||||
|
||||
private InetPattern newInetRange(String pattern)
|
||||
{
|
||||
if (pattern == null)
|
||||
return null;
|
||||
|
||||
int slash = pattern.lastIndexOf('/');
|
||||
int dash = pattern.lastIndexOf('-');
|
||||
try
|
||||
{
|
||||
if (slash >= 0)
|
||||
return new CidrInetRange(pattern, InetAddress.getByName(pattern.substring(0, slash).trim()), StringUtil.toInt(pattern, slash + 1));
|
||||
|
||||
if (dash >= 0)
|
||||
return new MinMaxInetRange(pattern, InetAddress.getByName(pattern.substring(0, dash).trim()), InetAddress.getByName(pattern.substring(dash + 1).trim()));
|
||||
|
||||
return new SingletonInetRange(pattern, InetAddress.getByName(pattern));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (slash < 0 && dash > 0)
|
||||
return new LegacyInetRange(pattern);
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
e.addSuppressed(e2);
|
||||
}
|
||||
throw new IllegalArgumentException("Bad pattern: " + pattern, e);
|
||||
}
|
||||
return _patterns.put(pattern, InetAddressPattern.from(pattern)) == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,219 +69,11 @@ public class InetAddressSet extends AbstractSet<String> implements Set<String>,
|
|||
{
|
||||
if (address == null)
|
||||
return false;
|
||||
byte[] raw = address.getAddress();
|
||||
for (InetPattern pattern : _patterns.values())
|
||||
for (InetAddressPattern pattern : _patterns.values())
|
||||
{
|
||||
if (pattern.test(address, raw))
|
||||
if (pattern.test(address))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
abstract static class InetPattern
|
||||
{
|
||||
final String _pattern;
|
||||
|
||||
InetPattern(String pattern)
|
||||
{
|
||||
_pattern = pattern;
|
||||
}
|
||||
|
||||
abstract boolean test(InetAddress address, byte[] raw);
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return _pattern;
|
||||
}
|
||||
}
|
||||
|
||||
static class SingletonInetRange extends InetPattern
|
||||
{
|
||||
final InetAddress _address;
|
||||
|
||||
public SingletonInetRange(String pattern, InetAddress address)
|
||||
{
|
||||
super(pattern);
|
||||
_address = address;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress address, byte[] raw)
|
||||
{
|
||||
return _address.equals(address);
|
||||
}
|
||||
}
|
||||
|
||||
static class MinMaxInetRange extends InetPattern
|
||||
{
|
||||
final int[] _min;
|
||||
final int[] _max;
|
||||
|
||||
public MinMaxInetRange(String pattern, InetAddress min, InetAddress max)
|
||||
{
|
||||
super(pattern);
|
||||
|
||||
byte[] rawMin = min.getAddress();
|
||||
byte[] rawMax = max.getAddress();
|
||||
if (rawMin.length != rawMax.length)
|
||||
throw new IllegalArgumentException("Cannot mix IPv4 and IPv6: " + pattern);
|
||||
|
||||
if (rawMin.length == 4)
|
||||
{
|
||||
// there must be 6 '.' or this is likely to be a legacy pattern
|
||||
int count = 0;
|
||||
for (char c : pattern.toCharArray())
|
||||
{
|
||||
if (c == '.')
|
||||
count++;
|
||||
}
|
||||
if (count != 6)
|
||||
throw new IllegalArgumentException("Legacy pattern: " + pattern);
|
||||
}
|
||||
|
||||
_min = new int[rawMin.length];
|
||||
_max = new int[rawMin.length];
|
||||
|
||||
for (int i = 0; i < _min.length; i++)
|
||||
{
|
||||
_min[i] = 0xff & rawMin[i];
|
||||
_max[i] = 0xff & rawMax[i];
|
||||
}
|
||||
|
||||
for (int i = 0; i < _min.length; i++)
|
||||
{
|
||||
if (_min[i] > _max[i])
|
||||
throw new IllegalArgumentException("min is greater than max: " + pattern);
|
||||
if (_min[i] < _max[i])
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress item, byte[] raw)
|
||||
{
|
||||
if (raw.length != _min.length)
|
||||
return false;
|
||||
|
||||
boolean minOk = false;
|
||||
boolean maxOk = false;
|
||||
|
||||
for (int i = 0; i < _min.length; i++)
|
||||
{
|
||||
int r = 0xff & raw[i];
|
||||
if (!minOk)
|
||||
{
|
||||
if (r < _min[i])
|
||||
return false;
|
||||
if (r > _min[i])
|
||||
minOk = true;
|
||||
}
|
||||
if (!maxOk)
|
||||
{
|
||||
if (r > _max[i])
|
||||
return false;
|
||||
if (r < _max[i])
|
||||
maxOk = true;
|
||||
}
|
||||
|
||||
if (minOk && maxOk)
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class CidrInetRange extends InetPattern
|
||||
{
|
||||
final byte[] _raw;
|
||||
final int _octets;
|
||||
final int _mask;
|
||||
final int _masked;
|
||||
|
||||
public CidrInetRange(String pattern, InetAddress address, int cidr)
|
||||
{
|
||||
super(pattern);
|
||||
_raw = address.getAddress();
|
||||
_octets = cidr / 8;
|
||||
_mask = 0xff & (0xff << (8 - cidr % 8));
|
||||
_masked = _mask == 0 ? 0 : _raw[_octets] & _mask;
|
||||
|
||||
if (cidr > (_raw.length * 8))
|
||||
throw new IllegalArgumentException("CIDR too large: " + pattern);
|
||||
|
||||
if (_mask != 0 && (0xff & _raw[_octets]) != _masked)
|
||||
throw new IllegalArgumentException("CIDR bits non zero: " + pattern);
|
||||
|
||||
for (int o = _octets + (_mask == 0 ? 0 : 1); o < _raw.length; o++)
|
||||
{
|
||||
if (_raw[o] != 0)
|
||||
throw new IllegalArgumentException("CIDR bits non zero: " + pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress item, byte[] raw)
|
||||
{
|
||||
if (raw.length != _raw.length)
|
||||
return false;
|
||||
|
||||
for (int o = 0; o < _octets; o++)
|
||||
{
|
||||
if (_raw[o] != raw[o])
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_mask != 0 && (raw[_octets] & _mask) != _masked)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static class LegacyInetRange extends InetPattern
|
||||
{
|
||||
int[] _min = new int[4];
|
||||
int[] _max = new int[4];
|
||||
|
||||
public LegacyInetRange(String pattern)
|
||||
{
|
||||
super(pattern);
|
||||
|
||||
String[] parts = pattern.split("\\.");
|
||||
if (parts.length != 4)
|
||||
throw new IllegalArgumentException("Bad legacy pattern: " + pattern);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
String part = parts[i].trim();
|
||||
int dash = part.indexOf('-');
|
||||
if (dash < 0)
|
||||
_min[i] = _max[i] = Integer.parseInt(part);
|
||||
else
|
||||
{
|
||||
_min[i] = (dash == 0) ? 0 : StringUtil.toInt(part, 0);
|
||||
_max[i] = (dash == part.length() - 1) ? 255 : StringUtil.toInt(part, dash + 1);
|
||||
}
|
||||
|
||||
if (_min[i] < 0 || _min[i] > _max[i] || _max[i] > 255)
|
||||
throw new IllegalArgumentException("Bad legacy pattern: " + pattern);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(InetAddress item, byte[] raw)
|
||||
{
|
||||
if (raw.length != 4)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if ((0xff & raw[i]) < _min[i] || (0xff & raw[i]) > _max[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue