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