1 /*
2  * Copyright (C) 2016 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 com.android.server.connectivity;
18 
19 import static android.Manifest.permission.CONTROL_VPN;
20 import static android.content.pm.PackageManager.PERMISSION_DENIED;
21 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
22 import static android.content.pm.UserInfo.FLAG_ADMIN;
23 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
24 import static android.content.pm.UserInfo.FLAG_PRIMARY;
25 import static android.content.pm.UserInfo.FLAG_RESTRICTED;
26 import static android.net.ConnectivityManager.NetworkCallback;
27 import static android.net.INetd.IF_STATE_DOWN;
28 import static android.net.INetd.IF_STATE_UP;
29 import static android.os.UserHandle.PER_USER_RANGE;
30 
31 import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
32 import static com.android.testutils.MiscAsserts.assertThrows;
33 
34 import static org.junit.Assert.assertArrayEquals;
35 import static org.junit.Assert.assertEquals;
36 import static org.junit.Assert.assertFalse;
37 import static org.junit.Assert.assertNotNull;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.fail;
40 import static org.junit.Assume.assumeTrue;
41 import static org.mockito.ArgumentMatchers.any;
42 import static org.mockito.ArgumentMatchers.anyBoolean;
43 import static org.mockito.ArgumentMatchers.anyInt;
44 import static org.mockito.ArgumentMatchers.anyString;
45 import static org.mockito.ArgumentMatchers.argThat;
46 import static org.mockito.ArgumentMatchers.eq;
47 import static org.mockito.Mockito.atLeastOnce;
48 import static org.mockito.Mockito.doAnswer;
49 import static org.mockito.Mockito.doCallRealMethod;
50 import static org.mockito.Mockito.doNothing;
51 import static org.mockito.Mockito.doReturn;
52 import static org.mockito.Mockito.inOrder;
53 import static org.mockito.Mockito.mock;
54 import static org.mockito.Mockito.never;
55 import static org.mockito.Mockito.timeout;
56 import static org.mockito.Mockito.times;
57 import static org.mockito.Mockito.verify;
58 import static org.mockito.Mockito.when;
59 
60 import android.annotation.NonNull;
61 import android.annotation.UserIdInt;
62 import android.app.AppOpsManager;
63 import android.app.NotificationManager;
64 import android.app.PendingIntent;
65 import android.content.Context;
66 import android.content.pm.ApplicationInfo;
67 import android.content.pm.PackageManager;
68 import android.content.pm.ResolveInfo;
69 import android.content.pm.ServiceInfo;
70 import android.content.pm.UserInfo;
71 import android.content.res.Resources;
72 import android.net.ConnectivityManager;
73 import android.net.INetd;
74 import android.net.Ikev2VpnProfile;
75 import android.net.InetAddresses;
76 import android.net.InterfaceConfigurationParcel;
77 import android.net.IpPrefix;
78 import android.net.IpSecManager;
79 import android.net.IpSecTunnelInterfaceResponse;
80 import android.net.LinkProperties;
81 import android.net.LocalSocket;
82 import android.net.Network;
83 import android.net.NetworkCapabilities;
84 import android.net.NetworkInfo.DetailedState;
85 import android.net.RouteInfo;
86 import android.net.UidRangeParcel;
87 import android.net.VpnManager;
88 import android.net.VpnService;
89 import android.net.VpnTransportInfo;
90 import android.net.ipsec.ike.IkeSessionCallback;
91 import android.net.ipsec.ike.exceptions.IkeProtocolException;
92 import android.os.Build.VERSION_CODES;
93 import android.os.Bundle;
94 import android.os.ConditionVariable;
95 import android.os.INetworkManagementService;
96 import android.os.Process;
97 import android.os.UserHandle;
98 import android.os.UserManager;
99 import android.os.test.TestLooper;
100 import android.provider.Settings;
101 import android.security.Credentials;
102 import android.util.ArrayMap;
103 import android.util.ArraySet;
104 import android.util.Range;
105 
106 import androidx.test.filters.SmallTest;
107 
108 import com.android.internal.R;
109 import com.android.internal.net.LegacyVpnInfo;
110 import com.android.internal.net.VpnConfig;
111 import com.android.internal.net.VpnProfile;
112 import com.android.server.IpSecService;
113 import com.android.testutils.DevSdkIgnoreRule;
114 import com.android.testutils.DevSdkIgnoreRunner;
115 
116 import org.junit.Before;
117 import org.junit.Test;
118 import org.junit.runner.RunWith;
119 import org.mockito.AdditionalAnswers;
120 import org.mockito.Answers;
121 import org.mockito.ArgumentCaptor;
122 import org.mockito.InOrder;
123 import org.mockito.Mock;
124 import org.mockito.MockitoAnnotations;
125 
126 import java.io.BufferedWriter;
127 import java.io.File;
128 import java.io.FileWriter;
129 import java.io.IOException;
130 import java.net.Inet4Address;
131 import java.net.InetAddress;
132 import java.util.ArrayList;
133 import java.util.Arrays;
134 import java.util.Collections;
135 import java.util.HashMap;
136 import java.util.List;
137 import java.util.Map;
138 import java.util.Set;
139 import java.util.concurrent.CompletableFuture;
140 import java.util.concurrent.TimeUnit;
141 import java.util.stream.Stream;
142 
143 /**
144  * Tests for {@link Vpn}.
145  *
146  * Build, install and run with:
147  *  runtest frameworks-net -c com.android.server.connectivity.VpnTest
148  */
149 @RunWith(DevSdkIgnoreRunner.class)
150 @SmallTest
151 @DevSdkIgnoreRule.IgnoreUpTo(VERSION_CODES.R)
152 public class VpnTest {
153     private static final String TAG = "VpnTest";
154 
155     // Mock users
156     static final UserInfo primaryUser = new UserInfo(27, "Primary", FLAG_ADMIN | FLAG_PRIMARY);
157     static final UserInfo secondaryUser = new UserInfo(15, "Secondary", FLAG_ADMIN);
158     static final UserInfo restrictedProfileA = new UserInfo(40, "RestrictedA", FLAG_RESTRICTED);
159     static final UserInfo restrictedProfileB = new UserInfo(42, "RestrictedB", FLAG_RESTRICTED);
160     static final UserInfo managedProfileA = new UserInfo(45, "ManagedA", FLAG_MANAGED_PROFILE);
161     static {
162         restrictedProfileA.restrictedProfileParentId = primaryUser.id;
163         restrictedProfileB.restrictedProfileParentId = secondaryUser.id;
164         managedProfileA.profileGroupId = primaryUser.id;
165     }
166 
167     static final Network EGRESS_NETWORK = new Network(101);
168     static final String EGRESS_IFACE = "wlan0";
169     static final String TEST_VPN_PKG = "com.testvpn.vpn";
170     private static final String TEST_VPN_SERVER = "1.2.3.4";
171     private static final String TEST_VPN_IDENTITY = "identity";
172     private static final byte[] TEST_VPN_PSK = "psk".getBytes();
173 
174     private static final Network TEST_NETWORK = new Network(Integer.MAX_VALUE);
175     private static final String TEST_IFACE_NAME = "TEST_IFACE";
176     private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
177     private static final long TEST_TIMEOUT_MS = 500L;
178 
179     /**
180      * Names and UIDs for some fake packages. Important points:
181      *  - UID is ordered increasing.
182      *  - One pair of packages have consecutive UIDs.
183      */
184     static final String[] PKGS = {"com.example", "org.example", "net.example", "web.vpn"};
185     static final int[] PKG_UIDS = {66, 77, 78, 400};
186 
187     // Mock packages
188     static final Map<String, Integer> mPackages = new ArrayMap<>();
189     static {
190         for (int i = 0; i < PKGS.length; i++) {
mPackages.put(PKGS[i], PKG_UIDS[i])191             mPackages.put(PKGS[i], PKG_UIDS[i]);
192         }
193     }
194     private static final Range<Integer> PRI_USER_RANGE = uidRangeForUser(primaryUser.id);
195 
196     @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
197     @Mock private UserManager mUserManager;
198     @Mock private PackageManager mPackageManager;
199     @Mock private INetworkManagementService mNetService;
200     @Mock private INetd mNetd;
201     @Mock private AppOpsManager mAppOps;
202     @Mock private NotificationManager mNotificationManager;
203     @Mock private Vpn.SystemServices mSystemServices;
204     @Mock private Vpn.Ikev2SessionCreator mIkev2SessionCreator;
205     @Mock private ConnectivityManager mConnectivityManager;
206     @Mock private IpSecService mIpSecService;
207     @Mock private VpnProfileStore mVpnProfileStore;
208     private final VpnProfile mVpnProfile;
209 
210     private IpSecManager mIpSecManager;
211 
VpnTest()212     public VpnTest() throws Exception {
213         // Build an actual VPN profile that is capable of being converted to and from an
214         // Ikev2VpnProfile
215         final Ikev2VpnProfile.Builder builder =
216                 new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
217         builder.setAuthPsk(TEST_VPN_PSK);
218         mVpnProfile = builder.build().toVpnProfile();
219     }
220 
221     @Before
setUp()222     public void setUp() throws Exception {
223         MockitoAnnotations.initMocks(this);
224 
225         mIpSecManager = new IpSecManager(mContext, mIpSecService);
226 
227         when(mContext.getPackageManager()).thenReturn(mPackageManager);
228         setMockedPackages(mPackages);
229 
230         when(mContext.getPackageName()).thenReturn(TEST_VPN_PKG);
231         when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
232         mockService(UserManager.class, Context.USER_SERVICE, mUserManager);
233         mockService(AppOpsManager.class, Context.APP_OPS_SERVICE, mAppOps);
234         mockService(NotificationManager.class, Context.NOTIFICATION_SERVICE, mNotificationManager);
235         mockService(ConnectivityManager.class, Context.CONNECTIVITY_SERVICE, mConnectivityManager);
236         mockService(IpSecManager.class, Context.IPSEC_SERVICE, mIpSecManager);
237         when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
238                 .thenReturn(Resources.getSystem().getString(
239                         R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
240         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
241                 .thenReturn(true);
242 
243         // Used by {@link Notification.Builder}
244         ApplicationInfo applicationInfo = new ApplicationInfo();
245         applicationInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
246         when(mContext.getApplicationInfo()).thenReturn(applicationInfo);
247         when(mPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
248                 .thenReturn(applicationInfo);
249 
250         doNothing().when(mNetService).registerObserver(any());
251 
252         // Deny all appops by default.
253         when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
254                 .thenReturn(AppOpsManager.MODE_IGNORED);
255 
256         // Setup IpSecService
257         final IpSecTunnelInterfaceResponse tunnelResp =
258                 new IpSecTunnelInterfaceResponse(
259                         IpSecManager.Status.OK, TEST_TUNNEL_RESOURCE_ID, TEST_IFACE_NAME);
260         when(mIpSecService.createTunnelInterface(any(), any(), any(), any(), any()))
261                 .thenReturn(tunnelResp);
262         // The unit test should know what kind of permission it needs and set the permission by
263         // itself, so set the default value of Context#checkCallingOrSelfPermission to
264         // PERMISSION_DENIED.
265         doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
266     }
267 
mockService(Class<T> clazz, String name, T service)268     private <T> void mockService(Class<T> clazz, String name, T service) {
269         doReturn(service).when(mContext).getSystemService(name);
270         doReturn(name).when(mContext).getSystemServiceName(clazz);
271         if (mContext.getSystemService(clazz).getClass().equals(Object.class)) {
272             // Test is using mockito-extended (mContext uses Answers.RETURNS_DEEP_STUBS and returned
273             // a mock object on a final method)
274             doCallRealMethod().when(mContext).getSystemService(clazz);
275         }
276     }
277 
rangeSet(Range<Integer> .... ranges)278     private Set<Range<Integer>> rangeSet(Range<Integer> ... ranges) {
279         final Set<Range<Integer>> range = new ArraySet<>();
280         for (Range<Integer> r : ranges) range.add(r);
281 
282         return range;
283     }
284 
uidRangeForUser(int userId)285     private static Range<Integer> uidRangeForUser(int userId) {
286         return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
287     }
288 
uidRange(int start, int stop)289     private Range<Integer> uidRange(int start, int stop) {
290         return new Range<Integer>(start, stop);
291     }
292 
293     @Test
testRestrictedProfilesAreAddedToVpn()294     public void testRestrictedProfilesAreAddedToVpn() {
295         setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
296 
297         final Vpn vpn = createVpn(primaryUser.id);
298 
299         // Assume the user can have restricted profiles.
300         doReturn(true).when(mUserManager).canHaveRestrictedProfile();
301         final Set<Range<Integer>> ranges =
302                 vpn.createUserAndRestrictedProfilesRanges(primaryUser.id, null, null);
303 
304         assertEquals(rangeSet(PRI_USER_RANGE, uidRangeForUser(restrictedProfileA.id)), ranges);
305     }
306 
307     @Test
testManagedProfilesAreNotAddedToVpn()308     public void testManagedProfilesAreNotAddedToVpn() {
309         setMockedUsers(primaryUser, managedProfileA);
310 
311         final Vpn vpn = createVpn(primaryUser.id);
312         final Set<Range<Integer>> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
313                 null, null);
314 
315         assertEquals(rangeSet(PRI_USER_RANGE), ranges);
316     }
317 
318     @Test
testAddUserToVpnOnlyAddsOneUser()319     public void testAddUserToVpnOnlyAddsOneUser() {
320         setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
321 
322         final Vpn vpn = createVpn(primaryUser.id);
323         final Set<Range<Integer>> ranges = new ArraySet<>();
324         vpn.addUserToRanges(ranges, primaryUser.id, null, null);
325 
326         assertEquals(rangeSet(PRI_USER_RANGE), ranges);
327     }
328 
329     @Test
testUidAllowAndDenylist()330     public void testUidAllowAndDenylist() throws Exception {
331         final Vpn vpn = createVpn(primaryUser.id);
332         final Range<Integer> user = PRI_USER_RANGE;
333         final int userStart = user.getLower();
334         final int userStop = user.getUpper();
335         final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
336 
337         // Allowed list
338         final Set<Range<Integer>> allow = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
339                 Arrays.asList(packages), null /* disallowedApplications */);
340         assertEquals(rangeSet(
341                 uidRange(userStart + PKG_UIDS[0], userStart + PKG_UIDS[0]),
342                 uidRange(userStart + PKG_UIDS[1], userStart + PKG_UIDS[2])),
343                 allow);
344 
345         // Denied list
346         final Set<Range<Integer>> disallow =
347                 vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
348                         null /* allowedApplications */, Arrays.asList(packages));
349         assertEquals(rangeSet(
350                 uidRange(userStart, userStart + PKG_UIDS[0] - 1),
351                 uidRange(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
352                 /* Empty range between UIDS[1] and UIDS[2], should be excluded, */
353                 uidRange(userStart + PKG_UIDS[2] + 1, userStop)),
354                 disallow);
355     }
356 
357     @Test
testGetAlwaysAndOnGetLockDown()358     public void testGetAlwaysAndOnGetLockDown() throws Exception {
359         final Vpn vpn = createVpn(primaryUser.id);
360 
361         // Default state.
362         assertFalse(vpn.getAlwaysOn());
363         assertFalse(vpn.getLockdown());
364 
365         // Set always-on without lockdown.
366         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, Collections.emptyList()));
367         assertTrue(vpn.getAlwaysOn());
368         assertFalse(vpn.getLockdown());
369 
370         // Set always-on with lockdown.
371         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, Collections.emptyList()));
372         assertTrue(vpn.getAlwaysOn());
373         assertTrue(vpn.getLockdown());
374 
375         // Remove always-on configuration.
376         assertTrue(vpn.setAlwaysOnPackage(null, false, Collections.emptyList()));
377         assertFalse(vpn.getAlwaysOn());
378         assertFalse(vpn.getLockdown());
379     }
380 
381     @Test
testLockdownChangingPackage()382     public void testLockdownChangingPackage() throws Exception {
383         final Vpn vpn = createVpn(primaryUser.id);
384         final Range<Integer> user = PRI_USER_RANGE;
385         final int userStart = user.getLower();
386         final int userStop = user.getUpper();
387         // Set always-on without lockdown.
388         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null));
389 
390         // Set always-on with lockdown.
391         assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null));
392         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
393                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
394                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
395         }));
396 
397         // Switch to another app.
398         assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null));
399         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
400                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
401                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
402         }));
403         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
404                 new UidRangeParcel(userStart, userStart + PKG_UIDS[3] - 1),
405                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
406         }));
407     }
408 
409     @Test
testLockdownAllowlist()410     public void testLockdownAllowlist() throws Exception {
411         final Vpn vpn = createVpn(primaryUser.id);
412         final Range<Integer> user = PRI_USER_RANGE;
413         final int userStart = user.getLower();
414         final int userStop = user.getUpper();
415         // Set always-on with lockdown and allow app PKGS[2] from lockdown.
416         assertTrue(vpn.setAlwaysOnPackage(
417                 PKGS[1], true, Collections.singletonList(PKGS[2])));
418         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[]  {
419                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
420                 new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
421         }));
422         // Change allowed app list to PKGS[3].
423         assertTrue(vpn.setAlwaysOnPackage(
424                 PKGS[1], true, Collections.singletonList(PKGS[3])));
425         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
426                 new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
427         }));
428         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
429                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1),
430                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
431         }));
432 
433         // Change the VPN app.
434         assertTrue(vpn.setAlwaysOnPackage(
435                 PKGS[0], true, Collections.singletonList(PKGS[3])));
436         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
437                 new UidRangeParcel(userStart, userStart + PKG_UIDS[1] - 1),
438                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStart + PKG_UIDS[3] - 1)
439         }));
440         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
441                 new UidRangeParcel(userStart, userStart + PKG_UIDS[0] - 1),
442                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1)
443         }));
444 
445         // Remove the list of allowed packages.
446         assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null));
447         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
448                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[3] - 1),
449                 new UidRangeParcel(userStart + PKG_UIDS[3] + 1, userStop)
450         }));
451         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
452                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop),
453         }));
454 
455         // Add the list of allowed packages.
456         assertTrue(vpn.setAlwaysOnPackage(
457                 PKGS[0], true, Collections.singletonList(PKGS[1])));
458         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
459                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStop)
460         }));
461         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
462                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
463                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
464         }));
465 
466         // Try allowing a package with a comma, should be rejected.
467         assertFalse(vpn.setAlwaysOnPackage(
468                 PKGS[0], true, Collections.singletonList("a.b,c.d")));
469 
470         // Pass a non-existent packages in the allowlist, they (and only they) should be ignored.
471         // allowed package should change from PGKS[1] to PKGS[2].
472         assertTrue(vpn.setAlwaysOnPackage(
473                 PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app")));
474         verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(new UidRangeParcel[] {
475                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[1] - 1),
476                 new UidRangeParcel(userStart + PKG_UIDS[1] + 1, userStop)
477         }));
478         verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(new UidRangeParcel[] {
479                 new UidRangeParcel(userStart + PKG_UIDS[0] + 1, userStart + PKG_UIDS[2] - 1),
480                 new UidRangeParcel(userStart + PKG_UIDS[2] + 1, userStop)
481         }));
482     }
483 
484     @Test
testLockdownRuleRepeatability()485     public void testLockdownRuleRepeatability() throws Exception {
486         final Vpn vpn = createVpn(primaryUser.id);
487         final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
488                 new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())};
489         // Given legacy lockdown is already enabled,
490         vpn.setLockdown(true);
491         verify(mConnectivityManager, times(1)).setRequireVpnForUids(true,
492                 toRanges(primaryUserRangeParcel));
493 
494         // Enabling legacy lockdown twice should do nothing.
495         vpn.setLockdown(true);
496         verify(mConnectivityManager, times(1)).setRequireVpnForUids(anyBoolean(), any());
497 
498         // And disabling should remove the rules exactly once.
499         vpn.setLockdown(false);
500         verify(mConnectivityManager, times(1)).setRequireVpnForUids(false,
501                 toRanges(primaryUserRangeParcel));
502 
503         // Removing the lockdown again should have no effect.
504         vpn.setLockdown(false);
505         verify(mConnectivityManager, times(2)).setRequireVpnForUids(anyBoolean(), any());
506     }
507 
toRanges(UidRangeParcel[] ranges)508     private ArrayList<Range<Integer>> toRanges(UidRangeParcel[] ranges) {
509         ArrayList<Range<Integer>> rangesArray = new ArrayList<>(ranges.length);
510         for (int i = 0; i < ranges.length; i++) {
511             rangesArray.add(new Range<>(ranges[i].start, ranges[i].stop));
512         }
513         return rangesArray;
514     }
515 
516     @Test
testLockdownRuleReversibility()517     public void testLockdownRuleReversibility() throws Exception {
518         doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
519         final Vpn vpn = createVpn(primaryUser.id);
520         final UidRangeParcel[] entireUser = {
521             new UidRangeParcel(PRI_USER_RANGE.getLower(), PRI_USER_RANGE.getUpper())
522         };
523         final UidRangeParcel[] exceptPkg0 = {
524             new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
525             new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
526         };
527 
528         final InOrder order = inOrder(mConnectivityManager);
529 
530         // Given lockdown is enabled with no package (legacy VPN),
531         vpn.setLockdown(true);
532         order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
533 
534         // When a new VPN package is set the rules should change to cover that package.
535         vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
536         order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(entireUser));
537         order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(exceptPkg0));
538 
539         // When that VPN package is unset, everything should be undone again in reverse.
540         vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
541         order.verify(mConnectivityManager).setRequireVpnForUids(false, toRanges(exceptPkg0));
542         order.verify(mConnectivityManager).setRequireVpnForUids(true, toRanges(entireUser));
543     }
544 
545     @Test
testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()546     public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()
547             throws Exception {
548         assumeTrue(isAtLeastT());
549         final Vpn vpn = createVpnAndSetupUidChecks();
550         assertThrows(SecurityException.class,
551                 () -> vpn.prepare("com.not.vpn.owner", null, VpnManager.TYPE_VPN_SERVICE));
552         assertThrows(SecurityException.class,
553                 () -> vpn.prepare(null, "com.not.vpn.owner", VpnManager.TYPE_VPN_SERVICE));
554         assertThrows(SecurityException.class,
555                 () -> vpn.prepare("com.not.vpn.owner1", "com.not.vpn.owner2",
556                         VpnManager.TYPE_VPN_SERVICE));
557     }
558 
559     @Test
testPrepare_bothOldPackageAndNewPackageAreNull()560     public void testPrepare_bothOldPackageAndNewPackageAreNull() throws Exception {
561         final Vpn vpn = createVpnAndSetupUidChecks();
562         assertTrue(vpn.prepare(null, null, VpnManager.TYPE_VPN_SERVICE));
563 
564     }
565 
566     @Test
testIsAlwaysOnPackageSupported()567     public void testIsAlwaysOnPackageSupported() throws Exception {
568         final Vpn vpn = createVpn(primaryUser.id);
569 
570         ApplicationInfo appInfo = new ApplicationInfo();
571         when(mPackageManager.getApplicationInfoAsUser(eq(PKGS[0]), anyInt(), eq(primaryUser.id)))
572                 .thenReturn(appInfo);
573 
574         ServiceInfo svcInfo = new ServiceInfo();
575         ResolveInfo resInfo = new ResolveInfo();
576         resInfo.serviceInfo = svcInfo;
577         when(mPackageManager.queryIntentServicesAsUser(any(), eq(PackageManager.GET_META_DATA),
578                 eq(primaryUser.id)))
579                 .thenReturn(Collections.singletonList(resInfo));
580 
581         // null package name should return false
582         assertFalse(vpn.isAlwaysOnPackageSupported(null));
583 
584         // Pre-N apps are not supported
585         appInfo.targetSdkVersion = VERSION_CODES.M;
586         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
587 
588         // N+ apps are supported by default
589         appInfo.targetSdkVersion = VERSION_CODES.N;
590         assertTrue(vpn.isAlwaysOnPackageSupported(PKGS[0]));
591 
592         // Apps that opt out explicitly are not supported
593         appInfo.targetSdkVersion = VERSION_CODES.CUR_DEVELOPMENT;
594         Bundle metaData = new Bundle();
595         metaData.putBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, false);
596         svcInfo.metaData = metaData;
597         assertFalse(vpn.isAlwaysOnPackageSupported(PKGS[0]));
598     }
599 
600     @Test
testNotificationShownForAlwaysOnApp()601     public void testNotificationShownForAlwaysOnApp() throws Exception {
602         final UserHandle userHandle = UserHandle.of(primaryUser.id);
603         final Vpn vpn = createVpn(primaryUser.id);
604         setMockedUsers(primaryUser);
605 
606         final InOrder order = inOrder(mNotificationManager);
607 
608         // Don't show a notification for regular disconnected states.
609         vpn.updateState(DetailedState.DISCONNECTED, TAG);
610         order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
611 
612         // Start showing a notification for disconnected once always-on.
613         vpn.setAlwaysOnPackage(PKGS[0], false, null);
614         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
615 
616         // Stop showing the notification once connected.
617         vpn.updateState(DetailedState.CONNECTED, TAG);
618         order.verify(mNotificationManager).cancel(anyString(), anyInt());
619 
620         // Show the notification if we disconnect again.
621         vpn.updateState(DetailedState.DISCONNECTED, TAG);
622         order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
623 
624         // Notification should be cleared after unsetting always-on package.
625         vpn.setAlwaysOnPackage(null, false, null);
626         order.verify(mNotificationManager).cancel(anyString(), anyInt());
627     }
628 
629     /**
630      * The profile name should NOT change between releases for backwards compatibility
631      *
632      * <p>If this is changed between releases, the {@link Vpn#getVpnProfilePrivileged()} method MUST
633      * be updated to ensure backward compatibility.
634      */
635     @Test
testGetProfileNameForPackage()636     public void testGetProfileNameForPackage() throws Exception {
637         final Vpn vpn = createVpn(primaryUser.id);
638         setMockedUsers(primaryUser);
639 
640         final String expected = Credentials.PLATFORM_VPN + primaryUser.id + "_" + TEST_VPN_PKG;
641         assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
642     }
643 
createVpnAndSetupUidChecks(String... grantedOps)644     private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception {
645         return createVpnAndSetupUidChecks(primaryUser, grantedOps);
646     }
647 
createVpnAndSetupUidChecks(UserInfo user, String... grantedOps)648     private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception {
649         final Vpn vpn = createVpn(user.id);
650         setMockedUsers(user);
651 
652         when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
653                 .thenReturn(Process.myUid());
654 
655         for (final String opStr : grantedOps) {
656             when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
657                     null /* attributionTag */, null /* message */))
658                     .thenReturn(AppOpsManager.MODE_ALLOWED);
659         }
660 
661         return vpn;
662     }
663 
checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps)664     private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
665         assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile));
666 
667         // The profile should always be stored, whether or not consent has been previously granted.
668         verify(mVpnProfileStore)
669                 .put(
670                         eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)),
671                         eq(mVpnProfile.encode()));
672 
673         for (final String checkedOpStr : checkedOps) {
674             verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
675                     null /* attributionTag */, null /* message */);
676         }
677     }
678 
679     @Test
testProvisionVpnProfileNoIpsecTunnels()680     public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
681         when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
682                 .thenReturn(false);
683         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
684 
685         try {
686             checkProvisionVpnProfile(
687                     vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
688             fail("Expected exception due to missing feature");
689         } catch (UnsupportedOperationException expected) {
690         }
691     }
692 
693     @Test
testProvisionVpnProfilePreconsented()694     public void testProvisionVpnProfilePreconsented() throws Exception {
695         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
696 
697         checkProvisionVpnProfile(
698                 vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
699     }
700 
701     @Test
testProvisionVpnProfileNotPreconsented()702     public void testProvisionVpnProfileNotPreconsented() throws Exception {
703         final Vpn vpn = createVpnAndSetupUidChecks();
704 
705         // Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
706         // had neither.
707         checkProvisionVpnProfile(vpn, false /* expectedResult */,
708                 AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
709     }
710 
711     @Test
testProvisionVpnProfileVpnServicePreconsented()712     public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
713         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
714 
715         checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
716     }
717 
718     @Test
testProvisionVpnProfileTooLarge()719     public void testProvisionVpnProfileTooLarge() throws Exception {
720         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
721 
722         final VpnProfile bigProfile = new VpnProfile("");
723         bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
724 
725         try {
726             vpn.provisionVpnProfile(TEST_VPN_PKG, bigProfile);
727             fail("Expected IAE due to profile size");
728         } catch (IllegalArgumentException expected) {
729         }
730     }
731 
732     @Test
testProvisionVpnProfileRestrictedUser()733     public void testProvisionVpnProfileRestrictedUser() throws Exception {
734         final Vpn vpn =
735                 createVpnAndSetupUidChecks(
736                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
737 
738         try {
739             vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile);
740             fail("Expected SecurityException due to restricted user");
741         } catch (SecurityException expected) {
742         }
743     }
744 
745     @Test
testDeleteVpnProfile()746     public void testDeleteVpnProfile() throws Exception {
747         final Vpn vpn = createVpnAndSetupUidChecks();
748 
749         vpn.deleteVpnProfile(TEST_VPN_PKG);
750 
751         verify(mVpnProfileStore)
752                 .remove(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
753     }
754 
755     @Test
testDeleteVpnProfileRestrictedUser()756     public void testDeleteVpnProfileRestrictedUser() throws Exception {
757         final Vpn vpn =
758                 createVpnAndSetupUidChecks(
759                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
760 
761         try {
762             vpn.deleteVpnProfile(TEST_VPN_PKG);
763             fail("Expected SecurityException due to restricted user");
764         } catch (SecurityException expected) {
765         }
766     }
767 
768     @Test
testGetVpnProfilePrivileged()769     public void testGetVpnProfilePrivileged() throws Exception {
770         final Vpn vpn = createVpnAndSetupUidChecks();
771 
772         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
773                 .thenReturn(new VpnProfile("").encode());
774 
775         vpn.getVpnProfilePrivileged(TEST_VPN_PKG);
776 
777         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
778     }
779 
780     @Test
testStartVpnProfile()781     public void testStartVpnProfile() throws Exception {
782         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
783 
784         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
785                 .thenReturn(mVpnProfile.encode());
786 
787         vpn.startVpnProfile(TEST_VPN_PKG);
788 
789         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
790         verify(mAppOps)
791                 .noteOpNoThrow(
792                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
793                         eq(Process.myUid()),
794                         eq(TEST_VPN_PKG),
795                         eq(null) /* attributionTag */,
796                         eq(null) /* message */);
797     }
798 
799     @Test
testStartVpnProfileVpnServicePreconsented()800     public void testStartVpnProfileVpnServicePreconsented() throws Exception {
801         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
802 
803         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
804                 .thenReturn(mVpnProfile.encode());
805 
806         vpn.startVpnProfile(TEST_VPN_PKG);
807 
808         // Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
809         verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
810                 TEST_VPN_PKG, null /* attributionTag */, null /* message */);
811     }
812 
813     @Test
testStartVpnProfileNotConsented()814     public void testStartVpnProfileNotConsented() throws Exception {
815         final Vpn vpn = createVpnAndSetupUidChecks();
816 
817         try {
818             vpn.startVpnProfile(TEST_VPN_PKG);
819             fail("Expected failure due to no user consent");
820         } catch (SecurityException expected) {
821         }
822 
823         // Verify both appops were checked.
824         verify(mAppOps)
825                 .noteOpNoThrow(
826                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
827                         eq(Process.myUid()),
828                         eq(TEST_VPN_PKG),
829                         eq(null) /* attributionTag */,
830                         eq(null) /* message */);
831         verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
832                 TEST_VPN_PKG, null /* attributionTag */, null /* message */);
833 
834         // Keystore should never have been accessed.
835         verify(mVpnProfileStore, never()).get(any());
836     }
837 
838     @Test
testStartVpnProfileMissingProfile()839     public void testStartVpnProfileMissingProfile() throws Exception {
840         final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
841 
842         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
843 
844         try {
845             vpn.startVpnProfile(TEST_VPN_PKG);
846             fail("Expected failure due to missing profile");
847         } catch (IllegalArgumentException expected) {
848         }
849 
850         verify(mVpnProfileStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
851         verify(mAppOps)
852                 .noteOpNoThrow(
853                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
854                         eq(Process.myUid()),
855                         eq(TEST_VPN_PKG),
856                         eq(null) /* attributionTag */,
857                         eq(null) /* message */);
858     }
859 
860     @Test
testStartVpnProfileRestrictedUser()861     public void testStartVpnProfileRestrictedUser() throws Exception {
862         final Vpn vpn =
863                 createVpnAndSetupUidChecks(
864                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
865 
866         try {
867             vpn.startVpnProfile(TEST_VPN_PKG);
868             fail("Expected SecurityException due to restricted user");
869         } catch (SecurityException expected) {
870         }
871     }
872 
873     @Test
testStopVpnProfileRestrictedUser()874     public void testStopVpnProfileRestrictedUser() throws Exception {
875         final Vpn vpn =
876                 createVpnAndSetupUidChecks(
877                         restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
878 
879         try {
880             vpn.stopVpnProfile(TEST_VPN_PKG);
881             fail("Expected SecurityException due to restricted user");
882         } catch (SecurityException expected) {
883         }
884     }
885 
886     @Test
testSetPackageAuthorizationVpnService()887     public void testSetPackageAuthorizationVpnService() throws Exception {
888         final Vpn vpn = createVpnAndSetupUidChecks();
889 
890         assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
891         verify(mAppOps)
892                 .setMode(
893                         eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
894                         eq(Process.myUid()),
895                         eq(TEST_VPN_PKG),
896                         eq(AppOpsManager.MODE_ALLOWED));
897     }
898 
899     @Test
testSetPackageAuthorizationPlatformVpn()900     public void testSetPackageAuthorizationPlatformVpn() throws Exception {
901         final Vpn vpn = createVpnAndSetupUidChecks();
902 
903         assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
904         verify(mAppOps)
905                 .setMode(
906                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
907                         eq(Process.myUid()),
908                         eq(TEST_VPN_PKG),
909                         eq(AppOpsManager.MODE_ALLOWED));
910     }
911 
912     @Test
testSetPackageAuthorizationRevokeAuthorization()913     public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
914         final Vpn vpn = createVpnAndSetupUidChecks();
915 
916         assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
917         verify(mAppOps)
918                 .setMode(
919                         eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
920                         eq(Process.myUid()),
921                         eq(TEST_VPN_PKG),
922                         eq(AppOpsManager.MODE_IGNORED));
923         verify(mAppOps)
924                 .setMode(
925                         eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
926                         eq(Process.myUid()),
927                         eq(TEST_VPN_PKG),
928                         eq(AppOpsManager.MODE_IGNORED));
929     }
930 
triggerOnAvailableAndGetCallback()931     private NetworkCallback triggerOnAvailableAndGetCallback() throws Exception {
932         final ArgumentCaptor<NetworkCallback> networkCallbackCaptor =
933                 ArgumentCaptor.forClass(NetworkCallback.class);
934         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
935                 .requestNetwork(any(), networkCallbackCaptor.capture());
936 
937         // onAvailable() will trigger onDefaultNetworkChanged(), so NetdUtils#setInterfaceUp will be
938         // invoked. Set the return value of INetd#interfaceGetCfg to prevent NullPointerException.
939         final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
940         config.flags = new String[] {IF_STATE_DOWN};
941         when(mNetd.interfaceGetCfg(anyString())).thenReturn(config);
942         final NetworkCallback cb = networkCallbackCaptor.getValue();
943         cb.onAvailable(TEST_NETWORK);
944         return cb;
945     }
946 
verifyInterfaceSetCfgWithFlags(String flag)947     private void verifyInterfaceSetCfgWithFlags(String flag) throws Exception {
948         // Add a timeout for waiting for interfaceSetCfg to be called.
949         verify(mNetd, timeout(TEST_TIMEOUT_MS)).interfaceSetCfg(argThat(
950                 config -> Arrays.asList(config.flags).contains(flag)));
951     }
952 
953     @Test
testStartPlatformVpnAuthenticationFailed()954     public void testStartPlatformVpnAuthenticationFailed() throws Exception {
955         final ArgumentCaptor<IkeSessionCallback> captor =
956                 ArgumentCaptor.forClass(IkeSessionCallback.class);
957         final IkeProtocolException exception = mock(IkeProtocolException.class);
958         when(exception.getErrorType())
959                 .thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
960 
961         final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
962         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
963 
964         verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
965 
966         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
967         // state
968         verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
969                 .createIkeSession(any(), any(), any(), any(), captor.capture(), any());
970         final IkeSessionCallback ikeCb = captor.getValue();
971         ikeCb.onClosedExceptionally(exception);
972 
973         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
974         assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
975     }
976 
977     @Test
testStartPlatformVpnIllegalArgumentExceptionInSetup()978     public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
979         when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
980                 .thenThrow(new IllegalArgumentException());
981         final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
982         final NetworkCallback cb = triggerOnAvailableAndGetCallback();
983 
984         verifyInterfaceSetCfgWithFlags(IF_STATE_UP);
985 
986         // Wait for createIkeSession() to be called before proceeding in order to ensure consistent
987         // state
988         verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
989         assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
990     }
991 
setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled)992     private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
993         assertTrue(vpn.setAlwaysOnPackage(TEST_VPN_PKG, lockdownEnabled, null));
994 
995         verify(mVpnProfileStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
996         verify(mAppOps).setMode(
997                 eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
998                 eq(AppOpsManager.MODE_ALLOWED));
999 
1000         verify(mSystemServices).settingsSecurePutStringForUser(
1001                 eq(Settings.Secure.ALWAYS_ON_VPN_APP), eq(TEST_VPN_PKG), eq(primaryUser.id));
1002         verify(mSystemServices).settingsSecurePutIntForUser(
1003                 eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN), eq(lockdownEnabled ? 1 : 0),
1004                 eq(primaryUser.id));
1005         verify(mSystemServices).settingsSecurePutStringForUser(
1006                 eq(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST), eq(""), eq(primaryUser.id));
1007     }
1008 
1009     @Test
testSetAndStartAlwaysOnVpn()1010     public void testSetAndStartAlwaysOnVpn() throws Exception {
1011         final Vpn vpn = createVpn(primaryUser.id);
1012         setMockedUsers(primaryUser);
1013 
1014         // UID checks must return a different UID; otherwise it'll be treated as already prepared.
1015         final int uid = Process.myUid() + 1;
1016         when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
1017                 .thenReturn(uid);
1018         when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
1019                 .thenReturn(mVpnProfile.encode());
1020 
1021         setAndVerifyAlwaysOnPackage(vpn, uid, false);
1022         assertTrue(vpn.startAlwaysOnVpn());
1023 
1024         // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
1025         // a subsequent CL.
1026     }
1027 
startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile)1028     private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
1029         setMockedUsers(primaryUser);
1030 
1031         // Dummy egress interface
1032         final LinkProperties lp = new LinkProperties();
1033         lp.setInterfaceName(EGRESS_IFACE);
1034 
1035         final RouteInfo defaultRoute = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
1036                         InetAddresses.parseNumericAddress("192.0.2.0"), EGRESS_IFACE);
1037         lp.addRoute(defaultRoute);
1038 
1039         vpn.startLegacyVpn(vpnProfile, EGRESS_NETWORK, lp);
1040         return vpn;
1041     }
1042 
1043     @Test
testStartPlatformVpn()1044     public void testStartPlatformVpn() throws Exception {
1045         startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
1046         // TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
1047         // a subsequent patch.
1048     }
1049 
1050     @Test
testStartRacoonNumericAddress()1051     public void testStartRacoonNumericAddress() throws Exception {
1052         startRacoon("1.2.3.4", "1.2.3.4");
1053     }
1054 
1055     @Test
testStartRacoonHostname()1056     public void testStartRacoonHostname() throws Exception {
1057         startRacoon("hostname", "5.6.7.8"); // address returned by deps.resolve
1058     }
1059 
assertTransportInfoMatches(NetworkCapabilities nc, int type)1060     private void assertTransportInfoMatches(NetworkCapabilities nc, int type) {
1061         assertNotNull(nc);
1062         VpnTransportInfo ti = (VpnTransportInfo) nc.getTransportInfo();
1063         assertNotNull(ti);
1064         assertEquals(type, ti.getType());
1065     }
1066 
startRacoon(final String serverAddr, final String expectedAddr)1067     public void startRacoon(final String serverAddr, final String expectedAddr)
1068             throws Exception {
1069         final ConditionVariable legacyRunnerReady = new ConditionVariable();
1070         final VpnProfile profile = new VpnProfile("testProfile" /* key */);
1071         profile.type = VpnProfile.TYPE_L2TP_IPSEC_PSK;
1072         profile.name = "testProfileName";
1073         profile.username = "userName";
1074         profile.password = "thePassword";
1075         profile.server = serverAddr;
1076         profile.ipsecIdentifier = "id";
1077         profile.ipsecSecret = "secret";
1078         profile.l2tpSecret = "l2tpsecret";
1079 
1080         when(mConnectivityManager.getAllNetworks())
1081             .thenReturn(new Network[] { new Network(101) });
1082 
1083         when(mConnectivityManager.registerNetworkAgent(any(), any(), any(), any(),
1084                 any(), any(), anyInt())).thenAnswer(invocation -> {
1085                     // The runner has registered an agent and is now ready.
1086                     legacyRunnerReady.open();
1087                     return new Network(102);
1088                 });
1089         final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
1090         final TestDeps deps = (TestDeps) vpn.mDeps;
1091         try {
1092             // udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
1093             assertArrayEquals(
1094                     new String[] { EGRESS_IFACE, expectedAddr, "udppsk",
1095                             profile.ipsecIdentifier, profile.ipsecSecret, "1701" },
1096                     deps.racoonArgs.get(10, TimeUnit.SECONDS));
1097             // literal values are hardcoded in Vpn.java for mtpd args
1098             assertArrayEquals(
1099                     new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
1100                             "name", profile.username, "password", profile.password,
1101                             "linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
1102                             "idle", "1800", "mtu", "1270", "mru", "1270" },
1103                     deps.mtpdArgs.get(10, TimeUnit.SECONDS));
1104 
1105             // Now wait for the runner to be ready before testing for the route.
1106             ArgumentCaptor<LinkProperties> lpCaptor = ArgumentCaptor.forClass(LinkProperties.class);
1107             ArgumentCaptor<NetworkCapabilities> ncCaptor =
1108                     ArgumentCaptor.forClass(NetworkCapabilities.class);
1109             verify(mConnectivityManager, timeout(10_000)).registerNetworkAgent(any(), any(),
1110                     lpCaptor.capture(), ncCaptor.capture(), any(), any(), anyInt());
1111 
1112             // In this test the expected address is always v4 so /32.
1113             // Note that the interface needs to be specified because RouteInfo objects stored in
1114             // LinkProperties objects always acquire the LinkProperties' interface.
1115             final RouteInfo expectedRoute = new RouteInfo(new IpPrefix(expectedAddr + "/32"),
1116                     null, EGRESS_IFACE, RouteInfo.RTN_THROW);
1117             final List<RouteInfo> actualRoutes = lpCaptor.getValue().getRoutes();
1118             assertTrue("Expected throw route (" + expectedRoute + ") not found in " + actualRoutes,
1119                     actualRoutes.contains(expectedRoute));
1120 
1121             assertTransportInfoMatches(ncCaptor.getValue(), VpnManager.TYPE_VPN_LEGACY);
1122         } finally {
1123             // Now interrupt the thread, unblock the runner and clean up.
1124             vpn.mVpnRunner.exitVpnRunner();
1125             deps.getStateFile().delete(); // set to delete on exit, but this deletes it earlier
1126             vpn.mVpnRunner.join(10_000); // wait for up to 10s for the runner to die and cleanup
1127         }
1128     }
1129 
1130     private static final class TestDeps extends Vpn.Dependencies {
1131         public final CompletableFuture<String[]> racoonArgs = new CompletableFuture();
1132         public final CompletableFuture<String[]> mtpdArgs = new CompletableFuture();
1133         public final File mStateFile;
1134 
1135         private final HashMap<String, Boolean> mRunningServices = new HashMap<>();
1136 
TestDeps()1137         TestDeps() {
1138             try {
1139                 mStateFile = File.createTempFile("vpnTest", ".tmp");
1140                 mStateFile.deleteOnExit();
1141             } catch (final IOException e) {
1142                 throw new RuntimeException(e);
1143             }
1144         }
1145 
1146         @Override
isCallerSystem()1147         public boolean isCallerSystem() {
1148             return true;
1149         }
1150 
1151         @Override
startService(final String serviceName)1152         public void startService(final String serviceName) {
1153             mRunningServices.put(serviceName, true);
1154         }
1155 
1156         @Override
stopService(final String serviceName)1157         public void stopService(final String serviceName) {
1158             mRunningServices.put(serviceName, false);
1159         }
1160 
1161         @Override
isServiceRunning(final String serviceName)1162         public boolean isServiceRunning(final String serviceName) {
1163             return mRunningServices.getOrDefault(serviceName, false);
1164         }
1165 
1166         @Override
isServiceStopped(final String serviceName)1167         public boolean isServiceStopped(final String serviceName) {
1168             return !isServiceRunning(serviceName);
1169         }
1170 
1171         @Override
getStateFile()1172         public File getStateFile() {
1173             return mStateFile;
1174         }
1175 
1176         @Override
getIntentForStatusPanel(Context context)1177         public PendingIntent getIntentForStatusPanel(Context context) {
1178             return null;
1179         }
1180 
1181         @Override
sendArgumentsToDaemon( final String daemon, final LocalSocket socket, final String[] arguments, final Vpn.RetryScheduler interruptChecker)1182         public void sendArgumentsToDaemon(
1183                 final String daemon, final LocalSocket socket, final String[] arguments,
1184                 final Vpn.RetryScheduler interruptChecker) throws IOException {
1185             if ("racoon".equals(daemon)) {
1186                 racoonArgs.complete(arguments);
1187             } else if ("mtpd".equals(daemon)) {
1188                 writeStateFile(arguments);
1189                 mtpdArgs.complete(arguments);
1190             } else {
1191                 throw new UnsupportedOperationException("Unsupported daemon : " + daemon);
1192             }
1193         }
1194 
writeStateFile(final String[] arguments)1195         private void writeStateFile(final String[] arguments) throws IOException {
1196             mStateFile.delete();
1197             mStateFile.createNewFile();
1198             mStateFile.deleteOnExit();
1199             final BufferedWriter writer = new BufferedWriter(
1200                     new FileWriter(mStateFile, false /* append */));
1201             writer.write(EGRESS_IFACE);
1202             writer.write("\n");
1203             // addresses
1204             writer.write("10.0.0.1/24\n");
1205             // routes
1206             writer.write("192.168.6.0/24\n");
1207             // dns servers
1208             writer.write("192.168.6.1\n");
1209             // search domains
1210             writer.write("vpn.searchdomains.com\n");
1211             // endpoint - intentionally empty
1212             writer.write("\n");
1213             writer.flush();
1214             writer.close();
1215         }
1216 
1217         @Override
1218         @NonNull
resolve(final String endpoint)1219         public InetAddress resolve(final String endpoint) {
1220             try {
1221                 // If a numeric IP address, return it.
1222                 return InetAddress.parseNumericAddress(endpoint);
1223             } catch (IllegalArgumentException e) {
1224                 // Otherwise, return some token IP to test for.
1225                 return InetAddress.parseNumericAddress("5.6.7.8");
1226             }
1227         }
1228 
1229         @Override
isInterfacePresent(final Vpn vpn, final String iface)1230         public boolean isInterfacePresent(final Vpn vpn, final String iface) {
1231             return true;
1232         }
1233     }
1234 
1235     /**
1236      * Mock some methods of vpn object.
1237      */
createVpn(@serIdInt int userId)1238     private Vpn createVpn(@UserIdInt int userId) {
1239         final Context asUserContext = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
1240         doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
1241         when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
1242                 .thenReturn(asUserContext);
1243         final TestLooper testLooper = new TestLooper();
1244         final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
1245                 mNetd, userId, mVpnProfileStore, mSystemServices, mIkev2SessionCreator);
1246         verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
1247                 provider -> provider.getName().contains("VpnNetworkProvider")
1248         ));
1249         return vpn;
1250     }
1251 
1252     /**
1253      * Populate {@link #mUserManager} with a list of fake users.
1254      */
setMockedUsers(UserInfo... users)1255     private void setMockedUsers(UserInfo... users) {
1256         final Map<Integer, UserInfo> userMap = new ArrayMap<>();
1257         for (UserInfo user : users) {
1258             userMap.put(user.id, user);
1259         }
1260 
1261         /**
1262          * @see UserManagerService#getUsers(boolean)
1263          */
1264         doAnswer(invocation -> {
1265             final ArrayList<UserInfo> result = new ArrayList<>(users.length);
1266             for (UserInfo ui : users) {
1267                 if (ui.isEnabled() && !ui.partial) {
1268                     result.add(ui);
1269                 }
1270             }
1271             return result;
1272         }).when(mUserManager).getAliveUsers();
1273 
1274         doAnswer(invocation -> {
1275             final int id = (int) invocation.getArguments()[0];
1276             return userMap.get(id);
1277         }).when(mUserManager).getUserInfo(anyInt());
1278     }
1279 
1280     /**
1281      * Populate {@link #mPackageManager} with a fake packageName-to-UID mapping.
1282      */
setMockedPackages(final Map<String, Integer> packages)1283     private void setMockedPackages(final Map<String, Integer> packages) {
1284         try {
1285             doAnswer(invocation -> {
1286                 final String appName = (String) invocation.getArguments()[0];
1287                 final int userId = (int) invocation.getArguments()[1];
1288                 Integer appId = packages.get(appName);
1289                 if (appId == null) throw new PackageManager.NameNotFoundException(appName);
1290                 return UserHandle.getUid(userId, appId);
1291             }).when(mPackageManager).getPackageUidAsUser(anyString(), anyInt());
1292         } catch (Exception e) {
1293         }
1294     }
1295 
setMockedNetworks(final Map<Network, NetworkCapabilities> networks)1296     private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
1297         doAnswer(invocation -> {
1298             final Network network = (Network) invocation.getArguments()[0];
1299             return networks.get(network);
1300         }).when(mConnectivityManager).getNetworkCapabilities(any());
1301     }
1302 
1303     // Need multiple copies of this, but Java's Stream objects can't be reused or
1304     // duplicated.
publicIpV4Routes()1305     private Stream<String> publicIpV4Routes() {
1306         return Stream.of(
1307                 "0.0.0.0/5", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4",
1308                 "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6",
1309                 "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9",
1310                 "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11",
1311                 "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14",
1312                 "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7",
1313                 "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4");
1314     }
1315 
publicIpV6Routes()1316     private Stream<String> publicIpV6Routes() {
1317         return Stream.of(
1318                 "::/1", "8000::/2", "c000::/3", "e000::/4", "f000::/5", "f800::/6",
1319                 "fe00::/8", "2605:ef80:e:af1d::/64");
1320     }
1321 }
1322