Merge remote-tracking branch 'origin/jetty-9.3.x' into jetty-9.4.x

This commit is contained in:
Greg Wilkins 2016-09-01 16:44:03 +10:00
commit 718c8e2444
7 changed files with 1060 additions and 140 deletions

View File

@ -100,6 +100,8 @@ import org.eclipse.jetty.util.log.Logger;
* to define a range of the internet addresses (e.g. 127., 10.10., 172.16.1.).
* They also used the first "/" character of the URI pattern to separate it from the
* internet address. Both of these features have been deprecated in the current version.
* @deprecated
* @see InetAccessHandler
*/
public class IPAccessHandler extends HandlerWrapper
{

View File

@ -0,0 +1,156 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server.handler;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.IncludeExcludeSet;
import org.eclipse.jetty.util.InetAddressSet;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Inet Address Access Handler
* <p>
* Controls access to the wrapped handler by the real remote IP. Control is 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>
*/
public class InetAccessHandler extends HandlerWrapper
{
private static final Logger LOG = Log.getLogger(InetAccessHandler.class);
IncludeExcludeSet<String, InetAddress> _set = new IncludeExcludeSet<>(InetAddressSet.class);
/* ------------------------------------------------------------ */
/**
* Creates new handler object
*/
public InetAccessHandler()
{
super();
}
/* ------------------------------------------------------------ */
/**
* Include a InetAddress pattern
* @see InetAddressSet
* @param pattern InetAddress pattern to exclude
*/
public void include(String pattern)
{
_set.include(pattern);
}
/* ------------------------------------------------------------ */
/**
* Include a InetAddress pattern
* @see InetAddressSet
* @param patterns InetAddress patterns to exclude
*/
public void include(String... patterns)
{
_set.include(patterns);
}
/* ------------------------------------------------------------ */
/**
* Exclude a InetAddress pattern
* @see InetAddressSet
* @param pattern InetAddress pattern to exclude
*/
public void exclude(String pattern)
{
_set.exclude(pattern);
}
/* ------------------------------------------------------------ */
/**
* Include a InetAddress pattern
* @see InetAddressSet
* @param patterns InetAddress patterns to exclude
*/
public void exclude(String... patterns)
{
_set.exclude(patterns);
}
/* ------------------------------------------------------------ */
/**
* Checks the incoming request against the whitelist and blacklist
*
* @see org.eclipse.jetty.server.handler.HandlerWrapper#handle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
// Get the real remote IP (not the one set by the forwarded headers (which may be forged))
HttpChannel channel = baseRequest.getHttpChannel();
if (channel!=null)
{
EndPoint endp=channel.getEndPoint();
if (endp!=null)
{
InetSocketAddress address = endp.getRemoteAddress();
if (address!=null && !isAllowed(address.getAddress()))
{
response.sendError(HttpStatus.FORBIDDEN_403);
baseRequest.setHandled(true);
return;
}
}
}
getHandler().handle(target,baseRequest, request, response);
}
/* ------------------------------------------------------------ */
/**
* Check if specified request is allowed by current IPAccess rules.
*
* @param address internet address
* @return true if address is allowed
*
*/
protected boolean isAllowed(InetAddress address)
{
return _set.test(address);
}
/* ------------------------------------------------------------ */
@Override
public void dump(Appendable out, String indent) throws IOException
{
dumpBeans(out,indent,_set.getIncluded(),_set.getExcluded());
}
}

View File

@ -18,162 +18,32 @@
package org.eclipse.jetty.util;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
/** Utility class to maintain a set of inclusions and exclusions.
* <p>Maintains a set of included and excluded elements. The method {@link #matches(Object)}
* will return true IFF the passed object is not in the excluded set AND ( either the
* included set is empty OR the object is in the included set)
* <p>The type of the underlying {@link Set} used may be passed into the
* constructor, so special sets like Servlet PathMap may be used.
* <p>This extension of the {@link IncludeExcludeSet} class is used
* when the type of the set elements is the same as the type of
* the predicate test.
* <p>
* @param <ITEM> The type of element
*/
public class IncludeExclude<ITEM>
public class IncludeExclude<ITEM> extends IncludeExcludeSet<ITEM,ITEM>
{
private final Set<ITEM> _includes;
private final Predicate<ITEM> _includePredicate;
private final Set<ITEM> _excludes;
private final Predicate<ITEM> _excludePredicate;
private static class SetContainsPredicate<ITEM> implements Predicate<ITEM>
{
private final Set<ITEM> set;
public SetContainsPredicate(Set<ITEM> set)
{
this.set = set;
}
@Override
public boolean test(ITEM item)
{
return set.contains(item);
}
}
/**
* Default constructor over {@link HashSet}
*/
@SuppressWarnings("unchecked")
public IncludeExclude()
{
this(HashSet.class);
super();
}
/**
* Construct an IncludeExclude.
* <p>
* If the {@link Set} class also implements {@link Predicate}, then that Predicate is
* used to match against the set, otherwise a simple {@link Set#contains(Object)} test is used.
* @param setClass The type of {@link Set} to using internally
* @param <SET> the {@link Set} type
*/
@SuppressWarnings("unchecked")
public <SET extends Set<ITEM>> IncludeExclude(Class<SET> setClass)
{
try
{
_includes = setClass.newInstance();
_excludes = setClass.newInstance();
if(_includes instanceof Predicate) {
_includePredicate = (Predicate<ITEM>)_includes;
} else {
_includePredicate = new SetContainsPredicate<>(_includes);
}
if(_excludes instanceof Predicate) {
_excludePredicate = (Predicate<ITEM>)_excludes;
} else {
_excludePredicate = new SetContainsPredicate<>(_excludes);
}
}
catch (InstantiationException | IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
/**
* Construct an IncludeExclude
*
* @param includeSet the Set of items that represent the included space
* @param includePredicate the Predicate for included item testing
* @param excludeSet the Set of items that represent the excluded space
* @param excludePredicate the Predicate for excluded item testing
* @param <SET> the {@link Set} type
*/
public <SET extends Set<ITEM>> IncludeExclude(Set<ITEM> includeSet, Predicate<ITEM> includePredicate, Set<ITEM> excludeSet, Predicate<ITEM> excludePredicate)
{
Objects.requireNonNull(includeSet,"Include Set");
Objects.requireNonNull(includePredicate,"Include Predicate");
Objects.requireNonNull(excludeSet,"Exclude Set");
Objects.requireNonNull(excludePredicate,"Exclude Predicate");
_includes = includeSet;
_includePredicate = includePredicate;
_excludes = excludeSet;
_excludePredicate = excludePredicate;
}
public void include(ITEM element)
{
_includes.add(element);
}
public void include(@SuppressWarnings("unchecked") ITEM... element)
{
for (ITEM e: element)
_includes.add(e);
super(setClass);
}
public void exclude(ITEM element)
public <SET extends Set<ITEM>> IncludeExclude(Set<ITEM> includeSet, Predicate<ITEM> includePredicate, Set<ITEM> excludeSet,
Predicate<ITEM> excludePredicate)
{
_excludes.add(element);
}
public void exclude(@SuppressWarnings("unchecked") ITEM... element)
{
for (ITEM e: element)
_excludes.add(e);
}
public boolean matches(ITEM e)
{
if (!_includes.isEmpty() && !_includePredicate.test(e))
return false;
return !_excludePredicate.test(e);
}
public int size()
{
return _includes.size()+_excludes.size();
}
public Set<ITEM> getIncluded()
{
return _includes;
}
public Set<ITEM> getExcluded()
{
return _excludes;
}
public void clear()
{
_includes.clear();
_excludes.clear();
}
@Override
public String toString()
{
return String.format("%s@%x{i=%s,ip=%s,e=%s,ep=%s}",this.getClass().getSimpleName(),hashCode(),_includes,_includePredicate,_excludes,_excludePredicate);
super(includeSet,includePredicate,excludeSet,excludePredicate);
}
}

View File

@ -0,0 +1,184 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
/** Utility class to maintain a set of inclusions and exclusions.
* <p>Maintains a set of included and excluded elements. The method {@link #matches(Object)}
* will return true IFF the passed object is not in the excluded set AND ( either the
* included set is empty OR the object is in the included set)
* <p>The type of the underlying {@link Set} used may be passed into the
* constructor, so special sets like Servlet PathMap may be used.
* <p>
* @param <P> The type of element
*/
public class IncludeExcludeSet<P,T> implements Predicate<T>
{
private final Set<P> _includes;
private final Predicate<T> _includePredicate;
private final Set<P> _excludes;
private final Predicate<T> _excludePredicate;
private static class SetContainsPredicate<T> implements Predicate<T>
{
private final Set<T> set;
public SetContainsPredicate(Set<T> set)
{
this.set = set;
}
@Override
public boolean test(T item)
{
return set.contains(item);
}
}
/**
* Default constructor over {@link HashSet}
*/
public IncludeExcludeSet()
{
this(HashSet.class);
}
/**
* Construct an IncludeExclude.
* <p>
* If the {@link Set} class also implements {@link Predicate}, then that Predicate is
* used to match against the set, otherwise a simple {@link Set#contains(Object)} test is used.
* @param setClass The type of {@link Set} to using internally
* @param predicate A predicate function to test if a passed ITEM is matched by the passed SET}
*/
public <SET extends Set<P>> IncludeExcludeSet(Class<SET> setClass)
{
try
{
_includes = setClass.newInstance();
_excludes = setClass.newInstance();
if(_includes instanceof Predicate)
{
_includePredicate = (Predicate<T>)_includes;
}
else
{
_includePredicate = new SetContainsPredicate(_includes);
}
if(_excludes instanceof Predicate) {
_excludePredicate = (Predicate<T>)_excludes;
} else {
_excludePredicate = new SetContainsPredicate(_excludes);
}
}
catch (InstantiationException | IllegalAccessException e)
{
throw new RuntimeException(e);
}
}
/**
* Construct an IncludeExclude
*
* @param includeSet the Set of items that represent the included space
* @param includePredicate the Predicate for included item testing (null for simple {@link Set#contains(Object)} test)
* @param excludeSet the Set of items that represent the excluded space
* @param excludePredicate the Predicate for excluded item testing (null for simple {@link Set#contains(Object)} test)
*/
public <SET extends Set<P>> IncludeExcludeSet(Set<P> includeSet, Predicate<T> includePredicate, Set<P> excludeSet, Predicate<T> excludePredicate)
{
Objects.requireNonNull(includeSet,"Include Set");
Objects.requireNonNull(includePredicate,"Include Predicate");
Objects.requireNonNull(excludeSet,"Exclude Set");
Objects.requireNonNull(excludePredicate,"Exclude Predicate");
_includes = includeSet;
_includePredicate = includePredicate;
_excludes = excludeSet;
_excludePredicate = excludePredicate;
}
public void include(P element)
{
_includes.add(element);
}
public void include(P... element)
{
for (P e: element)
_includes.add(e);
}
public void exclude(P element)
{
_excludes.add(element);
}
public void exclude(P... element)
{
for (P e: element)
_excludes.add(e);
}
public boolean matches(T t)
{
return test(t);
}
public boolean test(T t)
{
if (!_includes.isEmpty() && !_includePredicate.test(t))
return false;
return !_excludePredicate.test(t);
}
public int size()
{
return _includes.size()+_excludes.size();
}
public Set<P> getIncluded()
{
return _includes;
}
public Set<P> getExcluded()
{
return _excludes;
}
public void clear()
{
_includes.clear();
_excludes.clear();
}
@Override
public String toString()
{
return String.format("%s@%x{i=%s,ip=%s,e=%s,ep=%s}",this.getClass().getSimpleName(),hashCode(),_includes,_includePredicate,_excludes,_excludePredicate);
}
}

View File

@ -0,0 +1,318 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.net.InetAddress;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
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:
* <dl>
* <dt>InetAddress</dt><tt>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"</tt>
* <dt>InetAddress/CIDR</dt><tt>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" </tt>
* <dt>InetAddress-InetAddress</dt><tt>An inclusive range of InetAddresses.
* eg. "[a000::1]-[afff::]", "192.168.128.0-192.168.128.255"</tt>
* <dt>Legacy format</dt><tt>The legacy format used by {@link IPAddressMap} for IPv4 only.
* eg. "10.10.10-14.0-128"</tt>
* </dl>
* </p>
* <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<>();
@Override
public boolean add(String pattern)
{
return _patterns.put(pattern,newInetRange(pattern))==null;
}
protected 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);
}
}
@Override
public boolean remove(Object pattern)
{
return _patterns.remove(pattern)!=null;
}
@Override
public Iterator<String> iterator()
{
return _patterns.keySet().iterator();
}
@Override
public int size()
{
return _patterns.size();
}
@Override
public boolean test(InetAddress address)
{
if (address==null)
return false;
byte[] raw = address.getAddress();
for (InetPattern pattern : _patterns.values())
if (pattern.test(address,raw))
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;
}
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[] raw_min = min.getAddress();
byte[] raw_max = max.getAddress();
if (raw_min.length!=raw_max.length)
throw new IllegalArgumentException("Cannot mix IPv4 and IPv6: "+pattern);
if (raw_min.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[raw_min.length];
_max = new int[raw_min.length];
for (int i=0;i<_min.length;i++)
{
_min[i]=0xff&raw_min[i];
_max[i]=0xff&raw_max[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;
}
}
public boolean test(InetAddress item, byte[] raw)
{
if (raw.length!=_min.length)
return false;
boolean min_ok = false;
boolean max_ok = false;
for (int i=0;i<_min.length;i++)
{
int r = 0xff&raw[i];
if (!min_ok)
{
if (r<_min[i])
return false;
if (r>_min[i])
min_ok=true;
}
if (!max_ok)
{
if (r>_max[i])
return false;
if (r<_max[i])
max_ok=true;
}
if (min_ok && max_ok)
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 && _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);
}
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);
}
}
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;
}
}
}

