Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5ccee0c7 authored by Lorenzo Colitti's avatar Lorenzo Colitti
Browse files

Only apply VPN isolation if it's fully routed

VPN is considered fully routed if both IPv4 and IPv6 have
either a default route or a prohibit route.

Bug: 145332510
Test: atest FrameworksNetTests
Merged-In: I59cf48552bca98092d1212e3d718fd420add5458
Change-Id: I59cf48552bca98092d1212e3d718fd420add5458
parent 8e6f66bd
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -1073,6 +1073,21 @@ public final class LinkProperties implements Parcelable {
        return false;
    }

    /**
     * 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
@@ -1101,6 +1116,21 @@ public final class LinkProperties implements Parcelable {
        return false;
    }

    /**
     * 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
+26 −0
Original line number Diff line number Diff line
@@ -425,6 +425,16 @@ public final class RouteInfo implements Parcelable {
        return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
    }

    /**
     * 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
@@ -433,6 +443,14 @@ public final class RouteInfo implements Parcelable {
        return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
    }

    /**
     * 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
@@ -441,6 +459,14 @@ public final class RouteInfo implements Parcelable {
        return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
    }

    /**
     * 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).
     *
+2 −1
Original line number Diff line number Diff line
@@ -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,
+25 −0
Original line number Diff line number Diff line
@@ -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;
@@ -1251,4 +1254,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());
    }
}
+58 −0
Original line number Diff line number Diff line
@@ -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
Loading