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

Commit 7bec751f authored by Android Build Merger (Role)'s avatar Android Build Merger (Role) Committed by Android (Google) Code Review
Browse files

Merge "Merge "Added implementation for VTI add/remove address" am: 2543fbd8...

Merge "Merge "Added implementation for VTI add/remove address" am: 2543fbd8 am: 9dda91f8" into pi-dev-plus-aosp
parents 84022530 2e67bf5c
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.net;

import android.net.LinkAddress;
import android.net.Network;
import android.net.IpSecConfig;
import android.net.IpSecUdpEncapResponse;
@@ -48,11 +49,11 @@ interface IIpSecService

    void addAddressToTunnelInterface(
            int tunnelResourceId,
            String localAddr);
            in LinkAddress localAddr);

    void removeAddressFromTunnelInterface(
            int tunnelResourceId,
            String localAddr);
            in LinkAddress localAddr);

    void deleteTunnelInterface(int resourceId);

+12 −4
Original line number Diff line number Diff line
@@ -656,10 +656,14 @@ public final class IpSecManager {
         * tunneled traffic.
         *
         * @param address the local address for traffic inside the tunnel
         * @throws IOException if the address could not be added
         * @hide
         */
        public void addAddress(LinkAddress address) throws IOException {
        public void addAddress(LinkAddress address) {
            try {
                mService.addAddressToTunnelInterface(mResourceId, address);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        /**
@@ -668,10 +672,14 @@ public final class IpSecManager {
         * <p>Remove an address which was previously added to the IpSecTunnelInterface
         *
         * @param address to be removed
         * @throws IOException if the address could not be removed
         * @hide
         */
        public void removeAddress(LinkAddress address) throws IOException {
        public void removeAddress(LinkAddress address) {
            try {
                mService.removeAddressFromTunnelInterface(mResourceId, address);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }

        private IpSecTunnelInterface(@NonNull IIpSecService service,
+42 −18
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.net.IpSecTransform;
import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.IpSecUdpEncapResponse;
import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkUtils;
import android.net.TrafficStats;
@@ -618,10 +619,8 @@ public class IpSecService extends IIpSecService.Stub {
                                spi,
                                mConfig.getMarkValue(),
                                mConfig.getMarkMask());
            } catch (ServiceSpecificException e) {
                // FIXME: get the error code and throw is at an IOException from Errno Exception
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to delete SA with ID: " + mResourceId);
            } catch (RemoteException | ServiceSpecificException e) {
                Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
            }

            getResourceTracker().give();
@@ -681,10 +680,8 @@ public class IpSecService extends IIpSecService.Stub {
                        .getNetdInstance()
                        .ipSecDeleteSecurityAssociation(
                                mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
            } catch (ServiceSpecificException e) {
                // FIXME: get the error code and throw is at an IOException from Errno Exception
            } catch (RemoteException e) {
                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId);
            } catch (ServiceSpecificException | RemoteException e) {
                Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
            }

            mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
@@ -829,15 +826,13 @@ public class IpSecService extends IIpSecService.Stub {
                                        0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff);
                    }
                }
            } catch (ServiceSpecificException e) {
                // FIXME: get the error code and throw is at an IOException from Errno Exception
            } catch (RemoteException e) {
            } catch (ServiceSpecificException | RemoteException e) {
                Log.e(
                        TAG,
                        "Failed to delete VTI with interface name: "
                                + mInterfaceName
                                + " and id: "
                                + mResourceId);
                                + mResourceId, e);
            }

            getResourceTracker().give();
@@ -1319,7 +1314,9 @@ public class IpSecService extends IIpSecService.Stub {
     * from multiple local IP addresses over the same tunnel.
     */
    @Override
    public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) {
    public synchronized void addAddressToTunnelInterface(
            int tunnelResourceId, LinkAddress localAddr) {
        enforceNetworkStackPermission();
        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());

        // Get tunnelInterface record; if no such interface is found, will throw
@@ -1327,8 +1324,21 @@ public class IpSecService extends IIpSecService.Stub {
        TunnelInterfaceRecord tunnelInterfaceInfo =
                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);

        // TODO: Add calls to netd:
        //       Add address to TunnelInterface
        try {
            // We can assume general validity of the IP address, since we get them as a
            // LinkAddress, which does some validation.
            mSrvConfig
                    .getNetdInstance()
                    .interfaceAddAddress(
                            tunnelInterfaceInfo.mInterfaceName,
                            localAddr.getAddress().getHostAddress(),
                            localAddr.getPrefixLength());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
            // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
            throw new IllegalArgumentException(e);
        }
    }

    /**
@@ -1337,7 +1347,8 @@ public class IpSecService extends IIpSecService.Stub {
     */
    @Override
    public synchronized void removeAddressFromTunnelInterface(
            int tunnelResourceId, String localAddr) {
            int tunnelResourceId, LinkAddress localAddr) {
        enforceNetworkStackPermission();
        UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());

        // Get tunnelInterface record; if no such interface is found, will throw
@@ -1345,8 +1356,21 @@ public class IpSecService extends IIpSecService.Stub {
        TunnelInterfaceRecord tunnelInterfaceInfo =
                userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId);

        // TODO: Add calls to netd:
        //       Remove address from TunnelInterface
        try {
            // We can assume general validity of the IP address, since we get them as a
            // LinkAddress, which does some validation.
            mSrvConfig
                    .getNetdInstance()
                    .interfaceDelAddress(
                            tunnelInterfaceInfo.mInterfaceName,
                            localAddr.getAddress().getHostAddress(),
                            localAddr.getPrefixLength());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } catch (ServiceSpecificException e) {
            // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw.
            throw new IllegalArgumentException(e);
        }
    }

    /**
+55 −13
Original line number Diff line number Diff line
@@ -50,13 +50,18 @@ public class IpSecManagerTest {

    private static final int TEST_UDP_ENCAP_PORT = 34567;
    private static final int DROID_SPI = 0xD1201D;
    private static final int DUMMY_RESOURCE_ID = 0x1234;

    private static final InetAddress GOOGLE_DNS_4;
    private static final String VTI_INTF_NAME = "ipsec_test";
    private static final InetAddress VTI_LOCAL_ADDRESS;
    private static final LinkAddress VTI_INNER_ADDRESS = new LinkAddress("10.0.1.1/24");

    static {
        try {
            // Google Public DNS Addresses;
            GOOGLE_DNS_4 = InetAddress.getByName("8.8.8.8");
            VTI_LOCAL_ADDRESS = InetAddress.getByName("8.8.4.4");
        } catch (UnknownHostException e) {
            throw new RuntimeException("Could not resolve DNS Addresses", e);
        }
@@ -77,9 +82,8 @@ public class IpSecManagerTest {
     */
    @Test
    public void testAllocSpi() throws Exception {
        int resourceId = 1;
        IpSecSpiResponse spiResp =
                new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
                new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
        when(mMockIpSecService.allocateSecurityParameterIndex(
                        eq(GOOGLE_DNS_4.getHostAddress()),
                        eq(DROID_SPI),
@@ -92,14 +96,13 @@ public class IpSecManagerTest {

        droidSpi.close();

        verify(mMockIpSecService).releaseSecurityParameterIndex(resourceId);
        verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
    }

    @Test
    public void testAllocRandomSpi() throws Exception {
        int resourceId = 1;
        IpSecSpiResponse spiResp =
                new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, DROID_SPI);
                new IpSecSpiResponse(IpSecManager.Status.OK, DUMMY_RESOURCE_ID, DROID_SPI);
        when(mMockIpSecService.allocateSecurityParameterIndex(
                        eq(GOOGLE_DNS_4.getHostAddress()),
                        eq(IpSecManager.INVALID_SECURITY_PARAMETER_INDEX),
@@ -113,7 +116,7 @@ public class IpSecManagerTest {

        randomSpi.close();

        verify(mMockIpSecService).releaseSecurityParameterIndex(resourceId);
        verify(mMockIpSecService).releaseSecurityParameterIndex(DUMMY_RESOURCE_ID);
    }

    /*
@@ -165,11 +168,10 @@ public class IpSecManagerTest {

    @Test
    public void testOpenEncapsulationSocket() throws Exception {
        int resourceId = 1;
        IpSecUdpEncapResponse udpEncapResp =
                new IpSecUdpEncapResponse(
                        IpSecManager.Status.OK,
                        resourceId,
                        DUMMY_RESOURCE_ID,
                        TEST_UDP_ENCAP_PORT,
                        Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));
        when(mMockIpSecService.openUdpEncapsulationSocket(eq(TEST_UDP_ENCAP_PORT), anyObject()))
@@ -182,16 +184,15 @@ public class IpSecManagerTest {

        encapSocket.close();

        verify(mMockIpSecService).closeUdpEncapsulationSocket(resourceId);
        verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
    }

    @Test
    public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
        int resourceId = 1;
        IpSecUdpEncapResponse udpEncapResp =
                new IpSecUdpEncapResponse(
                        IpSecManager.Status.OK,
                        resourceId,
                        DUMMY_RESOURCE_ID,
                        TEST_UDP_ENCAP_PORT,
                        Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP));

@@ -206,7 +207,7 @@ public class IpSecManagerTest {

        encapSocket.close();

        verify(mMockIpSecService).closeUdpEncapsulationSocket(resourceId);
        verify(mMockIpSecService).closeUdpEncapsulationSocket(DUMMY_RESOURCE_ID);
    }

    @Test
@@ -219,4 +220,45 @@ public class IpSecManagerTest {
    }

    // TODO: add test when applicable transform builder interface is available

    private IpSecManager.IpSecTunnelInterface createAndValidateVti(int resourceId, String intfName)
            throws Exception {
        IpSecTunnelInterfaceResponse dummyResponse =
                new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
        when(mMockIpSecService.createTunnelInterface(
                eq(VTI_LOCAL_ADDRESS.getHostAddress()), eq(GOOGLE_DNS_4.getHostAddress()),
                anyObject(), anyObject()))
                        .thenReturn(dummyResponse);

        IpSecManager.IpSecTunnelInterface tunnelIntf = mIpSecManager.createIpSecTunnelInterface(
                VTI_LOCAL_ADDRESS, GOOGLE_DNS_4, mock(Network.class));

        assertNotNull(tunnelIntf);
        return tunnelIntf;
    }

    @Test
    public void testCreateVti() throws Exception {
        IpSecManager.IpSecTunnelInterface tunnelIntf =
                createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);

        assertEquals(VTI_INTF_NAME, tunnelIntf.getInterfaceName());

        tunnelIntf.close();
        verify(mMockIpSecService).deleteTunnelInterface(eq(DUMMY_RESOURCE_ID));
    }

    @Test
    public void testAddRemoveAddressesFromVti() throws Exception {
        IpSecManager.IpSecTunnelInterface tunnelIntf =
                createAndValidateVti(DUMMY_RESOURCE_ID, VTI_INTF_NAME);

        tunnelIntf.addAddress(VTI_INNER_ADDRESS);
        verify(mMockIpSecService)
                .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));

        tunnelIntf.removeAddress(VTI_INNER_ADDRESS);
        verify(mMockIpSecService)
                .addAddressToTunnelInterface(eq(DUMMY_RESOURCE_ID), eq(VTI_INNER_ADDRESS));
    }
}
 No newline at end of file
+113 −2
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
@@ -32,6 +33,9 @@ import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecSpiResponse;
import android.net.IpSecTransformResponse;
import android.net.IpSecTunnelInterfaceResponse;
import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkUtils;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
@@ -56,10 +60,15 @@ public class IpSecServiceParameterizedTest {

    private final String mDestinationAddr;
    private final String mSourceAddr;
    private final LinkAddress mLocalInnerAddress;

    @Parameterized.Parameters
    public static Collection ipSecConfigs() {
        return Arrays.asList(new Object[][] {{"1.2.3.4", "8.8.4.4"}, {"2601::2", "2601::10"}});
        return Arrays.asList(
                new Object[][] {
                {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"},
                {"2601::2", "2601::10", "2001:db8::1/64"}
        });
    }

    private static final byte[] AEAD_KEY = {
@@ -86,6 +95,7 @@ public class IpSecServiceParameterizedTest {
    INetd mMockNetd;
    IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
    IpSecService mIpSecService;
    Network fakeNetwork = new Network(0xAB);

    private static final IpSecAlgorithm AUTH_ALGO =
            new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
@@ -94,9 +104,11 @@ public class IpSecServiceParameterizedTest {
    private static final IpSecAlgorithm AEAD_ALGO =
            new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);

    public IpSecServiceParameterizedTest(String sourceAddr, String destAddr) {
    public IpSecServiceParameterizedTest(
            String sourceAddr, String destAddr, String localInnerAddr) {
        mSourceAddr = sourceAddr;
        mDestinationAddr = destAddr;
        mLocalInnerAddress = new LinkAddress(localInnerAddr);
    }

    @Before
@@ -406,4 +418,103 @@ public class IpSecServiceParameterizedTest {

        verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
    }

    private IpSecTunnelInterfaceResponse createAndValidateTunnel(
            String localAddr, String remoteAddr) {
        IpSecTunnelInterfaceResponse createTunnelResp =
                mIpSecService.createTunnelInterface(
                        mSourceAddr, mDestinationAddr, fakeNetwork, new Binder());

        assertNotNull(createTunnelResp);
        assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
        return createTunnelResp;
    }

    @Test
    public void testCreateTunnelInterface() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr);

        // Check that we have stored the tracking object, and retrieve it
        IpSecService.UserRecord userRecord =
                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
        IpSecService.RefcountedResource refcountedRecord =
                userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                        createTunnelResp.resourceId);

        assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
        verify(mMockNetd)
                .addVirtualTunnelInterface(
                        eq(createTunnelResp.interfaceName),
                        eq(mSourceAddr),
                        eq(mDestinationAddr),
                        anyInt(),
                        anyInt());
    }

    @Test
    public void testDeleteTunnelInterface() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr);

        IpSecService.UserRecord userRecord =
                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());

        mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId);

        // Verify quota and RefcountedResource objects cleaned up
        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
        try {
            userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                    createTunnelResp.resourceId);
            fail("Expected IllegalArgumentException on attempt to access deleted resource");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testTunnelInterfaceBinderDeath() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr);

        IpSecService.UserRecord userRecord =
                mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
        IpSecService.RefcountedResource refcountedRecord =
                userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                        createTunnelResp.resourceId);

        refcountedRecord.binderDied();

        // Verify quota and RefcountedResource objects cleaned up
        assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
        try {
            userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                    createTunnelResp.resourceId);
            fail("Expected IllegalArgumentException on attempt to access deleted resource");
        } catch (IllegalArgumentException expected) {
        }
    }

    @Test
    public void testAddRemoveAddressFromTunnelInterface() throws Exception {
        IpSecTunnelInterfaceResponse createTunnelResp =
                createAndValidateTunnel(mSourceAddr, mDestinationAddr);

        mIpSecService.addAddressToTunnelInterface(createTunnelResp.resourceId, mLocalInnerAddress);
        verify(mMockNetd)
                .interfaceAddAddress(
                        eq(createTunnelResp.interfaceName),
                        eq(mLocalInnerAddress.getAddress().getHostAddress()),
                        eq(mLocalInnerAddress.getPrefixLength()));

        mIpSecService.removeAddressFromTunnelInterface(
                createTunnelResp.resourceId, mLocalInnerAddress);
        verify(mMockNetd)
                .interfaceDelAddress(
                        eq(createTunnelResp.interfaceName),
                        eq(mLocalInnerAddress.getAddress().getHostAddress()),
                        eq(mLocalInnerAddress.getPrefixLength()));
    }
}