View File

@ -0,0 +1,58 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.net.InetAddress;
import org.junit.Test;
public class IncludeExcludeSetTest
{
@Test
public void testWithInetAddressSet() throws Exception
{
IncludeExcludeSet<String,InetAddress> set = new IncludeExcludeSet<>(InetAddressSet.class);
assertTrue(set.test(InetAddress.getByName("192.168.0.1")));
set.include("10.10.0.0/16");
assertFalse(set.test(InetAddress.getByName("192.168.0.1")));
assertTrue(set.test(InetAddress.getByName("10.10.128.1")));
set.exclude("[::ffff:10.10.128.1]");
assertFalse(set.test(InetAddress.getByName("10.10.128.1")));
set.include("[ffff:ff00::]/24");
assertTrue(set.test(InetAddress.getByName("ffff:ff00::1")));
assertTrue(set.test(InetAddress.getByName("ffff:ff00::42")));
set.exclude("[ffff:ff00::42]");
assertTrue(set.test(InetAddress.getByName("ffff:ff00::41")));
assertFalse(set.test(InetAddress.getByName("ffff:ff00::42")));
assertTrue(set.test(InetAddress.getByName("ffff:ff00::43")));
set.include("192.168.0.0-192.168.255.128");
assertTrue(set.test(InetAddress.getByName("192.168.0.1")));
assertTrue(set.test(InetAddress.getByName("192.168.254.255")));
assertFalse(set.test(InetAddress.getByName("192.168.255.255")));
}
}

