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

Commit 080f2179 authored by Rubin Xu's avatar Rubin Xu
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
Change-Id: I59cf48552bca98092d1212e3d718fd420add5458
parent 2ec47eeb
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -1073,6 +1073,21 @@ public final class LinkProperties implements Parcelable {
        return false;
        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.
     * For backward compatibility.
     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
     * 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;
        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.
     * For backward compatibility.
     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
     * This was annotated with @UnsupportedAppUsage in P, so we can't remove the method completely
+26 −0
Original line number Original line Diff line number Diff line
@@ -425,6 +425,16 @@ public final class RouteInfo implements Parcelable {
        return mType == RTN_UNICAST && mDestination.getPrefixLength() == 0;
        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.
     * Indicates if this route is an IPv4 default route.
     * @hide
     * @hide
@@ -433,6 +443,14 @@ public final class RouteInfo implements Parcelable {
        return isDefaultRoute() && mDestination.getAddress() instanceof Inet4Address;
        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.
     * Indicates if this route is an IPv6 default route.
     * @hide
     * @hide
@@ -441,6 +459,14 @@ public final class RouteInfo implements Parcelable {
        return isDefaultRoute() && mDestination.getAddress() instanceof Inet6Address;
        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).
     * Indicates if this route is a host route (ie, matches only a single host address).
     *
     *
+2 −1
Original line number Original line Diff line number Diff line
@@ -6304,7 +6304,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
                && !nai.networkAgentConfig.allowBypass
                && !nai.networkAgentConfig.allowBypass
                && nc.getOwnerUid() != Process.SYSTEM_UID
                && nc.getOwnerUid() != Process.SYSTEM_UID
                && lp.getInterfaceName() != null
                && lp.getInterfaceName() != null
                && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
                && (lp.hasIPv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
                && (lp.hasIPv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
    }
    }


    private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
    private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
+25 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package android.net;
package android.net;


import static android.net.RouteInfo.RTN_UNREACHABLE;

import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelSane;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtilsKt.assertParcelingIsLossless;
import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
import static com.android.testutils.ParcelUtilsKt.parcelingRoundTrip;
@@ -46,6 +48,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runner.RunWith;


import java.net.Inet4Address;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
@@ -1257,4 +1260,26 @@ public class LinkPropertiesTest {
        final LinkProperties Ipv6 = makeIpv6LinkProperties();
        final LinkProperties Ipv6 = makeIpv6LinkProperties();
        assertTrue(Ipv6.hasIpv6DnsServer());
        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 Original line Diff line number Diff line
@@ -31,6 +31,7 @@ import static org.junit.Assert.fail;


import android.os.Build;
import android.os.Build;


import androidx.core.os.BuildCompat;
import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.runner.AndroidJUnit4;


@@ -62,6 +63,11 @@ public class RouteInfoTest {
        return new IpPrefix(prefix);
        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
    @Test
    public void testConstructor() {
    public void testConstructor() {
        RouteInfo r;
        RouteInfo r;
@@ -195,78 +201,130 @@ public class RouteInfoTest {
        assertTrue(r.isDefaultRoute());
        assertTrue(r.isDefaultRoute());
        assertTrue(r.isIPv4Default());
        assertTrue(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
        r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
        assertFalse(r.isHostRoute());
        assertFalse(r.isHostRoute());
        assertTrue(r.isDefaultRoute());
        assertTrue(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertTrue(r.isIPv6Default());
        assertTrue(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
        r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
        assertFalse(r.isHostRoute());
        assertFalse(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
        r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
        assertFalse(r.isHostRoute());
        assertFalse(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        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");
        r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
        r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
        r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
        r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
        r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        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");
        r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        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");
        r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
        assertTrue(r.isHostRoute());
        assertTrue(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
        r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
        assertFalse(r.isHostRoute());
        assertFalse(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertTrue(r.isIPv4UnreachableDefault());
            assertFalse(r.isIPv6UnreachableDefault());
        }


        r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
        r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
        assertFalse(r.isHostRoute());
        assertFalse(r.isHostRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isDefaultRoute());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv4Default());
        assertFalse(r.isIPv6Default());
        assertFalse(r.isIPv6Default());
        if (isAtLeastR()) {
            assertFalse(r.isIPv4UnreachableDefault());
            assertTrue(r.isIPv6UnreachableDefault());
        }
    }
    }


    @Test
    @Test
Loading