diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 26049cc174..10e43e7b6a 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -76,11 +76,9 @@ public class IpSecBaseTest { protected ConnectivityManager mCM; protected IpSecManager mISM; - protected Context mContext; @Before public void setUp() throws Exception { - mContext = InstrumentationRegistry.getContext(); mISM = (IpSecManager) InstrumentationRegistry.getContext() @@ -475,7 +473,7 @@ public class IpSecBaseTest { private IpSecTransform buildDefaultTransform(InetAddress localAddr) throws Exception { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(localAddr)) { - return buildIpSecTransform(mContext, spi, null, localAddr); + return buildIpSecTransform(InstrumentationRegistry.getContext(), spi, null, localAddr); } } diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index 1241785a17..355b496829 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -41,6 +41,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; import java.io.FileDescriptor; @@ -73,12 +74,6 @@ public class IpSecManagerTest extends IpSecBaseTest { private static final byte[] AEAD_KEY = getKey(288); - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - } - /* * Allocate a random SPI * Allocate a specific SPI using previous randomly created SPI value @@ -244,7 +239,7 @@ public class IpSecManagerTest extends IpSecBaseTest { mISM.allocateSecurityParameterIndex(localAddr); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)) .setAuthentication( new IpSecAlgorithm( @@ -462,7 +457,8 @@ public class IpSecManagerTest extends IpSecBaseTest { IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local)) { - IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + IpSecTransform.Builder transformBuilder = + new IpSecTransform.Builder(InstrumentationRegistry.getContext()); if (crypt != null) { transformBuilder.setEncryption(crypt); } @@ -623,7 +619,7 @@ public class IpSecManagerTest extends IpSecBaseTest { try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(local); IpSecTransform transform = - new IpSecTransform.Builder(mContext) + new IpSecTransform.Builder(InstrumentationRegistry.getContext()) .setEncryption(crypt) .setAuthentication(auth) .setIpv4Encapsulation(encapSocket, encapSocket.getPort()) diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index ef6bfc04b2..999d2f187b 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -129,15 +129,15 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // right appop permissions. setAppop(OP_MANAGE_IPSEC_TUNNELS, true); - TestNetworkInterface testIntf = + TestNetworkInterface testIface = sTNM.createTunInterface( new LinkAddress[] { new LinkAddress(LOCAL_OUTER_4, IP4_PREFIX_LEN), new LinkAddress(LOCAL_OUTER_6, IP6_PREFIX_LEN) }); - sTunFd = testIntf.getFileDescriptor(); - sTunNetworkCallback = setupAndGetTestNetwork(testIntf.getInterfaceName()); + sTunFd = testIface.getFileDescriptor(); + sTunNetworkCallback = setupAndGetTestNetwork(testIface.getInterfaceName()); sTunNetwork = sTunNetworkCallback.getNetworkBlocking(); sTunUtils = new TunUtils(sTunFd); @@ -242,8 +242,16 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { } /* Test runnables for callbacks after IPsec tunnels are set up. */ - private interface TestRunnable { - void run(Network ipsecNetwork) throws Exception; + private abstract class IpSecTunnelTestRunnable { + /** + * Runs the test code, and returns the inner socket port, if any. + * + * @param ipsecNetwork The IPsec Interface based Network for binding sockets on + * @return the integer port of the inner socket if outbound, or 0 if inbound + * IpSecTunnelTestRunnable + * @throws Exception if any part of the test failed. + */ + public abstract int run(Network ipsecNetwork) throws Exception; } private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback { @@ -290,8 +298,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { return expectedPacketSize; } - private interface TestRunnableFactory { - TestRunnable getTestRunnable( + private interface IpSecTunnelTestRunnableFactory { + IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, @@ -301,12 +309,13 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, int encapPort, + int innerSocketPort, int expectedPacketSize) throws Exception; } - private class OutputTestRunnableFactory implements TestRunnableFactory { - public TestRunnable getTestRunnable( + private class OutputIpSecTunnelTestRunnableFactory implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, @@ -316,13 +325,15 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, int encapPort, + int unusedInnerSocketPort, int expectedPacketSize) { - return new TestRunnable() { + return new IpSecTunnelTestRunnable() { @Override - public void run(Network ipsecNetwork) throws Exception { + public int run(Network ipsecNetwork) throws Exception { // Build a socket and send traffic JavaUdpSocket socket = new JavaUdpSocket(localInner); ipsecNetwork.bindSocket(socket.mSocket); + int innerSocketPort = socket.getPort(); // For Transport-In-Tunnel mode, apply transform to socket if (transportInTunnelMode) { @@ -335,19 +346,22 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { socket.sendTo(TEST_DATA, remoteInner, socket.getPort()); // Verify that an encrypted packet is sent. As of right now, checking encrypted - // body is not possible, due to our not knowing some of the fields of the + // body is not possible, due to the test not knowing some of the fields of the // inner IP header (flow label, flags, etc) sTunUtils.awaitEspPacketNoPlaintext( spi, TEST_DATA, encapPort != 0, expectedPacketSize); socket.close(); + + return innerSocketPort; } }; } } - private class InputPacketGeneratorTestRunnableFactory implements TestRunnableFactory { - public TestRunnable getTestRunnable( + private class InputReflectedIpSecTunnelTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( boolean transportInTunnelMode, int spi, InetAddress localInner, @@ -357,14 +371,57 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { IpSecTransform inTransportTransform, IpSecTransform outTransportTransform, int encapPort, + int innerSocketPort, int expectedPacketSize) throws Exception { - return new TestRunnable() { + return new IpSecTunnelTestRunnable() { @Override - public void run(Network ipsecNetwork) throws Exception { + public int run(Network ipsecNetwork) throws Exception { + // Build a socket and receive traffic + JavaUdpSocket socket = new JavaUdpSocket(localInner, innerSocketPort); + ipsecNetwork.bindSocket(socket.mSocket); + + // For Transport-In-Tunnel mode, apply transform to socket + if (transportInTunnelMode) { + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_IN, outTransportTransform); + mISM.applyTransportModeTransform( + socket.mSocket, IpSecManager.DIRECTION_OUT, inTransportTransform); + } + + sTunUtils.reflectPackets(); + + // Receive packet from socket, and validate that the payload is correct + receiveAndValidatePacket(socket); + + socket.close(); + + return 0; + } + }; + } + } + + private class InputPacketGeneratorIpSecTunnelTestRunnableFactory + implements IpSecTunnelTestRunnableFactory { + public IpSecTunnelTestRunnable getIpSecTunnelTestRunnable( + boolean transportInTunnelMode, + int spi, + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + IpSecTransform inTransportTransform, + IpSecTransform outTransportTransform, + int encapPort, + int innerSocketPort, + int expectedPacketSize) + throws Exception { + return new IpSecTunnelTestRunnable() { + @Override + public int run(Network ipsecNetwork) throws Exception { // Build a socket and receive traffic JavaUdpSocket socket = new JavaUdpSocket(localInner); - // JavaUdpSocket socket = new JavaUdpSocket(localInner, socketPort.get()); ipsecNetwork.bindSocket(socket.mSocket); // For Transport-In-Tunnel mode, apply transform to socket @@ -404,6 +461,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { receiveAndValidatePacket(socket); socket.close(); + + return 0; } }; } @@ -417,7 +476,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { outerFamily, useEncap, transportInTunnelMode, - new OutputTestRunnableFactory()); + new OutputIpSecTunnelTestRunnableFactory()); } private void checkTunnelInput( @@ -428,7 +487,91 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { outerFamily, useEncap, transportInTunnelMode, - new InputPacketGeneratorTestRunnableFactory()); + new InputPacketGeneratorIpSecTunnelTestRunnableFactory()); + } + + /** + * Validates that the kernel can talk to itself. + * + *

This test takes an outbound IPsec packet, reflects it (by flipping IP src/dst), and + * injects it back into the TUN. This test then verifies that a packet with the correct payload + * is found on the specified socket/port. + */ + public void checkTunnelReflected( + int innerFamily, int outerFamily, boolean useEncap, boolean transportInTunnelMode) + throws Exception { + if (!hasTunnelsFeature()) return; + + InetAddress localInner = innerFamily == AF_INET ? LOCAL_INNER_4 : LOCAL_INNER_6; + InetAddress remoteInner = innerFamily == AF_INET ? REMOTE_INNER_4 : REMOTE_INNER_6; + + InetAddress localOuter = outerFamily == AF_INET ? LOCAL_OUTER_4 : LOCAL_OUTER_6; + InetAddress remoteOuter = outerFamily == AF_INET ? REMOTE_OUTER_4 : REMOTE_OUTER_6; + + // Preselect both SPI and encap port, to be used for both inbound and outbound tunnels. + int spi = getRandomSpi(localOuter, remoteOuter); + int expectedPacketSize = + getPacketSize(innerFamily, outerFamily, useEncap, transportInTunnelMode); + + try (IpSecManager.SecurityParameterIndex inTransportSpi = + mISM.allocateSecurityParameterIndex(localInner, spi); + IpSecManager.SecurityParameterIndex outTransportSpi = + mISM.allocateSecurityParameterIndex(remoteInner, spi); + IpSecTransform inTransportTransform = + buildIpSecTransform(sContext, inTransportSpi, null, remoteInner); + IpSecTransform outTransportTransform = + buildIpSecTransform(sContext, outTransportSpi, null, localInner); + UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { + + // Run output direction tests + IpSecTunnelTestRunnable outputIpSecTunnelTestRunnable = + new OutputIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + localInner, + remoteInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + 0, + expectedPacketSize); + int innerSocketPort = + buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + outputIpSecTunnelTestRunnable); + + // Input direction tests, with matching inner socket ports. + IpSecTunnelTestRunnable inputIpSecTunnelTestRunnable = + new InputReflectedIpSecTunnelTestRunnableFactory() + .getIpSecTunnelTestRunnable( + transportInTunnelMode, + spi, + remoteInner, + localInner, + localOuter, + remoteOuter, + inTransportTransform, + outTransportTransform, + useEncap ? encapSocket.getPort() : 0, + innerSocketPort, + expectedPacketSize); + buildTunnelNetworkAndRunTests( + remoteInner, + localInner, + localOuter, + remoteOuter, + spi, + useEncap ? encapSocket : null, + inputIpSecTunnelTestRunnable); + } } public void checkTunnel( @@ -436,7 +579,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { int outerFamily, boolean useEncap, boolean transportInTunnelMode, - TestRunnableFactory factory) + IpSecTunnelTestRunnableFactory factory) throws Exception { if (!hasTunnelsFeature()) return; @@ -463,14 +606,14 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { buildIpSecTransform(sContext, outTransportSpi, null, localInner); UdpEncapsulationSocket encapSocket = mISM.openUdpEncapsulationSocket()) { - buildTunnelAndNetwork( + buildTunnelNetworkAndRunTests( localInner, remoteInner, localOuter, remoteOuter, spi, useEncap ? encapSocket : null, - factory.getTestRunnable( + factory.getIpSecTunnelTestRunnable( transportInTunnelMode, spi, localInner, @@ -480,41 +623,42 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { inTransportTransform, outTransportTransform, useEncap ? encapSocket.getPort() : 0, + 0, expectedPacketSize)); } } - private void buildTunnelAndNetwork( + private int buildTunnelNetworkAndRunTests( InetAddress localInner, InetAddress remoteInner, InetAddress localOuter, InetAddress remoteOuter, int spi, UdpEncapsulationSocket encapSocket, - TestRunnable test) + IpSecTunnelTestRunnable test) throws Exception { int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; TestNetworkCallback testNetworkCb = null; + int innerSocketPort; try (IpSecManager.SecurityParameterIndex inSpi = mISM.allocateSecurityParameterIndex(localOuter, spi); IpSecManager.SecurityParameterIndex outSpi = mISM.allocateSecurityParameterIndex(remoteOuter, spi); - IpSecManager.IpSecTunnelInterface tunnelIntf = + IpSecManager.IpSecTunnelInterface tunnelIface = mISM.createIpSecTunnelInterface(localOuter, remoteOuter, sTunNetwork)) { // Build the test network - tunnelIntf.addAddress(localInner, innerPrefixLen); - testNetworkCb = setupAndGetTestNetwork(tunnelIntf.getInterfaceName()); + tunnelIface.addAddress(localInner, innerPrefixLen); + testNetworkCb = setupAndGetTestNetwork(tunnelIface.getInterfaceName()); Network testNetwork = testNetworkCb.getNetworkBlocking(); // Check interface was created - NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); - assertNotNull(netIntf); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); // Verify address was added - netIntf = NetworkInterface.getByInetAddress(localInner); - assertNotNull(netIntf); - assertEquals(tunnelIntf.getInterfaceName(), netIntf.getDisplayName()); + final NetworkInterface netIface = NetworkInterface.getByInetAddress(localInner); + assertNotNull(netIface); + assertEquals(tunnelIface.getInterfaceName(), netIface.getDisplayName()); // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); @@ -533,28 +677,31 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { transformBuilder.buildTunnelModeTransform(remoteOuter, inSpi); IpSecTransform outTransform = transformBuilder.buildTunnelModeTransform(localOuter, outSpi)) { - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, inTransform); - mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, outTransform); + mISM.applyTunnelModeTransform(tunnelIface, IpSecManager.DIRECTION_IN, inTransform); + mISM.applyTunnelModeTransform( + tunnelIface, IpSecManager.DIRECTION_OUT, outTransform); - test.run(testNetwork); + innerSocketPort = test.run(testNetwork); } // Teardown the test network sTNM.teardownTestNetwork(testNetwork); // Remove addresses and check that interface is still present, but fails lookup-by-addr - tunnelIntf.removeAddress(localInner, innerPrefixLen); - assertNotNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + tunnelIface.removeAddress(localInner, innerPrefixLen); + assertNotNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); assertNull(NetworkInterface.getByInetAddress(localInner)); // Check interface was cleaned up - tunnelIntf.close(); - assertNull(NetworkInterface.getByName(tunnelIntf.getInterfaceName())); + tunnelIface.close(); + assertNull(NetworkInterface.getByName(tunnelIface.getInterfaceName())); } finally { if (testNetworkCb != null) { sCM.unregisterNetworkCallback(testNetworkCb); } } + + return innerSocketPort; } private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { @@ -677,36 +824,66 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, true); checkTunnelInput(AF_INET, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, true); checkTunnelInput(AF_INET6, AF_INET, false, true); } + @Test + public void testTransportInTunnelModeV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, true); checkTunnelInput(AF_INET6, AF_INET, true, true); } + @Test + public void testTransportInTunnelModeV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + @Test public void testTransportInTunnelModeV6InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, true); checkTunnelInput(AF_INET, AF_INET6, false, true); } + @Test + public void testTransportInTunnelModeV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, true); + } + // Tunnel mode tests @Test public void testTunnelV4InV4() throws Exception { @@ -714,33 +891,63 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { checkTunnelInput(AF_INET, AF_INET, false, false); } + @Test + public void testTunnelV4InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, false, false); + } + @Test public void testTunnelV4InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET, AF_INET, true, false); checkTunnelInput(AF_INET, AF_INET, true, false); } + @Test + public void testTunnelV4InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET, true, false); + } + @Test public void testTunnelV4InV6() throws Exception { checkTunnelOutput(AF_INET, AF_INET6, false, false); checkTunnelInput(AF_INET, AF_INET6, false, false); } + @Test + public void testTunnelV4InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET, AF_INET6, false, false); + } + @Test public void testTunnelV6InV4() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, false, false); checkTunnelInput(AF_INET6, AF_INET, false, false); } + @Test + public void testTunnelV6InV4Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, false, false); + } + @Test public void testTunnelV6InV4UdpEncap() throws Exception { checkTunnelOutput(AF_INET6, AF_INET, true, false); checkTunnelInput(AF_INET6, AF_INET, true, false); } + @Test + public void testTunnelV6InV4UdpEncapReflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET, true, false); + } + @Test public void testTunnelV6InV6() throws Exception { checkTunnelOutput(AF_INET6, AF_INET6, false, false); checkTunnelInput(AF_INET6, AF_INET6, false, false); } + + @Test + public void testTunnelV6InV6Reflected() throws Exception { + checkTunnelReflected(AF_INET6, AF_INET6, false, false); + } }