Loading core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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 String); 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 addSearchDomain(@NonNull String); method @NonNull public android.net.VpnService.Builder allowBypass(); method @NonNull public android.net.VpnService.Builder allowFamily(int); 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 setConfigureIntent(@NonNull android.app.PendingIntent); method @NonNull public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo); core/java/android/net/VpnService.java +106 −17 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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}. Loading @@ -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(); Loading Loading @@ -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; } Loading @@ -575,6 +583,32 @@ public class VpnService extends Service { 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 * routes are supported. Loading @@ -582,25 +616,39 @@ 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. */ @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"); } return addRoute(new IpPrefix(address, prefixLength), RouteInfo.RTN_UNICAST); } } mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null, RouteInfo.RTN_UNICAST)); mConfig.updateAllowedFamilies(address); 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 IpPrefix prefix) { return addRoute(prefix, RouteInfo.RTN_UNICAST); } /** Loading @@ -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) */ Loading @@ -619,6 +673,23 @@ public class VpnService extends Service { 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 * addresses are supported. If none is set, the DNS servers of Loading Loading @@ -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); } } } core/java/com/android/internal/net/VpnConfig.java +28 −12 Original line number Diff line number Diff line Loading @@ -34,8 +34,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.List; Loading Loading @@ -93,8 +91,8 @@ public class VpnConfig implements Parcelable { public String interfaze; public String session; public int mtu = -1; public List<LinkAddress> addresses = new ArrayList<LinkAddress>(); public List<RouteInfo> routes = new ArrayList<RouteInfo>(); public List<LinkAddress> addresses = new ArrayList<>(); public List<RouteInfo> routes = new ArrayList<>(); public List<String> dnsServers; public List<String> searchDomains; public List<String> allowedApplications; Loading @@ -114,12 +112,32 @@ public class VpnConfig implements Parcelable { public VpnConfig() { } public void updateAllowedFamilies(InetAddress address) { if (address instanceof Inet4Address) { allowIPv4 = true; } else { allowIPv6 = true; public VpnConfig(VpnConfig other) { user = other.user; interfaze = other.interfaze; session = other.session; 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) { Loading @@ -131,7 +149,6 @@ public class VpnConfig implements Parcelable { //each route is ip/prefix RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST); this.routes.add(info); updateAllowedFamilies(info.getDestination().getAddress()); } } Loading @@ -144,7 +161,6 @@ public class VpnConfig implements Parcelable { //each address is ip/prefix LinkAddress addr = new LinkAddress(address); this.addresses.add(addr); updateAllowedFamilies(addr.getAddress()); } } Loading services/core/java/com/android/server/connectivity/Vpn.java +5 −2 Original line number Diff line number Diff line Loading @@ -1208,10 +1208,13 @@ public class Vpn { for (RouteInfo route : mConfig.routes) { lp.addRoute(route); InetAddress address = route.getDestination().getAddress(); if (route.getType() == RouteInfo.RTN_UNICAST) { allowIPv4 |= address instanceof Inet4Address; allowIPv6 |= address instanceof Inet6Address; } } } if (mConfig.dnsServers != null) { for (String dnsServer : mConfig.dnsServers) { Loading Loading
core/api/current.txt +2 −0 Original line number Diff line number Diff line Loading @@ -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 String); 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 addSearchDomain(@NonNull String); method @NonNull public android.net.VpnService.Builder allowBypass(); method @NonNull public android.net.VpnService.Builder allowFamily(int); 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 setConfigureIntent(@NonNull android.app.PendingIntent); method @NonNull public android.net.VpnService.Builder setHttpProxy(@NonNull android.net.ProxyInfo);
core/java/android/net/VpnService.java +106 −17 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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}. Loading @@ -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(); Loading Loading @@ -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; } Loading @@ -575,6 +583,32 @@ public class VpnService extends Service { 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 * routes are supported. Loading @@ -582,25 +616,39 @@ 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. */ @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"); } return addRoute(new IpPrefix(address, prefixLength), RouteInfo.RTN_UNICAST); } } mRoutes.add(new RouteInfo(new IpPrefix(address, prefixLength), null, null, RouteInfo.RTN_UNICAST)); mConfig.updateAllowedFamilies(address); 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 IpPrefix prefix) { return addRoute(prefix, RouteInfo.RTN_UNICAST); } /** Loading @@ -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) */ Loading @@ -619,6 +673,23 @@ public class VpnService extends Service { 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 * addresses are supported. If none is set, the DNS servers of Loading Loading @@ -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); } } }
core/java/com/android/internal/net/VpnConfig.java +28 −12 Original line number Diff line number Diff line Loading @@ -34,8 +34,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; import java.net.Inet4Address; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.List; Loading Loading @@ -93,8 +91,8 @@ public class VpnConfig implements Parcelable { public String interfaze; public String session; public int mtu = -1; public List<LinkAddress> addresses = new ArrayList<LinkAddress>(); public List<RouteInfo> routes = new ArrayList<RouteInfo>(); public List<LinkAddress> addresses = new ArrayList<>(); public List<RouteInfo> routes = new ArrayList<>(); public List<String> dnsServers; public List<String> searchDomains; public List<String> allowedApplications; Loading @@ -114,12 +112,32 @@ public class VpnConfig implements Parcelable { public VpnConfig() { } public void updateAllowedFamilies(InetAddress address) { if (address instanceof Inet4Address) { allowIPv4 = true; } else { allowIPv6 = true; public VpnConfig(VpnConfig other) { user = other.user; interfaze = other.interfaze; session = other.session; 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) { Loading @@ -131,7 +149,6 @@ public class VpnConfig implements Parcelable { //each route is ip/prefix RouteInfo info = new RouteInfo(new IpPrefix(route), null, null, RouteInfo.RTN_UNICAST); this.routes.add(info); updateAllowedFamilies(info.getDestination().getAddress()); } } Loading @@ -144,7 +161,6 @@ public class VpnConfig implements Parcelable { //each address is ip/prefix LinkAddress addr = new LinkAddress(address); this.addresses.add(addr); updateAllowedFamilies(addr.getAddress()); } } Loading
services/core/java/com/android/server/connectivity/Vpn.java +5 −2 Original line number Diff line number Diff line Loading @@ -1208,10 +1208,13 @@ public class Vpn { for (RouteInfo route : mConfig.routes) { lp.addRoute(route); InetAddress address = route.getDestination().getAddress(); if (route.getType() == RouteInfo.RTN_UNICAST) { allowIPv4 |= address instanceof Inet4Address; allowIPv6 |= address instanceof Inet6Address; } } } if (mConfig.dnsServers != null) { for (String dnsServer : mConfig.dnsServers) { Loading