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

Commit 02d3c218 authored by Paul Hu's avatar Paul Hu Committed by Android (Google) Code Review
Browse files

Merge "Record VPN connection IP protocols" into main

parents 40d44785 a5595b66
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2992,6 +2992,9 @@ public class Vpn {
            // The update on VPN and the IPsec tunnel will be done when migration is fully complete
            // in onChildMigrated
            mIkeConnectionInfo = ikeConnectionInfo;
            if (mVpnConnectivityMetrics != null) {
                mVpnConnectivityMetrics.setServerIpProtocol(ikeConnectionInfo.getRemoteAddress());
            }
        }

        /**
@@ -3061,6 +3064,9 @@ public class Vpn {

                    mConfig.addresses.clear();
                    mConfig.addresses.addAll(internalAddresses);
                    if (mVpnConnectivityMetrics != null) {
                        mVpnConnectivityMetrics.setVpnNetworkIpProtocol(mConfig.addresses);
                    }

                    mConfig.routes.clear();
                    mConfig.routes.addAll(newRoutes);
+68 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;

import android.net.ConnectivityManager;
import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.VpnManager;
@@ -38,6 +39,8 @@ import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.List;

@@ -50,6 +53,15 @@ public class VpnConnectivityMetrics {
    public static final int VPN_TYPE_UNKNOWN = 0;
    public static final int VPN_PROFILE_TYPE_UNKNOWN = 0;
    private static final int UNKNOWN_UNDERLYING_NETWORK_TYPE = -1;
    // Copied from corenetworking platform vpn enum
    @VisibleForTesting
    static final int IP_PROTOCOL_UNKNOWN = 0;
    @VisibleForTesting
    static final int IP_PROTOCOL_IPv4 = 1;
    @VisibleForTesting
    static final int IP_PROTOCOL_IPv6 = 2;
    @VisibleForTesting
    static final int IP_PROTOCOL_IPv4v6 = 3;
    private static final SparseArray<String> sAlgorithms = new SparseArray<>();
    private final int mUserId;
    @NonNull
@@ -75,6 +87,8 @@ public class VpnConnectivityMetrics {
     */
    @NonNull
    private int[] mUnderlyingNetworkTypes;
    private int mVpnNetworkIpProtocol = IP_PROTOCOL_UNKNOWN;
    private int mServerIpProtocol = IP_PROTOCOL_UNKNOWN;

    // Static initializer block to populate the sAlgorithms mapping. It associates integer keys
    // (which also serve as bit positions for the mAllowedAlgorithms bitmask) with their
@@ -197,4 +211,58 @@ public class VpnConnectivityMetrics {
            mUnderlyingNetworkTypes = new int[0];
        }
    }

    /**
     * Sets the IP protocol for the vpn network based on a list of {@link LinkAddress} objects.
     *
     * @param addresses A list of {@link LinkAddress} objects representing the IP addresses
     *                  configured on the VPN network.
     */
    public void setVpnNetworkIpProtocol(@NonNull List<LinkAddress> addresses) {
        mVpnNetworkIpProtocol = checkIpProtocol(addresses);
    }

    /**
     * Sets the IP protocol for the server based on its {@link InetAddress}.
     *
     * @param address The {@link InetAddress} of the server.
     */
    public void setServerIpProtocol(@NonNull InetAddress address) {
        // Assume that if the address is not IPv4, it is IPv6. It does not consider other cases like
        // IPv4-mapped IPv6 addresses.
        if (address instanceof Inet4Address) {
            mServerIpProtocol = IP_PROTOCOL_IPv4;
        } else {
            mServerIpProtocol = IP_PROTOCOL_IPv6;
        }
    }

    /**
     * Analyzes a list of {@link LinkAddress} objects to determine the overall IP protocol(s) in
     * use.
     *
     * @param addresses A list of {@link LinkAddress} objects to be checked.
     * @return An integer representing the detected IP protocol.
     */
    @VisibleForTesting
    static int checkIpProtocol(@NonNull List<LinkAddress> addresses) {
        boolean hasIpv4 = false;
        boolean hasIpv6 = false;
        int ipProtocol = IP_PROTOCOL_UNKNOWN;
        for (LinkAddress address : addresses) {
            if (address.isIpv4()) {
                hasIpv4 = true;
            } else if (address.isIpv6()) {
                hasIpv6 = true;
            }
        }
        if (hasIpv4 && hasIpv6) {
            ipProtocol = IP_PROTOCOL_IPv4v6;
        } else if (hasIpv4) {
            ipProtocol = IP_PROTOCOL_IPv4;
        } else if (hasIpv6) {
            ipProtocol = IP_PROTOCOL_IPv6;
        }
        return ipProtocol;
    }
}
+17 −0
Original line number Diff line number Diff line
@@ -28,13 +28,19 @@ import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512;
import static android.net.IpSecAlgorithm.CRYPT_AES_CBC;
import static android.net.IpSecAlgorithm.CRYPT_AES_CTR;

