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

Commit 6365796f authored by Chalard Jean's avatar Chalard Jean Committed by android-build-merger
Browse files

Merge changes Ia43f8811,I7de4f672 am: 3ef04b8e am: cbaed4e7 am: 40b8170b

am: c900f7e6

Change-Id: Ie13685fab53fb7f2482b9cf0a3294ccb284b71bd
parents 293bb896 c900f7e6
Loading
Loading
Loading
Loading
+16 −60
Original line number Original line Diff line number Diff line
@@ -29,7 +29,6 @@ import android.util.Log;
import android.util.Pair;
import android.util.Pair;


import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetAddress;
@@ -37,7 +36,6 @@ import java.net.SocketException;
import java.net.UnknownHostException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collection;
import java.util.Locale;
import java.util.Locale;
import java.util.TreeSet;


/**
/**
 * Native methods for managing network interfaces.
 * Native methods for managing network interfaces.
@@ -392,72 +390,30 @@ public class NetworkUtils {
        return result;
        return result;
    }
    }


    /**
    private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
     * Returns a prefix set without overlaps.
     *
     * This expects the src set to be sorted from shorter to longer. Results are undefined
     * failing this condition. The returned prefix set is sorted in the same order as the
     * passed set, with the same comparator.
     */
    private static TreeSet<IpPrefix> deduplicatePrefixSet(final TreeSet<IpPrefix> src) {
        final TreeSet<IpPrefix> dst = new TreeSet<>(src.comparator());
        // Prefixes match addresses that share their upper part up to their length, therefore
        // the only kind of possible overlap in two prefixes is strict inclusion of the longer
        // (more restrictive) in the shorter (including equivalence if they have the same
        // length).
        // Because prefixes in the src set are sorted from shorter to longer, deduplicating
        // is done by simply iterating in order, and not adding any longer prefix that is
        // already covered by a shorter one.
        newPrefixes:
        for (IpPrefix newPrefix : src) {
            for (IpPrefix existingPrefix : dst) {
                if (existingPrefix.containsPrefix(newPrefix)) {
                    continue newPrefixes;
                }
            }
            dst.add(newPrefix);
        }
        return dst;
    }


    /**
    /**
     * Returns how many IPv4 addresses match any of the prefixes in the passed ordered set.
     * Returns true if the hostname is weakly validated.
     *
     * @param hostname Name of host to validate.
     * Obviously this returns an integral value between 0 and 2**32.
     * @return True if it's a valid-ish hostname.
     * The behavior is undefined if any of the prefixes is not an IPv4 prefix or if the
     * set is not ordered smallest prefix to longer prefix.
     *
     *
     * @param prefixes the set of prefixes, ordered by length
     * @hide
     */
     */
    public static long routedIPv4AddressCount(final TreeSet<IpPrefix> prefixes) {
    public static boolean isWeaklyValidatedHostname(@NonNull String hostname) {
        long routedIPCount = 0;
        // TODO(b/34953048): Use a validation method that permits more accurate,
        for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
        // but still inexpensive, checking of likely valid DNS hostnames.
            if (!prefix.isIPv4()) {
        final String weakHostnameRegex = "^[a-zA-Z0-9_.-]+$";
                Log.wtf(TAG, "Non-IPv4 prefix in routedIPv4AddressCount");
        if (!hostname.matches(weakHostnameRegex)) {
            }
            return false;
            int rank = 32 - prefix.getPrefixLength();
            routedIPCount += 1L << rank;
        }
        return routedIPCount;
        }
        }


    /**
        for (int address_family : ADDRESS_FAMILIES) {
     * Returns how many IPv6 addresses match any of the prefixes in the passed ordered set.
            if (Os.inet_pton(address_family, hostname) != null) {
     *
                return false;
     * This returns a BigInteger between 0 and 2**128.
     * The behavior is undefined if any of the prefixes is not an IPv6 prefix or if the
     * set is not ordered smallest prefix to longer prefix.
     */
    public static BigInteger routedIPv6AddressCount(final TreeSet<IpPrefix> prefixes) {
        BigInteger routedIPCount = BigInteger.ZERO;
        for (final IpPrefix prefix : deduplicatePrefixSet(prefixes)) {
            if (!prefix.isIPv6()) {
                Log.wtf(TAG, "Non-IPv6 prefix in routedIPv6AddressCount");
            }
            }
            int rank = 128 - prefix.getPrefixLength();
            routedIPCount = routedIPCount.add(BigInteger.ONE.shiftLeft(rank));
        }
        }
        return routedIPCount;

        return true;
    }
    }


    private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
    private static final int[] ADDRESS_FAMILIES = new int[] {AF_INET, AF_INET6};
