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 
newBuilder()120     private static VcnGatewayConnectionConfig.Builder newBuilder() {
121         // Append a unique identifier to the name prefix to guarantee that all created
122         // VcnGatewayConnectionConfigs have a unique name (required by VcnConfig).
123         return new VcnGatewayConnectionConfig.Builder(
124                 GATEWAY_CONNECTION_NAME_PREFIX + sGatewayConnectionConfigCount++,
125                 TUNNEL_CONNECTION_PARAMS);
126     }
127 
buildTestConfigWithExposedCapsAndOptions( VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions, int... exposedCaps)128     private static VcnGatewayConnectionConfig buildTestConfigWithExposedCapsAndOptions(
129             VcnGatewayConnectionConfig.Builder builder,
130             Set<Integer> gatewayOptions,
131             int... exposedCaps) {
132         builder.setRetryIntervalsMillis(RETRY_INTERVALS_MS).setMaxMtu(MAX_MTU);
133 
134         for (int option : gatewayOptions) {
135             builder.addGatewayOption(option);
136         }
137 
138         for (int caps : exposedCaps) {
139             builder.addExposedCapability(caps);
140         }
141 
142         return builder.build();
143     }
144 
buildTestConfigWithExposedCaps( VcnGatewayConnectionConfig.Builder builder, int... exposedCaps)145     private static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(
146             VcnGatewayConnectionConfig.Builder builder, int... exposedCaps) {
147         return buildTestConfigWithExposedCapsAndOptions(
148                 builder, Collections.emptySet(), exposedCaps);
149     }
150 
151     // Public for use in VcnGatewayConnectionTest
buildTestConfigWithExposedCaps(int... exposedCaps)152     public static VcnGatewayConnectionConfig buildTestConfigWithExposedCaps(int... exposedCaps) {
153         return buildTestConfigWithExposedCaps(newBuilder(), exposedCaps);
154     }
155 
buildTestConfigWithGatewayOptions( VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions)156     private static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions(
157             VcnGatewayConnectionConfig.Builder builder, Set<Integer> gatewayOptions) {
158         return buildTestConfigWithExposedCapsAndOptions(builder, gatewayOptions, EXPOSED_CAPS);
159     }
160 
161     // Public for use in VcnGatewayConnectionTest
buildTestConfigWithGatewayOptions( Set<Integer> gatewayOptions)162     public static VcnGatewayConnectionConfig buildTestConfigWithGatewayOptions(
163             Set<Integer> gatewayOptions) {
164         return buildTestConfigWithExposedCapsAndOptions(newBuilder(), gatewayOptions, EXPOSED_CAPS);
165     }
166 
167     @Test
testBuilderRequiresNonNullGatewayConnectionName()168     public void testBuilderRequiresNonNullGatewayConnectionName() {
169         try {
170             new VcnGatewayConnectionConfig.Builder(
171                             null /* gatewayConnectionName */, TUNNEL_CONNECTION_PARAMS)
172                     .build();
173 
174             fail("Expected exception due to invalid gateway connection name");
175         } catch (NullPointerException e) {
176         }
177     }
178 
179     @Test
testBuilderRequiresNonNullTunnelConnectionParams()180     public void testBuilderRequiresNonNullTunnelConnectionParams() {
181         try {
182             new VcnGatewayConnectionConfig.Builder(
183                             GATEWAY_CONNECTION_NAME_PREFIX, null /* tunnelConnectionParams */)
184                     .build();
185 
186             fail("Expected exception due to the absence of tunnel connection parameters");
187         } catch (NullPointerException e) {
188         }
189     }
190 
191     @Test
testBuilderRequiresMobikeEnabled()192     public void testBuilderRequiresMobikeEnabled() {
193         try {
194             final IkeSessionParams ikeParams =
195                     IkeSessionParamsUtilsTest.createBuilderMinimum()
196                             .removeIkeOption(IKE_OPTION_MOBIKE)
197                             .build();
198             final IkeTunnelConnectionParams tunnelParams =
199                     TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
200             new VcnGatewayConnectionConfig.Builder(GATEWAY_CONNECTION_NAME_PREFIX, tunnelParams);
201             fail("Expected exception due to MOBIKE not enabled");
202         } catch (IllegalArgumentException e) {
203         }
204     }
205 
206     @Test
testBuilderRequiresNonEmptyExposedCaps()207     public void testBuilderRequiresNonEmptyExposedCaps() {
208         try {
209             newBuilder().build();
210 
211             fail("Expected exception due to invalid exposed capabilities");
212         } catch (IllegalArgumentException e) {
213         }
214     }
215 
216     @Test
testBuilderRequiresNonNullNetworkTemplates()217     public void testBuilderRequiresNonNullNetworkTemplates() {
218         try {
219             newBuilder().setVcnUnderlyingNetworkPriorities(null);
220             fail("Expected exception due to invalid underlyingNetworkTemplates");
221         } catch (NullPointerException e) {
222         }
223     }
224 
225     @Test
testBuilderRequiresNonNullRetryInterval()226     public void testBuilderRequiresNonNullRetryInterval() {
227         try {
228             newBuilder().setRetryIntervalsMillis(null);
229             fail("Expected exception due to invalid retryIntervalMs");
230         } catch (IllegalArgumentException e) {
231         }
232     }
233 
234     @Test
testBuilderRequiresNonEmptyRetryInterval()235     public void testBuilderRequiresNonEmptyRetryInterval() {
236         try {
237             newBuilder().setRetryIntervalsMillis(new long[0]);
238             fail("Expected exception due to invalid retryIntervalMs");
239         } catch (IllegalArgumentException e) {
240         }
241     }
242 
243     @Test
testBuilderRequiresValidMtu()244     public void testBuilderRequiresValidMtu() {
245         try {
246             newBuilder().setMaxMtu(VcnGatewayConnectionConfig.MIN_MTU_V6 - 1);
247             fail("Expected exception due to invalid mtu");
248         } catch (IllegalArgumentException e) {
249         }
250     }
251 
252     @Test
testBuilderRequiresValidOption()253     public void testBuilderRequiresValidOption() {
254         try {
255             newBuilder().addGatewayOption(-1);
256             fail("Expected exception due to the invalid VCN gateway option");
257         } catch (IllegalArgumentException e) {
258         }
259     }
260 
261     @Test
testBuilderAndGetters()262     public void testBuilderAndGetters() {
263         final VcnGatewayConnectionConfig config = buildTestConfig();
264 
265         assertTrue(config.getGatewayConnectionName().startsWith(GATEWAY_CONNECTION_NAME_PREFIX));
266 
267         int[] exposedCaps = config.getExposedCapabilities();
268         Arrays.sort(exposedCaps);
269         assertArrayEquals(EXPOSED_CAPS, exposedCaps);
270 
271         assertEquals(UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkPriorities());
272         assertEquals(TUNNEL_CONNECTION_PARAMS, config.getTunnelConnectionParams());
273 
274         assertArrayEquals(RETRY_INTERVALS_MS, config.getRetryIntervalsMillis());
275         assertEquals(MAX_MTU, config.getMaxMtu());
276 
277         assertFalse(
278                 config.hasGatewayOption(
279                         VCN_GATEWAY_OPTION_ENABLE_DATA_STALL_RECOVERY_WITH_MOBILITY));
280     }
281 
282     @Test
testBuilderAndGettersWithOptions()283     public void testBuilderAndGettersWithOptions() {
284         final VcnGatewayConnectionConfig config =
285                 buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS);
286 
287         for (int option : GATEWAY_OPTIONS) {
288             assertTrue(config.hasGatewayOption(option));
289         }
290     }
291 
292     @Test
testPersistableBundle()293     public void testPersistableBundle() {
294         final VcnGatewayConnectionConfig config = buildTestConfig();
295 
296         assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
297     }
298 
299     @Test
testPersistableBundleWithOptions()300     public void testPersistableBundleWithOptions() {
301         final VcnGatewayConnectionConfig config =
302                 buildTestConfigWithGatewayOptions(GATEWAY_OPTIONS);
303 
304         assertEquals(config, new VcnGatewayConnectionConfig(config.toPersistableBundle()));
305     }
306 
307     @Test
testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates()308     public void testParsePersistableBundleWithoutVcnUnderlyingNetworkTemplates() {
309         PersistableBundle configBundle = buildTestConfig().toPersistableBundle();
310         configBundle.putPersistableBundle(UNDERLYING_NETWORK_TEMPLATES_KEY, null);
311 
312         final VcnGatewayConnectionConfig config = new VcnGatewayConnectionConfig(configBundle);
313         assertEquals(
314                 DEFAULT_UNDERLYING_NETWORK_TEMPLATES, config.getVcnUnderlyingNetworkPriorities());
315     }
316 
buildTunnelConnectionParams(String ikePsk)317     private static IkeTunnelConnectionParams buildTunnelConnectionParams(String ikePsk) {
318         final IkeSessionParams ikeParams =
319                 IkeSessionParamsUtilsTest.createBuilderMinimum()
320                         .setAuthPsk(ikePsk.getBytes())
321                         .build();
322         return TunnelConnectionParamsUtilsTest.buildTestParams(ikeParams);
323     }
324 
325     @Test
testTunnelConnectionParamsEquals()326     public void testTunnelConnectionParamsEquals() throws Exception {
327         final String connectionName = "testTunnelConnectionParamsEquals.connectionName";
328         final String psk = "testTunnelConnectionParamsEquals.psk";
329 
330         final IkeTunnelConnectionParams tunnelParams = buildTunnelConnectionParams(psk);
331         final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
332 
333         final IkeTunnelConnectionParams anotherTunnelParams = buildTunnelConnectionParams(psk);
334         final VcnGatewayConnectionConfig anotherConfig =
335                 buildTestConfig(connectionName, anotherTunnelParams);
336 
337         assertNotSame(tunnelParams, anotherTunnelParams);
338         assertEquals(tunnelParams, anotherTunnelParams);
339         assertEquals(config, anotherConfig);
340     }
341 
342     @Test
testTunnelConnectionParamsNotEquals()343     public void testTunnelConnectionParamsNotEquals() throws Exception {
344         final String connectionName = "testTunnelConnectionParamsNotEquals.connectionName";
345 
346         final IkeTunnelConnectionParams tunnelParams =
347                 buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskA");
348         final VcnGatewayConnectionConfig config = buildTestConfig(connectionName, tunnelParams);
349 
350         final IkeTunnelConnectionParams anotherTunnelParams =
351                 buildTunnelConnectionParams("testTunnelConnectionParamsNotEquals.pskB");
352         final VcnGatewayConnectionConfig anotherConfig =
353                 buildTestConfig(connectionName, anotherTunnelParams);
354 
355         assertNotEquals(tunnelParams, anotherTunnelParams);
356         assertNotEquals(config, anotherConfig);
357     }
358 
buildTestConfigWithVcnUnderlyingNetworkTemplates( List<VcnUnderlyingNetworkTemplate> networkTemplates)359     private static VcnGatewayConnectionConfig buildTestConfigWithVcnUnderlyingNetworkTemplates(
360             List<VcnUnderlyingNetworkTemplate> networkTemplates) {
361         return buildTestConfigWithExposedCaps(
362                 new VcnGatewayConnectionConfig.Builder(
363                                 "buildTestConfigWithVcnUnderlyingNetworkTemplates",
364                                 TUNNEL_CONNECTION_PARAMS)
365                         .setVcnUnderlyingNetworkPriorities(networkTemplates),
366                 EXPOSED_CAPS);
367     }
368 
369     @Test
testVcnUnderlyingNetworkTemplatesEquality()370     public void testVcnUnderlyingNetworkTemplatesEquality() throws Exception {
371         final VcnGatewayConnectionConfig config =
372                 buildTestConfigWithVcnUnderlyingNetworkTemplates(UNDERLYING_NETWORK_TEMPLATES);
373 
374         final List<VcnUnderlyingNetworkTemplate> networkTemplatesEqual = new ArrayList();
375         networkTemplatesEqual.add(VcnCellUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
376         networkTemplatesEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
377         final VcnGatewayConnectionConfig configEqual =
378                 buildTestConfigWithVcnUnderlyingNetworkTemplates(networkTemplatesEqual);
379 
380         final List<VcnUnderlyingNetworkTemplate> networkTemplatesNotEqual = new ArrayList();
381         networkTemplatesNotEqual.add(VcnWifiUnderlyingNetworkTemplateTest.getTestNetworkTemplate());
382         final VcnGatewayConnectionConfig configNotEqual =
383                 buildTestConfigWithVcnUnderlyingNetworkTemplates(networkTemplatesNotEqual);
384 
385         assertEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesEqual);
386         assertEquals(config, configEqual);
387 
388         assertNotEquals(UNDERLYING_NETWORK_TEMPLATES, networkTemplatesNotEqual);
389         assertNotEquals(config, configNotEqual);
390     }
391 
buildConfigWithGatewayOptionsForEqualityTest( Set<Integer> gatewayOptions)392     private static VcnGatewayConnectionConfig buildConfigWithGatewayOptionsForEqualityTest(
393             Set<Integer> gatewayOptions) {
394         return buildTestConfigWithGatewayOptions(
395                 new VcnGatewayConnectionConfig.Builder(
396                         "buildConfigWithGatewayOptionsForEqualityTest", TUNNEL_CONNECTION_PARAMS),
397                 gatewayOptions);
398     }
399 
400     @Test
testVcnGatewayOptionsEquality()401     public void testVcnGatewayOptionsEquality() throws Exception {
402         final VcnGatewayConnectionConfig config =
403                 buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS);
404 
405         final VcnGatewayConnectionConfig configEqual =
406                 buildConfigWithGatewayOptionsForEqualityTest(GATEWAY_OPTIONS);
407 
408         final VcnGatewayConnectionConfig configNotEqual =
409                 buildConfigWithGatewayOptionsForEqualityTest(Collections.emptySet());
410 
411         assertEquals(config, configEqual);
412         assertNotEquals(config, configNotEqual);
413     }
414 }
415