mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-10 00:00:19 -04:00
android: Add class to manage a set of IP address ranges/subnets
This commit is contained in:
parent
bcba14504a
commit
d852a02717
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2012-2017 Tobias Brunner
|
||||||
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.strongswan.android.utils;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class that represents a set of IP address ranges (not necessarily proper subnets) and allows
|
||||||
|
* modifying the set and enumerating the resulting subnets.
|
||||||
|
*/
|
||||||
|
public class IPRangeSet
|
||||||
|
{
|
||||||
|
private TreeSet<IPRange> mRanges = new TreeSet<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the given string (space separated subnets in CIDR notation) and return the resulting
|
||||||
|
* set or {@code null} if the string was invalid. And empty set is returned if the given string
|
||||||
|
* is {@code null}.
|
||||||
|
*/
|
||||||
|
public static IPRangeSet fromString(String ranges)
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
if (ranges != null)
|
||||||
|
{
|
||||||
|
for (String range : ranges.split("\\s+"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
set.add(new IPRange(range));
|
||||||
|
}
|
||||||
|
catch (Exception unused)
|
||||||
|
{ /* besides due to invalid strings exceptions might get thrown if the string
|
||||||
|
* contains a hostname (NetworkOnMainThreadException) */
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a range to this set. Automatically gets merged with existing ranges.
|
||||||
|
*/
|
||||||
|
public void add(IPRange range)
|
||||||
|
{
|
||||||
|
if (mRanges.contains(range))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
reinsert:
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Iterator<IPRange> iterator = mRanges.iterator();
|
||||||
|
while (iterator.hasNext())
|
||||||
|
{
|
||||||
|
IPRange existing = iterator.next();
|
||||||
|
IPRange replacement = existing.merge(range);
|
||||||
|
if (replacement != null)
|
||||||
|
{
|
||||||
|
iterator.remove();
|
||||||
|
range = replacement;
|
||||||
|
continue reinsert;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mRanges.add(range);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given range from this set. Existing ranges are automatically adjusted.
|
||||||
|
*/
|
||||||
|
public void remove(IPRange range)
|
||||||
|
{
|
||||||
|
ArrayList <IPRange> additions = new ArrayList<>();
|
||||||
|
Iterator<IPRange> iterator = mRanges.iterator();
|
||||||
|
while (iterator.hasNext())
|
||||||
|
{
|
||||||
|
IPRange existing = iterator.next();
|
||||||
|
List<IPRange> result = existing.remove(range);
|
||||||
|
if (result.size() == 0)
|
||||||
|
{
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
else if (!result.get(0).equals(existing))
|
||||||
|
{
|
||||||
|
iterator.remove();
|
||||||
|
additions.addAll(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mRanges.addAll(additions);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subnets derived from all the ranges in this set.
|
||||||
|
*/
|
||||||
|
public Enumeration<IPRange> getSubnets()
|
||||||
|
{
|
||||||
|
return new Enumeration<IPRange>()
|
||||||
|
{
|
||||||
|
private Iterator<IPRange> mIterator = mRanges.iterator();
|
||||||
|
private List<IPRange> mSubnets;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMoreElements()
|
||||||
|
{
|
||||||
|
return (mSubnets != null && mSubnets.size() > 0) || mIterator.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPRange nextElement()
|
||||||
|
{
|
||||||
|
if (mSubnets == null || mSubnets.size() == 0)
|
||||||
|
{
|
||||||
|
IPRange range = mIterator.next();
|
||||||
|
mSubnets = range.toSubnets();
|
||||||
|
}
|
||||||
|
return mSubnets.remove(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of ranges, not subnets.
|
||||||
|
*/
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return mRanges.size();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Tobias Brunner
|
||||||
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.strongswan.android.test;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.strongswan.android.utils.IPRange;
|
||||||
|
import org.strongswan.android.utils.IPRangeSet;
|
||||||
|
|
||||||
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class IPRangeSetTest
|
||||||
|
{
|
||||||
|
private void assertSubnets(Enumeration<IPRange> subnets, IPRange...exp)
|
||||||
|
{
|
||||||
|
if (exp.length == 0)
|
||||||
|
{
|
||||||
|
assertEquals("no subnets", false, subnets.hasMoreElements());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < exp.length; i++)
|
||||||
|
{
|
||||||
|
assertEquals("has subnet", true, subnets.hasMoreElements());
|
||||||
|
assertEquals("range", exp[i], subnets.nextElement());
|
||||||
|
}
|
||||||
|
assertEquals("done", false, subnets.hasMoreElements());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmpty()
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
assertEquals("size", 0, set.size());
|
||||||
|
assertSubnets(set.getSubnets());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddDistinct() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("10.0.1.0/24"));
|
||||||
|
assertEquals("size", 2, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("10.0.1.0/24"), new IPRange("192.168.1.0/24"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddAdjacent() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("192.168.2.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"), new IPRange("192.168.2.0/24"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddAdjacentJoin() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("192.168.3.0/24"));
|
||||||
|
assertEquals("size", 2, set.size());
|
||||||
|
set.add(new IPRange("192.168.2.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"), new IPRange("192.168.2.0/23"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddSame() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddLarger() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("192.168.0.0/16"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.0.0/16"));
|
||||||
|
set.add(new IPRange("0.0.0.0/0"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("0.0.0.0/0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddLargerMulti() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("10.0.1.0/24"));
|
||||||
|
set.add(new IPRange("255.255.255.255/32"));
|
||||||
|
assertEquals("size", 3, set.size());
|
||||||
|
set.add(new IPRange("0.0.0.0/0"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("0.0.0.0/0"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveNothing() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
set.remove(new IPRange("192.168.2.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
set.remove(new IPRange("10.0.1.0/24"));
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveAll() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
set.remove(new IPRange("192.168.0.0/16"));
|
||||||
|
assertEquals("size", 0, set.size());
|
||||||
|
assertSubnets(set.getSubnets());
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("10.0.1.0/24"));
|
||||||
|
set.add(new IPRange("255.255.255.255/32"));
|
||||||
|
assertEquals("size", 3, set.size());
|
||||||
|
set.remove(new IPRange("0.0.0.0/0"));
|
||||||
|
assertEquals("size", 0, set.size());
|
||||||
|
assertSubnets(set.getSubnets());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveOverlap() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = new IPRangeSet();
|
||||||
|
set.add(new IPRange("192.168.1.0/24"));
|
||||||
|
set.add(new IPRange("192.168.2.0/24"));
|
||||||
|
set.remove(new IPRange("192.168.1.128", "192.168.2.127"));
|
||||||
|
assertEquals("size", 2, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/25"), new IPRange("192.168.2.128/25"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromStringSingle() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = IPRangeSet.fromString("192.168.1.0/24");
|
||||||
|
assertEquals("size", 1, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("192.168.1.0/24"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromString() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = IPRangeSet.fromString("192.168.1.0/24 fec1::/64 10.0.1.0/24 255.255.255.255");
|
||||||
|
assertEquals("size", 4, set.size());
|
||||||
|
assertSubnets(set.getSubnets(), new IPRange("10.0.1.0/24"), new IPRange("192.168.1.0/24"),
|
||||||
|
new IPRange("255.255.255.255/32"), new IPRange("fec1::/64"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromStringInvalidRange() throws UnknownHostException
|
||||||
|
{
|
||||||
|
IPRangeSet set = IPRangeSet.fromString("192.168.1.0/65");
|
||||||
|
assertEquals("failed", null, set);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user