+9 −71
Original line number Original line Diff line number Diff line
@@ -58,7 +58,6 @@ import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
import android.net.NetworkMisc;
import android.net.NetworkUtils;
import android.net.RouteInfo;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.UidRange;
import android.net.VpnService;
import android.net.VpnService;
@@ -105,7 +104,6 @@ import java.io.File;
import java.io.IOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetAddress;
@@ -114,7 +112,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collection;
import java.util.Collections;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.List;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
@@ -134,31 +131,6 @@ public class Vpn {
    // the device idle whitelist during service launch and VPN bootstrap.
    // the device idle whitelist during service launch and VPN bootstrap.
    private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000;
    private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000;


    // Settings for how much of the address space should be routed so that Vpn considers
    // "most" of the address space is routed. This is used to determine whether this Vpn
    // should be marked with the INTERNET capability.
    private static final long MOST_IPV4_ADDRESSES_COUNT;
    private static final BigInteger MOST_IPV6_ADDRESSES_COUNT;
    static {
        // 85% of the address space must be routed for Vpn to consider this VPN to provide
        // INTERNET access.
        final int howManyPercentIsMost = 85;

        final long twoPower32 = 1L << 32;
        MOST_IPV4_ADDRESSES_COUNT = twoPower32 * howManyPercentIsMost / 100;
        final BigInteger twoPower128 = BigInteger.ONE.shiftLeft(128);
        MOST_IPV6_ADDRESSES_COUNT = twoPower128
                .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 address 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
    // TODO: create separate trackers for each unique VPN to support
    // automated reconnection
    // automated reconnection


@@ -256,7 +228,7 @@ public class Vpn {
    }
    }


    /**
    /**
     * Update current state, dispaching event to listeners.
     * Update current state, dispatching event to listeners.
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    protected void updateState(DetailedState detailedState, String reason) {
    protected void updateState(DetailedState detailedState, String reason) {
@@ -301,7 +273,7 @@ public class Vpn {
    }
    }


    @VisibleForTesting
    @VisibleForTesting
    public static void applyUnderlyingCapabilities(
    static void applyUnderlyingCapabilities(
            ConnectivityManager cm,
            ConnectivityManager cm,
            Network[] underlyingNetworks,
            Network[] underlyingNetworks,
            NetworkCapabilities caps,
            NetworkCapabilities caps,
@@ -901,38 +873,6 @@ public class Vpn {
        return lp;
        return lp;
    }
    }


    /**
     * Analyzes the passed LinkedProperties to figure out whether it routes to most of the IP space.
     *
     * This returns true if the passed LinkedProperties contains routes to either most of the IPv4
     * space or to most of the IPv6 address space, where "most" is defined by the value of the
     * MOST_IPV{4,6}_ADDRESSES_COUNT constants : if more than this number of addresses are matched
     * by any of the routes, then it's decided that most of the space is routed.
     * @hide
     */
    @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 : routes) {
            if (route.getType() == RouteInfo.RTN_UNREACHABLE) continue;
            IpPrefix destination = route.getDestination();
            if (destination.isIPv4()) {
                ipv4Prefixes.add(destination);
            } else {
                ipv6Prefixes.add(destination);
            }
        }
        if (NetworkUtils.routedIPv4AddressCount(ipv4Prefixes) > MOST_IPV4_ADDRESSES_COUNT) {
            return true;
        }
        return NetworkUtils.routedIPv6AddressCount(ipv6Prefixes)
                .compareTo(MOST_IPV6_ADDRESSES_COUNT) >= 0;
    }

    /**
    /**
     * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without
     * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without
     * registering a new NetworkAgent. This is not always possible if the new VPN configuration
     * registering a new NetworkAgent. This is not always possible if the new VPN configuration
@@ -1765,7 +1705,7 @@ public class Vpn {
            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
            byte[] value = keyStore.get(Credentials.USER_CERTIFICATE + profile.ipsecServerCert);
            serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
            serverCert = (value == null) ? null : new String(value, StandardCharsets.UTF_8);
        }
        }
        if (privateKey == null || userCert == null || caCert == null || serverCert == null) {
        if (userCert == null || caCert == null || serverCert == null) {
            throw new IllegalStateException("Cannot load credentials");
            throw new IllegalStateException("Cannot load credentials");
        }
        }


@@ -1884,7 +1824,7 @@ public class Vpn {
     * Return the information of the current ongoing legacy VPN.
     * Return the information of the current ongoing legacy VPN.
     * Callers are responsible for checking permissions if needed.
     * Callers are responsible for checking permissions if needed.
     */
     */
    public synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
    private synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() {
        if (mLegacyVpnRunner == null) return null;
        if (mLegacyVpnRunner == null) return null;


        final LegacyVpnInfo info = new LegacyVpnInfo();
        final LegacyVpnInfo info = new LegacyVpnInfo();
@@ -2038,7 +1978,6 @@ public class Vpn {


        private void bringup() {
        private void bringup() {
            // Catch all exceptions so we can clean up a few things.
            // Catch all exceptions so we can clean up a few things.
            boolean initFinished = false;
            try {
            try {
                // Initialize the timer.
                // Initialize the timer.
                mBringupStartTime = SystemClock.elapsedRealtime();
                mBringupStartTime = SystemClock.elapsedRealtime();
@@ -2057,7 +1996,6 @@ public class Vpn {
                    throw new IllegalStateException("Cannot delete the state");
                    throw new IllegalStateException("Cannot delete the state");
                }
                }
                new File("/data/misc/vpn/abort").delete();
                new File("/data/misc/vpn/abort").delete();
                initFinished = true;


                // Check if we need to restart any of the daemons.
                // Check if we need to restart any of the daemons.
                boolean restart = false;
                boolean restart = false;
+0 −128
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.net;

import static junit.framework.Assert.assertEquals;

import androidx.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.math.BigInteger;
import java.util.TreeSet;

@RunWith(AndroidJUnit4.class)
@androidx.test.filters.SmallTest
public class NetworkUtilsTest {
    @Test
    public void testRoutedIPv4AddressCount() {
        final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
        // No routes routes to no addresses.
        assertEquals(0, NetworkUtils.routedIPv4AddressCount(set));

        set.add(new IpPrefix("0.0.0.0/0"));
        assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));

        set.add(new IpPrefix("20.18.0.0/16"));
        set.add(new IpPrefix("20.18.0.0/24"));
        set.add(new IpPrefix("20.18.0.0/8"));
        // There is a default route, still covers everything
        assertEquals(1l << 32, NetworkUtils.routedIPv4AddressCount(set));

        set.clear();
        set.add(new IpPrefix("20.18.0.0/24"));
        set.add(new IpPrefix("20.18.0.0/8"));
        // The 8-length includes the 24-length prefix
        assertEquals(1l << 24, NetworkUtils.routedIPv4AddressCount(set));

        set.add(new IpPrefix("10.10.10.126/25"));
        // The 8-length does not include this 25-length prefix
        assertEquals((1l << 24) + (1 << 7), NetworkUtils.routedIPv4AddressCount(set));

        set.clear();
        set.add(new IpPrefix("1.2.3.4/32"));
        set.add(new IpPrefix("1.2.3.4/32"));
        set.add(new IpPrefix("1.2.3.4/32"));
        set.add(new IpPrefix("1.2.3.4/32"));
        assertEquals(1l, NetworkUtils.routedIPv4AddressCount(set));

        set.add(new IpPrefix("1.2.3.5/32"));
        set.add(new IpPrefix("1.2.3.6/32"));

        set.add(new IpPrefix("1.2.3.7/32"));
        set.add(new IpPrefix("1.2.3.8/32"));
        set.add(new IpPrefix("1.2.3.9/32"));
        set.add(new IpPrefix("1.2.3.0/32"));
        assertEquals(7l, NetworkUtils.routedIPv4AddressCount(set));

        // 1.2.3.4/30 eats 1.2.3.{4-7}/32
        set.add(new IpPrefix("1.2.3.4/30"));
        set.add(new IpPrefix("6.2.3.4/28"));
        set.add(new IpPrefix("120.2.3.4/16"));
        assertEquals(7l - 4 + 4 + 16 + 65536, NetworkUtils.routedIPv4AddressCount(set));
    }

    @Test
    public void testRoutedIPv6AddressCount() {
        final TreeSet<IpPrefix> set = new TreeSet<>(IpPrefix.lengthComparator());
        // No routes routes to no addresses.
        assertEquals(BigInteger.ZERO, NetworkUtils.routedIPv6AddressCount(set));

        set.add(new IpPrefix("::/0"));
        assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));

        set.add(new IpPrefix("1234:622a::18/64"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
        // There is a default route, still covers everything
        assertEquals(BigInteger.ONE.shiftLeft(128), NetworkUtils.routedIPv6AddressCount(set));

        set.clear();
        set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/96"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6adb/8"));
        // The 8-length includes the 96-length prefix
        assertEquals(BigInteger.ONE.shiftLeft(120), NetworkUtils.routedIPv6AddressCount(set));

        set.add(new IpPrefix("10::26/64"));
        // The 8-length does not include this 64-length prefix
        assertEquals(BigInteger.ONE.shiftLeft(120).add(BigInteger.ONE.shiftLeft(64)),
                NetworkUtils.routedIPv6AddressCount(set));

        set.clear();
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/128"));
        assertEquals(BigInteger.ONE, NetworkUtils.routedIPv6AddressCount(set));

        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad5/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad6/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad7/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad8/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad9/128"));
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad0/128"));
        assertEquals(BigInteger.valueOf(7), NetworkUtils.routedIPv6AddressCount(set));

        // add4:f00:80:f7:1111::6ad4/126 eats add4:f00:8[:f7:1111::6ad{4-7}/128
        set.add(new IpPrefix("add4:f00:80:f7:1111::6ad4/126"));
        set.add(new IpPrefix("d00d:f00:80:f7:1111::6ade/124"));
        set.add(new IpPrefix("f00b:a33::/112"));
        assertEquals(BigInteger.valueOf(7l - 4 + 4 + 16 + 65536),
                NetworkUtils.routedIPv6AddressCount(set));
    }
}