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