View File

@ -0,0 +1,332 @@
//
// ========================================================================
// Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import static org.junit.Assert.*;
import java.net.InetAddress;
import java.util.Iterator;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
public class InetAddressSetTest
{
@Test
public void testInetAddress() throws Exception
{
assertTrue(InetAddress.getByName("127.0.0.1").isLoopbackAddress());
assertTrue(InetAddress.getByName("::1").isLoopbackAddress());
assertTrue(InetAddress.getByName("::0.0.0.1").isLoopbackAddress());
assertTrue(InetAddress.getByName("[::1]").isLoopbackAddress());
assertTrue(InetAddress.getByName("[::0.0.0.1]").isLoopbackAddress());
assertTrue(InetAddress.getByName("[::ffff:127.0.0.1]").isLoopbackAddress());
}
@Test
public void testSingleton() throws Exception
{
InetAddressSet set = new InetAddressSet();
set.add("webtide.com");
set.add("1.2.3.4");
set.add("::abcd");
assertTrue(set.test(InetAddress.getByName("webtide.com")));
assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress())));
assertTrue(set.test(InetAddress.getByName("1.2.3.4")));
assertTrue(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertTrue(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertTrue(set.test(InetAddress.getByName("::0:0:abcd")));
assertTrue(set.test(InetAddress.getByName("::abcd")));
assertTrue(set.test(InetAddress.getByName("[::abcd]")));
assertTrue(set.test(InetAddress.getByName("::ffff:1.2.3.4")));
assertFalse(set.test(InetAddress.getByName("www.google.com")));
assertFalse(set.test(InetAddress.getByName("1.2.3.5")));
assertFalse(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)5})));
assertFalse(set.test(InetAddress.getByAddress("webtide.com",new byte[]{(byte)1,(byte)2,(byte)3,(byte)5})));
assertFalse(set.test(InetAddress.getByName("::1.2.3.4")));
assertFalse(set.test(InetAddress.getByName("::1234")));
assertFalse(set.test(InetAddress.getByName("::abce")));
assertFalse(set.test(InetAddress.getByName("1::abcd")));
}
@Test
public void testBadSingleton() throws Exception
{
String[] tests = new String[]
{
"unknown",
"1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16",
"a.b.c.d",
"[::1",
"[xxx]",
"[:::1]",
};
InetAddressSet set = new InetAddressSet();
for (String t:tests)
{
try
{
set.add(t);
fail(t);
}
catch(IllegalArgumentException e)
{
Assert.assertThat(e.getMessage(),Matchers.containsString(t));
}
}
}
@Test
public void testCIDR() throws Exception
{
InetAddressSet set = new InetAddressSet();
set.add("10.10.0.0/16");
set.add("192.0.80.0/22");
set.add("168.0.0.80/30");
set.add("abcd:ef00::/24");
assertTrue(set.test(InetAddress.getByName("10.10.0.0")));
assertTrue(set.test(InetAddress.getByName("10.10.0.1")));
assertTrue(set.test(InetAddress.getByName("10.10.255.255")));
assertTrue(set.test(InetAddress.getByName("::ffff:10.10.0.1")));
assertTrue(set.test(InetAddress.getByName("192.0.80.0")));
assertTrue(set.test(InetAddress.getByName("192.0.83.1")));
assertTrue(set.test(InetAddress.getByName("168.0.0.80")));
assertTrue(set.test(InetAddress.getByName("168.0.0.83")));
assertTrue(set.test(InetAddress.getByName("abcd:ef00::1")));
assertTrue(set.test(InetAddress.getByName("abcd:efff::ffff")));
assertFalse(set.test(InetAddress.getByName("10.11.0.0")));
assertFalse(set.test(InetAddress.getByName("1.2.3.5")));
assertFalse(set.test(InetAddress.getByName("192.0.84.1")));
assertFalse(set.test(InetAddress.getByName("168.0.0.84")));
assertFalse(set.test(InetAddress.getByName("::10.10.0.1")));
assertFalse(set.test(InetAddress.getByName("abcd:eeff::1")));
assertFalse(set.test(InetAddress.getByName("abcd:f000::")));
set.add("255.255.255.255/32");
assertTrue(set.test(InetAddress.getByName("255.255.255.255")));
assertFalse(set.test(InetAddress.getByName("10.11.0.0")));
set.add("0.0.0.0/0");
assertTrue(set.test(InetAddress.getByName("10.11.0.0")));
}
@Test
public void testBadCIDR() throws Exception
{
String[] tests = new String[]
{
"unknown/8",
"1.2.3.4/-1",
"1.2.3.4/xxx",
"1.2.3.4/33",
"255.255.8.0/16",
"255.255.8.1/17",
"[::1]/129",
};
InetAddressSet set = new InetAddressSet();
for (String t:tests)
{
try
{
set.add(t);
fail(t);
}
catch(IllegalArgumentException e)
{
Assert.assertThat(e.getMessage(),Matchers.containsString(t));
}
}
}
@Test
public void testMinMax() throws Exception
{
InetAddressSet set = new InetAddressSet();
set.add("10.0.0.4-10.0.0.6");
set.add("10.1.0.254-10.1.1.1");
set.add("[abcd:ef::fffe]-[abcd:ef::1:1]");
assertFalse(set.test(InetAddress.getByName("10.0.0.3")));
assertTrue(set.test(InetAddress.getByName("10.0.0.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.5")));
assertTrue(set.test(InetAddress.getByName("10.0.0.6")));
assertFalse(set.test(InetAddress.getByName("10.0.0.7")));
assertFalse(set.test(InetAddress.getByName("10.1.0.253")));
assertTrue(set.test(InetAddress.getByName("10.1.0.254")));
assertTrue(set.test(InetAddress.getByName("10.1.0.255")));
assertTrue(set.test(InetAddress.getByName("10.1.1.0")));
assertTrue(set.test(InetAddress.getByName("10.1.1.1")));
assertFalse(set.test(InetAddress.getByName("10.1.1.2")));
assertFalse(set.test(InetAddress.getByName("ABCD:EF::FFFD")));
assertTrue(set.test(InetAddress.getByName("ABCD:EF::FFFE")));
assertTrue(set.test(InetAddress.getByName("ABCD:EF::FFFF")));
assertTrue(set.test(InetAddress.getByName("ABCD:EF::1:0")));
assertTrue(set.test(InetAddress.getByName("ABCD:EF::1:1")));
assertFalse(set.test(InetAddress.getByName("ABCD:EF::1:2")));
}
@Test
public void testBadMinMax() throws Exception
{
String[] tests = new String[]
{
"10.0.0.0-9.0.0.0",
"9.0.0.0-[::10.0.0.0]",
};
InetAddressSet set = new InetAddressSet();
for (String t:tests)
{
try
{
set.add(t);
fail(t);
}
catch(IllegalArgumentException e)
{
Assert.assertThat(e.getMessage(),Matchers.containsString(t));
}
}
}
@Test
public void testLegacy() throws Exception
{
InetAddressSet set = new InetAddressSet();
set.add("10.-.245-.-2");
set.add("11.11.11.127-129");
assertFalse(set.test(InetAddress.getByName("9.0.245.0")));
assertTrue(set.test(InetAddress.getByName("10.0.245.0")));
assertTrue(set.test(InetAddress.getByName("10.0.245.1")));
assertTrue(set.test(InetAddress.getByName("10.0.245.2")));
assertFalse(set.test(InetAddress.getByName("10.0.245.3")));
assertTrue(set.test(InetAddress.getByName("10.255.255.0")));
assertTrue(set.test(InetAddress.getByName("10.255.255.1")));
assertTrue(set.test(InetAddress.getByName("10.255.255.2")));
assertFalse(set.test(InetAddress.getByName("10.255.255.3")));
assertFalse(set.test(InetAddress.getByName("10.0.244.0")));
assertFalse(set.test(InetAddress.getByName("10.0.244.1")));
assertFalse(set.test(InetAddress.getByName("10.0.244.2")));
assertFalse(set.test(InetAddress.getByName("10.0.244.3")));
}
@Test
public void testBadLegacy() throws Exception
{
String[] tests = new String[]
{
"9.0-10.0",
"10.0.0--1.1",
"10.0.0-256.1",
};
InetAddressSet set = new InetAddressSet();
for (String t:tests)
{
try
{
set.add(t);
fail(t);
}
catch(IllegalArgumentException e)
{
Assert.assertThat(e.getMessage(),Matchers.containsString(t));
}
}
}
@Test
public void testRemove() throws Exception
{
InetAddressSet set = new InetAddressSet();
set.add("webtide.com");
set.add("1.2.3.4");
set.add("::abcd");
set.add("10.0.0.4-10.0.0.6");
assertTrue(set.test(InetAddress.getByName("webtide.com")));
assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress())));
assertTrue(set.test(InetAddress.getByName("1.2.3.4")));
assertTrue(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertTrue(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertTrue(set.test(InetAddress.getByName("::0:0:abcd")));
assertTrue(set.test(InetAddress.getByName("::abcd")));
assertTrue(set.test(InetAddress.getByName("[::abcd]")));
assertTrue(set.test(InetAddress.getByName("::ffff:1.2.3.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.5")));
assertTrue(set.test(InetAddress.getByName("10.0.0.6")));
set.remove("1.2.3.4");
assertTrue(set.test(InetAddress.getByName("webtide.com")));
assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress())));
assertFalse(set.test(InetAddress.getByName("1.2.3.4")));
assertFalse(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertFalse(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertTrue(set.test(InetAddress.getByName("::0:0:abcd")));
assertTrue(set.test(InetAddress.getByName("::abcd")));
assertTrue(set.test(InetAddress.getByName("[::abcd]")));
assertFalse(set.test(InetAddress.getByName("::ffff:1.2.3.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.5")));
assertTrue(set.test(InetAddress.getByName("10.0.0.6")));
for (Iterator<String> i=set.iterator();i.hasNext();)
{
if ("::abcd".equals(i.next()))
i.remove();
}
assertTrue(set.test(InetAddress.getByName("webtide.com")));
assertTrue(set.test(InetAddress.getByName(InetAddress.getByName("webtide.com").getHostAddress())));
assertFalse(set.test(InetAddress.getByName("1.2.3.4")));
assertFalse(set.test(InetAddress.getByAddress(new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertFalse(set.test(InetAddress.getByAddress("hostname",new byte[]{(byte)1,(byte)2,(byte)3,(byte)4})));
assertFalse(set.test(InetAddress.getByName("::0:0:abcd")));
assertFalse(set.test(InetAddress.getByName("::abcd")));
assertFalse(set.test(InetAddress.getByName("[::abcd]")));
assertFalse(set.test(InetAddress.getByName("::ffff:1.2.3.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.4")));
assertTrue(set.test(InetAddress.getByName("10.0.0.5")));
assertTrue(set.test(InetAddress.getByName("10.0.0.6")));
}
}