Merge "Revert "Revert "Revert "Revert "Add APIs that allow to exclude r..."" am: bc8f256721

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1938732

Change-Id: I52eff7abb30ba8e67838b4eec530f189bf91d84e
This commit is contained in:
Taras Antoshchuk
2022-01-12 15:46:55 +00:00
committed by Automerger Merge Worker
4 changed files with 141 additions and 31 deletions

View File

@@ -26896,11 +26896,13 @@ package android.net {
method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull java.net.InetAddress); method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull java.net.InetAddress);
method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull String); method @NonNull public android.net.VpnService.Builder addDnsServer(@NonNull String);
method @NonNull public android.net.VpnService.Builder addRoute(@NonNull java.net.InetAddress, int); method @NonNull public android.net.VpnService.Builder addRoute(@NonNull java.net.InetAddress, int);
method @NonNull public android.net.VpnService.Builder addRoute(@NonNull android.net.IpPrefix);
method @NonNull public android.net.VpnService.Builder addRoute(@NonNull String, int); method @NonNull public android.net.VpnService.Builder addRoute(@NonNull String, int);
method @NonNull public android.net.VpnService.Builder addSearchDomain(@NonNull String); method @NonNull public android.net.VpnService.Builder addSearchDomain(@NonNull String);
method @NonNull public android.net.VpnService.Builder allowBypass(); method @NonNull public android.net.VpnService.Builder allowBypass();
method @NonNull public android.net.VpnService.Builder allowFamily(int); method @NonNull public android.net.VpnService.Builder allowFamily(int);
method @Nullable public android.os.ParcelFileDescriptor establish(); method @Nullable public android.os.ParcelFileDescriptor establish();
method @NonNull public android.net.VpnService.Builder excludeRoute(@NonNull android.net.IpPrefix);
method @NonNull public android.net.VpnService.Builder setBlocking(boolean); method @NonNull public android.net.VpnService.Builder setBlocking(boolean);
method @NonNull public android.net.VpnService.Builder setConfigureIntent(@NonNull android.app.PendingIntent); method @NonNull public android.net.VpnService.Builder setConfigureIntent(@NonNull android.app.PendingIntent);
method @NonNull public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo); method @NonNull public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo);

View File

