summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2020-04-04 03:44:46 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-04-04 03:44:46 +0000
commit43bc020fc0e1e3648354c44503294af8258a8314 (patch)
tree26d0d28632b15b1c5741d8b04a8543239088e6ae
parent27b4fb4c9f17af05dac98bfb241e9629c286325b (diff)
parent5ccee0c73c9144264ba310e230bfdb0c78b7d74f (diff)
Merge "Only apply VPN isolation if it's fully routed" into rvc-dev
-rw-r--r--core/java/android/net/LinkProperties.java30
-rw-r--r--core/java/android/net/RouteInfo.java26
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java3
-rw-r--r--tests/net/common/java/android/net/LinkPropertiesTest.java25
-rw-r--r--tests/net/common/java/android/net/RouteInfoTest.java58
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java5
6 files changed, 146 insertions, 1 deletions
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 7ff954bdc1d2..651494d1c99c 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -1074,6 +1074,21 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Returns true if this link has an IPv4 unreachable default route.
+ *
+ * @return {@code true} if there is an IPv4 unreachable default route, {@code false} otherwise.
+ * @hide
+ */
+ public boolean hasIpv4UnreachableDefaultRoute() {
+ for (RouteInfo r : mRoutes) {
+ if (r.isIPv4UnreachableDefault()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* For backward compatibility.
* This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
* just yet.
@@ -1102,6 +1117,21 @@ public final class LinkProperties implements Parcelable {
}
/**
+ * Returns true if this link has an IPv6 unreachable default route.
+ *
+ * @return {@code true} if there is an IPv6 unreachable default route, {@code false} otherwise.
+ * @hide
+ */
+ public boolean hasIpv6UnreachableDefaultRoute() {
+ for (RouteInfo r : mRoutes) {
+ if (r.isIPv6UnreachableDefault()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* For backward compatibility.
* This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
* just yet.
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index dbdaa4c2da67..e550f85e6b9a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -426,6 +426,16 @@ public final class RouteInfo implements Parcelable {
}
/**
+ * Indicates if this route is an unreachable default route.
+ *
+ * @return {@code true} if it's an unreachable route with prefix length of 0.
+ * @hide
+ */
+ private boolean isUnreachableDefaultRoute() {
+ return mType == RTN_UNREACHABLE && mDestination.getPrefixLength() == 0;
+ }
+
+ /**
* Indicates if this route is an IPv4 default route.
* @hide
*/
@@ -434,6 +444,14 @@ public final class RouteInfo implements Parcelable {
}
/**
+ * Indicates if this route is an IPv4 unreachable default route.
+ * @hide
+ */
+ public boolean isIPv4UnreachableDefault() {
+ return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
+ }
+
+ /**
* Indicates if this route is an IPv6 default route.
* @hide
*/
@@ -442,6 +460,14 @@ public final class RouteInfo implements Parcelable {
}
/**
+ * Indicates if this route is an IPv6 unreachable default route.
+ * @hide
+ */
+ public boolean isIPv6UnreachableDefault() {
+ return isUnreachableDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
+ }
+
+ /**
* Indicates if this route is a host route (ie, matches only a single host address).
*
* @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6,
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4ab035e7f44f..2eaa766ad32d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6313,7 +6313,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
&& !nai.networkAgentConfig.allowBypass
&& nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
- && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
+ && (lp.hasIPv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
+ && (lp.hasIPv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
}
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 8de27e8eb281..0fc9be32f4cf 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -16,6 +16,8 @@
package android.net;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
+
import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
@@ -46,6 +48,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1257,4 +1260,26 @@ public class LinkPropertiesTest {
final LinkProperties Ipv6 = makeIpv6LinkProperties();
assertTrue(Ipv6.hasIpv6DnsServer());
}
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testHasIpv4UnreachableDefaultRoute() {
+ final LinkProperties lp = makeTestObject();
+ assertFalse(lp.hasIpv4UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv6UnreachableDefaultRoute());
+
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
+ assertTrue(lp.hasIpv4UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv6UnreachableDefaultRoute());
+ }
+
+ @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
+ public void testHasIpv6UnreachableDefaultRoute() {
+ final LinkProperties lp = makeTestObject();
+ assertFalse(lp.hasIpv6UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv4UnreachableDefaultRoute());
+
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
+ assertTrue(lp.hasIpv6UnreachableDefaultRoute());
+ assertFalse(lp.hasIpv4UnreachableDefaultRoute());
+ }
}
diff --git a/tests/net/common/java/android/net/RouteInfoTest.java b/tests/net/common/java/android/net/RouteInfoTest.java
index 1658262c17f6..8204b494bbb8 100644
--- a/tests/net/common/java/android/net/RouteInfoTest.java
+++ b/tests/net/common/java/android/net/RouteInfoTest.java
@@ -31,6 +31,7 @@ import static org.junit.Assert.fail;
import android.os.Build;
+import androidx.core.os.BuildCompat;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -62,6 +63,11 @@ public class RouteInfoTest {
return new IpPrefix(prefix);
}
+ private static boolean isAtLeastR() {
+ // BuildCompat.isAtLeastR is documented to return false on release SDKs (including R)
+ return Build.VERSION.SDK_INT > Build.VERSION_CODES.Q || BuildCompat.isAtLeastR();
+ }
+
@Test
public void testConstructor() {
RouteInfo r;
@@ -195,78 +201,130 @@ public class RouteInfoTest {
assertTrue(r.isDefaultRoute());
assertTrue(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
assertFalse(r.isHostRoute());
assertTrue(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertTrue(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
assertTrue(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertTrue(r.isIPv4UnreachableDefault());
+ assertFalse(r.isIPv6UnreachableDefault());
+ }
r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
assertFalse(r.isHostRoute());
assertFalse(r.isDefaultRoute());
assertFalse(r.isIPv4Default());
assertFalse(r.isIPv6Default());
+ if (isAtLeastR()) {
+ assertFalse(r.isIPv4UnreachableDefault());
+ assertTrue(r.isIPv6UnreachableDefault());
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b02398d1f1f5..912a27f08f30 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -6336,6 +6336,7 @@ public class ConnectivityServiceTest {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
@@ -6361,6 +6362,7 @@ public class ConnectivityServiceTest {
public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
@@ -6392,6 +6394,7 @@ public class ConnectivityServiceTest {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
@@ -6428,6 +6431,7 @@ public class ConnectivityServiceTest {
reset(mMockNetd);
lp = new LinkProperties();
lp.setInterfaceName("tun1");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
vpnNetworkAgent.sendLinkProperties(lp);
waitForIdle();
@@ -6440,6 +6444,7 @@ public class ConnectivityServiceTest {
public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final UidRange vpnRange = UidRange.createForUser(VPN_USER);