import static com.android.server.connectivity.VpnConnectivityMetrics.IP_PROTOCOL_IPv4;
import static com.android.server.connectivity.VpnConnectivityMetrics.IP_PROTOCOL_IPv4v6;
import static com.android.server.connectivity.VpnConnectivityMetrics.IP_PROTOCOL_IPv6;
import static com.android.server.connectivity.VpnConnectivityMetrics.IP_PROTOCOL_UNKNOWN;
import static com.android.testutils.Cleanup.testAndCleanup;
import static com.android.server.connectivity.VpnConnectivityMetrics.buildAllowedAlgorithmsBitmask;
import static com.android.server.connectivity.VpnConnectivityMetrics.checkIpProtocol;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import android.net.Ikev2VpnProfile;
import android.net.LinkAddress;
import android.util.Log;

import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -71,4 +77,15 @@ public class VpnConnectivityMetricsTest {
            assertTrue(hasFailed.get());
        }, () -> Log.setWtfHandler(originalHandler));
    }

    @Test
    public void testCheckIpProtocol() {
        final LinkAddress vpnClientIpv4 = new LinkAddress("192.0.2.1/32");
        final LinkAddress vpnClientIpv6 = new LinkAddress("2001:db8:1:2::ffe/128");

        assertEquals(IP_PROTOCOL_UNKNOWN, checkIpProtocol(List.of()));
        assertEquals(IP_PROTOCOL_IPv4, checkIpProtocol(List.of(vpnClientIpv4)));
        assertEquals(IP_PROTOCOL_IPv6, checkIpProtocol(List.of(vpnClientIpv6)));
        assertEquals(IP_PROTOCOL_IPv4v6, checkIpProtocol(List.of(vpnClientIpv4, vpnClientIpv6)));
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -180,6 +180,7 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.CollectionUtils;
import com.android.server.DeviceIdleInternal;
import com.android.server.IpSecService;
import com.android.server.VpnTestBase;
@@ -2219,6 +2220,13 @@ public class VpnTest extends VpnTestBase {
                any(), any(), anyString(), ncCaptor.capture(), lpCaptor.capture(),
                any(), nacCaptor.capture(), any(), any());
        verify(mIkeSessionWrapper).setUnderpinnedNetwork(TEST_NETWORK);
        verify(mVpnConnectivityMetrics).setUnderlyingNetwork(any());
        verify(mVpnConnectivityMetrics).setVpnNetworkIpProtocol(argThat(addresses ->
                CollectionUtils.all(List.of(
                                new LinkAddress(TEST_VPN_INTERNAL_IP, IP4_PREFIX_LEN),
                                new LinkAddress(TEST_VPN_INTERNAL_IP6, IP6_PREFIX_LEN)),
                        address -> addresses.contains(address))));
        verify(mVpnConnectivityMetrics).setServerIpProtocol(TEST_VPN_SERVER_IP);
        // Check LinkProperties
        final LinkProperties lp = lpCaptor.getValue();
        final List<RouteInfo> expectedRoutes =