@@ -41,6 +41,7 @@ import android.os.RemoteException;
import android.os.ServiceManager; import android.os.ServiceManager;
import android.os.UserHandle; import android.os.UserHandle;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.net.NetworkUtilsInternal; import com.android.internal.net.NetworkUtilsInternal;
import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnConfig;
@@ -50,6 +51,7 @@ import java.net.Inet6Address;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; 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 * Helper class to create a VPN interface. This class should be always
* used within the scope of the outer {@link VpnService}. * used within the scope of the outer {@link VpnService}.
@@ -481,9 +490,9 @@ public class VpnService extends Service {
private final VpnConfig mConfig = new VpnConfig(); private final VpnConfig mConfig = new VpnConfig();
@UnsupportedAppUsage @UnsupportedAppUsage
private final List<LinkAddress> mAddresses = new ArrayList<LinkAddress>(); private final List<LinkAddress> mAddresses = new ArrayList<>();
@UnsupportedAppUsage @UnsupportedAppUsage
private final List<RouteInfo> mRoutes = new ArrayList<RouteInfo>(); private final List<RouteInfo> mRoutes = new ArrayList<>();
public Builder() { public Builder() {
mConfig.user = VpnService.this.getClass().getName(); mConfig.user = VpnService.this.getClass().getName();
@@ -555,7 +564,6 @@ public class VpnService extends Service {
throw new IllegalArgumentException("Bad address"); throw new IllegalArgumentException("Bad address");
} }
mAddresses.add(new LinkAddress(address, prefixLength)); mAddresses.add(new LinkAddress(address, prefixLength));
mConfig.updateAllowedFamilies(address);
return this; return this;
} }
@@ -575,6 +583,32 @@ public class VpnService extends Service {
return addAddress(InetAddress.parseNumericAddress(address), prefixLength); return addAddress(InetAddress.parseNumericAddress(address), prefixLength);
} }
/**
* 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 * Add a network route to the VPN interface. Both IPv4 and IPv6
* routes are supported. * routes are supported.
@@ -582,25 +616,39 @@ public class VpnService extends Service {
* Adding a route implicitly allows traffic from that address family * Adding a route implicitly allows traffic from that address family
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily * (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. * @throws IllegalArgumentException if the route is invalid.
*/ */
@NonNull @NonNull
public Builder addRoute(@NonNull InetAddress address, int prefixLength) { public Builder addRoute(@NonNull InetAddress address, int prefixLength) {
check(address, prefixLength); checkNonPrefixBytes(address, prefixLength);
int offset = prefixLength / 8; return addRoute(new IpPrefix(address, prefixLength), RouteInfo.RTN_UNICAST);
byte[] bytes = address.getAddress(); }
if (offset < bytes.length) {
for (bytes[offset] <<= prefixLength % 8; offset < bytes.length; ++offset) { /**
if (bytes[offset] != 0) { * Add a network route to the VPN interface. Both IPv4 and IPv6
throw new IllegalArgumentException("Bad address"); * 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
mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null, *
RouteInfo.RTN_UNICAST)); * Calling this method overrides previous calls to {@link #excludeRoute} for the same
mConfig.updateAllowedFamilies(address); * destination.
return this; *
* 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 * Adding a route implicitly allows traffic from that address family
* (i.e., IPv4 or IPv6) to be routed over the VPN. @see #allowFamily * (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. * @throws IllegalArgumentException if the route is invalid.
* @see #addRoute(InetAddress, int) * @see #addRoute(InetAddress, int)
*/ */
@@ -619,6 +673,23 @@ public class VpnService extends Service {
return addRoute(InetAddress.parseNumericAddress(address), prefixLength); return addRoute(InetAddress.parseNumericAddress(address), prefixLength);
} }
/**
* 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 * Add a DNS server to the VPN connection. Both IPv4 and IPv6
* addresses are supported. If none is set, the DNS servers of * addresses are supported. If none is set, the DNS servers of
@@ -900,5 +971,23 @@ public class VpnService extends Service {
throw new IllegalStateException(e); 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);
}
} }
} }

View File

@@ -34,8 +34,6 @@ import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.os.UserHandle; import android.os.UserHandle;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -93,8 +91,8 @@ public class VpnConfig implements Parcelable {
public String interfaze; public String interfaze;
public String session; public String session;
public int mtu = -1; public int mtu = -1;
public List<LinkAddress> addresses = new ArrayList<LinkAddress>(); public List<LinkAddress> addresses = new ArrayList<>();
public List<RouteInfo> routes = new ArrayList<RouteInfo>(); public List<RouteInfo> routes = new ArrayList<>();
public List<String> dnsServers; public List<String> dnsServers;
public List<String> searchDomains; public List<String> searchDomains;
public List<String> allowedApplications; public List<String> allowedApplications;
@@ -114,12 +112,32 @@ public class VpnConfig implements Parcelable {
public VpnConfig() { public VpnConfig() {
} }
public void updateAllowedFamilies(InetAddress address) { public VpnConfig(VpnConfig other) {
if (address instanceof Inet4Address) { user = other.user;
allowIPv4 = true; interfaze = other.interfaze;
} else { session = other.session;
allowIPv6 = true; mtu = other.mtu;
} addresses = copyOf(other.addresses);
routes = copyOf(other.routes);
dnsServers = copyOf(other.dnsServers);
searchDomains = copyOf(other.searchDomains);
allowedApplications = copyOf(other.allowedApplications);
disallowedApplications = copyOf(other.disallowedApplications);
configureIntent = other.configureIntent;
startTime = other.startTime;
legacy = other.legacy;
blocking = other.blocking;
allowBypass = other.allowBypass;
allowIPv4 = other.allowIPv4;
allowIPv6 = other.allowIPv6;
isMetered = other.isMetered;
underlyingNetworks = other.underlyingNetworks != null ? Arrays.copyOf(
other.underlyingNetworks, other.underlyingNetworks.length) : null;
proxyInfo = other.proxyInfo;
}
private static <T> List<T> copyOf(List<T> list) {
return list != null ? new ArrayList<>(list) : null;
} }
public void addLegacyRoutes(String routesStr) { public void addLegacyRoutes(String routesStr) {
@@ -131,7 +149,6 @@ public class VpnConfig implements Parcelable {
//each route is ip/prefix //each route is ip/prefix
RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST); RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST);
this.routes.add(info); this.routes.add(info);
updateAllowedFamilies(info.getDestination().getAddress());
} }
} }
@@ -144,7 +161,6 @@ public class VpnConfig implements Parcelable {
//each address is ip/prefix //each address is ip/prefix
LinkAddress addr = new LinkAddress(address); LinkAddress addr = new LinkAddress(address);
this.addresses.add(addr); this.addresses.add(addr);
updateAllowedFamilies(addr.getAddress());
} }
} }

View File

@@ -1208,8 +1208,11 @@ public class Vpn {
for (RouteInfo route : mConfig.routes) { for (RouteInfo route : mConfig.routes) {
lp.addRoute(route); lp.addRoute(route);
InetAddress address = route.getDestination().getAddress(); InetAddress address = route.getDestination().getAddress();
allowIPv4 |= address instanceof Inet4Address;
allowIPv6 |= address instanceof Inet6Address; if (route.getType() == RouteInfo.RTN_UNICAST) {
allowIPv4 |= address instanceof Inet4Address;
allowIPv6 |= address instanceof Inet6Address;
}
} }
} }