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  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.vcn;
18 
19 import static android.net.ipsec.ike.IkeSessionParams.IKE_OPTION_MOBIKE;
20 import static android.net.vcn.VcnGatewayConnectionConfig.DEFAULT_UNDERLYING_NETWORK_TEMPLATES;
21 import static android.net.vcn.VcnGatewayConnectionConfig.UNDERLYING_NETWORK_TEMPLATES_KEY;
22 import static android.net.vcn.VcnGatewayConnectionConfig.VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY;
23 
24 import static org.junit.Assert.assertArrayEquals;
25 import static org.junit.Assert.assertEquals;
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertNotEquals;
28 import static org.junit.Assert.assertNotSame;
29 import static org.junit.Assert.assertTrue;
30 import static org.junit.Assert.fail;
31 
32 import android.net.NetworkCapabilities;
33 import android.net.ipsec.ike.IkeSessionParams;
34 import android.net.ipsec.ike.IkeTunnelConnectionParams;
35 import android.net.vcn.persistablebundleutils.IkeSessionParamsUtilsTest;
36 import android.net.vcn.persistablebundleutils.TunnelConnectionParamsUtilsTest;
37 import android.os.PersistableBundle;
38 
39 import androidx.test.filters.SmallTest;
40 import androidx.test.runner.AndroidJUnit4;
41 
42 import org.junit.Test;
43 import org.junit.runner.RunWith;
44 
45 import java.util.ArrayList;
46 import java.util.Arrays;
47 import java.util.Collections;
48 import java.util.List;
49 import java.util.Set;
50 import java.util.concurrent.TimeUnit;
51 
52 @RunWith(AndroidJUnit4.class)
53 @SmallTest
54 public class VcnGatewayConnectionConfigTest {
55     // Public for use in VcnGatewayConnectionTest
56     public static final int[] EXPOSED_CAPS =
57             new int[] {
58                 NetworkCapabilities.NET_CAPABILITY_INTERNET, NetworkCapabilities.NET_CAPABILITY_MMS
59             };
60     public static final int[] UNDERLYING_CAPS = new int[] {NetworkCapabilities.NET_CAPABILITY_DUN};
61 
62     private static final List<VcnUnderlyingNetworkTemplate> UNDERLYING_NETWORK_TEMPLATES =
63             new ArrayList();
64 
65     static {
66         Arrays.sort(EXPOSED_CAPS);
67         Arrays.sort(UNDERLYING_CAPS);
68 
69         UNDERLYING_NETWORK_TEMPLATES.add(
VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate()70                 VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
71         UNDERLYING_NETWORK_TEMPLATES.add(
VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate()72                 VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
73     }
74 
75     public static final long[] RETRY_INTERVALS_MS =
76             new long[] {
77                 TimeUnit.SECONDS.toMillis(5),
78                 TimeUnit.SECONDS.toMillis(30),
79                 TimeUnit.MINUTES.toMillis(1),
80                 TimeUnit.MINUTES.toMillis(5),
81                 TimeUnit.MINUTES.toMillis(15),
82                 TimeUnit.MINUTES.toMillis(30)
83             };
84     public static final int MAX_MTU = 1360;
85     public static final int MIN_UDP_PORT_4500_NAT_TIMEOUT = 120;
86 
87     private static final Set<Integer> GATEWAY_OPTIONS =
88             Collections.singleton(VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY);
89 
90     public static final IkeTunnelConnectionParams TUNNEL_CONNECTION_PARAMS =
91             TunnelConnectionParamsUtilsTest.buildTestParams();
92 
93     public static final String GATEWAY_CONNECTION_NAME_PREFIX = "gatewayConnectionName-";
94     private static int sGatewayConnectionConfigCount = 0;
95 
buildTestConfig( String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams)96     private static VcnGatewayConnectionConfig buildTestConfig(
97             String gatewayConnectionName, IkeTunnelConnectionParams tunnelConnectionParams) {
98         return buildTestConfigWithExposedCaps(
99                 new VcnGatewayConnectionConfig.Builder(
100                         gatewayConnectionName, tunnelConnectionParams),
101                 EXPOSED_CAPS);
102     }
103 
104     // Public for use in UnderlyingNetworkControllerTest
buildTestConfig( List<VcnUnderlyingNetworkTemplate> nwTemplates)105     public static VcnGatewayConnectionConfig buildTestConfig(
106             List<VcnUnderlyingNetworkTemplate> nwTemplates) {
107         final VcnGatewayConnectionConfig.Builder builder =
108                 newBuilder()
109                         .setVcnUnderlyingNetworkPriorities(nwTemplates)
110                         .setMinUdpPort4500NatTimeoutSeconds(MIN_UDP_PORT_4500_NAT_TIMEOUT);
111 
112         return buildTestConfigWithExposedCaps(builder, EXPOSED_CAPS);
113     }
114 
115     // Public for use in VcnGatewayConnectionTest
buildTestConfig()116     public static VcnGatewayConnectionConfig buildTestConfig() {
117         return buildTestConfig(UNDERLYING_NETWORK_TEMPLATES);
118     }
119 
120     // Public for use in VcnGatewayConnectionTest
newTestBuilderMinimal()121     public static VcnGatewayConnectionConfig.Builder newTestBuilderMinimal() {
122         final VcnGatewayConnectionConfig.Builder builder = newBuilder();
123         for (int caps : EXPOSED_CAPS) {
124             builder.addExposedCapability(caps);
125         }
126 
127         return builder;
128     }
129 
newBuilder()130     private static VcnGatewayConnectionConfig.Builder newBuilder() {
131         // Append a unique identifier to the name prefix to guarantee that all created
132         // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
133         return new VcnGatewayConnectionConfig.Builder(
134                 GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
135                 TUNNEL_CONNECTION_PARAMS);
136     }
137 
newBuilderMinimal()138     private static VcnGatewayConnectionConfig.Builder newBuilderMinimal() {
139         final VcnGatewayConnectionConfig.Builder builder =
140                 new VcnGatewayConnectionConfig.Builder(
141                         "newBuilderMinimal", TUNNEL_CONNECTION_PARAMS);
142         for (int caps : EXPOSED_CAPS) {
143             builder.addExposedCapability(caps);
144         }
145 
146         return builder;
147     }
148 
buildTestConfigWithExposedCapsAndOptions( VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions, int... exposedCaps)149     private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions(
150             VcnGatewayConnectionConfig.Builder builder,
151             Set<Integer> gatewayOptions,
152             int... exposedCaps) {
153         builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
154 
155         for (int option : gatewayOptions) {
156             builder.addGatewayOption(option);
157         }
158 
159         for (int caps : exposedCaps) {
160             builder.addExposedCapability(caps);
161         }
162 
163         return builder.build();
164     }
165 
buildTestConfigWithExposedCaps( VcnGatewayConnectionConfig.Builder builder, int... exposedCaps)166     private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
167             VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
168         return buildTestConfigWithExposedCapsAndOptions(
169                 builder, Collections.emptySet(), exposedCaps);
170     }
171 
172     // Public for use in VcnGatewayConnectionTest
buildTestConfigWithExposedCaps(int... exposedCaps)173     public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
174         return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps);
175     }
176 
buildTestConfigWithGatewayOptions( VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions)177     private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions(
178             VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions) {
179         return buildTestConfigWithExposedCapsAndOptions(builder, gatewayOptions, EXPOSED_CAPS);
180     }
181 
182     // Public for use in VcnGatewayConnectionTest
buildTestConfigWithGatewayOptions( Set<Integer> gatewayOptions)183     public static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions(
184             Set<Integer> gatewayOptions) {
185         return buildTestConfigWithExposedCapsAndOptions(newBuilder(), gatewayOptions, EXPOSED_CAPS);
186     }
187 
188     @Test
testBuilderRequiresNonNullGatewayConnectionName()189     public void testBuilderRequiresNonNullGatewayConnectionName() {
190         try {
191             new VcnGatewayConnectionConfig.Builder(
192                             null /* gatewayConnectionName */, TUNNEL_CONNECTION_PARAMS)
193                     .build();
194 
195             fail("Expected exception due to invalid gateway connection name");
196         } catch (NullPointerException e) {
197         }
198     }
199 
200     @Test
testBuilderRequiresNonNullTunnelConnectionParams()201     public void testBuilderRequiresNonNullTunnelConnectionParams() {
202         try {
203             new VcnGatewayConnectionConfig.Builder(
204                             GATEWAY_CONNECTION_NAME_PREFIX, null /* tunnelConnectionParams */)
205                     .build();
206 
207             fail("Expected exception due to the absence of tunnel connection parameters");
208         } catch (NullPointerException e) {
209         }
210     }
211 
212     @Test
testBuilderRequiresMobikeEnabled()213     public void testBuilderRequiresMobikeEnabled() {
214         try {
215             final IkeSessionParams ikeParams =
216                     IkeSessionParamsUtilsTest.createBuilderMinimum()
217                             .removeIkeOption(IKE_OPTION_MOBIKE)
218                             .build();
219             final IkeTunnelConnectionParams tunnelParams =
220                     TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
221             new VcnGatewayConnectionConfig.Builder(GATEWAY_CONNECTION_NAME_PREFIX, tunnelParams);
222             fail("Expected exception due to MOBIKE not enabled");
223         } catch (IllegalArgumentException e) {
224         }
225     }
226 
227     @Test
testBuilderRequiresNonEmptyExposedCaps()228     public void testBuilderRequiresNonEmptyExposedCaps() {
229         try {
230             newBuilder().build();
231 
232             fail("Expected exception due to invalid exposed capabilities");
233         } catch (IllegalArgumentException e) {
234         }
235     }
236 
237     @Test
testBuilderRequiresNonNullNetworkTemplates()238     public void testBuilderRequiresNonNullNetworkTemplates() {
239         try {
240             newBuilder().setVcnUnderlyingNetworkPriorities(null);
241             fail("Expected exception due to invalid underlyingNetworkTemplates");
242         } catch (NullPointerException e) {
243         }
244     }
245 
246     @Test
testBuilderRequiresNonNullRetryInterval()247     public void testBuilderRequiresNonNullRetryInterval() {
248         try {
249             newBuilder().setRetryIntervalsMillis(null);
250             fail("Expected exception due to invalid retryIntervalMs");
251         } catch (IllegalArgumentException e) {
252         }
253     }
254 
255     @Test
testBuilderRequiresNonEmptyRetryInterval()256     public void testBuilderRequiresNonEmptyRetryInterval() {
257         try {
258             newBuilder().setRetryIntervalsMillis(new long[0]);
259             fail("Expected exception due to invalid retryIntervalMs");
260         } catch (IllegalArgumentException e) {
261         }
262     }
263 
264     @Test
testBuilderRequiresValidMtu()265     public void testBuilderRequiresValidMtu() {
266         try {
267             newBuilder().setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
268             fail("Expected exception due to invalid mtu");
269         } catch (IllegalArgumentException e) {
270         }
271     }
272 
273     @Test
testBuilderRequiresValidOption()274     public void testBuilderRequiresValidOption() {
275         try {
276             newBuilder().addGatewayOption(-1);
277             fail("Expected exception due to the invalid VCN gateway option");
278         } catch (IllegalArgumentException e) {
279         }
280     }
281 
282     @Test
testBuilderAndGetters()283     public void testBuilderAndGetters() {
284         final VcnGatewayConnectionConfig config = buildTestConfig();
285 
286         assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX));
287 
288         int[] exposedCaps = config.getExposedCapabilities();
289         Arrays.sort(exposedCaps);
290         assertArrayEquals(EXPOSED_CAPS, exposedCaps);
291 
292         assertEquals(UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkPriorities());
293         assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
294 
295         assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
296         assertEquals(MAX_MTU, config.getMaxMtu());
297         assertTrue(config.isSafeModeEnabled());
298 
299         assertFalse(
300                 config.hasGatewayOption(
301                         VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY));
302     }
303 
304     @Test
testBuilderAndGettersWithOptions()305     public void testBuilderAndGettersWithOptions() {
306         final VcnGatewayConnectionConfig config =
307                 buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS);
308 
309         for (int option : GATEWAY_OPTIONS) {
310             assertTrue(config.hasGatewayOption(option));
311         }
312     }
313 
314     @Test
testBuilderAndGettersSafeModeDisabled()315     public void testBuilderAndGettersSafeModeDisabled() {
316         final VcnGatewayConnectionConfig config =
317                 newBuilderMinimal().setSafeModeEnabled(false).build();
318 
319         assertFalse(config.isSafeModeEnabled());
320     }
321 
322     @Test
testPersistableBundle()323     public void testPersistableBundle() {
324         final VcnGatewayConnectionConfig config = buildTestConfig();
325 
326         assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
327     }
328 
329     @Test
testPersistableBundleWithOptions()330     public void testPersistableBundleWithOptions() {
331         final VcnGatewayConnectionConfig config =
332                 buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS);
333 
334         assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
335     }
336 
337     @Test
testPersistableBundleSafeModeDisabled()338     public void testPersistableBundleSafeModeDisabled() {
339         final VcnGatewayConnectionConfig config =
340                 newBuilderMinimal().setSafeModeEnabled(false).build();
341 
342         assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
343     }
344 
345     @Test
testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates()346     public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() {
347         PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
348         configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null);
349 
350         final VcnGatewayConnectionConfig config = new VcnGatewayConnectionConfig(configBundle);
351         assertEquals(
352                 DEFAULT_UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkPriorities());
353     }
354 
buildTunnelConnectionParams(String ikePsk)355     private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) {
356         final IkeSessionParams ikeParams =
357                 IkeSessionParamsUtilsTest.createBuilderMinimum()
358                         .setAuthPsk(ikePsk.getBytes())
359                         .build();
360         return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
361     }
362 
363     @Test
testTunnelConnectionParamsEquals()364     public void testTunnelConnectionParamsEquals() throws Exception {
365         final String connectionName = "testTunnelConnectionParamsEquals.connectionName";
366         final String psk = "testTunnelConnectionParamsEquals.psk";
367 
368         final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk);
369         final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
370 
371         final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk);
372         final VcnGatewayConnectionConfig anotherConfig =
373                 buildTestConfig(connectionName, anotherTunnelParams);
374 
375         assertNotSame(tunnelParams, anotherTunnelParams);
376         assertEquals(tunnelParams, anotherTunnelParams);
377         assertEquals(config, anotherConfig);
378     }
379 
380     @Test
testTunnelConnectionParamsNotEquals()381     public void testTunnelConnectionParamsNotEquals() throws Exception {
382         final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName";
383 
384         final IkeTunnelConnectionParams tunnelParams =
385                 buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA");
386         final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
387 
388         final IkeTunnelConnectionParams anotherTunnelParams =
389                 buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB");
390         final VcnGatewayConnectionConfig anotherConfig =
391                 buildTestConfig(connectionName, anotherTunnelParams);
392 
393         assertNotEquals(tunnelParams, anotherTunnelParams);
394         assertNotEquals(config, anotherConfig);
395     }
396 
buildTestConfigWithVcnUnderlyingNetworkTemplates( List<VcnUnderlyingNetworkTemplate> networkTemplates)397     private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkTemplates(
398             List<VcnUnderlyingNetworkTemplate> networkTemplates) {
399         return buildTestConfigWithExposedCaps(
400                 new VcnGatewayConnectionConfig.Builder(
401                                 "buildTestConfigWithVcnUnderlyingNetworkTemplates",
402                                 TUNNEL_CONNECTION_PARAMS)
403                         .setVcnUnderlyingNetworkPriorities(networkTemplates),
404                 EXPOSED_CAPS);
405     }
406 
407     @Test
testVcnUnderlyingNetworkTemplatesEquality()408     public void testVcnUnderlyingNetworkTemplatesEquality() throws Exception {
409         final VcnGatewayConnectionConfig config =
410                 buildTestConfigWithVcnUnderlyingNetworkTemplates(UNDERLYING_NETWORK_TEMPLATES);
411 
412         final List<VcnUnderlyingNetworkTemplate> networkTemplatesEqual = new ArrayList();
413         networkTemplatesEqual.add(VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
414         networkTemplatesEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
415         final VcnGatewayConnectionConfig configEqual =
416                 buildTestConfigWithVcnUnderlyingNetworkTemplates(networkTemplatesEqual);
417 
418         final List<VcnUnderlyingNetworkTemplate> networkTemplatesNotEqual = new ArrayList();
419         networkTemplatesNotEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
420         final VcnGatewayConnectionConfig configNotEqual =
421                 buildTestConfigWithVcnUnderlyingNetworkTemplates(networkTemplatesNotEqual);
422 
423         assertEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesEqual);
424         assertEquals(config, configEqual);
425 
426         assertNotEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesNotEqual);
427         assertNotEquals(config, configNotEqual);
428     }
429 
buildConfigWithGatewayOptionsForEqualityTest( Set<Integer> gatewayOptions)430     private static VcnGatewayConnectionConfig buildConfigWithGatewayOptionsForEqualityTest(
431             Set<Integer> gatewayOptions) {
432         return buildTestConfigWithGatewayOptions(
433                 new VcnGatewayConnectionConfig.Builder(
434                         "buildConfigWithGatewayOptionsForEqualityTest", TUNNEL_CONNECTION_PARAMS),
435                 gatewayOptions);
436     }
437 
438     @Test
testVcnGatewayOptionsEquality()439     public void testVcnGatewayOptionsEquality() throws Exception {
440         final VcnGatewayConnectionConfig config =
441                 buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS);
442 
443         final VcnGatewayConnectionConfig configEqual =
444                 buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS);
445 
446         final VcnGatewayConnectionConfig configNotEqual =
447                 buildConfigWithGatewayOptionsForEqualityTest(Collections.emptySet());
448 
449         assertEquals(config, configEqual);
450         assertNotEquals(config, configNotEqual);
451     }
452 
453     @Test
testSafeModeEnableDisableEquality()454     public void testSafeModeEnableDisableEquality() throws Exception {
455         final VcnGatewayConnectionConfig config = newBuilderMinimal().build();
456         final VcnGatewayConnectionConfig configEqual = newBuilderMinimal().build();
457 
458         assertEquals(config.isSafeModeEnabled(), configEqual.isSafeModeEnabled());
459 
460         final VcnGatewayConnectionConfig configNotEqual =
461                 newBuilderMinimal().setSafeModeEnabled(false).build();
462 
463         assertEquals(config, configEqual);
464         assertNotEquals(config, configNotEqual);
465     }
466 }
467