From 3479e57fd288fec7a735fad0cd2204bfca24cfdd Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 20 Aug 2024 16:23:16 -0700 Subject: [PATCH] Handle ICMP in testRequestIpSecTransformStateForTx testRequestIpSecTransformStateForTs was flaky because sometimes ICMPv6(Router Solicitation) might be sent and failed the validation of packet/byte count. This CL provides two improvements - Change the validation to handle possible ICMP packets - In the await method, require sequence number match to ensure the expected packet has been sent out. Otherwise the await method will still return true on an old packet with the same SPI. Bug: 358324865 Test: atest IpSecManagerTunnelTest Flag: Exempt test code only Change-Id: I471014c11328bc0f32ee1f805accbaf7b29b8e7c --- .../src/android/net/cts/IpSecBaseTest.java | 16 ++++- .../net/cts/IpSecManagerTunnelTest.java | 70 ++++++++++++++----- 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 2a6c638243..c48013542f 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -23,10 +23,13 @@ import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA256; import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA384; import static android.net.IpSecAlgorithm.AUTH_HMAC_SHA512; import static android.net.IpSecAlgorithm.CRYPT_AES_CBC; +import static android.net.cts.PacketUtils.ICMP_HDRLEN; +import static android.net.cts.PacketUtils.IP6_HDRLEN; import static android.system.OsConstants.FIONREAD; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import android.content.Context; import android.net.ConnectivityManager; @@ -152,10 +155,17 @@ public class IpSecBaseTest { final IpSecTransformState transformState = futureIpSecTransform.get(SOCK_TIMEOUT, TimeUnit.MILLISECONDS); - assertEquals(txHighestSeqNum, transformState.getTxHighestSequenceNumber()); + // There might be ICMPv6(Router Solicitation) packets. Thus we can only check the lower + // bound of the outgoing traffic. + final long icmpV6RsCnt = transformState.getTxHighestSequenceNumber() - txHighestSeqNum; + assertTrue(icmpV6RsCnt >= 0); + + final long adjustedPacketCnt = packetCnt + icmpV6RsCnt; + final long adjustedByteCnt = byteCnt + icmpV6RsCnt * (IP6_HDRLEN + ICMP_HDRLEN); + + assertEquals(adjustedPacketCnt, transformState.getPacketCount()); + assertEquals(adjustedByteCnt, transformState.getByteCount()); assertEquals(rxHighestSeqNum, transformState.getRxHighestSequenceNumber()); - assertEquals(packetCnt, transformState.getPacketCount()); - assertEquals(byteCnt, transformState.getByteCount()); assertArrayEquals(replayBitmap, transformState.getReplayBitmap()); } diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java index 22a51d64a2..890c07134b 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -65,6 +65,7 @@ import android.platform.test.annotations.AppModeFull; import androidx.test.InstrumentationRegistry; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.CollectionUtils; import com.android.testutils.DevSdkIgnoreRule; import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo; @@ -119,7 +120,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { private static final int TIMEOUT_MS = 500; - private static final int PACKET_COUNT = 5000; + private static final int PACKET_COUNT = 100; // Static state to reduce setup/teardown private static ConnectivityManager sCM; @@ -1088,6 +1089,27 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { UdpEncapsulationSocket encapSocket, IpSecTunnelTestRunnable test) throws Exception { + return buildTunnelNetworkAndRunTests( + localInner, + remoteInner, + localOuter, + remoteOuter, + spi, + encapSocket, + test, + true /* enableEncrypt */); + } + + private int buildTunnelNetworkAndRunTests( + InetAddress localInner, + InetAddress remoteInner, + InetAddress localOuter, + InetAddress remoteOuter, + int spi, + UdpEncapsulationSocket encapSocket, + IpSecTunnelTestRunnable test, + boolean enableEncrypt) + throws Exception { int innerPrefixLen = localInner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; TestNetworkCallback testNetworkCb = null; int innerSocketPort; @@ -1115,8 +1137,12 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { // Configure Transform parameters IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext); - transformBuilder.setEncryption( - new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); + + if (enableEncrypt) { + transformBuilder.setEncryption( + new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); + } + transformBuilder.setAuthentication( new IpSecAlgorithm( IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); @@ -1167,8 +1193,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { return innerSocketPort; } - private int buildTunnelNetworkAndRunTestsSimple(int spi, IpSecTunnelTestRunnable test) - throws Exception { + private int buildTunnelNetworkAndRunTestsSimple( + int spi, IpSecTunnelTestRunnable test, boolean enableEncrypt) throws Exception { return buildTunnelNetworkAndRunTests( LOCAL_INNER_6, REMOTE_INNER_6, @@ -1176,7 +1202,8 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { REMOTE_OUTER_6, spi, null /* encapSocket */, - test); + test, + enableEncrypt); } private static void receiveAndValidatePacket(JavaUdpSocket socket) throws Exception { @@ -1787,10 +1814,11 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { PACKET_COUNT, PACKET_COUNT, PACKET_COUNT * (long) innerPacketSize, - newReplayBitmap(REPLAY_BITMAP_LEN_BYTE * 8)); + newReplayBitmap(PACKET_COUNT)); return innerSocketPort; - }); + }, + true /* enableEncrypt */); } @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) @@ -1814,17 +1842,22 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { ipsecNetwork.bindSocket(outSocket.mSocket); int innerSocketPort = outSocket.getPort(); - int expectedPacketSize = - getPacketSize( - AF_INET6, - AF_INET6, - false /* useEncap */, - false /* transportInTunnelMode */); + int outSeqNum = 1; + int receivedTestDataEspCnt = 0; - for (int i = 0; i < PACKET_COUNT; i++) { + while (receivedTestDataEspCnt < PACKET_COUNT) { outSocket.sendTo(TEST_DATA, REMOTE_INNER_6, innerSocketPort); - tunUtils.awaitEspPacketNoPlaintext( - spi, TEST_DATA, false /* useEncap */, expectedPacketSize); + + byte[] pkt = null; + + // If it is an ESP that contains the TEST_DATA, move to the next + // loop. Otherwise, the ESP may contain an ICMPv6(Router Solicitation). + // In this case, just increase the expected sequence number and continue + // waiting for the ESP with TEST_DATA + do { + pkt = tunUtils.awaitEspPacket(spi, false /* useEncap */, outSeqNum++); + } while (CollectionUtils.indexOfSubArray(pkt, TEST_DATA) == -1); + receivedTestDataEspCnt++; } final int innerPacketSize = @@ -1838,6 +1871,7 @@ public class IpSecManagerTunnelTest extends IpSecBaseTest { newReplayBitmap(0)); return innerSocketPort; - }); + }, + false /* enableEncrypt */); } }