summaryrefslogtreecommitdiff
path: root/core/java/android
diff options
context:
space:
mode:
authorTaras Antoshchuk <tantoshchuk@google.com>2021-12-16 12:04:23 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-12-16 12:04:23 +0000
commita5d20fcf3c4d8cf64aee0fa0255b5f00a8de8660 (patch)
tree6dc5c07af7cc5a0213ee672b5ec3ea881d93459f /core/java/android
parent2d6a82665fbf115bbaf1c6b50c481794d59f4c9e (diff)
parent0cfd695f07a13ee19d02cbd7576478000fad6259 (diff)
Merge "Add APIs that allow to exclude routes from VPN" am: 55f030225b am: 1e2f898c30 am: 0cfd695f07
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1619406 Change-Id: If11e20ea47987c6017d52ee93489b6784af580ec
Diffstat (limited to 'core/java/android')
-rw-r--r--core/java/android/net/VpnService.java123
1 files changed, 106 insertions, 17 deletions
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index 2ced05693755..1ae1b050d32f 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -41,6 +41,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.NetworkUtilsInternal;
import com.android.internal.net.VpnConfig;
@@ -50,6 +51,7 @@ import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -471,6 +473,13 @@ public class VpnService extends Service {
}
}
+ private static void checkNonPrefixBytes(@NonNull InetAddress address, int prefixLength) {
+ final IpPrefix prefix = new IpPrefix(address, prefixLength);
+ if (!prefix.getAddress().equals(address)) {
+ throw new IllegalArgumentException("Bad address");
+ }
+ }
+
/**
* Helper class to create a VPN interface. This class should be always
* used within the scope of the outer {@link VpnService}.
@@ -481,9 +490,9 @@ public class VpnService extends Service {
private final VpnConfig mConfig = new VpnConfig();
@UnsupportedAppUsage
- private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>();
+ private final List<LinkAddress> mAddresses = new ArrayList<>();
@UnsupportedAppUsage
- private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+ private final List<RouteInfo> mRoutes = new ArrayList<>();
public Builder() {
mConfig.user = VpnService.this.getClass().getName();
@@ -555,7 +564,6 @@ public class VpnService extends Service {
throw new IllegalArgumentException("Bad address");
}
mAddresses.add(new LinkAddress(address, prefixLength));
- mConfig.updateAllowedFamilies(address);
return this;
}
@@ -579,28 +587,68 @@ public class VpnService extends Service {
* Add a network route to the VPN interface. Both IPv4 and IPv6
* routes are supported.
*
+ * If a route with the same destination is already present, its type will be updated.
+ *
+ * @throws IllegalArgumentException if the route is invalid.
+ */
+ @NonNull
+ private Builder addRoute(@NonNull IpPrefix prefix, int type) {
+ check(prefix.getAddress(), prefix.getPrefixLength());
+
+ final RouteInfo newRoute = new RouteInfo(prefix, /* gateway */
+ null, /* interface */ null, type);
+
+ final int index = findRouteIndexByDestination(newRoute);
+
+ if (index == -1) {
+ mRoutes.add(newRoute);
+ } else {
+ mRoutes.set(index, newRoute);
+ }
+
+ return this;
+ }
+
+ /**
+ * Add a network route to the VPN interface. Both IPv4 and IPv6
+ * routes are supported.
+ *
* Adding a route implicitly allows traffic from that address family
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
*
+ * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+ * destination.
+ *
+ * If multiple routes match the packet destination, route with the longest prefix takes
+ * precedence.
+ *
* @throws IllegalArgumentException if the route is invalid.
*/
@NonNull
public Builder addRoute(@NonNull InetAddress address, int prefixLength) {
- check(address, prefixLength);
+ checkNonPrefixBytes(address, prefixLength);
- int offset = prefixLength / 8;
- byte[] bytes = address.getAddress();
- if (offset < bytes.length) {
- for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) {
- if (bytes[offset] != 0) {
- throw new IllegalArgumentException("Bad address");
- }
- }
- }
- mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null,
- RouteInfo.RTN_UNICAST));
- mConfig.updateAllowedFamilies(address);
- return this;
+ return addRoute(new IpPrefix(address, prefixLength), RouteInfo.RTN_UNICAST);
+ }
+
+ /**
+ * Add a network route to the VPN interface. Both IPv4 and IPv6
+ * routes are supported.
+ *
+ * Adding a route implicitly allows traffic from that address family
+ * (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
+ *
+ * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+ * destination.
+ *
+ * If multiple routes match the packet destination, route with the longest prefix takes
+ * precedence.
+ *
+ * @throws IllegalArgumentException if the route is invalid.
+ */
+ @NonNull
+ public Builder addRoute(@NonNull IpPrefix prefix) {
+ return addRoute(prefix, RouteInfo.RTN_UNICAST);
}
/**
@@ -611,6 +659,12 @@ public class VpnService extends Service {
* Adding a route implicitly allows traffic from that address family
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily
*
+ * Calling this method overrides previous calls to {@link #excludeRoute} for the same
+ * destination.
+ *
+ * If multiple routes match the packet destination, route with the longest prefix takes
+ * precedence.
+ *
* @throws IllegalArgumentException if the route is invalid.
* @see #addRoute(InetAddress, int)
*/
@@ -620,6 +674,23 @@ public class VpnService extends Service {
}
/**
+ * Exclude a network route from the VPN interface. Both IPv4 and IPv6
+ * routes are supported.
+ *
+ * Calling this method overrides previous calls to {@link #addRoute} for the same
+ * destination.
+ *
+ * If multiple routes match the packet destination, route with the longest prefix takes
+ * precedence.
+ *
+ * @throws IllegalArgumentException if the route is invalid.
+ */
+ @NonNull
+ public Builder excludeRoute(@NonNull IpPrefix prefix) {
+ return addRoute(prefix, RouteInfo.RTN_THROW);
+ }
+
+ /**
* Add a DNS server to the VPN connection. Both IPv4 and IPv6
* addresses are supported. If none is set, the DNS servers of
* the default network will be used.
@@ -900,5 +971,23 @@ public class VpnService extends Service {
throw new IllegalStateException(e);
}
}
+
+ private int findRouteIndexByDestination(RouteInfo route) {
+ for (int i = 0; i < mRoutes.size(); i++) {
+ if (mRoutes.get(i).getDestination().equals(route.getDestination())) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Method for testing, to observe mRoutes while builder is being used.
+ * @hide
+ */
+ @VisibleForTesting
+ public List<RouteInfo> routes() {
+ return Collections.unmodifiableList(mRoutes);
+ }
}
}