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

Commit 7d25b9ab authored by Chalard Jean's avatar Chalard Jean Committed by android-build-merger
Browse files

Merge "Limit the number of routes for performance"

am: b8a1509d

Change-Id: If4de2779b24560f75a7bb977dbb0f996115a0648
parents 3621eb75 b8a1509d
Loading
Loading
Loading
Loading
+10 −1
Original line number Diff line number Diff line
@@ -151,6 +151,13 @@ public class Vpn {
                .multiply(BigInteger.valueOf(howManyPercentIsMost))
                .divide(BigInteger.valueOf(100));
    }
    // How many routes to evaluate before bailing and declaring this Vpn should provide
    // the INTERNET capability. This is necessary because computing the adress space is
    // O(n²) and this is running in the system service, so a limit is needed to alleviate
    // the risk of attack.
    // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
    // is actually O(n²)+O(n²).
    private static final int MAX_ROUTES_TO_EVALUATE = 150;

    // TODO: create separate trackers for each unique VPN to support
    // automated reconnection
@@ -862,10 +869,12 @@ public class Vpn {
     */
    @VisibleForTesting
    static boolean providesRoutesToMostDestinations(LinkProperties lp) {
        final List<RouteInfo> routes = lp.getAllRoutes();
        if (routes.size() > MAX_ROUTES_TO_EVALUATE) return true;
        final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
        TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
        TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
        for (final RouteInfo route : lp.getAllRoutes()) {
        for (final RouteInfo route : routes) {
            IpPrefix destination = route.getDestination();
            if (destination.isIPv4()) {
                ipv4Prefixes.add(destination);
+31 −0
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import android.os.Build.VERSION_CODES;
import android.os.Bundle;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.test.filters.SmallTest;
@@ -88,6 +89,8 @@ import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -639,4 +642,32 @@ public class VpnTest {
        lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
    }

    @Test
    public void testDoesNotLockUpWithTooManyRoutes() {
        final LinkProperties lp = new LinkProperties();
        final byte[] ad = new byte[4];
        // Actually evaluating this many routes under 1500ms is impossible on
        // current hardware and for some time, as the algorithm is O(n²).
        // Make sure the system has a safeguard against this and does not
        // lock up.
        final int MAX_ROUTES = 4000;
        final long MAX_ALLOWED_TIME_MS = 1500;
        for (int i = 0; i < MAX_ROUTES; ++i) {
            ad[0] = (byte)((i >> 24) & 0xFF);
            ad[1] = (byte)((i >> 16) & 0xFF);
            ad[2] = (byte)((i >> 8) & 0xFF);
            ad[3] = (byte)(i & 0xFF);
            try {
                lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
            } catch (UnknownHostException e) {
                // UnknownHostException is only thrown for an address of illegal length,
                // which can't happen in the case above.
            }
        }
        final long start = SystemClock.currentThreadTimeMillis();
        assertTrue(Vpn.providesRoutesToMostDestinations(lp));
        final long end = SystemClock.currentThreadTimeMillis();
        assertTrue(end - start < MAX_ALLOWED_TIME_MS);
    }
}