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

Commit a5595b66 authored by Paul Hu's avatar Paul Hu
Browse files

Record VPN connection IP protocols

Bug: 306313287
Test: atest FrameworksVpnTests
Flag: android.net.platform.flags.collect_vpn_metrics
Change-Id: Ie99c35e6eb58a0863caa435f0442fce0c0ea2ef8
parent a924d42f
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 =