• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 package android.ipsec.ike.cts;
17 
18 import static android.net.ipsec.ike.IkeSessionConfiguration.EXTENSION_TYPE_FRAGMENTATION;
19 import static android.system.OsConstants.AF_INET;
20 import static android.system.OsConstants.AF_INET6;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertNotNull;
24 import static org.junit.Assert.assertTrue;
25 
26 import android.annotation.NonNull;
27 import android.app.AppOpsManager;
28 import android.content.pm.PackageManager;
29 import android.ipsec.ike.cts.IkeTunUtils.PortPair;
30 import android.net.InetAddresses;
31 import android.net.IpSecManager;
32 import android.net.IpSecTransform;
33 import android.net.LinkAddress;
34 import android.net.ipsec.ike.ChildSessionCallback;
35 import android.net.ipsec.ike.ChildSessionConfiguration;
36 import android.net.ipsec.ike.IkeSessionCallback;
37 import android.net.ipsec.ike.IkeSessionConfiguration;
38 import android.net.ipsec.ike.IkeSessionConnectionInfo;
39 import android.net.ipsec.ike.IkeTrafficSelector;
40 import android.net.ipsec.ike.TransportModeChildSessionParams;
41 import android.net.ipsec.ike.TunnelModeChildSessionParams;
42 import android.net.ipsec.ike.exceptions.IkeException;
43 import android.os.UserHandle;
44 import android.platform.test.annotations.AppModeFull;
45 
46 import androidx.test.ext.junit.runners.AndroidJUnit4;
47 
48 import com.android.compatibility.common.util.SystemUtil;
49 import com.android.internal.net.annotations.PolicyDirection;
50 import com.android.net.module.util.ArrayTrackRecord;
51 
52 import org.junit.After;
53 import org.junit.Before;
54 import org.junit.runner.RunWith;
55 
56 import java.net.Inet4Address;
57 import java.net.Inet6Address;
58 import java.net.InetAddress;
59 import java.util.ArrayList;
60 import java.util.HashSet;
61 import java.util.List;
62 import java.util.Objects;
63 import java.util.Set;
64 import java.util.concurrent.CompletableFuture;
65 import java.util.concurrent.Executor;
66 import java.util.concurrent.Executors;
67 import java.util.concurrent.TimeUnit;
68 
69 /**
70  * Package private base class for testing IkeSessionParams and IKE exchanges.
71  *
72  * <p>Subclasses MUST explicitly call #setUpTestNetwork and #tearDownTestNetwork to be able to use
73  * the test network
74  *
75  * <p>All IKE Sessions running in test mode will generate SPIs deterministically. That is to say
76  * each IKE Session will always generate the same IKE INIT SPI and test vectors are generated based
77  * on this deterministic IKE SPI. Each test will use different local and remote addresses to avoid
78  * the case that the next test try to allocate the same SPI before the previous test has released
79  * it, since SPI resources are not released in testing thread. Similarly, each test MUST use
80  * different Network instances to avoid sharing the same IkeSocket and hitting IKE SPI collision.
81  */
82 @RunWith(AndroidJUnit4.class)
83 @AppModeFull(reason = "MANAGE_TEST_NETWORKS permission can't be granted to instant apps")
84 abstract class IkeSessionTestBase extends IkeTestNetworkBase {
85     // Package-wide common expected results that will be shared by all IKE/Child SA creation tests
86     static final String EXPECTED_REMOTE_APP_VERSION_EMPTY = "";
87     static final byte[] EXPECTED_PROTOCOL_ERROR_DATA_NONE = new byte[0];
88 
89     static final InetAddress EXPECTED_DNS_SERVERS_ONE =
90             InetAddresses.parseNumericAddress("8.8.8.8");
91     static final InetAddress EXPECTED_DNS_SERVERS_TWO =
92             InetAddresses.parseNumericAddress("8.8.4.4");
93 
94     static final InetAddress EXPECTED_INTERNAL_ADDR =
95             InetAddresses.parseNumericAddress("198.51.100.10");
96     static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR =
97             new LinkAddress(EXPECTED_INTERNAL_ADDR, IP4_PREFIX_LEN);
98     static final InetAddress EXPECTED_INTERNAL_ADDR_V6 =
99             InetAddresses.parseNumericAddress("2001:db8::2");
100     static final LinkAddress EXPECTED_INTERNAL_LINK_ADDR_V6 =
101             new LinkAddress(EXPECTED_INTERNAL_ADDR_V6, IP6_PREFIX_LEN);
102 
103     static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS =
104             new IkeTrafficSelector(
105                     MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR, EXPECTED_INTERNAL_ADDR);
106     static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS = DEFAULT_V4_TS;
107     static final IkeTrafficSelector TUNNEL_MODE_INBOUND_TS_V6 =
108             new IkeTrafficSelector(
109                     MIN_PORT, MAX_PORT, EXPECTED_INTERNAL_ADDR_V6, EXPECTED_INTERNAL_ADDR_V6);
110     static final IkeTrafficSelector TUNNEL_MODE_OUTBOUND_TS_V6 = DEFAULT_V6_TS;
111 
112     // This value is align with the test vectors hex that are generated in an IPv4 environment
113     static final IkeTrafficSelector TRANSPORT_MODE_OUTBOUND_TS =
114             new IkeTrafficSelector(
115                     MIN_PORT,
116                     MAX_PORT,
117                     InetAddresses.parseNumericAddress("10.138.0.2"),
118                     InetAddresses.parseNumericAddress("10.138.0.2"));
119 
120     static final long IKE_DETERMINISTIC_INITIATOR_SPI = Long.parseLong("46B8ECA1E0D72A18", 16);
121 
122     private static final int TIMEOUT_MS = 1000;
123 
124     // Constants to be used for providing different IP addresses for each tests
125     private static final byte IP_ADDR_LAST_BYTE_MAX = (byte) 100;
126     private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_LOCAL =
127             InetAddresses.parseNumericAddress("192.0.2.1").getAddress();
128     private static final byte[] INITIAL_AVAILABLE_IP4_ADDR_REMOTE =
129             InetAddresses.parseNumericAddress("198.51.100.1").getAddress();
130     private static final byte[] NEXT_AVAILABLE_IP4_ADDR_LOCAL = INITIAL_AVAILABLE_IP4_ADDR_LOCAL;
131     private static final byte[] NEXT_AVAILABLE_IP4_ADDR_REMOTE = INITIAL_AVAILABLE_IP4_ADDR_REMOTE;
132 
133     private static final byte[] INITIAL_AVAILABLE_IP6_ADDR_LOCAL =
134             InetAddresses.parseNumericAddress("2a00:1000::0").getAddress();
135     private static final byte[] INITIAL_AVAILABLE_IP6_ADDR_REMOTE =
136             InetAddresses.parseNumericAddress("2404:6800:4004:820::2004").getAddress();
137     private static final byte[] NEXT_AVAILABLE_IP6_ADDR_LOCAL = INITIAL_AVAILABLE_IP6_ADDR_LOCAL;
138     private static final byte[] NEXT_AVAILABLE_IP6_ADDR_REMOTE = INITIAL_AVAILABLE_IP6_ADDR_REMOTE;
139 
140     TunNetworkContext mTunNetworkContext;
141 
142     InetAddress mLocalAddress;
143     InetAddress mRemoteAddress;
144 
145     Executor mUserCbExecutor;
146     TestIkeSessionCallback mIkeSessionCallback;
147     TestChildSessionCallback mFirstChildSessionCallback;
148 
149     @Before
setUp()150     public void setUp() throws Exception {
151         mLocalAddress = getNextAvailableIpv4AddressLocal();
152         mRemoteAddress = getNextAvailableIpv4AddressRemote();
153         mTunNetworkContext = new TunNetworkContext(mLocalAddress);
154 
155         mUserCbExecutor = Executors.newSingleThreadExecutor();
156         mIkeSessionCallback = new DefaultTestIkeSessionCallback();
157         mFirstChildSessionCallback = new DefaultTestChildSessionCallback();
158     }
159 
160     @After
tearDown()161     public void tearDown() throws Exception {
162         if (mTunNetworkContext != null) {
163             mTunNetworkContext.close();
164         }
165     }
166 
setAppOp(int appop, boolean allow)167     static void setAppOp(int appop, boolean allow) {
168         String opName = AppOpsManager.opToName(appop);
169         for (String pkg : new String[] {"com.android.shell", sContext.getPackageName()}) {
170             String cmd =
171                     String.format(
172                             "appops set %s %s %s --user %d",
173                             pkg, // Package name
174                             opName, // Appop
175                             (allow ? "allow" : "deny"), // Action
176                             UserHandle.myUserId());
177 
178             SystemUtil.runShellCommand(cmd);
179         }
180     }
181 
getNextAvailableIpv4AddressLocal()182     Inet4Address getNextAvailableIpv4AddressLocal() throws Exception {
183         return (Inet4Address)
184                 getNextAvailableAddress(
185                         NEXT_AVAILABLE_IP4_ADDR_LOCAL,
186                         INITIAL_AVAILABLE_IP4_ADDR_LOCAL,
187                         false /* isIp6 */);
188     }
189 
getNextAvailableIpv4AddressRemote()190     Inet4Address getNextAvailableIpv4AddressRemote() throws Exception {
191         return (Inet4Address)
192                 getNextAvailableAddress(
193                         NEXT_AVAILABLE_IP4_ADDR_REMOTE,
194                         INITIAL_AVAILABLE_IP4_ADDR_REMOTE,
195                         false /* isIp6 */);
196     }
197 
getNextAvailableIpv6AddressLocal()198     Inet6Address getNextAvailableIpv6AddressLocal() throws Exception {
199         return (Inet6Address)
200                 getNextAvailableAddress(
201                         NEXT_AVAILABLE_IP6_ADDR_LOCAL,
202                         INITIAL_AVAILABLE_IP6_ADDR_LOCAL,
203                         true /* isIp6 */);
204     }
205 
getNextAvailableIpv6AddressRemote()206     Inet6Address getNextAvailableIpv6AddressRemote() throws Exception {
207         return (Inet6Address)
208                 getNextAvailableAddress(
209                         NEXT_AVAILABLE_IP6_ADDR_REMOTE,
210                         INITIAL_AVAILABLE_IP6_ADDR_REMOTE,
211                         true /* isIp6 */);
212     }
213 
getNextAvailableAddress( byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6)214     InetAddress getNextAvailableAddress(
215             byte[] nextAddressBytes, byte[] initialAddressBytes, boolean isIp6) throws Exception {
216         int addressLen = isIp6 ? IP6_ADDRESS_LEN : IP4_ADDRESS_LEN;
217 
218         synchronized (nextAddressBytes) {
219             if (nextAddressBytes[addressLen - 1] == IP_ADDR_LAST_BYTE_MAX) {
220                 resetNextAvailableAddress(nextAddressBytes, initialAddressBytes);
221             }
222 
223             InetAddress address = InetAddress.getByAddress(nextAddressBytes);
224             nextAddressBytes[addressLen - 1]++;
225             return address;
226         }
227     }
228 
resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes)229     private void resetNextAvailableAddress(byte[] nextAddressBytes, byte[] initialAddressBytes) {
230         synchronized (nextAddressBytes) {
231             System.arraycopy(
232                     nextAddressBytes, 0, initialAddressBytes, 0, initialAddressBytes.length);
233         }
234     }
235 
buildTransportModeChildParamsWithTs( IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs)236     TransportModeChildSessionParams buildTransportModeChildParamsWithTs(
237             IkeTrafficSelector inboundTs, IkeTrafficSelector outboundTs) {
238         return new TransportModeChildSessionParams.Builder()
239                 .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
240                 .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
241                 .addInboundTrafficSelectors(inboundTs)
242                 .addOutboundTrafficSelectors(outboundTs)
243                 .build();
244     }
245 
buildTransportModeChildParamsWithDefaultTs()246     TransportModeChildSessionParams buildTransportModeChildParamsWithDefaultTs() {
247         return new TransportModeChildSessionParams.Builder()
248                 .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
249                 .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
250                 .build();
251     }
252 
buildTunnelModeChildSessionParams()253     TunnelModeChildSessionParams buildTunnelModeChildSessionParams() {
254         return new TunnelModeChildSessionParams.Builder()
255                 .addSaProposal(SaProposalTest.buildChildSaProposalWithNormalModeCipher())
256                 .addSaProposal(SaProposalTest.buildChildSaProposalWithCombinedModeCipher())
257                 .addInternalAddressRequest(AF_INET)
258                 .addInternalAddressRequest(AF_INET6)
259                 .build();
260     }
261 
performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes)262     PortPair performSetupIkeAndFirstChildBlocking(String ikeInitRespHex, String... ikeAuthRespHexes)
263             throws Exception {
264         return performSetupIkeAndFirstChildBlocking(
265                 ikeInitRespHex,
266                 1 /* expectedAuthReqPktCnt */,
267                 true /*expectedAuthUseEncap*/,
268                 ikeAuthRespHexes);
269     }
270 
performSetupIkeAndFirstChildBlocking( String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes)271     PortPair performSetupIkeAndFirstChildBlocking(
272             String ikeInitRespHex, boolean expectedAuthUseEncap, String... ikeAuthRespHexes)
273             throws Exception {
274         return performSetupIkeAndFirstChildBlocking(
275                 ikeInitRespHex,
276                 1 /* expectedAuthReqPktCnt */,
277                 expectedAuthUseEncap,
278                 ikeAuthRespHexes);
279     }
280 
performSetupIkeAndFirstChildBlocking( String ikeInitRespHex, int expectedAuthReqPktCnt, boolean expectedAuthUseEncap, String... ikeAuthRespHexes)281     PortPair performSetupIkeAndFirstChildBlocking(
282             String ikeInitRespHex,
283             int expectedAuthReqPktCnt,
284             boolean expectedAuthUseEncap,
285             String... ikeAuthRespHexes)
286             throws Exception {
287         mTunNetworkContext.tunUtils.awaitReqAndInjectResp(
288                 IKE_DETERMINISTIC_INITIATOR_SPI,
289                 0 /* expectedMsgId */,
290                 false /* expectedUseEncap */,
291                 ikeInitRespHex);
292 
293         byte[] ikeAuthReqPkt =
294                 mTunNetworkContext
295                         .tunUtils
296                         .awaitReqAndInjectResp(
297                                 IKE_DETERMINISTIC_INITIATOR_SPI,
298                                 1 /* expectedMsgId */,
299                                 expectedAuthUseEncap,
300                                 expectedAuthReqPktCnt,
301                                 ikeAuthRespHexes)
302                         .get(0);
303         return IkeTunUtils.getSrcDestPortPair(ikeAuthReqPkt);
304     }
305 
performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex)306     void performCloseIkeBlocking(int expectedMsgId, String deleteIkeRespHex) throws Exception {
307         performCloseIkeBlocking(expectedMsgId, true /* expectedUseEncap*/, deleteIkeRespHex);
308     }
309 
performCloseIkeBlocking( int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex)310     void performCloseIkeBlocking(
311             int expectedMsgId, boolean expectedUseEncap, String deleteIkeRespHex) throws Exception {
312         mTunNetworkContext.tunUtils.awaitReqAndInjectResp(
313                 IKE_DETERMINISTIC_INITIATOR_SPI, expectedMsgId, expectedUseEncap, deleteIkeRespHex);
314     }
315 
316     /**
317      * Base testing callback that allows caller to block current thread until a method get called
318      */
319     abstract static class TestIkeSessionCallback implements IkeSessionCallback {
320         private CompletableFuture<IkeSessionConfiguration> mFutureIkeConfig =
321                 new CompletableFuture<>();
322         private CompletableFuture<Boolean> mFutureOnClosedCall = new CompletableFuture<>();
323         private CompletableFuture<IkeSessionConnectionInfo> mFutureConnectionConfig =
324                 new CompletableFuture<>();
325 
326         private int mOnErrorExceptionsCount = 0;
327         private ArrayTrackRecord<IkeException> mOnErrorExceptionsTrackRecord =
328                 new ArrayTrackRecord<>();
329 
330         protected CompletableFuture<IkeException> mFutureOnClosedException =
331                 new CompletableFuture<>();
332 
333         @Override
onOpened(@onNull IkeSessionConfiguration sessionConfiguration)334         public void onOpened(@NonNull IkeSessionConfiguration sessionConfiguration) {
335             mFutureIkeConfig.complete(sessionConfiguration);
336         }
337 
338         @Override
onClosed()339         public void onClosed() {
340             mFutureOnClosedCall.complete(true /* unused */);
341         }
342 
343         @Override
onError(@onNull IkeException exception)344         public void onError(@NonNull IkeException exception) {
345             IkeSessionCallback.super.onError(exception);
346             mOnErrorExceptionsTrackRecord.add(exception);
347         }
348 
349         @Override
onIkeSessionConnectionInfoChanged( @onNull IkeSessionConnectionInfo connectionInfo)350         public void onIkeSessionConnectionInfoChanged(
351                 @NonNull IkeSessionConnectionInfo connectionInfo) {
352             IkeSessionCallback.super.onIkeSessionConnectionInfoChanged(connectionInfo);
353             mFutureConnectionConfig.complete(connectionInfo);
354         }
355 
awaitIkeConfig()356         public IkeSessionConfiguration awaitIkeConfig() throws Exception {
357             return mFutureIkeConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
358         }
359 
awaitOnClosedException()360         public IkeException awaitOnClosedException() throws Exception {
361             return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
362         }
363 
awaitNextOnErrorException()364         public IkeException awaitNextOnErrorException() {
365             return mOnErrorExceptionsTrackRecord.poll(
366                     (long) TIMEOUT_MS,
367                     mOnErrorExceptionsCount++,
368                     (transform) -> {
369                         return true;
370                     });
371         }
372 
awaitOnClosed()373         public void awaitOnClosed() throws Exception {
374             mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
375         }
376 
awaitOnIkeSessionConnectionInfoChanged()377         public IkeSessionConnectionInfo awaitOnIkeSessionConnectionInfoChanged() throws Exception {
378             return mFutureConnectionConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
379         }
380     }
381 
382     /** Default testing callback for all IKE exchange tests */
383     static class DefaultTestIkeSessionCallback extends TestIkeSessionCallback {
384         @Override
onClosedWithException(@onNull IkeException exception)385         public void onClosedWithException(@NonNull IkeException exception) {
386             mFutureOnClosedException.complete(exception);
387         }
388     }
389 
390     /** Testing callback to verify deprecated methods before they are removed */
391     static class LegacyTestIkeSessionCallback extends TestIkeSessionCallback {
392         @Override
onClosedExceptionally(@onNull IkeException exception)393         public void onClosedExceptionally(@NonNull IkeException exception) {
394             mFutureOnClosedException.complete(exception);
395         }
396     }
397 
398     /**
399      * Base testing callback that allows caller to block current thread until a method get called
400      */
401     abstract static class TestChildSessionCallback implements ChildSessionCallback {
402         private CompletableFuture<ChildSessionConfiguration> mFutureChildConfig =
403                 new CompletableFuture<>();
404         private CompletableFuture<Boolean> mFutureOnClosedCall = new CompletableFuture<>();
405 
406         protected CompletableFuture<IkeException> mFutureOnClosedException =
407                 new CompletableFuture<>();
408 
409         private int mCreatedIpSecTransformCount = 0;
410         private int mMigratedIpSecTransformCount = 0;
411         private int mDeletedIpSecTransformCount = 0;
412         private ArrayTrackRecord<IpSecTransformCallRecord> mCreatedIpSecTransformsTrackRecord =
413                 new ArrayTrackRecord<>();
414         private ArrayTrackRecord<IpSecTransformCallRecord[]> mMigratedIpSecTransformsTrackRecord =
415                 new ArrayTrackRecord<>();
416         private ArrayTrackRecord<IpSecTransformCallRecord> mDeletedIpSecTransformsTrackRecord =
417                 new ArrayTrackRecord<>();
418 
419         @Override
onOpened(@onNull ChildSessionConfiguration sessionConfiguration)420         public void onOpened(@NonNull ChildSessionConfiguration sessionConfiguration) {
421             mFutureChildConfig.complete(sessionConfiguration);
422         }
423 
424         @Override
onClosed()425         public void onClosed() {
426             mFutureOnClosedCall.complete(true /* unused */);
427         }
428 
429         @Override
onIpSecTransformCreated(@onNull IpSecTransform ipSecTransform, int direction)430         public void onIpSecTransformCreated(@NonNull IpSecTransform ipSecTransform, int direction) {
431             mCreatedIpSecTransformsTrackRecord.add(
432                     new IpSecTransformCallRecord(ipSecTransform, direction));
433         }
434 
435         @Override
onIpSecTransformsMigrated( IpSecTransform inIpSecTransform, IpSecTransform outIpSecTransform)436         public void onIpSecTransformsMigrated(
437                 IpSecTransform inIpSecTransform, IpSecTransform outIpSecTransform) {
438             ChildSessionCallback.super.onIpSecTransformsMigrated(
439                     inIpSecTransform, outIpSecTransform);
440 
441             IpSecTransformCallRecord inRecord =
442                     new IpSecTransformCallRecord(inIpSecTransform, IpSecManager.DIRECTION_IN);
443             IpSecTransformCallRecord outRecord =
444                     new IpSecTransformCallRecord(outIpSecTransform, IpSecManager.DIRECTION_OUT);
445             mMigratedIpSecTransformsTrackRecord.add(
446                     new IpSecTransformCallRecord[] {inRecord, outRecord});
447         }
448 
449         @Override
onIpSecTransformDeleted(@onNull IpSecTransform ipSecTransform, int direction)450         public void onIpSecTransformDeleted(@NonNull IpSecTransform ipSecTransform, int direction) {
451             mDeletedIpSecTransformsTrackRecord.add(
452                     new IpSecTransformCallRecord(ipSecTransform, direction));
453         }
454 
awaitChildConfig()455         public ChildSessionConfiguration awaitChildConfig() throws Exception {
456             return mFutureChildConfig.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
457         }
458 
awaitOnClosedException()459         public IkeException awaitOnClosedException() throws Exception {
460             return mFutureOnClosedException.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
461         }
462 
awaitNextCreatedIpSecTransform()463         public IpSecTransformCallRecord awaitNextCreatedIpSecTransform() {
464             return mCreatedIpSecTransformsTrackRecord.poll(
465                     (long) TIMEOUT_MS,
466                     mCreatedIpSecTransformCount++,
467                     (transform) -> {
468                         return true;
469                     });
470         }
471 
awaitNextMigratedIpSecTransform()472         public IpSecTransformCallRecord[] awaitNextMigratedIpSecTransform() {
473             return mMigratedIpSecTransformsTrackRecord.poll(
474                     (long) TIMEOUT_MS,
475                     mMigratedIpSecTransformCount++,
476                     (transform) -> {
477                         return true;
478                     });
479         }
480 
481         public IpSecTransformCallRecord awaitNextDeletedIpSecTransform() {
482             return mDeletedIpSecTransformsTrackRecord.poll(
483                     (long) TIMEOUT_MS,
484                     mDeletedIpSecTransformCount++,
485                     (transform) -> {
486                         return true;
487                     });
488         }
489 
490         public void awaitOnClosed() throws Exception {
491             mFutureOnClosedCall.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
492         }
493     }
494 
495     /** Default testing callback for all IKE exchange tests */
496     static class DefaultTestChildSessionCallback extends TestChildSessionCallback {
497         @Override
498         public void onClosedWithException(@NonNull IkeException exception) {
499             mFutureOnClosedException.complete(exception);
500         }
501     }
502 
503     /** Testing callback to verify deprecated methods before they are removed */
504     static class LegacyTestChildSessionCallback extends TestChildSessionCallback {
505         @Override
506         public void onClosedExceptionally(@NonNull IkeException exception) {
507             mFutureOnClosedException.complete(exception);
508         }
509     }
510 
511     /**
512      * This class represents a created or deleted IpSecTransfrom that is provided by
513      * ChildSessionCallback
514      */
515     static class IpSecTransformCallRecord {
516         public final IpSecTransform ipSecTransform;
517         public final int direction;
518 
519         IpSecTransformCallRecord(IpSecTransform ipSecTransform, @PolicyDirection int direction) {
520             this.ipSecTransform = ipSecTransform;
521             this.direction = direction;
522         }
523 
524         @Override
525         public int hashCode() {
526             return Objects.hash(ipSecTransform, direction);
527         }
528 
529         @Override
530         public boolean equals(Object o) {
531             if (!(o instanceof IpSecTransformCallRecord)) return false;
532 
533             IpSecTransformCallRecord record = (IpSecTransformCallRecord) o;
534             return ipSecTransform.equals(record.ipSecTransform) && direction == record.direction;
535         }
536     }
537 
538     // TODO: b/275938211 Rename the method to reflect that it will return a value besides doing
539     // validations
540     IkeSessionConnectionInfo verifyIkeSessionSetupBlocking() throws Exception {
541         return verifyIkeSessionSetupBlocking(EXTENSION_TYPE_FRAGMENTATION);
542     }
543 
544     IkeSessionConnectionInfo verifyIkeSessionSetupBlocking(int... expectedIkeExtensions)
545             throws Exception {
546         IkeSessionConfiguration ikeConfig = mIkeSessionCallback.awaitIkeConfig();
547         assertNotNull(ikeConfig);
548         assertEquals(EXPECTED_REMOTE_APP_VERSION_EMPTY, ikeConfig.getRemoteApplicationVersion());
549         assertTrue(ikeConfig.getRemoteVendorIds().isEmpty());
550         assertTrue(ikeConfig.getPcscfServers().isEmpty());
551         for (int ikeExtension : expectedIkeExtensions) {
552             assertTrue(ikeConfig.isIkeExtensionEnabled(ikeExtension));
553         }
554 
555         IkeSessionConnectionInfo ikeConnectInfo = ikeConfig.getIkeSessionConnectionInfo();
556         assertNotNull(ikeConnectInfo);
557         assertEquals(mLocalAddress, ikeConnectInfo.getLocalAddress());
558         assertEquals(mRemoteAddress, ikeConnectInfo.getRemoteAddress());
559         assertEquals(mTunNetworkContext.tunNetwork, ikeConnectInfo.getNetwork());
560 
561         return ikeConnectInfo;
562     }
563 
564     ChildSessionConfiguration verifyChildSessionSetupBlocking(
565             TestChildSessionCallback childCallback,
566             List<IkeTrafficSelector> expectedInboundTs,
567             List<IkeTrafficSelector> expectedOutboundTs,
568             List<LinkAddress> expectedInternalAddresses)
569             throws Exception {
570         return verifyChildSessionSetupBlocking(
571                 childCallback,
572                 expectedInboundTs,
573                 expectedOutboundTs,
574                 expectedInternalAddresses,
575                 new ArrayList<InetAddress>() /* expectedDnsServers */);
576     }
577 
578     ChildSessionConfiguration verifyChildSessionSetupBlocking(
579             TestChildSessionCallback childCallback,
580             List<IkeTrafficSelector> expectedInboundTs,
581             List<IkeTrafficSelector> expectedOutboundTs,
582             List<LinkAddress> expectedInternalAddresses,
583             List<InetAddress> expectedDnsServers)
584             throws Exception {
585         ChildSessionConfiguration childConfig = childCallback.awaitChildConfig();
586         assertNotNull(childConfig);
587         assertEquals(expectedInboundTs, childConfig.getInboundTrafficSelectors());
588         assertEquals(expectedOutboundTs, childConfig.getOutboundTrafficSelectors());
589         assertEquals(expectedInternalAddresses, childConfig.getInternalAddresses());
590         assertEquals(expectedDnsServers, childConfig.getInternalDnsServers());
591         assertTrue(childConfig.getInternalSubnets().isEmpty());
592         assertTrue(childConfig.getInternalDhcpServers().isEmpty());
593         return childConfig;
594     }
595 
596     void verifyCloseIkeAndChildBlocking(
597             IpSecTransformCallRecord expectedTransformRecordA,
598             IpSecTransformCallRecord expectedTransformRecordB)
599             throws Exception {
600         verifyDeleteIpSecTransformPair(
601                 mFirstChildSessionCallback, expectedTransformRecordA, expectedTransformRecordB);
602         mFirstChildSessionCallback.awaitOnClosed();
603         mIkeSessionCallback.awaitOnClosed();
604     }
605 
606     static void verifyCreateIpSecTransformPair(
607             IpSecTransformCallRecord transformRecordA, IpSecTransformCallRecord transformRecordB) {
608         IpSecTransform transformA = transformRecordA.ipSecTransform;
609         IpSecTransform transformB = transformRecordB.ipSecTransform;
610 
611         assertNotNull(transformA);
612         assertNotNull(transformB);
613 
614         Set<Integer> expectedDirections = new HashSet<>();
615         expectedDirections.add(IpSecManager.DIRECTION_IN);
616         expectedDirections.add(IpSecManager.DIRECTION_OUT);
617 
618         Set<Integer> resultDirections = new HashSet<>();
619         resultDirections.add(transformRecordA.direction);
620         resultDirections.add(transformRecordB.direction);
621 
622         assertEquals(expectedDirections, resultDirections);
623     }
624 
625     static void verifyDeleteIpSecTransformPair(
626             TestChildSessionCallback childCb,
627             IpSecTransformCallRecord expectedTransformRecordA,
628             IpSecTransformCallRecord expectedTransformRecordB) {
629         Set<IpSecTransformCallRecord> expectedTransforms = new HashSet<>();
630         expectedTransforms.add(expectedTransformRecordA);
631         expectedTransforms.add(expectedTransformRecordB);
632 
633         Set<IpSecTransformCallRecord> resultTransforms = new HashSet<>();
634         resultTransforms.add(childCb.awaitNextDeletedIpSecTransform());
635         resultTransforms.add(childCb.awaitNextDeletedIpSecTransform());
636 
637         assertEquals(expectedTransforms, resultTransforms);
638     }
639 
640     /** Package private method to check if device has IPsec tunnels feature */
641     static boolean hasTunnelsFeature() {
642         return sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS);
643     }
644 
645     /** Package private method to check if device has IPsec tunnel migration feature */
646     static boolean hasTunnelMigrationFeature() {
647         return sContext.getPackageManager()
648                 .hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNEL_MIGRATION);
649     }
650 
651     // TODO(b/148689509): Verify hostname based creation
652 }
653