android: Exclude configured subnets from the VPN

This commit is contained in:
Tobias Brunner
2017-07-03 10:27:52 +02:00
parent 1e26483167
commit 72b7c289ad
@@ -47,6 +47,8 @@ import org.strongswan.android.logic.VpnStateService.State;
import org.strongswan.android.logic.imc.ImcState; import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction; import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.MainActivity; import org.strongswan.android.ui.MainActivity;
import org.strongswan.android.utils.IPRange;
import org.strongswan.android.utils.IPRangeSet;
import org.strongswan.android.utils.SettingsWriter; import org.strongswan.android.utils.SettingsWriter;
import java.io.File; import java.io.File;
@@ -238,7 +240,8 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
mIsDisconnecting = false; mIsDisconnecting = false;
addNotification(); addNotification();
BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName(), mCurrentProfile.getSplitTunneling()); BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName(), mCurrentProfile.getExcludedSubnets(),
mCurrentProfile.getSplitTunneling());
if (initializeCharon(builder, mLogFile, mCurrentProfile.getVpnType().has(VpnTypeFeature.BYOD))) if (initializeCharon(builder, mLogFile, mCurrentProfile.getVpnType().has(VpnTypeFeature.BYOD)))
{ {
Log.i(TAG, "charon started"); Log.i(TAG, "charon started");
@@ -649,17 +652,19 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
public class BuilderAdapter public class BuilderAdapter
{ {
private final String mName; private final String mName;
private final String mExcludedSubnets;
private final Integer mSplitTunneling; private final Integer mSplitTunneling;
private VpnService.Builder mBuilder; private VpnService.Builder mBuilder;
private BuilderCache mCache; private BuilderCache mCache;
private BuilderCache mEstablishedCache; private BuilderCache mEstablishedCache;
public BuilderAdapter(String name, Integer splitTunneling) public BuilderAdapter(String name, String excludedSubnets, Integer splitTunneling)
{ {
mName = name; mName = name;
mExcludedSubnets = excludedSubnets;
mSplitTunneling = splitTunneling; mSplitTunneling = splitTunneling;
mBuilder = createBuilder(name); mBuilder = createBuilder(name);
mCache = new BuilderCache(mSplitTunneling); mCache = new BuilderCache(mExcludedSubnets, mSplitTunneling);
} }
private VpnService.Builder createBuilder(String name) private VpnService.Builder createBuilder(String name)
@@ -764,7 +769,7 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
* builder anymore, but we might need another when reestablishing */ * builder anymore, but we might need another when reestablishing */
mBuilder = createBuilder(mName); mBuilder = createBuilder(mName);
mEstablishedCache = mCache; mEstablishedCache = mCache;
mCache = new BuilderCache(mSplitTunneling); mCache = new BuilderCache(mExcludedSubnets, mSplitTunneling);
return fd.detachFd(); return fd.detachFd();
} }
@@ -801,23 +806,32 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
*/ */
public class BuilderCache public class BuilderCache
{ {
private final List<PrefixedAddress> mAddresses = new ArrayList<PrefixedAddress>(); private final List<IPRange> mAddresses = new ArrayList<>();
private final List<PrefixedAddress> mRoutesIPv4 = new ArrayList<PrefixedAddress>(); private final List<IPRange> mRoutesIPv4 = new ArrayList<>();
private final List<PrefixedAddress> mRoutesIPv6 = new ArrayList<PrefixedAddress>(); private final List<IPRange> mRoutesIPv6 = new ArrayList<>();
private final IPRangeSet mExcludedSubnets;
private final int mSplitTunneling; private final int mSplitTunneling;
private int mMtu; private int mMtu;
private boolean mIPv4Seen, mIPv6Seen; private boolean mIPv4Seen, mIPv6Seen;
public BuilderCache(Integer splitTunneling) public BuilderCache(String excludedSubnets, Integer splitTunneling)
{ {
mExcludedSubnets = IPRangeSet.fromString(excludedSubnets);
mSplitTunneling = splitTunneling != null ? splitTunneling : 0; mSplitTunneling = splitTunneling != null ? splitTunneling : 0;
} }
public void addAddress(String address, int prefixLength) public void addAddress(String address, int prefixLength)
{ {
mAddresses.add(new PrefixedAddress(address, prefixLength)); try
{
mAddresses.add(new IPRange(address, prefixLength));
recordAddressFamily(address); recordAddressFamily(address);
} }
catch (UnknownHostException ex)
{
ex.printStackTrace();
}
}
public void addRoute(String address, int prefixLength) public void addRoute(String address, int prefixLength)
{ {
@@ -825,11 +839,11 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
{ {
if (isIPv6(address)) if (isIPv6(address))
{ {
mRoutesIPv6.add(new PrefixedAddress(address, prefixLength)); mRoutesIPv6.add(new IPRange(address, prefixLength));
} }
else else
{ {
mRoutesIPv4.add(new PrefixedAddress(address, prefixLength)); mRoutesIPv4.add(new IPRange(address, prefixLength));
} }
} }
catch (UnknownHostException ex) catch (UnknownHostException ex)
@@ -865,19 +879,22 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
@TargetApi(Build.VERSION_CODES.LOLLIPOP) @TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void applyData(VpnService.Builder builder) public void applyData(VpnService.Builder builder)
{ {
for (PrefixedAddress address : mAddresses) for (IPRange address : mAddresses)
{ {
builder.addAddress(address.mAddress, address.mPrefix); builder.addAddress(address.getFrom(), address.getPrefix());
} }
/* add routes depending on whether split tunneling is allowed or not, /* add routes depending on whether split tunneling is allowed or not,
* that is, whether we have to handle and block non-VPN traffic */ * that is, whether we have to handle and block non-VPN traffic */
if ((mSplitTunneling & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4) == 0) if ((mSplitTunneling & VpnProfile.SPLIT_TUNNELING_BLOCK_IPV4) == 0)
{ {
if (mIPv4Seen) if (mIPv4Seen)
{ /* split tunneling is used depending on the routes */ { /* split tunneling is used depending on the routes and configuration */
for (PrefixedAddress route : mRoutesIPv4) IPRangeSet ranges = new IPRangeSet();
ranges.addAll(mRoutesIPv4);
ranges.remove(mExcludedSubnets);
for (IPRange subnet : ranges.subnets())
{ {
builder.addRoute(route.mAddress, route.mPrefix); builder.addRoute(subnet.getFrom(), subnet.getPrefix());
} }
} }
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
@@ -895,9 +912,12 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
{ {
if (mIPv6Seen) if (mIPv6Seen)
{ {
for (PrefixedAddress route : mRoutesIPv6) IPRangeSet ranges = new IPRangeSet();
ranges.addAll(mRoutesIPv6);
ranges.remove(mExcludedSubnets);
for (IPRange subnet : ranges.subnets())
{ {
builder.addRoute(route.mAddress, route.mPrefix); builder.addRoute(subnet.getFrom(), subnet.getPrefix());
} }
} }
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
@@ -925,18 +945,6 @@ public class CharonVpnService extends VpnService implements Runnable, VpnStateSe
} }
return false; return false;
} }
private class PrefixedAddress
{
public String mAddress;
public int mPrefix;
public PrefixedAddress(String address, int prefix)
{
this.mAddress = address;
this.mPrefix = prefix;
}
}
} }
/** /**