1 /* 2 * Copyright (C) 2011 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.BIND_VPN_SERVICE; 20 import static android.Manifest.permission.CONTROL_VPN; 21 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 22 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; 23 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; 24 import static android.net.RouteInfo.RTN_THROW; 25 import static android.net.RouteInfo.RTN_UNREACHABLE; 26 import static android.net.VpnManager.NOTIFICATION_CHANNEL_VPN; 27 import static android.os.PowerWhitelistManager.REASON_VPN; 28 import static android.os.UserHandle.PER_USER_RANGE; 29 30 import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; 31 32 import static java.util.Objects.requireNonNull; 33 34 import android.Manifest; 35 import android.annotation.NonNull; 36 import android.annotation.Nullable; 37 import android.annotation.UserIdInt; 38 import android.app.AppOpsManager; 39 import android.app.Notification; 40 import android.app.NotificationManager; 41 import android.app.PendingIntent; 42 import android.content.BroadcastReceiver; 43 import android.content.ComponentName; 44 import android.content.ContentResolver; 45 import android.content.Context; 46 import android.content.Intent; 47 import android.content.IntentFilter; 48 import android.content.ServiceConnection; 49 import android.content.pm.ApplicationInfo; 50 import android.content.pm.PackageManager; 51 import android.content.pm.PackageManager.NameNotFoundException; 52 import android.content.pm.ResolveInfo; 53 import android.content.pm.UserInfo; 54 import android.net.ConnectivityManager; 55 import android.net.DnsResolver; 56 import android.net.INetd; 57 import android.net.INetworkManagementEventObserver; 58 import android.net.Ikev2VpnProfile; 59 import android.net.InetAddresses; 60 import android.net.IpPrefix; 61 import android.net.IpSecManager; 62 import android.net.IpSecManager.IpSecTunnelInterface; 63 import android.net.IpSecTransform; 64 import android.net.LinkAddress; 65 import android.net.LinkProperties; 66 import android.net.LocalSocket; 67 import android.net.LocalSocketAddress; 68 import android.net.Network; 69 import android.net.NetworkAgent; 70 import android.net.NetworkAgentConfig; 71 import android.net.NetworkCapabilities; 72 import android.net.NetworkInfo; 73 import android.net.NetworkInfo.DetailedState; 74 import android.net.NetworkProvider; 75 import android.net.NetworkRequest; 76 import android.net.NetworkScore; 77 import android.net.RouteInfo; 78 import android.net.UidRangeParcel; 79 import android.net.UnderlyingNetworkInfo; 80 import android.net.VpnManager; 81 import android.net.VpnProfileState; 82 import android.net.VpnService; 83 import android.net.VpnTransportInfo; 84 import android.net.ipsec.ike.ChildSessionCallback; 85 import android.net.ipsec.ike.ChildSessionConfiguration; 86 import android.net.ipsec.ike.ChildSessionParams; 87 import android.net.ipsec.ike.IkeSession; 88 import android.net.ipsec.ike.IkeSessionCallback; 89 import android.net.ipsec.ike.IkeSessionConfiguration; 90 import android.net.ipsec.ike.IkeSessionConnectionInfo; 91 import android.net.ipsec.ike.IkeSessionParams; 92 import android.net.ipsec.ike.IkeTunnelConnectionParams; 93 import android.net.ipsec.ike.exceptions.IkeNetworkLostException; 94 import android.net.ipsec.ike.exceptions.IkeNonProtocolException; 95 import android.net.ipsec.ike.exceptions.IkeProtocolException; 96 import android.net.ipsec.ike.exceptions.IkeTimeoutException; 97 import android.os.Binder; 98 import android.os.Build.VERSION_CODES; 99 import android.os.Bundle; 100 import android.os.CancellationSignal; 101 import android.os.FileUtils; 102 import android.os.IBinder; 103 import android.os.INetworkManagementService; 104 import android.os.Looper; 105 import android.os.Parcel; 106 import android.os.ParcelFileDescriptor; 107 import android.os.PersistableBundle; 108 import android.os.Process; 109 import android.os.RemoteException; 110 import android.os.SystemClock; 111 import android.os.SystemService; 112 import android.os.UserHandle; 113 import android.os.UserManager; 114 import android.provider.Settings; 115 import android.security.Credentials; 116 import android.security.KeyStore2; 117 import android.security.keystore.KeyProperties; 118 import android.system.keystore2.Domain; 119 import android.system.keystore2.KeyDescriptor; 120 import android.system.keystore2.KeyPermission; 121 import android.text.TextUtils; 122 import android.util.ArraySet; 123 import android.util.Log; 124 import android.util.Range; 125 126 import com.android.internal.R; 127 import com.android.internal.annotations.GuardedBy; 128 import com.android.internal.annotations.VisibleForTesting; 129 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; 130 import com.android.internal.net.LegacyVpnInfo; 131 import com.android.internal.net.VpnConfig; 132 import com.android.internal.net.VpnProfile; 133 import com.android.modules.utils.build.SdkLevel; 134 import com.android.net.module.util.NetdUtils; 135 import com.android.net.module.util.NetworkStackConstants; 136 import com.android.server.DeviceIdleInternal; 137 import com.android.server.LocalServices; 138 import com.android.server.net.BaseNetworkObserver; 139 import com.android.server.vcn.util.PersistableBundleUtils; 140 141 import libcore.io.IoUtils; 142 143 import java.io.File; 144 import java.io.FileDescriptor; 145 import java.io.IOException; 146 import java.io.InputStream; 147 import java.io.OutputStream; 148 import java.net.Inet4Address; 149 import java.net.Inet6Address; 150 import java.net.InetAddress; 151 import java.net.UnknownHostException; 152 import java.nio.charset.StandardCharsets; 153 import java.security.GeneralSecurityException; 154 import java.security.KeyStore; 155 import java.security.KeyStoreException; 156 import java.security.NoSuchAlgorithmException; 157 import java.security.cert.Certificate; 158 import java.security.cert.CertificateEncodingException; 159 import java.security.cert.CertificateException; 160 import java.util.ArrayList; 161 import java.util.Arrays; 162 import java.util.Collection; 163 import java.util.Collections; 164 import java.util.List; 165 import java.util.Objects; 166 import java.util.Set; 167 import java.util.SortedSet; 168 import java.util.TreeSet; 169 import java.util.UUID; 170 import java.util.concurrent.CompletableFuture; 171 import java.util.concurrent.ExecutionException; 172 import java.util.concurrent.Executor; 173 import java.util.concurrent.RejectedExecutionException; 174 import java.util.concurrent.ScheduledFuture; 175 import java.util.concurrent.ScheduledThreadPoolExecutor; 176 import java.util.concurrent.TimeUnit; 177 import java.util.concurrent.atomic.AtomicInteger; 178 179 /** 180 * @hide 181 */ 182 public class Vpn { 183 private static final String NETWORKTYPE = "VPN"; 184 private static final String TAG = "Vpn"; 185 private static final String VPN_PROVIDER_NAME_BASE = "VpnNetworkProvider:"; 186 private static final boolean LOGD = true; 187 private static final String ANDROID_KEYSTORE_PROVIDER = "AndroidKeyStore"; 188 /** Key containing prefix of vpn app excluded list */ 189 @VisibleForTesting static final String VPN_APP_EXCLUDED = "VPNAPPEXCLUDED_"; 190 191 // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on 192 // the device idle allowlist during service launch and VPN bootstrap. 193 private static final long VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS = 60 * 1000; 194 195 // Length of time (in milliseconds) that an app registered for VpnManager events is placed on 196 // the device idle allowlist each time the VpnManager event is fired. 197 private static final long VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS = 30 * 1000; 198 199 private static final String LOCKDOWN_ALLOWLIST_SETTING_NAME = 200 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN_WHITELIST; 201 202 /** 203 * The retries for consecutive failures. 204 * 205 * <p>If retries have exceeded the length of this array, the last entry in the array will be 206 * used as a repeating interval. 207 */ 208 private static final long[] IKEV2_VPN_RETRY_DELAYS_SEC = {1L, 2L, 5L, 30L, 60L, 300L, 900L}; 209 /** 210 * Largest profile size allowable for Platform VPNs. 211 * 212 * <p>The largest platform VPN profiles use IKEv2 RSA Certificate Authentication and have two 213 * X509Certificates, and one RSAPrivateKey. This should lead to a max size of 2x 12kB for the 214 * certificates, plus a reasonable upper bound on the private key of 32kB. The rest of the 215 * profile is expected to be negligible in size. 216 */ 217 @VisibleForTesting static final int MAX_VPN_PROFILE_SIZE_BYTES = 1 << 17; // 128kB 218 219 /** 220 * Network score that VPNs will announce to ConnectivityService. 221 * TODO: remove when the network scoring refactor lands. 222 */ 223 private static final int VPN_DEFAULT_SCORE = 101; 224 225 /** 226 * The initial token value of IKE session. 227 */ 228 private static final int STARTING_TOKEN = -1; 229 230 // TODO: create separate trackers for each unique VPN to support 231 // automated reconnection 232 233 private final Context mContext; 234 private final ConnectivityManager mConnectivityManager; 235 private final AppOpsManager mAppOpsManager; 236 // The context is for specific user which is created from mUserId 237 private final Context mUserIdContext; 238 @VisibleForTesting final Dependencies mDeps; 239 private final NetworkInfo mNetworkInfo; 240 @GuardedBy("this") 241 private int mLegacyState; 242 @GuardedBy("this") 243 @VisibleForTesting protected String mPackage; 244 private int mOwnerUID; 245 private boolean mIsPackageTargetingAtLeastQ; 246 @VisibleForTesting 247 protected String mInterface; 248 private Connection mConnection; 249 250 /** Tracks the runners for all VPN types managed by the platform (eg. LegacyVpn, PlatformVpn) */ 251 @VisibleForTesting protected VpnRunner mVpnRunner; 252 253 private PendingIntent mStatusIntent; 254 private volatile boolean mEnableTeardown = true; 255 private final INetworkManagementService mNms; 256 private final INetd mNetd; 257 @VisibleForTesting 258 protected VpnConfig mConfig; 259 private final NetworkProvider mNetworkProvider; 260 @VisibleForTesting 261 protected NetworkAgent mNetworkAgent; 262 private final Looper mLooper; 263 @VisibleForTesting 264 protected NetworkCapabilities mNetworkCapabilities; 265 private final SystemServices mSystemServices; 266 private final Ikev2SessionCreator mIkev2SessionCreator; 267 private final UserManager mUserManager; 268 269 private final VpnProfileStore mVpnProfileStore; 270 271 @VisibleForTesting getVpnProfileStore()272 VpnProfileStore getVpnProfileStore() { 273 return mVpnProfileStore; 274 } 275 276 /** 277 * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This 278 * only applies to {@link VpnService} connections. 279 */ 280 @GuardedBy("this") 281 @VisibleForTesting protected boolean mAlwaysOn = false; 282 283 /** 284 * Whether to disable traffic outside of this VPN even when the VPN is not connected. System 285 * apps can still bypass by choosing explicit networks. Has no effect if {@link mAlwaysOn} is 286 * not set. Applies to all types of VPNs. 287 */ 288 @GuardedBy("this") 289 @VisibleForTesting protected boolean mLockdown = false; 290 291 /** 292 * Set of packages in addition to the VPN app itself that can access the network directly when 293 * VPN is not connected even if {@code mLockdown} is set. 294 */ 295 private @NonNull List<String> mLockdownAllowlist = Collections.emptyList(); 296 297 /** 298 * A memory of what UIDs this class told ConnectivityService to block for the lockdown feature. 299 * 300 * Netd maintains ranges of UIDs for which network should be restricted to using only the VPN 301 * for the lockdown feature. This class manages these UIDs and sends this information to netd. 302 * To avoid sending the same commands multiple times (which would be wasteful) and to be able 303 * to revoke lists (when the rules should change), it's simplest to keep this cache of what 304 * netd knows, so it can be diffed and sent most efficiently. 305 * 306 * The contents of this list must only be changed when updating the UIDs lists with netd, 307 * since it needs to keep in sync with the picture netd has of them. 308 * 309 * @see mLockdown 310 */ 311 @GuardedBy("this") 312 private final Set<UidRangeParcel> mBlockedUidsAsToldToConnectivity = new ArraySet<>(); 313 314 // The user id of initiating VPN. 315 private final int mUserId; 316 317 interface RetryScheduler { checkInterruptAndDelay(boolean sleepLonger)318 void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException; 319 } 320 321 @VisibleForTesting 322 public static class Dependencies { isCallerSystem()323 public boolean isCallerSystem() { 324 return Binder.getCallingUid() == Process.SYSTEM_UID; 325 } 326 startService(final String serviceName)327 public void startService(final String serviceName) { 328 SystemService.start(serviceName); 329 } 330 stopService(final String serviceName)331 public void stopService(final String serviceName) { 332 SystemService.stop(serviceName); 333 } 334 isServiceRunning(final String serviceName)335 public boolean isServiceRunning(final String serviceName) { 336 return SystemService.isRunning(serviceName); 337 } 338 isServiceStopped(final String serviceName)339 public boolean isServiceStopped(final String serviceName) { 340 return SystemService.isStopped(serviceName); 341 } 342 getStateFile()343 public File getStateFile() { 344 return new File("/data/misc/vpn/state"); 345 } 346 getDeviceIdleInternal()347 public DeviceIdleInternal getDeviceIdleInternal() { 348 return LocalServices.getService(DeviceIdleInternal.class); 349 } 350 getIntentForStatusPanel(Context context)351 public PendingIntent getIntentForStatusPanel(Context context) { 352 return VpnConfig.getIntentForStatusPanel(context); 353 } 354 sendArgumentsToDaemon( final String daemon, final LocalSocket socket, final String[] arguments, final RetryScheduler retryScheduler)355 public void sendArgumentsToDaemon( 356 final String daemon, final LocalSocket socket, final String[] arguments, 357 final RetryScheduler retryScheduler) throws IOException, InterruptedException { 358 final LocalSocketAddress address = new LocalSocketAddress( 359 daemon, LocalSocketAddress.Namespace.RESERVED); 360 361 // Wait for the socket to connect. 362 while (true) { 363 try { 364 socket.connect(address); 365 break; 366 } catch (Exception e) { 367 // ignore 368 } 369 retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); 370 } 371 socket.setSoTimeout(500); 372 373 final OutputStream out = socket.getOutputStream(); 374 for (String argument : arguments) { 375 byte[] bytes = argument.getBytes(StandardCharsets.UTF_8); 376 if (bytes.length >= 0xFFFF) { 377 throw new IllegalArgumentException("Argument is too large"); 378 } 379 out.write(bytes.length >> 8); 380 out.write(bytes.length); 381 out.write(bytes); 382 retryScheduler.checkInterruptAndDelay(false /* sleepLonger */); 383 } 384 out.write(0xFF); 385 out.write(0xFF); 386 387 // Wait for End-of-File. 388 final InputStream in = socket.getInputStream(); 389 while (true) { 390 try { 391 if (in.read() == -1) { 392 break; 393 } 394 } catch (Exception e) { 395 // ignore 396 } 397 retryScheduler.checkInterruptAndDelay(true /* sleepLonger */); 398 } 399 } 400 401 @NonNull resolve(final String endpoint)402 public InetAddress resolve(final String endpoint) 403 throws ExecutionException, InterruptedException { 404 try { 405 return InetAddresses.parseNumericAddress(endpoint); 406 } catch (IllegalArgumentException e) { 407 // Endpoint is not numeric : fall through and resolve 408 } 409 410 final CancellationSignal cancellationSignal = new CancellationSignal(); 411 try { 412 final DnsResolver resolver = DnsResolver.getInstance(); 413 final CompletableFuture<InetAddress> result = new CompletableFuture(); 414 final DnsResolver.Callback<List<InetAddress>> cb = 415 new DnsResolver.Callback<List<InetAddress>>() { 416 @Override 417 public void onAnswer(@NonNull final List<InetAddress> answer, 418 final int rcode) { 419 if (answer.size() > 0) { 420 result.complete(answer.get(0)); 421 } else { 422 result.completeExceptionally( 423 new UnknownHostException(endpoint)); 424 } 425 } 426 427 @Override 428 public void onError(@Nullable final DnsResolver.DnsException error) { 429 // Unfortunately UnknownHostException doesn't accept a cause, so 430 // print a message here instead. Only show the summary, not the 431 // full stack trace. 432 Log.e(TAG, "Async dns resolver error : " + error); 433 result.completeExceptionally(new UnknownHostException(endpoint)); 434 } 435 }; 436 resolver.query(null /* network, null for default */, endpoint, 437 DnsResolver.FLAG_EMPTY, r -> r.run(), cancellationSignal, cb); 438 return result.get(); 439 } catch (final ExecutionException e) { 440 Log.e(TAG, "Cannot resolve VPN endpoint : " + endpoint + ".", e); 441 throw e; 442 } catch (final InterruptedException e) { 443 Log.e(TAG, "Legacy VPN was interrupted while resolving the endpoint", e); 444 cancellationSignal.cancel(); 445 throw e; 446 } 447 } 448 isInterfacePresent(final Vpn vpn, final String iface)449 public boolean isInterfacePresent(final Vpn vpn, final String iface) { 450 return vpn.jniCheck(iface) != 0; 451 } 452 453 /** 454 * @see ParcelFileDescriptor#adoptFd(int) 455 */ adoptFd(Vpn vpn, int mtu)456 public ParcelFileDescriptor adoptFd(Vpn vpn, int mtu) { 457 return ParcelFileDescriptor.adoptFd(jniCreate(vpn, mtu)); 458 } 459 460 /** 461 * Call native method to create the VPN interface and return the FileDescriptor of /dev/tun. 462 */ jniCreate(Vpn vpn, int mtu)463 public int jniCreate(Vpn vpn, int mtu) { 464 return vpn.jniCreate(mtu); 465 } 466 467 /** 468 * Call native method to get the interface name of VPN. 469 */ jniGetName(Vpn vpn, int fd)470 public String jniGetName(Vpn vpn, int fd) { 471 return vpn.jniGetName(fd); 472 } 473 474 /** 475 * Call native method to set the VPN addresses and return the number of addresses. 476 */ jniSetAddresses(Vpn vpn, String interfaze, String addresses)477 public int jniSetAddresses(Vpn vpn, String interfaze, String addresses) { 478 return vpn.jniSetAddresses(interfaze, addresses); 479 } 480 481 /** 482 * @see IoUtils#setBlocking(FileDescriptor, boolean) 483 */ setBlocking(FileDescriptor fd, boolean blocking)484 public void setBlocking(FileDescriptor fd, boolean blocking) { 485 try { 486 IoUtils.setBlocking(fd, blocking); 487 } catch (IOException e) { 488 throw new IllegalStateException( 489 "Cannot set tunnel's fd as blocking=" + blocking, e); 490 } 491 } 492 493 /** 494 * Retrieves the next retry delay 495 * 496 * <p>If retries have exceeded the IKEV2_VPN_RETRY_DELAYS_SEC, the last entry in 497 * the array will be used as a repeating interval. 498 */ getNextRetryDelaySeconds(int retryCount)499 public long getNextRetryDelaySeconds(int retryCount) { 500 if (retryCount >= IKEV2_VPN_RETRY_DELAYS_SEC.length) { 501 return IKEV2_VPN_RETRY_DELAYS_SEC[IKEV2_VPN_RETRY_DELAYS_SEC.length - 1]; 502 } else { 503 return IKEV2_VPN_RETRY_DELAYS_SEC[retryCount]; 504 } 505 } 506 507 /** Get single threaded executor for IKEv2 VPN */ newScheduledThreadPoolExecutor()508 public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() { 509 return new ScheduledThreadPoolExecutor(1); 510 } 511 512 /** Get a NetworkAgent instance */ newNetworkAgent( @onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)513 public NetworkAgent newNetworkAgent( 514 @NonNull Context context, 515 @NonNull Looper looper, 516 @NonNull String logTag, 517 @NonNull NetworkCapabilities nc, 518 @NonNull LinkProperties lp, 519 @NonNull NetworkScore score, 520 @NonNull NetworkAgentConfig config, 521 @Nullable NetworkProvider provider) { 522 return new VpnNetworkAgentWrapper( 523 context, looper, logTag, nc, lp, score, config, provider); 524 } 525 } 526 Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, @UserIdInt int userId, VpnProfileStore vpnProfileStore)527 public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd, 528 @UserIdInt int userId, VpnProfileStore vpnProfileStore) { 529 this(looper, context, new Dependencies(), netService, netd, userId, vpnProfileStore, 530 new SystemServices(context), new Ikev2SessionCreator()); 531 } 532 533 @VisibleForTesting Vpn(Looper looper, Context context, Dependencies deps, INetworkManagementService netService, INetd netd, @UserIdInt int userId, VpnProfileStore vpnProfileStore)534 public Vpn(Looper looper, Context context, Dependencies deps, 535 INetworkManagementService netService, INetd netd, @UserIdInt int userId, 536 VpnProfileStore vpnProfileStore) { 537 this(looper, context, deps, netService, netd, userId, vpnProfileStore, 538 new SystemServices(context), new Ikev2SessionCreator()); 539 } 540 541 @VisibleForTesting Vpn(Looper looper, Context context, Dependencies deps, INetworkManagementService netService, INetd netd, int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices, Ikev2SessionCreator ikev2SessionCreator)542 protected Vpn(Looper looper, Context context, Dependencies deps, 543 INetworkManagementService netService, INetd netd, 544 int userId, VpnProfileStore vpnProfileStore, SystemServices systemServices, 545 Ikev2SessionCreator ikev2SessionCreator) { 546 mVpnProfileStore = vpnProfileStore; 547 mContext = context; 548 mConnectivityManager = mContext.getSystemService(ConnectivityManager.class); 549 mAppOpsManager = mContext.getSystemService(AppOpsManager.class); 550 mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); 551 mDeps = deps; 552 mNms = netService; 553 mNetd = netd; 554 mUserId = userId; 555 mLooper = looper; 556 mSystemServices = systemServices; 557 mIkev2SessionCreator = ikev2SessionCreator; 558 mUserManager = mContext.getSystemService(UserManager.class); 559 560 mPackage = VpnConfig.LEGACY_VPN; 561 mOwnerUID = getAppUid(mPackage, mUserId); 562 mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage); 563 564 try { 565 netService.registerObserver(mObserver); 566 } catch (RemoteException e) { 567 Log.wtf(TAG, "Problem registering observer", e); 568 } 569 570 mNetworkProvider = new NetworkProvider(context, looper, VPN_PROVIDER_NAME_BASE + mUserId); 571 // This constructor is called in onUserStart and registers the provider. The provider 572 // will be unregistered in onUserStop. 573 mConnectivityManager.registerNetworkProvider(mNetworkProvider); 574 mLegacyState = LegacyVpnInfo.STATE_DISCONNECTED; 575 mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE, 576 "" /* subtypeName */); 577 mNetworkCapabilities = new NetworkCapabilities.Builder() 578 .addTransportType(NetworkCapabilities.TRANSPORT_VPN) 579 .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) 580 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) 581 .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null)) 582 .build(); 583 584 loadAlwaysOnPackage(); 585 } 586 587 /** 588 * Set whether this object is responsible for watching for {@link NetworkInfo} 589 * teardown. When {@code false}, teardown is handled externally by someone 590 * else. 591 */ setEnableTeardown(boolean enableTeardown)592 public void setEnableTeardown(boolean enableTeardown) { 593 mEnableTeardown = enableTeardown; 594 } 595 596 @VisibleForTesting getEnableTeardown()597 public boolean getEnableTeardown() { 598 return mEnableTeardown; 599 } 600 601 /** 602 * Update current state, dispatching event to listeners. 603 */ 604 @VisibleForTesting 605 @GuardedBy("this") updateState(DetailedState detailedState, String reason)606 protected void updateState(DetailedState detailedState, String reason) { 607 if (LOGD) Log.d(TAG, "setting state=" + detailedState + ", reason=" + reason); 608 mLegacyState = LegacyVpnInfo.stateFromNetworkInfo(detailedState); 609 mNetworkInfo.setDetailedState(detailedState, reason, null); 610 // TODO : only accept transitions when the agent is in the correct state (non-null for 611 // CONNECTED, DISCONNECTED and FAILED, null for CONNECTED). 612 // This will require a way for tests to pretend the VPN is connected that's not 613 // calling this method with CONNECTED. 614 // It will also require audit of where the code calls this method with DISCONNECTED 615 // with a null agent, which it was doing historically to make sure the agent is 616 // disconnected as this was a no-op if the agent was null. 617 switch (detailedState) { 618 case CONNECTED: 619 if (null != mNetworkAgent) { 620 mNetworkAgent.markConnected(); 621 } 622 break; 623 case DISCONNECTED: 624 case FAILED: 625 if (null != mNetworkAgent) { 626 mNetworkAgent.unregister(); 627 mNetworkAgent = null; 628 } 629 break; 630 case CONNECTING: 631 if (null != mNetworkAgent) { 632 throw new IllegalStateException("VPN can only go to CONNECTING state when" 633 + " the agent is null."); 634 } 635 break; 636 default: 637 throw new IllegalArgumentException("Illegal state argument " + detailedState); 638 } 639 updateAlwaysOnNotification(detailedState); 640 } 641 resetNetworkCapabilities()642 private void resetNetworkCapabilities() { 643 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) 644 .setUids(null) 645 .setTransportInfo(new VpnTransportInfo(VpnManager.TYPE_VPN_NONE, null)) 646 .build(); 647 } 648 649 /** 650 * Chooses whether to force all connections to go though VPN. 651 * 652 * Used to enable/disable legacy VPN lockdown. 653 * 654 * This uses the same ip rule mechanism as 655 * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling 656 * that function will be replaced and saved with the always-on state. 657 * 658 * @param lockdown whether to prevent all traffic outside of a VPN. 659 */ setLockdown(boolean lockdown)660 public synchronized void setLockdown(boolean lockdown) { 661 enforceControlPermissionOrInternalCaller(); 662 663 setVpnForcedLocked(lockdown); 664 mLockdown = lockdown; 665 666 // Update app lockdown setting if it changed. Legacy VPN lockdown status is controlled by 667 // LockdownVpnTracker.isEnabled() which keeps track of its own state. 668 if (mAlwaysOn) { 669 saveAlwaysOnPackage(); 670 } 671 } 672 673 /** Returns the package name that is currently prepared. */ getPackage()674 public synchronized String getPackage() { 675 return mPackage; 676 } 677 678 /** 679 * Check whether to prevent all traffic outside of a VPN even when the VPN is not connected. 680 * 681 * @return {@code true} if VPN lockdown is enabled. 682 */ getLockdown()683 public synchronized boolean getLockdown() { 684 return mLockdown; 685 } 686 687 /** 688 * Returns whether VPN is configured as always-on. 689 */ getAlwaysOn()690 public synchronized boolean getAlwaysOn() { 691 return mAlwaysOn; 692 } 693 694 /** 695 * Checks if a VPN app supports always-on mode. 696 * 697 * <p>In order to support the always-on feature, an app has to either have an installed 698 * PlatformVpnProfile, or: 699 * 700 * <ul> 701 * <li>target {@link VERSION_CODES#N API 24} or above, and 702 * <li>not opt out through the {@link VpnService#SERVICE_META_DATA_SUPPORTS_ALWAYS_ON} 703 * meta-data field. 704 * </ul> 705 * 706 * @param packageName the canonical package name of the VPN app 707 * @return {@code true} if and only if the VPN app exists and supports always-on mode 708 */ isAlwaysOnPackageSupported(String packageName)709 public boolean isAlwaysOnPackageSupported(String packageName) { 710 enforceSettingsPermission(); 711 712 if (packageName == null) { 713 return false; 714 } 715 716 final long oldId = Binder.clearCallingIdentity(); 717 try { 718 if (getVpnProfilePrivileged(packageName) != null) { 719 return true; 720 } 721 } finally { 722 Binder.restoreCallingIdentity(oldId); 723 } 724 725 PackageManager pm = mContext.getPackageManager(); 726 ApplicationInfo appInfo = null; 727 try { 728 appInfo = pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId); 729 } catch (NameNotFoundException unused) { 730 Log.w(TAG, "Can't find \"" + packageName + "\" when checking always-on support"); 731 } 732 if (appInfo == null || appInfo.targetSdkVersion < VERSION_CODES.N) { 733 return false; 734 } 735 736 final Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 737 intent.setPackage(packageName); 738 List<ResolveInfo> services = 739 pm.queryIntentServicesAsUser(intent, PackageManager.GET_META_DATA, mUserId); 740 if (services == null || services.size() == 0) { 741 return false; 742 } 743 744 for (ResolveInfo rInfo : services) { 745 final Bundle metaData = rInfo.serviceInfo.metaData; 746 if (metaData != null && 747 !metaData.getBoolean(VpnService.SERVICE_META_DATA_SUPPORTS_ALWAYS_ON, true)) { 748 return false; 749 } 750 } 751 752 return true; 753 } 754 buildVpnManagerEventIntent(@onNull String category, int errorClass, int errorCode, @NonNull final String packageName, @Nullable final String sessionKey, @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork, @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp)755 private Intent buildVpnManagerEventIntent(@NonNull String category, int errorClass, 756 int errorCode, @NonNull final String packageName, @Nullable final String sessionKey, 757 @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork, 758 @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) { 759 final Intent intent = new Intent(VpnManager.ACTION_VPN_MANAGER_EVENT); 760 intent.setPackage(packageName); 761 intent.addCategory(category); 762 intent.putExtra(VpnManager.EXTRA_VPN_PROFILE_STATE, profileState); 763 intent.putExtra(VpnManager.EXTRA_SESSION_KEY, sessionKey); 764 intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK, underlyingNetwork); 765 intent.putExtra(VpnManager.EXTRA_UNDERLYING_NETWORK_CAPABILITIES, nc); 766 intent.putExtra(VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES, lp); 767 intent.putExtra(VpnManager.EXTRA_TIMESTAMP_MILLIS, System.currentTimeMillis()); 768 if (!VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER.equals(category) 769 || !VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED.equals(category)) { 770 intent.putExtra(VpnManager.EXTRA_ERROR_CLASS, errorClass); 771 intent.putExtra(VpnManager.EXTRA_ERROR_CODE, errorCode); 772 } 773 774 return intent; 775 } 776 sendEventToVpnManagerApp(@onNull String category, int errorClass, int errorCode, @NonNull final String packageName, @Nullable final String sessionKey, @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork, @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp)777 private boolean sendEventToVpnManagerApp(@NonNull String category, int errorClass, 778 int errorCode, @NonNull final String packageName, @Nullable final String sessionKey, 779 @NonNull final VpnProfileState profileState, @Nullable final Network underlyingNetwork, 780 @Nullable final NetworkCapabilities nc, @Nullable final LinkProperties lp) { 781 final Intent intent = buildVpnManagerEventIntent(category, errorClass, errorCode, 782 packageName, sessionKey, profileState, underlyingNetwork, nc, lp); 783 return sendEventToVpnManagerApp(intent, packageName); 784 } 785 sendEventToVpnManagerApp(@onNull final Intent intent, @NonNull final String packageName)786 private boolean sendEventToVpnManagerApp(@NonNull final Intent intent, 787 @NonNull final String packageName) { 788 // Allow VpnManager app to temporarily run background services to handle this error. 789 // If an app requires anything beyond this grace period, they MUST either declare 790 // themselves as a foreground service, or schedule a job/workitem. 791 DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal(); 792 idleController.addPowerSaveTempWhitelistApp(Process.myUid(), packageName, 793 VPN_MANAGER_EVENT_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN, 794 "VpnManager event"); 795 try { 796 return mUserIdContext.startService(intent) != null; 797 } catch (RuntimeException e) { 798 Log.e(TAG, "Service of VpnManager app " + intent + " failed to start", e); 799 return false; 800 } 801 } 802 isVpnApp(String packageName)803 private static boolean isVpnApp(String packageName) { 804 return packageName != null && !VpnConfig.LEGACY_VPN.equals(packageName); 805 } 806 807 /** 808 * Configures an always-on VPN connection through a specific application. This connection is 809 * automatically granted and persisted after a reboot. 810 * 811 * <p>The designated package should either have a PlatformVpnProfile installed, or declare a 812 * {@link VpnService} in its manifest guarded by {@link 813 * android.Manifest.permission.BIND_VPN_SERVICE}, otherwise the call will fail. 814 * 815 * <p>Note that this method does not check if the VPN app supports always-on mode. The check is 816 * delayed to {@link #startAlwaysOnVpn()}, which is always called immediately after this method 817 * in {@link android.net.IConnectivityManager#setAlwaysOnVpnPackage}. 818 * 819 * @param packageName the package to designate as always-on VPN supplier. 820 * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. 821 * @param lockdownAllowlist packages to be allowed from lockdown. 822 * @return {@code true} if the package has been set as always-on, {@code false} otherwise. 823 */ setAlwaysOnPackage( @ullable String packageName, boolean lockdown, @Nullable List<String> lockdownAllowlist)824 public synchronized boolean setAlwaysOnPackage( 825 @Nullable String packageName, 826 boolean lockdown, 827 @Nullable List<String> lockdownAllowlist) { 828 enforceControlPermissionOrInternalCaller(); 829 // Store mPackage since it might be reset or might be replaced with the other VPN app. 830 final String oldPackage = mPackage; 831 final boolean isPackageChanged = !Objects.equals(packageName, oldPackage); 832 // TODO: Remove "SdkLevel.isAtLeastT()" check once VpnManagerService is decoupled from 833 // ConnectivityServiceTest. 834 // Only notify VPN apps that were already always-on, and only if the always-on provider 835 // changed, or the lockdown mode changed. 836 final boolean shouldNotifyOldPkg = isVpnApp(oldPackage) && mAlwaysOn 837 && (lockdown != mLockdown || isPackageChanged); 838 // Also notify the new package if there was a provider change. 839 final boolean shouldNotifyNewPkg = isVpnApp(packageName) && isPackageChanged; 840 841 if (!setAlwaysOnPackageInternal(packageName, lockdown, lockdownAllowlist)) { 842 return false; 843 } 844 845 saveAlwaysOnPackage(); 846 847 // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from 848 // ConnectivityServiceTest. 849 if (!SdkLevel.isAtLeastT()) { 850 return true; 851 } 852 853 if (shouldNotifyOldPkg) { 854 // If both of shouldNotifyOldPkg & isPackageChanged are true, that means the 855 // always-on of old package is disabled or the old package is replaced with the new 856 // package. In this case, VpnProfileState should be disconnected. 857 sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, 858 -1 /* errorClass */, -1 /* errorCode*/, oldPackage, 859 null /* sessionKey */, isPackageChanged ? makeDisconnectedVpnProfileState() 860 : makeVpnProfileStateLocked(), 861 null /* underlyingNetwork */, null /* nc */, null /* lp */); 862 } 863 864 if (shouldNotifyNewPkg) { 865 sendEventToVpnManagerApp(VpnManager.CATEGORY_EVENT_ALWAYS_ON_STATE_CHANGED, 866 -1 /* errorClass */, -1 /* errorCode*/, packageName, 867 getSessionKeyLocked(), makeVpnProfileStateLocked(), 868 null /* underlyingNetwork */, null /* nc */, null /* lp */); 869 } 870 return true; 871 } 872 873 /** 874 * Configures an always-on VPN connection through a specific application, the same as {@link 875 * #setAlwaysOnPackage}. 876 * 877 * <p>Does not perform permission checks. Does not persist any of the changes to storage. 878 * 879 * @param packageName the package to designate as always-on VPN supplier. 880 * @param lockdown whether to prevent traffic outside of a VPN, for example while connecting. 881 * @param lockdownAllowlist packages to be allowed to bypass lockdown. This is only used if 882 * {@code lockdown} is {@code true}. Packages must not contain commas. 883 * @return {@code true} if the package has been set as always-on, {@code false} otherwise. 884 */ 885 @GuardedBy("this") setAlwaysOnPackageInternal( @ullable String packageName, boolean lockdown, @Nullable List<String> lockdownAllowlist)886 private boolean setAlwaysOnPackageInternal( 887 @Nullable String packageName, boolean lockdown, 888 @Nullable List<String> lockdownAllowlist) { 889 if (VpnConfig.LEGACY_VPN.equals(packageName)) { 890 Log.w(TAG, "Not setting legacy VPN \"" + packageName + "\" as always-on."); 891 return false; 892 } 893 894 if (lockdownAllowlist != null) { 895 for (String pkg : lockdownAllowlist) { 896 if (pkg.contains(",")) { 897 Log.w(TAG, "Not setting always-on vpn, invalid allowed package: " + pkg); 898 return false; 899 } 900 } 901 } 902 903 if (packageName != null) { 904 final VpnProfile profile; 905 final long oldId = Binder.clearCallingIdentity(); 906 try { 907 profile = getVpnProfilePrivileged(packageName); 908 } finally { 909 Binder.restoreCallingIdentity(oldId); 910 } 911 912 // Pre-authorize new always-on VPN package. 913 final int grantType = 914 (profile == null) ? VpnManager.TYPE_VPN_SERVICE : VpnManager.TYPE_VPN_PLATFORM; 915 if (!setPackageAuthorization(packageName, grantType)) { 916 return false; 917 } 918 mAlwaysOn = true; 919 } else { 920 packageName = VpnConfig.LEGACY_VPN; 921 mAlwaysOn = false; 922 } 923 924 mLockdown = (mAlwaysOn && lockdown); 925 mLockdownAllowlist = (mLockdown && lockdownAllowlist != null) 926 ? Collections.unmodifiableList(new ArrayList<>(lockdownAllowlist)) 927 : Collections.emptyList(); 928 929 if (isCurrentPreparedPackage(packageName)) { 930 updateAlwaysOnNotification(mNetworkInfo.getDetailedState()); 931 setVpnForcedLocked(mLockdown); 932 } else { 933 // Prepare this app. The notification will update as a side-effect of updateState(). 934 // It also calls setVpnForcedLocked(). 935 prepareInternal(packageName); 936 } 937 return true; 938 } 939 isNullOrLegacyVpn(String packageName)940 private static boolean isNullOrLegacyVpn(String packageName) { 941 return packageName == null || VpnConfig.LEGACY_VPN.equals(packageName); 942 } 943 944 /** 945 * @return the package name of the VPN controller responsible for always-on VPN, 946 * or {@code null} if none is set or always-on VPN is controlled through 947 * lockdown instead. 948 */ getAlwaysOnPackage()949 public synchronized String getAlwaysOnPackage() { 950 enforceControlPermissionOrInternalCaller(); 951 return (mAlwaysOn ? mPackage : null); 952 } 953 954 /** 955 * @return an immutable list of packages allowed to bypass always-on VPN lockdown. 956 */ getLockdownAllowlist()957 public synchronized List<String> getLockdownAllowlist() { 958 return mLockdown ? mLockdownAllowlist : null; 959 } 960 961 /** 962 * Save the always-on package and lockdown config into Settings.Secure 963 */ 964 @GuardedBy("this") saveAlwaysOnPackage()965 private void saveAlwaysOnPackage() { 966 final long token = Binder.clearCallingIdentity(); 967 try { 968 mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP, 969 getAlwaysOnPackage(), mUserId); 970 mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 971 (mAlwaysOn && mLockdown ? 1 : 0), mUserId); 972 mSystemServices.settingsSecurePutStringForUser( 973 LOCKDOWN_ALLOWLIST_SETTING_NAME, 974 String.join(",", mLockdownAllowlist), mUserId); 975 } finally { 976 Binder.restoreCallingIdentity(token); 977 } 978 } 979 980 /** Load the always-on package and lockdown config from Settings. */ 981 @GuardedBy("this") loadAlwaysOnPackage()982 private void loadAlwaysOnPackage() { 983 final long token = Binder.clearCallingIdentity(); 984 try { 985 final String alwaysOnPackage = mSystemServices.settingsSecureGetStringForUser( 986 Settings.Secure.ALWAYS_ON_VPN_APP, mUserId); 987 final boolean alwaysOnLockdown = mSystemServices.settingsSecureGetIntForUser( 988 Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN, 0 /*default*/, mUserId) != 0; 989 final String allowlistString = mSystemServices.settingsSecureGetStringForUser( 990 LOCKDOWN_ALLOWLIST_SETTING_NAME, mUserId); 991 final List<String> allowedPackages = TextUtils.isEmpty(allowlistString) 992 ? Collections.emptyList() : Arrays.asList(allowlistString.split(",")); 993 setAlwaysOnPackageInternal( 994 alwaysOnPackage, alwaysOnLockdown, allowedPackages); 995 } finally { 996 Binder.restoreCallingIdentity(token); 997 } 998 } 999 1000 /** 1001 * Starts the currently selected always-on VPN 1002 * 1003 * @return {@code true} if the service was started, the service was already connected, or there 1004 * was no always-on VPN to start. {@code false} otherwise. 1005 */ startAlwaysOnVpn()1006 public boolean startAlwaysOnVpn() { 1007 final String alwaysOnPackage; 1008 synchronized (this) { 1009 alwaysOnPackage = getAlwaysOnPackage(); 1010 // Skip if there is no service to start. 1011 if (alwaysOnPackage == null) { 1012 return true; 1013 } 1014 // Remove always-on VPN if it's not supported. 1015 if (!isAlwaysOnPackageSupported(alwaysOnPackage)) { 1016 setAlwaysOnPackage(null, false, null); 1017 return false; 1018 } 1019 // Skip if the service is already established. This isn't bulletproof: it's not bound 1020 // until after establish(), so if it's mid-setup onStartCommand will be sent twice, 1021 // which may restart the connection. 1022 if (getNetworkInfo().isConnected()) { 1023 return true; 1024 } 1025 } 1026 1027 final long oldId = Binder.clearCallingIdentity(); 1028 try { 1029 // Prefer VPN profiles, if any exist. 1030 VpnProfile profile = getVpnProfilePrivileged(alwaysOnPackage); 1031 if (profile != null) { 1032 startVpnProfilePrivileged(profile, alwaysOnPackage); 1033 // If the above startVpnProfilePrivileged() call returns, the Ikev2VpnProfile was 1034 // correctly parsed, and the VPN has started running in a different thread. The only 1035 // other possibility is that the above call threw an exception, which will be 1036 // caught below, and returns false (clearing the always-on VPN). Once started, the 1037 // Platform VPN cannot permanently fail, and is resilient to temporary failures. It 1038 // will continue retrying until shut down by the user, or always-on is toggled off. 1039 return true; 1040 } 1041 1042 // Tell the OS that background services in this app need to be allowed for 1043 // a short time, so we can bootstrap the VPN service. 1044 DeviceIdleInternal idleController = mDeps.getDeviceIdleInternal(); 1045 idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, 1046 VPN_LAUNCH_IDLE_ALLOWLIST_DURATION_MS, mUserId, false, REASON_VPN, 1047 "vpn"); 1048 1049 // Start the VPN service declared in the app's manifest. 1050 Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE); 1051 serviceIntent.setPackage(alwaysOnPackage); 1052 try { 1053 return mUserIdContext.startService(serviceIntent) != null; 1054 } catch (RuntimeException e) { 1055 Log.e(TAG, "VpnService " + serviceIntent + " failed to start", e); 1056 return false; 1057 } 1058 } catch (Exception e) { 1059 Log.e(TAG, "Error starting always-on VPN", e); 1060 return false; 1061 } finally { 1062 Binder.restoreCallingIdentity(oldId); 1063 } 1064 } 1065 1066 /** 1067 * Prepare for a VPN application. This method is designed to solve 1068 * race conditions. It first compares the current prepared package 1069 * with {@code oldPackage}. If they are the same, the prepared 1070 * package is revoked and replaced with {@code newPackage}. If 1071 * {@code oldPackage} is {@code null}, the comparison is omitted. 1072 * If {@code newPackage} is the same package or {@code null}, the 1073 * revocation is omitted. This method returns {@code true} if the 1074 * operation is succeeded. 1075 * 1076 * Legacy VPN is handled specially since it is not a real package. 1077 * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and 1078 * it can be revoked by itself. 1079 * 1080 * The permission checks to verify that the VPN has already been granted 1081 * user consent are dependent on the type of the VPN being prepared. See 1082 * {@link AppOpsManager#OP_ACTIVATE_VPN} and {@link 1083 * AppOpsManager#OP_ACTIVATE_PLATFORM_VPN} for more information. 1084 * 1085 * Note: when we added VPN pre-consent in 1086 * https://android.googlesource.com/platform/frameworks/base/+/0554260 1087 * the names oldPackage and newPackage became misleading, because when 1088 * an app is pre-consented, we actually prepare oldPackage, not newPackage. 1089 * 1090 * Their meanings actually are: 1091 * 1092 * - oldPackage non-null, newPackage null: App calling VpnService#prepare(). 1093 * - oldPackage null, newPackage non-null: ConfirmDialog calling prepareVpn(). 1094 * - oldPackage null, newPackage=LEGACY_VPN: Used internally to disconnect 1095 * and revoke any current app VPN and re-prepare legacy vpn. 1096 * - oldPackage null, newPackage null: always returns true for backward compatibility. 1097 * 1098 * TODO: Rename the variables - or split this method into two - and end this confusion. 1099 * TODO: b/29032008 Migrate code from prepare(oldPackage=non-null, newPackage=LEGACY_VPN) 1100 * to prepare(oldPackage=null, newPackage=LEGACY_VPN) 1101 * 1102 * @param oldPackage The package name of the old VPN application 1103 * @param newPackage The package name of the new VPN application 1104 * @param vpnType The type of VPN being prepared. One of {@link VpnManager.VpnType} Preparing a 1105 * platform VPN profile requires only the lesser ACTIVATE_PLATFORM_VPN appop. 1106 * @return true if the operation succeeded. 1107 */ prepare( String oldPackage, String newPackage, @VpnManager.VpnType int vpnType)1108 public synchronized boolean prepare( 1109 String oldPackage, String newPackage, @VpnManager.VpnType int vpnType) { 1110 // Except for Settings and VpnDialogs, the caller should be matched one of oldPackage or 1111 // newPackage. Otherwise, non VPN owner might get the VPN always-on status of the VPN owner. 1112 // See b/191382886. 1113 if (mContext.checkCallingOrSelfPermission(CONTROL_VPN) != PERMISSION_GRANTED) { 1114 if (oldPackage != null) { 1115 verifyCallingUidAndPackage(oldPackage); 1116 } 1117 if (newPackage != null) { 1118 verifyCallingUidAndPackage(newPackage); 1119 } 1120 } 1121 1122 if (oldPackage != null) { 1123 // Stop an existing always-on VPN from being dethroned by other apps. 1124 if (mAlwaysOn && !isCurrentPreparedPackage(oldPackage)) { 1125 return false; 1126 } 1127 1128 // Package is not the same or old package was reinstalled. 1129 if (!isCurrentPreparedPackage(oldPackage)) { 1130 // The package doesn't match. We return false (to obtain user consent) unless the 1131 // user has already consented to that VPN package. 1132 if (!oldPackage.equals(VpnConfig.LEGACY_VPN) 1133 && isVpnPreConsented(mContext, oldPackage, vpnType)) { 1134 prepareInternal(oldPackage); 1135 return true; 1136 } 1137 return false; 1138 } else if (!oldPackage.equals(VpnConfig.LEGACY_VPN) 1139 && !isVpnPreConsented(mContext, oldPackage, vpnType)) { 1140 // Currently prepared VPN is revoked, so unprepare it and return false. 1141 prepareInternal(VpnConfig.LEGACY_VPN); 1142 return false; 1143 } 1144 } 1145 1146 // Return true if we do not need to revoke. 1147 if (newPackage == null || (!newPackage.equals(VpnConfig.LEGACY_VPN) && 1148 isCurrentPreparedPackage(newPackage))) { 1149 return true; 1150 } 1151 1152 // Check that the caller is authorized. 1153 enforceControlPermission(); 1154 1155 // Stop an existing always-on VPN from being dethroned by other apps. 1156 if (mAlwaysOn && !isCurrentPreparedPackage(newPackage)) { 1157 return false; 1158 } 1159 1160 prepareInternal(newPackage); 1161 return true; 1162 } 1163 1164 @GuardedBy("this") isCurrentPreparedPackage(String packageName)1165 private boolean isCurrentPreparedPackage(String packageName) { 1166 // We can't just check that packageName matches mPackage, because if the app was uninstalled 1167 // and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the 1168 // calling package may not be the same as the prepared package. Check both UID and package. 1169 return getAppUid(packageName, mUserId) == mOwnerUID && mPackage.equals(packageName); 1170 } 1171 1172 /** Prepare the VPN for the given package. Does not perform permission checks. */ 1173 @GuardedBy("this") prepareInternal(String newPackage)1174 private void prepareInternal(String newPackage) { 1175 final long token = Binder.clearCallingIdentity(); 1176 try { 1177 // Reset the interface. 1178 if (mInterface != null) { 1179 mStatusIntent = null; 1180 agentDisconnect(); 1181 jniReset(mInterface); 1182 mInterface = null; 1183 resetNetworkCapabilities(); 1184 } 1185 1186 // Revoke the connection or stop the VpnRunner. 1187 if (mConnection != null) { 1188 try { 1189 mConnection.mService.transact(IBinder.LAST_CALL_TRANSACTION, 1190 Parcel.obtain(), null, IBinder.FLAG_ONEWAY); 1191 } catch (Exception e) { 1192 // ignore 1193 } 1194 mAppOpsManager.finishOp( 1195 AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null); 1196 mContext.unbindService(mConnection); 1197 cleanupVpnStateLocked(); 1198 } else if (mVpnRunner != null) { 1199 stopVpnRunnerAndNotifyAppLocked(mPackage); 1200 } 1201 1202 try { 1203 mNms.denyProtect(mOwnerUID); 1204 } catch (Exception e) { 1205 Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e); 1206 } 1207 1208 Log.i(TAG, "Switched from " + mPackage + " to " + newPackage); 1209 mPackage = newPackage; 1210 mOwnerUID = getAppUid(newPackage, mUserId); 1211 mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage); 1212 try { 1213 mNms.allowProtect(mOwnerUID); 1214 } catch (Exception e) { 1215 Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e); 1216 } 1217 mConfig = null; 1218 1219 updateState(DetailedState.DISCONNECTED, "prepare"); 1220 setVpnForcedLocked(mLockdown); 1221 } finally { 1222 Binder.restoreCallingIdentity(token); 1223 } 1224 } 1225 1226 /** Set whether a package has the ability to launch VPNs without user intervention. */ setPackageAuthorization(String packageName, @VpnManager.VpnType int vpnType)1227 public boolean setPackageAuthorization(String packageName, @VpnManager.VpnType int vpnType) { 1228 // Check if the caller is authorized. 1229 enforceControlPermissionOrInternalCaller(); 1230 1231 final int uid = getAppUid(packageName, mUserId); 1232 if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) { 1233 // Authorization for nonexistent packages (or fake ones) can't be updated. 1234 return false; 1235 } 1236 1237 final long token = Binder.clearCallingIdentity(); 1238 try { 1239 final String[] toChange; 1240 1241 // Clear all AppOps if the app is being unauthorized. 1242 switch (vpnType) { 1243 case VpnManager.TYPE_VPN_NONE: 1244 toChange = new String[] { 1245 AppOpsManager.OPSTR_ACTIVATE_VPN, 1246 AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN 1247 }; 1248 break; 1249 case VpnManager.TYPE_VPN_PLATFORM: 1250 toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN}; 1251 break; 1252 case VpnManager.TYPE_VPN_SERVICE: 1253 toChange = new String[] {AppOpsManager.OPSTR_ACTIVATE_VPN}; 1254 break; 1255 case VpnManager.TYPE_VPN_LEGACY: 1256 return false; 1257 default: 1258 Log.wtf(TAG, "Unrecognized VPN type while granting authorization"); 1259 return false; 1260 } 1261 1262 for (final String appOpStr : toChange) { 1263 mAppOpsManager.setMode( 1264 appOpStr, 1265 uid, 1266 packageName, 1267 vpnType == VpnManager.TYPE_VPN_NONE 1268 ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED); 1269 } 1270 return true; 1271 } catch (Exception e) { 1272 Log.wtf(TAG, "Failed to set app ops for package " + packageName + ", uid " + uid, e); 1273 } finally { 1274 Binder.restoreCallingIdentity(token); 1275 } 1276 return false; 1277 } 1278 isVpnPreConsented(Context context, String packageName, int vpnType)1279 private static boolean isVpnPreConsented(Context context, String packageName, int vpnType) { 1280 switch (vpnType) { 1281 case VpnManager.TYPE_VPN_SERVICE: 1282 return isVpnServicePreConsented(context, packageName); 1283 case VpnManager.TYPE_VPN_PLATFORM: 1284 return isVpnProfilePreConsented(context, packageName); 1285 case VpnManager.TYPE_VPN_LEGACY: 1286 return VpnConfig.LEGACY_VPN.equals(packageName); 1287 default: 1288 return false; 1289 } 1290 } 1291 doesPackageHaveAppop(Context context, String packageName, String appOpStr)1292 private static boolean doesPackageHaveAppop(Context context, String packageName, 1293 String appOpStr) { 1294 final AppOpsManager appOps = 1295 (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 1296 1297 // Verify that the caller matches the given package and has the required permission. 1298 return appOps.noteOpNoThrow(appOpStr, Binder.getCallingUid(), packageName, 1299 null /* attributionTag */, null /* message */) == AppOpsManager.MODE_ALLOWED; 1300 } 1301 isVpnServicePreConsented(Context context, String packageName)1302 private static boolean isVpnServicePreConsented(Context context, String packageName) { 1303 return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_VPN); 1304 } 1305 isVpnProfilePreConsented(Context context, String packageName)1306 private static boolean isVpnProfilePreConsented(Context context, String packageName) { 1307 return doesPackageHaveAppop(context, packageName, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN) 1308 || isVpnServicePreConsented(context, packageName); 1309 } 1310 getAppUid(final String app, final int userId)1311 private int getAppUid(final String app, final int userId) { 1312 if (VpnConfig.LEGACY_VPN.equals(app)) { 1313 return Process.myUid(); 1314 } 1315 PackageManager pm = mContext.getPackageManager(); 1316 final long token = Binder.clearCallingIdentity(); 1317 try { 1318 return pm.getPackageUidAsUser(app, userId); 1319 } catch (NameNotFoundException e) { 1320 return -1; 1321 } finally { 1322 Binder.restoreCallingIdentity(token); 1323 } 1324 } 1325 doesPackageTargetAtLeastQ(String packageName)1326 private boolean doesPackageTargetAtLeastQ(String packageName) { 1327 if (VpnConfig.LEGACY_VPN.equals(packageName)) { 1328 return true; 1329 } 1330 PackageManager pm = mContext.getPackageManager(); 1331 try { 1332 ApplicationInfo appInfo = 1333 pm.getApplicationInfoAsUser(packageName, 0 /*flags*/, mUserId); 1334 return appInfo.targetSdkVersion >= VERSION_CODES.Q; 1335 } catch (NameNotFoundException unused) { 1336 Log.w(TAG, "Can't find \"" + packageName + "\""); 1337 return false; 1338 } 1339 } 1340 getNetworkInfo()1341 public NetworkInfo getNetworkInfo() { 1342 return mNetworkInfo; 1343 } 1344 1345 /** 1346 * Return Network of current running VPN network. 1347 * 1348 * @return a Network if there is a running VPN network or null if there is no running VPN 1349 * network or network is null. 1350 */ 1351 @VisibleForTesting 1352 @Nullable getNetwork()1353 public synchronized Network getNetwork() { 1354 final NetworkAgent agent = mNetworkAgent; 1355 if (null == agent) return null; 1356 final Network network = agent.getNetwork(); 1357 if (null == network) return null; 1358 return network; 1359 } 1360 makeLinkProperties()1361 private LinkProperties makeLinkProperties() { 1362 boolean allowIPv4 = mConfig.allowIPv4; 1363 boolean allowIPv6 = mConfig.allowIPv6; 1364 1365 LinkProperties lp = new LinkProperties(); 1366 1367 lp.setInterfaceName(mInterface); 1368 1369 if (mConfig.addresses != null) { 1370 for (LinkAddress address : mConfig.addresses) { 1371 lp.addLinkAddress(address); 1372 allowIPv4 |= address.getAddress() instanceof Inet4Address; 1373 allowIPv6 |= address.getAddress() instanceof Inet6Address; 1374 } 1375 } 1376 1377 if (mConfig.routes != null) { 1378 for (RouteInfo route : mConfig.routes) { 1379 lp.addRoute(route); 1380 InetAddress address = route.getDestination().getAddress(); 1381 1382 if (route.getType() == RouteInfo.RTN_UNICAST) { 1383 allowIPv4 |= address instanceof Inet4Address; 1384 allowIPv6 |= address instanceof Inet6Address; 1385 } 1386 } 1387 } 1388 1389 if (mConfig.dnsServers != null) { 1390 for (String dnsServer : mConfig.dnsServers) { 1391 InetAddress address = InetAddresses.parseNumericAddress(dnsServer); 1392 lp.addDnsServer(address); 1393 allowIPv4 |= address instanceof Inet4Address; 1394 allowIPv6 |= address instanceof Inet6Address; 1395 } 1396 } 1397 1398 lp.setHttpProxy(mConfig.proxyInfo); 1399 1400 if (!allowIPv4) { 1401 lp.addRoute(new RouteInfo(new IpPrefix( 1402 NetworkStackConstants.IPV4_ADDR_ANY, 0), null /*gateway*/, 1403 null /*iface*/, RTN_UNREACHABLE)); 1404 } 1405 if (!allowIPv6) { 1406 lp.addRoute(new RouteInfo(new IpPrefix( 1407 NetworkStackConstants.IPV6_ADDR_ANY, 0), null /*gateway*/, 1408 null /*iface*/, RTN_UNREACHABLE)); 1409 } 1410 1411 // Concatenate search domains into a string. 1412 StringBuilder buffer = new StringBuilder(); 1413 if (mConfig.searchDomains != null) { 1414 for (String domain : mConfig.searchDomains) { 1415 buffer.append(domain).append(' '); 1416 } 1417 } 1418 lp.setDomains(buffer.toString().trim()); 1419 1420 if (mConfig.mtu > 0) { 1421 lp.setMtu(mConfig.mtu); 1422 } 1423 1424 // TODO: Stop setting the MTU in jniCreate 1425 1426 return lp; 1427 } 1428 1429 /** 1430 * Attempt to perform a seamless handover of VPNs by only updating LinkProperties without 1431 * registering a new NetworkAgent. This is not always possible if the new VPN configuration 1432 * has certain changes, in which case this method would just return {@code false}. 1433 */ updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig)1434 private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) { 1435 // NetworkAgentConfig cannot be updated without registering a new NetworkAgent. 1436 if (oldConfig.allowBypass != mConfig.allowBypass) { 1437 Log.i(TAG, "Handover not possible due to changes to allowBypass"); 1438 return false; 1439 } 1440 1441 // TODO: we currently do not support seamless handover if the allowed or disallowed 1442 // applications have changed. Consider diffing UID ranges and only applying the delta. 1443 if (!Objects.equals(oldConfig.allowedApplications, mConfig.allowedApplications) || 1444 !Objects.equals(oldConfig.disallowedApplications, mConfig.disallowedApplications)) { 1445 Log.i(TAG, "Handover not possible due to changes to allowed/denied apps"); 1446 return false; 1447 } 1448 1449 agent.sendLinkProperties(makeLinkProperties()); 1450 return true; 1451 } 1452 1453 @GuardedBy("this") agentConnect()1454 private void agentConnect() { 1455 LinkProperties lp = makeLinkProperties(); 1456 1457 // VPN either provide a default route (IPv4 or IPv6 or both), or they are a split tunnel 1458 // that falls back to the default network, which by definition provides INTERNET (unless 1459 // there is no default network, in which case none of this matters in any sense). 1460 // Also, always setting the INTERNET bit guarantees that when a VPN applies to an app, 1461 // the VPN will always be reported as the network by getDefaultNetwork and callbacks 1462 // registered with registerDefaultNetworkCallback. This in turn protects the invariant 1463 // that an app calling ConnectivityManager#bindProcessToNetwork(getDefaultNetwork()) 1464 // behaves the same as when it uses the default network. 1465 final NetworkCapabilities.Builder capsBuilder = 1466 new NetworkCapabilities.Builder(mNetworkCapabilities); 1467 capsBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 1468 1469 mLegacyState = LegacyVpnInfo.STATE_CONNECTING; 1470 updateState(DetailedState.CONNECTING, "agentConnect"); 1471 1472 final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder() 1473 .setLegacyType(ConnectivityManager.TYPE_VPN) 1474 .setLegacyTypeName("VPN") 1475 .setBypassableVpn(mConfig.allowBypass && !mLockdown) 1476 .setVpnRequiresValidation(mConfig.requiresInternetValidation) 1477 .setLocalRoutesExcludedForVpn(mConfig.excludeLocalRoutes) 1478 .build(); 1479 1480 capsBuilder.setOwnerUid(mOwnerUID); 1481 capsBuilder.setAdministratorUids(new int[] {mOwnerUID}); 1482 capsBuilder.setUids(createUserAndRestrictedProfilesRanges(mUserId, 1483 mConfig.allowedApplications, mConfig.disallowedApplications)); 1484 1485 capsBuilder.setTransportInfo(new VpnTransportInfo(getActiveVpnType(), mConfig.session)); 1486 1487 // Only apps targeting Q and above can explicitly declare themselves as metered. 1488 // These VPNs are assumed metered unless they state otherwise. 1489 if (mIsPackageTargetingAtLeastQ && mConfig.isMetered) { 1490 capsBuilder.removeCapability(NET_CAPABILITY_NOT_METERED); 1491 } else { 1492 capsBuilder.addCapability(NET_CAPABILITY_NOT_METERED); 1493 } 1494 1495 capsBuilder.setUnderlyingNetworks((mConfig.underlyingNetworks != null) 1496 ? Arrays.asList(mConfig.underlyingNetworks) : null); 1497 1498 mNetworkCapabilities = capsBuilder.build(); 1499 mNetworkAgent = mDeps.newNetworkAgent(mContext, mLooper, NETWORKTYPE /* logtag */, 1500 mNetworkCapabilities, lp, 1501 new NetworkScore.Builder().setLegacyInt(VPN_DEFAULT_SCORE).build(), 1502 networkAgentConfig, mNetworkProvider); 1503 final long token = Binder.clearCallingIdentity(); 1504 try { 1505 mNetworkAgent.register(); 1506 } catch (final Exception e) { 1507 // If register() throws, don't keep an unregistered agent. 1508 mNetworkAgent = null; 1509 throw e; 1510 } finally { 1511 Binder.restoreCallingIdentity(token); 1512 } 1513 updateState(DetailedState.CONNECTED, "agentConnect"); 1514 } 1515 canHaveRestrictedProfile(int userId)1516 private boolean canHaveRestrictedProfile(int userId) { 1517 final long token = Binder.clearCallingIdentity(); 1518 try { 1519 final Context userContext = mContext.createContextAsUser(UserHandle.of(userId), 0); 1520 return userContext.getSystemService(UserManager.class).canHaveRestrictedProfile(); 1521 } finally { 1522 Binder.restoreCallingIdentity(token); 1523 } 1524 } 1525 agentDisconnect(NetworkAgent networkAgent)1526 private void agentDisconnect(NetworkAgent networkAgent) { 1527 if (networkAgent != null) { 1528 networkAgent.unregister(); 1529 } 1530 } 1531 agentDisconnect()1532 private void agentDisconnect() { 1533 updateState(DetailedState.DISCONNECTED, "agentDisconnect"); 1534 } 1535 1536 /** 1537 * Establish a VPN network and return the file descriptor of the VPN interface. This methods 1538 * returns {@code null} if the application is revoked or not prepared. 1539 * 1540 * <p>This method supports ONLY VpnService-based VPNs. For Platform VPNs, see {@link 1541 * provisionVpnProfile} and {@link startVpnProfile} 1542 * 1543 * @param config The parameters to configure the network. 1544 * @return The file descriptor of the VPN interface. 1545 */ establish(VpnConfig config)1546 public synchronized ParcelFileDescriptor establish(VpnConfig config) { 1547 // Check if the caller is already prepared. 1548 if (Binder.getCallingUid() != mOwnerUID) { 1549 return null; 1550 } 1551 // Check to ensure consent hasn't been revoked since we were prepared. 1552 if (!isVpnServicePreConsented(mContext, mPackage)) { 1553 return null; 1554 } 1555 // Check if the service is properly declared. 1556 Intent intent = new Intent(VpnConfig.SERVICE_INTERFACE); 1557 intent.setClassName(mPackage, config.user); 1558 final long token = Binder.clearCallingIdentity(); 1559 try { 1560 // Restricted users are not allowed to create VPNs, they are tied to Owner 1561 enforceNotRestrictedUser(); 1562 1563 final PackageManager packageManager = mUserIdContext.getPackageManager(); 1564 if (packageManager == null) { 1565 throw new IllegalStateException("Cannot get PackageManager."); 1566 } 1567 final ResolveInfo info = packageManager.resolveService(intent, 0 /* flags */); 1568 if (info == null) { 1569 throw new SecurityException("Cannot find " + config.user); 1570 } 1571 if (!BIND_VPN_SERVICE.equals(info.serviceInfo.permission)) { 1572 throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); 1573 } 1574 } finally { 1575 Binder.restoreCallingIdentity(token); 1576 } 1577 1578 // Save the old config in case we need to go back. 1579 VpnConfig oldConfig = mConfig; 1580 String oldInterface = mInterface; 1581 Connection oldConnection = mConnection; 1582 NetworkAgent oldNetworkAgent = mNetworkAgent; 1583 Set<Range<Integer>> oldUsers = mNetworkCapabilities.getUids(); 1584 1585 // Configure the interface. Abort if any of these steps fails. 1586 final ParcelFileDescriptor tun = mDeps.adoptFd(this, config.mtu); 1587 try { 1588 final String interfaze = mDeps.jniGetName(this, tun.getFd()); 1589 1590 // TEMP use the old jni calls until there is support for netd address setting 1591 StringBuilder builder = new StringBuilder(); 1592 for (LinkAddress address : config.addresses) { 1593 builder.append(" "); 1594 builder.append(address); 1595 } 1596 if (mDeps.jniSetAddresses(this, interfaze, builder.toString()) < 1) { 1597 throw new IllegalArgumentException("At least one address must be specified"); 1598 } 1599 Connection connection = new Connection(); 1600 if (!mContext.bindServiceAsUser(intent, connection, 1601 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, 1602 new UserHandle(mUserId))) { 1603 throw new IllegalStateException("Cannot bind " + config.user); 1604 } 1605 1606 mConnection = connection; 1607 mInterface = interfaze; 1608 1609 // Fill more values. 1610 config.user = mPackage; 1611 config.interfaze = mInterface; 1612 config.startTime = SystemClock.elapsedRealtime(); 1613 mConfig = config; 1614 1615 // Set up forwarding and DNS rules. 1616 // First attempt to do a seamless handover that only changes the interface name and 1617 // parameters. If that fails, disconnect. 1618 if (oldConfig != null 1619 && updateLinkPropertiesInPlaceIfPossible(mNetworkAgent, oldConfig)) { 1620 // Update underlying networks if it is changed. 1621 if (!Arrays.equals(oldConfig.underlyingNetworks, config.underlyingNetworks)) { 1622 setUnderlyingNetworks(config.underlyingNetworks); 1623 } 1624 } else { 1625 // Initialize the state for a new agent, while keeping the old one connected 1626 // in case this new connection fails. 1627 mNetworkAgent = null; 1628 updateState(DetailedState.CONNECTING, "establish"); 1629 // Set up forwarding and DNS rules. 1630 agentConnect(); 1631 // Remove the old tun's user forwarding rules 1632 // The new tun's user rules have already been added above so they will take over 1633 // as rules are deleted. This prevents data leakage as the rules are moved over. 1634 agentDisconnect(oldNetworkAgent); 1635 } 1636 1637 if (oldConnection != null) { 1638 mContext.unbindService(oldConnection); 1639 } 1640 1641 if (oldInterface != null && !oldInterface.equals(interfaze)) { 1642 jniReset(oldInterface); 1643 } 1644 1645 mDeps.setBlocking(tun.getFileDescriptor(), config.blocking); 1646 // Record that the VPN connection is established by an app which uses VpnService API. 1647 if (oldNetworkAgent != mNetworkAgent) { 1648 mAppOpsManager.startOp( 1649 AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, null, null); 1650 } 1651 } catch (RuntimeException e) { 1652 IoUtils.closeQuietly(tun); 1653 // If this is not seamless handover, disconnect partially-established network when error 1654 // occurs. 1655 if (oldNetworkAgent != mNetworkAgent) { 1656 agentDisconnect(); 1657 } 1658 // restore old state 1659 mConfig = oldConfig; 1660 mConnection = oldConnection; 1661 mNetworkCapabilities = 1662 new NetworkCapabilities.Builder(mNetworkCapabilities).setUids(oldUsers).build(); 1663 mNetworkAgent = oldNetworkAgent; 1664 mInterface = oldInterface; 1665 throw e; 1666 } 1667 Log.i(TAG, "Established by " + config.user + " on " + mInterface); 1668 return tun; 1669 } 1670 isRunningLocked()1671 private boolean isRunningLocked() { 1672 return mNetworkAgent != null && mInterface != null; 1673 } 1674 1675 // Returns true if the VPN has been established and the calling UID is its owner. Used to check 1676 // that a call to mutate VPN state is admissible. 1677 @VisibleForTesting isCallerEstablishedOwnerLocked()1678 protected boolean isCallerEstablishedOwnerLocked() { 1679 return isRunningLocked() && Binder.getCallingUid() == mOwnerUID; 1680 } 1681 1682 // Note: Return type guarantees results are deduped and sorted, which callers require. 1683 // This method also adds the SDK sandbox UIDs corresponding to the applications by default, 1684 // since apps are generally not aware of them, yet they should follow the VPN configuration 1685 // of the app they belong to. getAppsUids(List<String> packageNames, int userId)1686 private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) { 1687 SortedSet<Integer> uids = new TreeSet<>(); 1688 for (String app : packageNames) { 1689 int uid = getAppUid(app, userId); 1690 if (uid != -1) uids.add(uid); 1691 // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from 1692 // ConnectivityServiceTest. 1693 if (Process.isApplicationUid(uid) && SdkLevel.isAtLeastT()) { 1694 uids.add(Process.toSdkSandboxUid(uid)); 1695 } 1696 } 1697 return uids; 1698 } 1699 1700 /** 1701 * Creates a {@link Set} of non-intersecting {@code Range<Integer>} objects including all UIDs 1702 * associated with one user, and any restricted profiles attached to that user. 1703 * 1704 * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, 1705 * the UID ranges will match the app list specified there. Otherwise, all UIDs 1706 * in each user and profile will be included. 1707 * 1708 * @param userId The userId to create UID ranges for along with any of its restricted 1709 * profiles. 1710 * @param allowedApplications (optional) List of applications to allow. 1711 * @param disallowedApplications (optional) List of applications to deny. 1712 */ 1713 @VisibleForTesting createUserAndRestrictedProfilesRanges(@serIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications)1714 Set<Range<Integer>> createUserAndRestrictedProfilesRanges(@UserIdInt int userId, 1715 @Nullable List<String> allowedApplications, 1716 @Nullable List<String> disallowedApplications) { 1717 final Set<Range<Integer>> ranges = new ArraySet<>(); 1718 1719 // Assign the top-level user to the set of ranges 1720 addUserToRanges(ranges, userId, allowedApplications, disallowedApplications); 1721 1722 // If the user can have restricted profiles, assign all its restricted profiles too 1723 if (canHaveRestrictedProfile(userId)) { 1724 final long token = Binder.clearCallingIdentity(); 1725 List<UserInfo> users; 1726 try { 1727 users = mUserManager.getAliveUsers(); 1728 } finally { 1729 Binder.restoreCallingIdentity(token); 1730 } 1731 for (UserInfo user : users) { 1732 if (user.isRestricted() && (user.restrictedProfileParentId == userId)) { 1733 addUserToRanges(ranges, user.id, allowedApplications, disallowedApplications); 1734 } 1735 } 1736 } 1737 return ranges; 1738 } 1739 1740 /** 1741 * Updates a {@link Set} of non-intersecting {@code Range<Integer>} objects to include all UIDs 1742 * associated with one user. 1743 * 1744 * <p>If one of {@param allowedApplications} or {@param disallowedApplications} is provided, 1745 * the UID ranges will match the app allowlist or denylist specified there. Otherwise, all UIDs 1746 * in the user will be included. 1747 * 1748 * @param ranges {@link Set} of {@code Range<Integer>}s to which to add. 1749 * @param userId The userId to add to {@param ranges}. 1750 * @param allowedApplications (optional) allowlist of applications to include. 1751 * @param disallowedApplications (optional) denylist of applications to exclude. 1752 */ 1753 @VisibleForTesting addUserToRanges(@onNull Set<Range<Integer>> ranges, @UserIdInt int userId, @Nullable List<String> allowedApplications, @Nullable List<String> disallowedApplications)1754 void addUserToRanges(@NonNull Set<Range<Integer>> ranges, @UserIdInt int userId, 1755 @Nullable List<String> allowedApplications, 1756 @Nullable List<String> disallowedApplications) { 1757 if (allowedApplications != null) { 1758 // Add ranges covering all UIDs for allowedApplications. 1759 int start = -1, stop = -1; 1760 for (int uid : getAppsUids(allowedApplications, userId)) { 1761 if (start == -1) { 1762 start = uid; 1763 } else if (uid != stop + 1) { 1764 ranges.add(new Range<Integer>(start, stop)); 1765 start = uid; 1766 } 1767 stop = uid; 1768 } 1769 if (start != -1) ranges.add(new Range<Integer>(start, stop)); 1770 } else if (disallowedApplications != null) { 1771 // Add all ranges for user skipping UIDs for disallowedApplications. 1772 final Range<Integer> userRange = createUidRangeForUser(userId); 1773 int start = userRange.getLower(); 1774 for (int uid : getAppsUids(disallowedApplications, userId)) { 1775 if (uid == start) { 1776 start++; 1777 } else { 1778 ranges.add(new Range<Integer>(start, uid - 1)); 1779 start = uid + 1; 1780 } 1781 } 1782 if (start <= userRange.getUpper()) { 1783 ranges.add(new Range<Integer>(start, userRange.getUpper())); 1784 } 1785 } else { 1786 // Add all UIDs for the user. 1787 ranges.add(createUidRangeForUser(userId)); 1788 } 1789 } 1790 1791 // Returns the subset of the full list of active UID ranges the VPN applies to (mVpnUsers) that 1792 // apply to userId. uidRangesForUser(int userId, Set<Range<Integer>> existingRanges)1793 private static List<Range<Integer>> uidRangesForUser(int userId, 1794 Set<Range<Integer>> existingRanges) { 1795 final Range<Integer> userRange = createUidRangeForUser(userId); 1796 final List<Range<Integer>> ranges = new ArrayList<>(); 1797 for (Range<Integer> range : existingRanges) { 1798 if (userRange.contains(range)) { 1799 ranges.add(range); 1800 } 1801 } 1802 return ranges; 1803 } 1804 1805 /** 1806 * Updates UID ranges for this VPN and also updates its internal capabilities. 1807 * 1808 * <p>Should be called on primary ConnectivityService thread. 1809 */ onUserAdded(int userId)1810 public void onUserAdded(int userId) { 1811 // If the user is restricted tie them to the parent user's VPN 1812 UserInfo user = mUserManager.getUserInfo(userId); 1813 if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { 1814 synchronized(Vpn.this) { 1815 final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); 1816 if (existingRanges != null) { 1817 try { 1818 addUserToRanges(existingRanges, userId, mConfig.allowedApplications, 1819 mConfig.disallowedApplications); 1820 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) 1821 .setUids(existingRanges).build(); 1822 } catch (Exception e) { 1823 Log.wtf(TAG, "Failed to add restricted user to owner", e); 1824 } 1825 if (mNetworkAgent != null) { 1826 doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities); 1827 } 1828 } 1829 setVpnForcedLocked(mLockdown); 1830 } 1831 } 1832 } 1833 1834 /** 1835 * Updates UID ranges for this VPN and also updates its capabilities. 1836 * 1837 * <p>Should be called on primary ConnectivityService thread. 1838 */ onUserRemoved(int userId)1839 public void onUserRemoved(int userId) { 1840 // clean up if restricted 1841 UserInfo user = mUserManager.getUserInfo(userId); 1842 if (user.isRestricted() && user.restrictedProfileParentId == mUserId) { 1843 synchronized(Vpn.this) { 1844 final Set<Range<Integer>> existingRanges = mNetworkCapabilities.getUids(); 1845 if (existingRanges != null) { 1846 try { 1847 final List<Range<Integer>> removedRanges = 1848 uidRangesForUser(userId, existingRanges); 1849 existingRanges.removeAll(removedRanges); 1850 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) 1851 .setUids(existingRanges).build(); 1852 } catch (Exception e) { 1853 Log.wtf(TAG, "Failed to remove restricted user to owner", e); 1854 } 1855 if (mNetworkAgent != null) { 1856 doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities); 1857 } 1858 } 1859 setVpnForcedLocked(mLockdown); 1860 } 1861 } 1862 } 1863 1864 /** 1865 * Called when the user associated with this VPN has just been stopped. 1866 */ onUserStopped()1867 public synchronized void onUserStopped() { 1868 // Switch off networking lockdown (if it was enabled) 1869 setVpnForcedLocked(false); 1870 mAlwaysOn = false; 1871 1872 // Quit any active connections 1873 agentDisconnect(); 1874 1875 // The provider has been registered in the constructor, which is called in onUserStart. 1876 mConnectivityManager.unregisterNetworkProvider(mNetworkProvider); 1877 } 1878 1879 /** 1880 * Restricts network access from all UIDs affected by this {@link Vpn}, apart from the VPN 1881 * service app itself and allowed packages, to only sockets that have had {@code protect()} 1882 * called on them. All non-VPN traffic is blocked via a {@code PROHIBIT} response from the 1883 * kernel. 1884 * 1885 * The exception for the VPN UID isn't technically necessary -- setup should use protected 1886 * sockets -- but in practice it saves apps that don't protect their sockets from breaking. 1887 * 1888 * Calling multiple times with {@param enforce} = {@code true} will recreate the set of UIDs to 1889 * block every time, and if anything has changed update using {@link #setAllowOnlyVpnForUids}. 1890 * 1891 * @param enforce {@code true} to require that all traffic under the jurisdiction of this 1892 * {@link Vpn} goes through a VPN connection or is blocked until one is 1893 * available, {@code false} to lift the requirement. 1894 * 1895 * @see #mBlockedUidsAsToldToConnectivity 1896 */ 1897 @GuardedBy("this") setVpnForcedLocked(boolean enforce)1898 private void setVpnForcedLocked(boolean enforce) { 1899 final List<String> exemptedPackages; 1900 if (isNullOrLegacyVpn(mPackage)) { 1901 exemptedPackages = null; 1902 } else { 1903 exemptedPackages = new ArrayList<>(mLockdownAllowlist); 1904 exemptedPackages.add(mPackage); 1905 } 1906 final Set<UidRangeParcel> rangesToRemove = new ArraySet<>(mBlockedUidsAsToldToConnectivity); 1907 final Set<UidRangeParcel> rangesToAdd; 1908 if (enforce) { 1909 final Set<Range<Integer>> restrictedProfilesRanges = 1910 createUserAndRestrictedProfilesRanges(mUserId, 1911 /* allowedApplications */ null, 1912 /* disallowedApplications */ exemptedPackages); 1913 final Set<UidRangeParcel> rangesThatShouldBeBlocked = new ArraySet<>(); 1914 1915 // The UID range of the first user (0-99999) would block the IPSec traffic, which comes 1916 // directly from the kernel and is marked as uid=0. So we adjust the range to allow 1917 // it through (b/69873852). 1918 for (Range<Integer> range : restrictedProfilesRanges) { 1919 if (range.getLower() == 0 && range.getUpper() != 0) { 1920 rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.getUpper())); 1921 } else if (range.getLower() != 0) { 1922 rangesThatShouldBeBlocked.add( 1923 new UidRangeParcel(range.getLower(), range.getUpper())); 1924 } 1925 } 1926 1927 rangesToRemove.removeAll(rangesThatShouldBeBlocked); 1928 rangesToAdd = rangesThatShouldBeBlocked; 1929 // The ranges to tell ConnectivityService to add are the ones that should be blocked 1930 // minus the ones it already knows to block. Note that this will change the contents of 1931 // rangesThatShouldBeBlocked, but the list of ranges that should be blocked is 1932 // not used after this so it's fine to destroy it. 1933 rangesToAdd.removeAll(mBlockedUidsAsToldToConnectivity); 1934 } else { 1935 rangesToAdd = Collections.emptySet(); 1936 } 1937 1938 // If mBlockedUidsAsToldToNetd used to be empty, this will always be a no-op. 1939 setAllowOnlyVpnForUids(false, rangesToRemove); 1940 // If nothing should be blocked now, this will now be a no-op. 1941 setAllowOnlyVpnForUids(true, rangesToAdd); 1942 } 1943 1944 /** 1945 * Tell ConnectivityService to add or remove a list of {@link UidRangeParcel}s to the list of 1946 * UIDs that are only allowed to make connections through sockets that have had 1947 * {@code protect()} called on them. 1948 * 1949 * @param enforce {@code true} to add to the denylist, {@code false} to remove. 1950 * @param ranges {@link Collection} of {@link UidRangeParcel}s to add (if {@param enforce} is 1951 * {@code true}) or to remove. 1952 * @return {@code true} if all of the UIDs were added/removed. {@code false} otherwise, 1953 * including added ranges that already existed or removed ones that didn't. 1954 */ 1955 @GuardedBy("this") setAllowOnlyVpnForUids(boolean enforce, Collection<UidRangeParcel> ranges)1956 private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRangeParcel> ranges) { 1957 if (ranges.size() == 0) { 1958 return true; 1959 } 1960 // Convert to Collection<Range> which is what the ConnectivityManager API takes. 1961 ArrayList<Range<Integer>> integerRanges = new ArrayList<>(ranges.size()); 1962 for (UidRangeParcel uidRange : ranges) { 1963 integerRanges.add(new Range<>(uidRange.start, uidRange.stop)); 1964 } 1965 try { 1966 mConnectivityManager.setRequireVpnForUids(enforce, integerRanges); 1967 } catch (RuntimeException e) { 1968 Log.e(TAG, "Updating blocked=" + enforce 1969 + " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e); 1970 return false; 1971 } 1972 if (enforce) { 1973 mBlockedUidsAsToldToConnectivity.addAll(ranges); 1974 } else { 1975 mBlockedUidsAsToldToConnectivity.removeAll(ranges); 1976 } 1977 return true; 1978 } 1979 1980 /** 1981 * Return the configuration of the currently running VPN. 1982 */ getVpnConfig()1983 public synchronized VpnConfig getVpnConfig() { 1984 enforceControlPermission(); 1985 return mConfig; 1986 } 1987 1988 @Deprecated interfaceStatusChanged(String iface, boolean up)1989 public synchronized void interfaceStatusChanged(String iface, boolean up) { 1990 try { 1991 mObserver.interfaceStatusChanged(iface, up); 1992 } catch (RemoteException e) { 1993 // ignored; target is local 1994 } 1995 } 1996 1997 private INetworkManagementEventObserver mObserver = new BaseNetworkObserver() { 1998 @Override 1999 public void interfaceStatusChanged(String interfaze, boolean up) { 2000 synchronized (Vpn.this) { 2001 if (!up && mVpnRunner != null && mVpnRunner instanceof LegacyVpnRunner) { 2002 ((LegacyVpnRunner) mVpnRunner).exitIfOuterInterfaceIs(interfaze); 2003 } 2004 } 2005 } 2006 2007 @Override 2008 public void interfaceRemoved(String interfaze) { 2009 synchronized (Vpn.this) { 2010 if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) { 2011 if (mConnection != null) { 2012 mAppOpsManager.finishOp( 2013 AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, mOwnerUID, mPackage, 2014 null); 2015 mContext.unbindService(mConnection); 2016 cleanupVpnStateLocked(); 2017 } else if (mVpnRunner != null) { 2018 if (!VpnConfig.LEGACY_VPN.equals(mPackage)) { 2019 mAppOpsManager.finishOp( 2020 AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, 2021 null); 2022 } 2023 // cleanupVpnStateLocked() is called from mVpnRunner.exit() 2024 mVpnRunner.exit(); 2025 } 2026 } 2027 } 2028 } 2029 }; 2030 cleanupVpnStateLocked()2031 private void cleanupVpnStateLocked() { 2032 mStatusIntent = null; 2033 resetNetworkCapabilities(); 2034 mConfig = null; 2035 mInterface = null; 2036 2037 // Unconditionally clear both VpnService and VpnRunner fields. 2038 mVpnRunner = null; 2039 mConnection = null; 2040 agentDisconnect(); 2041 } 2042 enforceControlPermission()2043 private void enforceControlPermission() { 2044 mContext.enforceCallingPermission(CONTROL_VPN, "Unauthorized Caller"); 2045 } 2046 enforceControlPermissionOrInternalCaller()2047 private void enforceControlPermissionOrInternalCaller() { 2048 // Require the caller to be either an application with CONTROL_VPN permission or a process 2049 // in the system server. 2050 mContext.enforceCallingOrSelfPermission(CONTROL_VPN, "Unauthorized Caller"); 2051 } 2052 enforceSettingsPermission()2053 private void enforceSettingsPermission() { 2054 mContext.enforceCallingOrSelfPermission(Manifest.permission.NETWORK_SETTINGS, 2055 "Unauthorized Caller"); 2056 } 2057 2058 private class Connection implements ServiceConnection { 2059 private IBinder mService; 2060 2061 @Override onServiceConnected(ComponentName name, IBinder service)2062 public void onServiceConnected(ComponentName name, IBinder service) { 2063 mService = service; 2064 } 2065 2066 @Override onServiceDisconnected(ComponentName name)2067 public void onServiceDisconnected(ComponentName name) { 2068 mService = null; 2069 } 2070 } 2071 prepareStatusIntent()2072 private void prepareStatusIntent() { 2073 final long token = Binder.clearCallingIdentity(); 2074 try { 2075 mStatusIntent = mDeps.getIntentForStatusPanel(mContext); 2076 } finally { 2077 Binder.restoreCallingIdentity(token); 2078 } 2079 } 2080 addAddress(String address, int prefixLength)2081 public synchronized boolean addAddress(String address, int prefixLength) { 2082 if (!isCallerEstablishedOwnerLocked()) { 2083 return false; 2084 } 2085 boolean success = jniAddAddress(mInterface, address, prefixLength); 2086 doSendLinkProperties(mNetworkAgent, makeLinkProperties()); 2087 return success; 2088 } 2089 removeAddress(String address, int prefixLength)2090 public synchronized boolean removeAddress(String address, int prefixLength) { 2091 if (!isCallerEstablishedOwnerLocked()) { 2092 return false; 2093 } 2094 boolean success = jniDelAddress(mInterface, address, prefixLength); 2095 doSendLinkProperties(mNetworkAgent, makeLinkProperties()); 2096 return success; 2097 } 2098 2099 /** 2100 * Updates underlying network set. 2101 */ setUnderlyingNetworks(@ullable Network[] networks)2102 public synchronized boolean setUnderlyingNetworks(@Nullable Network[] networks) { 2103 if (!isCallerEstablishedOwnerLocked()) { 2104 return false; 2105 } 2106 // Make defensive copy since the content of array might be altered by the caller. 2107 mConfig.underlyingNetworks = 2108 (networks != null) ? Arrays.copyOf(networks, networks.length) : null; 2109 doSetUnderlyingNetworks( 2110 mNetworkAgent, 2111 (mConfig.underlyingNetworks != null) 2112 ? Arrays.asList(mConfig.underlyingNetworks) 2113 : null); 2114 return true; 2115 } 2116 2117 /** 2118 * This method should not be called if underlying interfaces field is needed, because it doesn't 2119 * have enough data to fill VpnInfo.underlyingIfaces field. 2120 */ getUnderlyingNetworkInfo()2121 public synchronized UnderlyingNetworkInfo getUnderlyingNetworkInfo() { 2122 if (!isRunningLocked()) { 2123 return null; 2124 } 2125 2126 return new UnderlyingNetworkInfo(mOwnerUID, mInterface, new ArrayList<>()); 2127 } 2128 appliesToUid(int uid)2129 public synchronized boolean appliesToUid(int uid) { 2130 if (!isRunningLocked()) { 2131 return false; 2132 } 2133 final Set<Range<Integer>> uids = mNetworkCapabilities.getUids(); 2134 if (uids == null) return true; 2135 for (final Range<Integer> range : uids) { 2136 if (range.contains(uid)) return true; 2137 } 2138 return false; 2139 } 2140 2141 /** 2142 * Gets the currently running VPN type 2143 * 2144 * @return the {@link VpnManager.VpnType}. {@link VpnManager.TYPE_VPN_NONE} if not running a 2145 * VPN. While VpnService-based VPNs are always app VPNs and LegacyVpn is always 2146 * Settings-based, the Platform VPNs can be initiated by both apps and Settings. 2147 */ getActiveVpnType()2148 public synchronized int getActiveVpnType() { 2149 if (!mNetworkInfo.isConnectedOrConnecting()) return VpnManager.TYPE_VPN_NONE; 2150 if (mVpnRunner == null) return VpnManager.TYPE_VPN_SERVICE; 2151 return isIkev2VpnRunner() ? VpnManager.TYPE_VPN_PLATFORM : VpnManager.TYPE_VPN_LEGACY; 2152 } 2153 2154 @GuardedBy("this") updateAlwaysOnNotification(DetailedState networkState)2155 private void updateAlwaysOnNotification(DetailedState networkState) { 2156 final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED); 2157 2158 final UserHandle user = UserHandle.of(mUserId); 2159 final long token = Binder.clearCallingIdentity(); 2160 try { 2161 final NotificationManager notificationManager = 2162 mUserIdContext.getSystemService(NotificationManager.class); 2163 if (!visible) { 2164 notificationManager.cancel(TAG, SystemMessage.NOTE_VPN_DISCONNECTED); 2165 return; 2166 } 2167 final Intent intent = new Intent(); 2168 intent.setComponent(ComponentName.unflattenFromString(mContext.getString( 2169 R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))); 2170 intent.putExtra("lockdown", mLockdown); 2171 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2172 final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser( 2173 intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user); 2174 final Notification.Builder builder = 2175 new Notification.Builder(mContext, NOTIFICATION_CHANNEL_VPN) 2176 .setSmallIcon(R.drawable.vpn_connected) 2177 .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected)) 2178 .setContentText(mContext.getString(R.string.vpn_lockdown_config)) 2179 .setContentIntent(configIntent) 2180 .setCategory(Notification.CATEGORY_SYSTEM) 2181 .setVisibility(Notification.VISIBILITY_PUBLIC) 2182 .setOngoing(true) 2183 .setColor(mContext.getColor( 2184 android.R.color.system_notification_accent_color)); 2185 notificationManager.notify(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, builder.build()); 2186 } finally { 2187 Binder.restoreCallingIdentity(token); 2188 } 2189 } 2190 2191 /** 2192 * Facade for system service calls that change, or depend on, state outside of 2193 * {@link ConnectivityService} and have hard-to-mock interfaces. 2194 * 2195 * @see com.android.server.connectivity.VpnTest 2196 */ 2197 @VisibleForTesting 2198 public static class SystemServices { 2199 private final Context mContext; 2200 SystemServices(@onNull Context context)2201 public SystemServices(@NonNull Context context) { 2202 mContext = context; 2203 } 2204 2205 /** 2206 * @see PendingIntent#getActivityAsUser() 2207 */ pendingIntentGetActivityAsUser( Intent intent, int flags, UserHandle user)2208 public PendingIntent pendingIntentGetActivityAsUser( 2209 Intent intent, int flags, UserHandle user) { 2210 return PendingIntent.getActivity( 2211 mContext.createContextAsUser(user, 0 /* flags */), 0 /* requestCode */, 2212 intent, flags); 2213 } 2214 2215 /** 2216 * @see Settings.Secure#putStringForUser 2217 */ settingsSecurePutStringForUser(String key, String value, int userId)2218 public void settingsSecurePutStringForUser(String key, String value, int userId) { 2219 Settings.Secure.putString(getContentResolverAsUser(userId), key, value); 2220 } 2221 2222 /** 2223 * @see Settings.Secure#putIntForUser 2224 */ settingsSecurePutIntForUser(String key, int value, int userId)2225 public void settingsSecurePutIntForUser(String key, int value, int userId) { 2226 Settings.Secure.putInt(getContentResolverAsUser(userId), key, value); 2227 } 2228 2229 /** 2230 * @see Settings.Secure#getStringForUser 2231 */ settingsSecureGetStringForUser(String key, int userId)2232 public String settingsSecureGetStringForUser(String key, int userId) { 2233 return Settings.Secure.getString(getContentResolverAsUser(userId), key); 2234 } 2235 2236 /** 2237 * @see Settings.Secure#getIntForUser 2238 */ settingsSecureGetIntForUser(String key, int def, int userId)2239 public int settingsSecureGetIntForUser(String key, int def, int userId) { 2240 return Settings.Secure.getInt(getContentResolverAsUser(userId), key, def); 2241 } 2242 getContentResolverAsUser(int userId)2243 private ContentResolver getContentResolverAsUser(int userId) { 2244 return mContext.createContextAsUser( 2245 UserHandle.of(userId), 0 /* flags */).getContentResolver(); 2246 } 2247 } 2248 jniCreate(int mtu)2249 private native int jniCreate(int mtu); jniGetName(int tun)2250 private native String jniGetName(int tun); jniSetAddresses(String interfaze, String addresses)2251 private native int jniSetAddresses(String interfaze, String addresses); jniReset(String interfaze)2252 private native void jniReset(String interfaze); jniCheck(String interfaze)2253 private native int jniCheck(String interfaze); jniAddAddress(String interfaze, String address, int prefixLen)2254 private native boolean jniAddAddress(String interfaze, String address, int prefixLen); jniDelAddress(String interfaze, String address, int prefixLen)2255 private native boolean jniDelAddress(String interfaze, String address, int prefixLen); 2256 findIPv4DefaultRoute(LinkProperties prop)2257 private static RouteInfo findIPv4DefaultRoute(LinkProperties prop) { 2258 for (RouteInfo route : prop.getAllRoutes()) { 2259 // Currently legacy VPN only works on IPv4. 2260 if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address) { 2261 return route; 2262 } 2263 } 2264 2265 throw new IllegalStateException("Unable to find IPv4 default gateway"); 2266 } 2267 enforceNotRestrictedUser()2268 private void enforceNotRestrictedUser() { 2269 final long token = Binder.clearCallingIdentity(); 2270 try { 2271 final UserInfo user = mUserManager.getUserInfo(mUserId); 2272 2273 if (user.isRestricted()) { 2274 throw new SecurityException("Restricted users cannot configure VPNs"); 2275 } 2276 } finally { 2277 Binder.restoreCallingIdentity(token); 2278 } 2279 } 2280 2281 /** 2282 * Start legacy VPN, controlling native daemons as needed. Creates a 2283 * secondary thread to perform connection work, returning quickly. 2284 * 2285 * Should only be called to respond to Binder requests as this enforces caller permission. Use 2286 * {@link #startLegacyVpnPrivileged(VpnProfile, Network, LinkProperties)} to skip the 2287 * permission check only when the caller is trusted (or the call is initiated by the system). 2288 */ startLegacyVpn(VpnProfile profile, @Nullable Network underlying, LinkProperties egress)2289 public void startLegacyVpn(VpnProfile profile, @Nullable Network underlying, 2290 LinkProperties egress) { 2291 enforceControlPermission(); 2292 final long token = Binder.clearCallingIdentity(); 2293 try { 2294 startLegacyVpnPrivileged(profile, underlying, egress); 2295 } finally { 2296 Binder.restoreCallingIdentity(token); 2297 } 2298 } 2299 makeKeystoreEngineGrantString(String alias)2300 private String makeKeystoreEngineGrantString(String alias) { 2301 if (alias == null) { 2302 return null; 2303 } 2304 final KeyStore2 keystore2 = KeyStore2.getInstance(); 2305 2306 KeyDescriptor key = new KeyDescriptor(); 2307 key.domain = Domain.APP; 2308 key.nspace = KeyProperties.NAMESPACE_APPLICATION; 2309 key.alias = alias; 2310 key.blob = null; 2311 2312 final int grantAccessVector = KeyPermission.USE | KeyPermission.GET_INFO; 2313 2314 try { 2315 // The native vpn daemon is running as VPN_UID. This tells Keystore 2.0 2316 // to allow a process running with this UID to access the key designated by 2317 // the KeyDescriptor `key`. `grant` returns a new KeyDescriptor with a grant 2318 // identifier. This identifier needs to be communicated to the vpn daemon. 2319 key = keystore2.grant(key, android.os.Process.VPN_UID, grantAccessVector); 2320 } catch (android.security.KeyStoreException e) { 2321 Log.e(TAG, "Failed to get grant for keystore key.", e); 2322 throw new IllegalStateException("Failed to get grant for keystore key.", e); 2323 } 2324 2325 // Turn the grant identifier into a string as understood by the keystore boringssl engine 2326 // in system/security/keystore-engine. 2327 return KeyStore2.makeKeystoreEngineGrantString(key.nspace); 2328 } 2329 getCaCertificateFromKeystoreAsPem(@onNull KeyStore keystore, @NonNull String alias)2330 private String getCaCertificateFromKeystoreAsPem(@NonNull KeyStore keystore, 2331 @NonNull String alias) 2332 throws KeyStoreException, IOException, CertificateEncodingException { 2333 if (keystore.isCertificateEntry(alias)) { 2334 final Certificate cert = keystore.getCertificate(alias); 2335 if (cert == null) return null; 2336 return new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8); 2337 } else { 2338 final Certificate[] certs = keystore.getCertificateChain(alias); 2339 // If there is none or one entry it means there is no CA entry associated with this 2340 // alias. 2341 if (certs == null || certs.length <= 1) { 2342 return null; 2343 } 2344 // If this is not a (pure) certificate entry, then there is a user certificate which 2345 // will be included at the beginning of the certificate chain. But the caller of this 2346 // function does not expect this certificate to be included, so we cut it off. 2347 return new String(Credentials.convertToPem( 2348 Arrays.copyOfRange(certs, 1, certs.length)), StandardCharsets.UTF_8); 2349 } 2350 } 2351 2352 /** 2353 * Like {@link #startLegacyVpn(VpnProfile, Network, LinkProperties)}, but does not 2354 * check permissions under the assumption that the caller is the system. 2355 * 2356 * Callers are responsible for checking permissions if needed. 2357 */ startLegacyVpnPrivileged(VpnProfile profile, @Nullable Network underlying, @NonNull LinkProperties egress)2358 public void startLegacyVpnPrivileged(VpnProfile profile, 2359 @Nullable Network underlying, @NonNull LinkProperties egress) { 2360 UserInfo user = mUserManager.getUserInfo(mUserId); 2361 if (user.isRestricted() || mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, 2362 new UserHandle(mUserId))) { 2363 throw new SecurityException("Restricted users cannot establish VPNs"); 2364 } 2365 2366 final RouteInfo ipv4DefaultRoute = findIPv4DefaultRoute(egress); 2367 final String gateway = ipv4DefaultRoute.getGateway().getHostAddress(); 2368 final String iface = ipv4DefaultRoute.getInterface(); 2369 2370 // Load certificates. 2371 String privateKey = ""; 2372 String userCert = ""; 2373 String caCert = ""; 2374 String serverCert = ""; 2375 2376 try { 2377 final KeyStore keystore = KeyStore.getInstance(ANDROID_KEYSTORE_PROVIDER); 2378 keystore.load(null); 2379 if (!profile.ipsecUserCert.isEmpty()) { 2380 privateKey = profile.ipsecUserCert; 2381 final Certificate cert = keystore.getCertificate(profile.ipsecUserCert); 2382 userCert = (cert == null) ? null 2383 : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8); 2384 } 2385 if (!profile.ipsecCaCert.isEmpty()) { 2386 caCert = getCaCertificateFromKeystoreAsPem(keystore, profile.ipsecCaCert); 2387 } 2388 if (!profile.ipsecServerCert.isEmpty()) { 2389 final Certificate cert = keystore.getCertificate(profile.ipsecServerCert); 2390 serverCert = (cert == null) ? null 2391 : new String(Credentials.convertToPem(cert), StandardCharsets.UTF_8); 2392 } 2393 } catch (CertificateException | KeyStoreException | IOException 2394 | NoSuchAlgorithmException e) { 2395 throw new IllegalStateException("Failed to load credentials from AndroidKeyStore", e); 2396 } 2397 if (userCert == null || caCert == null || serverCert == null) { 2398 throw new IllegalStateException("Cannot load credentials"); 2399 } 2400 2401 // Prepare arguments for racoon. 2402 String[] racoon = null; 2403 switch (profile.type) { 2404 case VpnProfile.TYPE_IKEV2_IPSEC_RSA: 2405 // Secret key is still just the alias (not the actual private key). The private key 2406 // is retrieved from the KeyStore during conversion of the VpnProfile to an 2407 // Ikev2VpnProfile. 2408 profile.ipsecSecret = Ikev2VpnProfile.PREFIX_KEYSTORE_ALIAS + privateKey; 2409 profile.ipsecUserCert = userCert; 2410 // Fallthrough 2411 case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: 2412 profile.ipsecCaCert = caCert; 2413 2414 // Start VPN profile 2415 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS); 2416 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); 2417 return; 2418 case VpnProfile.TYPE_IKEV2_IPSEC_PSK: 2419 // Ikev2VpnProfiles expect a base64-encoded preshared key. 2420 profile.ipsecSecret = 2421 Ikev2VpnProfile.encodeForIpsecSecret(profile.ipsecSecret.getBytes()); 2422 2423 // Start VPN profile 2424 profile.setAllowedAlgorithms(Ikev2VpnProfile.DEFAULT_ALGORITHMS); 2425 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); 2426 return; 2427 case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: 2428 // All the necessary IKE options should come from IkeTunnelConnectionParams in the 2429 // profile. 2430 startVpnProfilePrivileged(profile, VpnConfig.LEGACY_VPN); 2431 return; 2432 case VpnProfile.TYPE_L2TP_IPSEC_PSK: 2433 racoon = new String[] { 2434 iface, profile.server, "udppsk", profile.ipsecIdentifier, 2435 profile.ipsecSecret, "1701", 2436 }; 2437 break; 2438 case VpnProfile.TYPE_L2TP_IPSEC_RSA: 2439 racoon = new String[] { 2440 iface, profile.server, "udprsa", makeKeystoreEngineGrantString(privateKey), 2441 userCert, caCert, serverCert, "1701", 2442 }; 2443 break; 2444 case VpnProfile.TYPE_IPSEC_XAUTH_PSK: 2445 racoon = new String[] { 2446 iface, profile.server, "xauthpsk", profile.ipsecIdentifier, 2447 profile.ipsecSecret, profile.username, profile.password, "", gateway, 2448 }; 2449 break; 2450 case VpnProfile.TYPE_IPSEC_XAUTH_RSA: 2451 racoon = new String[] { 2452 iface, profile.server, "xauthrsa", makeKeystoreEngineGrantString(privateKey), 2453 userCert, caCert, serverCert, profile.username, profile.password, "", gateway, 2454 }; 2455 break; 2456 case VpnProfile.TYPE_IPSEC_HYBRID_RSA: 2457 racoon = new String[] { 2458 iface, profile.server, "hybridrsa", 2459 caCert, serverCert, profile.username, profile.password, "", gateway, 2460 }; 2461 break; 2462 } 2463 2464 // Prepare arguments for mtpd. MTU/MRU calculated conservatively. Only IPv4 supported 2465 // because LegacyVpn. 2466 // 1500 - 60 (Carrier-internal IPv6 + UDP + GTP) - 10 (PPP) - 16 (L2TP) - 8 (UDP) 2467 // - 77 (IPsec w/ SHA-2 512, 256b trunc-len, AES-CBC) - 8 (UDP encap) - 20 (IPv4) 2468 // - 28 (464xlat) 2469 String[] mtpd = null; 2470 switch (profile.type) { 2471 case VpnProfile.TYPE_PPTP: 2472 mtpd = new String[] { 2473 iface, "pptp", profile.server, "1723", 2474 "name", profile.username, "password", profile.password, 2475 "linkname", "vpn", "refuse-eap", "nodefaultroute", 2476 "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270", 2477 (profile.mppe ? "+mppe" : "nomppe"), 2478 }; 2479 if (profile.mppe) { 2480 // Disallow PAP authentication when MPPE is requested, as MPPE cannot work 2481 // with PAP anyway, and users may not expect PAP (plain text) to be used when 2482 // MPPE was requested. 2483 mtpd = Arrays.copyOf(mtpd, mtpd.length + 1); 2484 mtpd[mtpd.length - 1] = "-pap"; 2485 } 2486 break; 2487 case VpnProfile.TYPE_L2TP_IPSEC_PSK: 2488 case VpnProfile.TYPE_L2TP_IPSEC_RSA: 2489 mtpd = new String[] { 2490 iface, "l2tp", profile.server, "1701", profile.l2tpSecret, 2491 "name", profile.username, "password", profile.password, 2492 "linkname", "vpn", "refuse-eap", "nodefaultroute", 2493 "usepeerdns", "idle", "1800", "mtu", "1270", "mru", "1270", 2494 }; 2495 break; 2496 } 2497 2498 VpnConfig config = new VpnConfig(); 2499 config.legacy = true; 2500 config.user = profile.key; 2501 config.interfaze = iface; 2502 config.session = profile.name; 2503 config.isMetered = false; 2504 config.proxyInfo = profile.proxy; 2505 if (underlying != null) { 2506 config.underlyingNetworks = new Network[] { underlying }; 2507 } 2508 2509 config.addLegacyRoutes(profile.routes); 2510 if (!profile.dnsServers.isEmpty()) { 2511 config.dnsServers = Arrays.asList(profile.dnsServers.split(" +")); 2512 } 2513 if (!profile.searchDomains.isEmpty()) { 2514 config.searchDomains = Arrays.asList(profile.searchDomains.split(" +")); 2515 } 2516 startLegacyVpn(config, racoon, mtpd, profile); 2517 } 2518 startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd, VpnProfile profile)2519 private synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd, 2520 VpnProfile profile) { 2521 stopVpnRunnerPrivileged(); 2522 2523 // Prepare for the new request. 2524 prepareInternal(VpnConfig.LEGACY_VPN); 2525 updateState(DetailedState.CONNECTING, "startLegacyVpn"); 2526 2527 // Start a new LegacyVpnRunner and we are done! 2528 mVpnRunner = new LegacyVpnRunner(config, racoon, mtpd, profile); 2529 startLegacyVpnRunner(); 2530 } 2531 2532 @VisibleForTesting startLegacyVpnRunner()2533 protected void startLegacyVpnRunner() { 2534 mVpnRunner.start(); 2535 } 2536 2537 /** 2538 * Checks if this the currently running VPN (if any) was started by the Settings app 2539 * 2540 * <p>This includes both Legacy VPNs and Platform VPNs. 2541 */ isSettingsVpnLocked()2542 private boolean isSettingsVpnLocked() { 2543 return mVpnRunner != null && VpnConfig.LEGACY_VPN.equals(mPackage); 2544 } 2545 2546 /** Stop VPN runner. Permissions must be checked by callers. */ stopVpnRunnerPrivileged()2547 public synchronized void stopVpnRunnerPrivileged() { 2548 if (!isSettingsVpnLocked()) { 2549 return; 2550 } 2551 2552 final boolean isLegacyVpn = mVpnRunner instanceof LegacyVpnRunner; 2553 2554 mVpnRunner.exit(); 2555 mVpnRunner = null; 2556 2557 // LegacyVpn uses daemons that must be shut down before new ones are brought up. 2558 // The same limitation does not apply to Platform VPNs. 2559 if (isLegacyVpn) { 2560 synchronized (LegacyVpnRunner.TAG) { 2561 // wait for old thread to completely finish before spinning up 2562 // new instance, otherwise state updates can be out of order. 2563 } 2564 } 2565 } 2566 2567 /** 2568 * Return the information of the current ongoing legacy VPN. 2569 */ getLegacyVpnInfo()2570 public synchronized LegacyVpnInfo getLegacyVpnInfo() { 2571 // Check if the caller is authorized. 2572 enforceControlPermission(); 2573 return getLegacyVpnInfoPrivileged(); 2574 } 2575 2576 /** 2577 * Return the information of the current ongoing legacy VPN. 2578 * Callers are responsible for checking permissions if needed. 2579 */ getLegacyVpnInfoPrivileged()2580 private synchronized LegacyVpnInfo getLegacyVpnInfoPrivileged() { 2581 if (!isSettingsVpnLocked()) return null; 2582 2583 final LegacyVpnInfo info = new LegacyVpnInfo(); 2584 info.key = mConfig.user; 2585 info.state = mLegacyState; 2586 if (mNetworkInfo.isConnected()) { 2587 info.intent = mStatusIntent; 2588 } 2589 return info; 2590 } 2591 getLegacyVpnConfig()2592 public synchronized VpnConfig getLegacyVpnConfig() { 2593 if (isSettingsVpnLocked()) { 2594 return mConfig; 2595 } else { 2596 return null; 2597 } 2598 } 2599 2600 @Nullable getRedactedNetworkCapabilities( NetworkCapabilities nc)2601 private synchronized NetworkCapabilities getRedactedNetworkCapabilities( 2602 NetworkCapabilities nc) { 2603 if (nc == null) return null; 2604 return mConnectivityManager.getRedactedNetworkCapabilitiesForPackage( 2605 nc, mOwnerUID, mPackage); 2606 } 2607 2608 @Nullable getRedactedLinkProperties(LinkProperties lp)2609 private synchronized LinkProperties getRedactedLinkProperties(LinkProperties lp) { 2610 if (lp == null) return null; 2611 return mConnectivityManager.getRedactedLinkPropertiesForPackage(lp, mOwnerUID, mPackage); 2612 } 2613 2614 /** This class represents the common interface for all VPN runners. */ 2615 @VisibleForTesting 2616 abstract class VpnRunner extends Thread { 2617 VpnRunner(String name)2618 protected VpnRunner(String name) { 2619 super(name); 2620 } 2621 run()2622 public abstract void run(); 2623 2624 /** 2625 * Disconnects the NetworkAgent and cleans up all state related to the VpnRunner. 2626 * 2627 * <p>All outer Vpn instance state is cleaned up in cleanupVpnStateLocked() 2628 */ exitVpnRunner()2629 protected abstract void exitVpnRunner(); 2630 2631 /** 2632 * Triggers the cleanup of the VpnRunner, and additionally cleans up Vpn instance-wide state 2633 * 2634 * <p>This method ensures that simple calls to exit() will always clean up global state 2635 * properly. 2636 */ exit()2637 protected final void exit() { 2638 synchronized (Vpn.this) { 2639 exitVpnRunner(); 2640 cleanupVpnStateLocked(); 2641 } 2642 } 2643 } 2644 2645 interface IkeV2VpnRunnerCallback { onDefaultNetworkChanged(@onNull Network network)2646 void onDefaultNetworkChanged(@NonNull Network network); 2647 onDefaultNetworkCapabilitiesChanged(@onNull NetworkCapabilities nc)2648 void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc); 2649 onDefaultNetworkLinkPropertiesChanged(@onNull LinkProperties lp)2650 void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp); 2651 onDefaultNetworkLost(@onNull Network network)2652 void onDefaultNetworkLost(@NonNull Network network); 2653 onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration)2654 void onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration); 2655 onIkeConnectionInfoChanged( int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo)2656 void onIkeConnectionInfoChanged( 2657 int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo); 2658 onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig)2659 void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig); 2660 onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction)2661 void onChildTransformCreated(int token, @NonNull IpSecTransform transform, int direction); 2662 onChildMigrated( int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform)2663 void onChildMigrated( 2664 int token, 2665 @NonNull IpSecTransform inTransform, 2666 @NonNull IpSecTransform outTransform); 2667 onSessionLost(int token, @Nullable Exception exception)2668 void onSessionLost(int token, @Nullable Exception exception); 2669 } 2670 2671 /** 2672 * Internal class managing IKEv2/IPsec VPN connectivity 2673 * 2674 * <p>The IKEv2 VPN will listen to, and run based on the lifecycle of Android's default Network. 2675 * As a new default is selected, old IKE sessions will be torn down, and a new one will be 2676 * started. 2677 * 2678 * <p>This class uses locking minimally - the Vpn instance lock is only ever held when fields of 2679 * the outer class are modified. As such, care must be taken to ensure that no calls are added 2680 * that might modify the outer class' state without acquiring a lock. 2681 * 2682 * <p>The overall structure of the Ikev2VpnRunner is as follows: 2683 * 2684 * <ol> 2685 * <li>Upon startup, a NetworkRequest is registered with ConnectivityManager. This is called 2686 * any time a new default network is selected 2687 * <li>When a new default is connected, an IKE session is started on that Network. If there 2688 * were any existing IKE sessions on other Networks, they are torn down before starting 2689 * the new IKE session 2690 * <li>Upon establishment, the onChildTransformCreated() callback is called twice, one for 2691 * each direction, and finally onChildOpened() is called 2692 * <li>Upon the onChildOpened() call, the VPN is fully set up. 2693 * <li>Subsequent Network changes result in new onDefaultNetworkChanged() callbacks. See (2). 2694 * </ol> 2695 */ 2696 class IkeV2VpnRunner extends VpnRunner implements IkeV2VpnRunnerCallback { 2697 @NonNull private static final String TAG = "IkeV2VpnRunner"; 2698 2699 // 5 seconds grace period before tearing down the IKE Session in case new default network 2700 // will come up 2701 private static final long NETWORK_LOST_TIMEOUT_MS = 5000L; 2702 2703 @NonNull private final IpSecManager mIpSecManager; 2704 @NonNull private final Ikev2VpnProfile mProfile; 2705 @NonNull private final ConnectivityManager.NetworkCallback mNetworkCallback; 2706 2707 /** 2708 * Executor upon which ALL callbacks must be run. 2709 * 2710 * <p>This executor MUST be a single threaded executor, in order to ensure the consistency 2711 * of the mutable Ikev2VpnRunner fields. The Ikev2VpnRunner is built mostly lock-free by 2712 * virtue of everything being serialized on this executor. 2713 */ 2714 @NonNull private final ScheduledThreadPoolExecutor mExecutor; 2715 2716 @Nullable private ScheduledFuture<?> mScheduledHandleNetworkLostFuture; 2717 @Nullable private ScheduledFuture<?> mScheduledHandleRetryIkeSessionFuture; 2718 2719 /** Signal to ensure shutdown is honored even if a new Network is connected. */ 2720 private boolean mIsRunning = true; 2721 2722 /** 2723 * The token that identifies the most recently created IKE session. 2724 * 2725 * <p>This token is monotonically increasing and will never be reset in the lifetime of this 2726 * Ikev2VpnRunner, but it does get reset across runs. It also MUST be accessed on the 2727 * executor thread and updated when a new IKE session is created. 2728 */ 2729 private int mCurrentToken = STARTING_TOKEN; 2730 2731 @Nullable private IpSecTunnelInterface mTunnelIface; 2732 @Nullable private Network mActiveNetwork; 2733 @Nullable private NetworkCapabilities mUnderlyingNetworkCapabilities; 2734 @Nullable private LinkProperties mUnderlyingLinkProperties; 2735 private final String mSessionKey; 2736 2737 @Nullable private IkeSessionWrapper mSession; 2738 @Nullable private IkeSessionConnectionInfo mIkeConnectionInfo; 2739 2740 // mMobikeEnabled can only be updated after IKE AUTH is finished. 2741 private boolean mMobikeEnabled = false; 2742 2743 /** 2744 * The number of attempts since the last successful connection. 2745 * 2746 * <p>This variable controls the retry delay, and is reset when a new IKE session is 2747 * opened or when there is a new default network. 2748 */ 2749 private int mRetryCount = 0; 2750 IkeV2VpnRunner( @onNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor)2751 IkeV2VpnRunner( 2752 @NonNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor) { 2753 super(TAG); 2754 mProfile = profile; 2755 mExecutor = executor; 2756 mIpSecManager = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE); 2757 mNetworkCallback = new VpnIkev2Utils.Ikev2VpnNetworkCallback(TAG, this, mExecutor); 2758 mSessionKey = UUID.randomUUID().toString(); 2759 2760 // Set the policy so that cancelled tasks will be removed from the work queue 2761 mExecutor.setRemoveOnCancelPolicy(true); 2762 2763 // Set the policy so that all delayed tasks will not be executed 2764 mExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); 2765 2766 // To avoid hitting RejectedExecutionException upon shutdown of the mExecutor */ 2767 mExecutor.setRejectedExecutionHandler( 2768 (r, exe) -> { 2769 Log.d(TAG, "Runnable " + r + " rejected by the mExecutor"); 2770 }); 2771 } 2772 2773 @Override run()2774 public void run() { 2775 // Unless the profile is restricted to test networks, explicitly use only the network 2776 // that ConnectivityService thinks is the "best." In other words, only ever use the 2777 // currently selected default network. This does mean that in both onLost() and 2778 // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs. 2779 // 2780 // When restricted to test networks, select any network with TRANSPORT_TEST. Since the 2781 // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS, 2782 // this is considered safe. 2783 final NetworkRequest req; 2784 2785 if (mProfile.isRestrictedToTestNetworks()) { 2786 req = new NetworkRequest.Builder() 2787 .clearCapabilities() 2788 .addTransportType(NetworkCapabilities.TRANSPORT_TEST) 2789 .addCapability(NET_CAPABILITY_NOT_VPN) 2790 .build(); 2791 } else { 2792 // Basically, the request here is referring to the default request which is defined 2793 // in ConnectivityService. Ideally, ConnectivityManager should provide an new API 2794 // which can provide the status of physical network even though there is a virtual 2795 // network. b/147280869 is used for tracking the new API. 2796 // TODO: Use the new API to register default physical network. 2797 req = new NetworkRequest.Builder() 2798 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 2799 .build(); 2800 } 2801 2802 mConnectivityManager.requestNetwork(req, mNetworkCallback); 2803 } 2804 isActiveNetwork(@ullable Network network)2805 private boolean isActiveNetwork(@Nullable Network network) { 2806 return Objects.equals(mActiveNetwork, network) && mIsRunning; 2807 } 2808 isActiveToken(int token)2809 private boolean isActiveToken(int token) { 2810 return (mCurrentToken == token) && mIsRunning; 2811 } 2812 2813 /** 2814 * Called when an IKE session has been opened 2815 * 2816 * <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor 2817 * thread in order to ensure consistency of the Ikev2VpnRunner fields. 2818 */ onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration)2819 public void onIkeOpened(int token, @NonNull IkeSessionConfiguration ikeConfiguration) { 2820 if (!isActiveToken(token)) { 2821 Log.d(TAG, "onIkeOpened called for obsolete token " + token); 2822 return; 2823 } 2824 2825 mMobikeEnabled = 2826 ikeConfiguration.isIkeExtensionEnabled( 2827 IkeSessionConfiguration.EXTENSION_TYPE_MOBIKE); 2828 onIkeConnectionInfoChanged(token, ikeConfiguration.getIkeSessionConnectionInfo()); 2829 mRetryCount = 0; 2830 } 2831 2832 /** 2833 * Called when an IKE session's {@link IkeSessionConnectionInfo} is available or updated 2834 * 2835 * <p>This callback is usually fired when an IKE session has been opened or migrated. 2836 * 2837 * <p>This method is called multiple times over the lifetime of an IkeSession, and MUST run 2838 * on the mExecutor thread in order to ensure consistency of the Ikev2VpnRunner fields. 2839 */ onIkeConnectionInfoChanged( int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo)2840 public void onIkeConnectionInfoChanged( 2841 int token, @NonNull IkeSessionConnectionInfo ikeConnectionInfo) { 2842 if (!isActiveToken(token)) { 2843 Log.d(TAG, "onIkeConnectionInfoChanged called for obsolete token " + token); 2844 return; 2845 } 2846 2847 // The update on VPN and the IPsec tunnel will be done when migration is fully complete 2848 // in onChildMigrated 2849 mIkeConnectionInfo = ikeConnectionInfo; 2850 } 2851 2852 /** 2853 * Called when an IKE Child session has been opened, signalling completion of the startup. 2854 * 2855 * <p>This method is only ever called once per IkeSession, and MUST run on the mExecutor 2856 * thread in order to ensure consistency of the Ikev2VpnRunner fields. 2857 */ onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig)2858 public void onChildOpened(int token, @NonNull ChildSessionConfiguration childConfig) { 2859 if (!isActiveToken(token)) { 2860 Log.d(TAG, "onChildOpened called for obsolete token " + token); 2861 2862 // Do nothing; this signals that either: (1) a new/better Network was found, 2863 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in 2864 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited, 2865 // or an error was encountered somewhere else). In both cases, all resources and 2866 // sessions are torn down via resetIkeState(). 2867 return; 2868 } 2869 2870 try { 2871 final String interfaceName = mTunnelIface.getInterfaceName(); 2872 final int maxMtu = mProfile.getMaxMtu(); 2873 final List<LinkAddress> internalAddresses = childConfig.getInternalAddresses(); 2874 final List<String> dnsAddrStrings = new ArrayList<>(); 2875 2876 final Collection<RouteInfo> newRoutes = VpnIkev2Utils.getRoutesFromTrafficSelectors( 2877 childConfig.getOutboundTrafficSelectors()); 2878 for (final LinkAddress address : internalAddresses) { 2879 mTunnelIface.addAddress(address.getAddress(), address.getPrefixLength()); 2880 } 2881 for (InetAddress addr : childConfig.getInternalDnsServers()) { 2882 dnsAddrStrings.add(addr.getHostAddress()); 2883 } 2884 2885 // The actual network of this IKE session has been set up with is 2886 // mIkeConnectionInfo.getNetwork() instead of mActiveNetwork because 2887 // mActiveNetwork might have been updated after the setup was triggered. 2888 final Network network = mIkeConnectionInfo.getNetwork(); 2889 2890 final NetworkAgent networkAgent; 2891 final LinkProperties lp; 2892 2893 synchronized (Vpn.this) { 2894 // Ignore stale runner. 2895 if (mVpnRunner != this) return; 2896 2897 mInterface = interfaceName; 2898 mConfig.mtu = maxMtu; 2899 mConfig.interfaze = mInterface; 2900 2901 mConfig.addresses.clear(); 2902 mConfig.addresses.addAll(internalAddresses); 2903 2904 mConfig.routes.clear(); 2905 mConfig.routes.addAll(newRoutes); 2906 2907 if (mConfig.dnsServers == null) mConfig.dnsServers = new ArrayList<>(); 2908 mConfig.dnsServers.clear(); 2909 mConfig.dnsServers.addAll(dnsAddrStrings); 2910 2911 mConfig.underlyingNetworks = new Network[] {network}; 2912 mConfig.disallowedApplications = getAppExclusionList(mPackage); 2913 2914 networkAgent = mNetworkAgent; 2915 2916 // The below must be done atomically with the mConfig update, otherwise 2917 // isRunningLocked() will be racy. 2918 if (networkAgent == null) { 2919 if (isSettingsVpnLocked()) { 2920 prepareStatusIntent(); 2921 } 2922 agentConnect(); 2923 return; // Link properties are already sent. 2924 } else { 2925 // Underlying networks also set in agentConnect() 2926 doSetUnderlyingNetworks(networkAgent, Collections.singletonList(network)); 2927 mNetworkCapabilities = 2928 new NetworkCapabilities.Builder(mNetworkCapabilities) 2929 .setUnderlyingNetworks(Collections.singletonList(network)) 2930 .build(); 2931 } 2932 2933 lp = makeLinkProperties(); // Accesses VPN instance fields; must be locked 2934 } 2935 2936 doSendLinkProperties(networkAgent, lp); 2937 } catch (Exception e) { 2938 Log.d(TAG, "Error in ChildOpened for token " + token, e); 2939 onSessionLost(token, e); 2940 } 2941 } 2942 2943 /** 2944 * Called when an IPsec transform has been created, and should be applied. 2945 * 2946 * <p>This method is called multiple times over the lifetime of an IkeSession (or default 2947 * network), and MUST always be called on the mExecutor thread in order to ensure 2948 * consistency of the Ikev2VpnRunner fields. 2949 */ onChildTransformCreated( int token, @NonNull IpSecTransform transform, int direction)2950 public void onChildTransformCreated( 2951 int token, @NonNull IpSecTransform transform, int direction) { 2952 if (!isActiveToken(token)) { 2953 Log.d(TAG, "ChildTransformCreated for obsolete token " + token); 2954 2955 // Do nothing; this signals that either: (1) a new/better Network was found, 2956 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in 2957 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited, 2958 // or an error was encountered somewhere else). In both cases, all resources and 2959 // sessions are torn down via resetIkeState(). 2960 return; 2961 } 2962 2963 try { 2964 mTunnelIface.setUnderlyingNetwork(mIkeConnectionInfo.getNetwork()); 2965 2966 // Transforms do not need to be persisted; the IkeSession will keep 2967 // them alive for us 2968 mIpSecManager.applyTunnelModeTransform(mTunnelIface, direction, transform); 2969 } catch (IOException e) { 2970 Log.d(TAG, "Transform application failed for token " + token, e); 2971 onSessionLost(token, e); 2972 } 2973 } 2974 2975 /** 2976 * Called when an IPsec transform has been created, and should be re-applied. 2977 * 2978 * <p>This method is called multiple times over the lifetime of an IkeSession (or default 2979 * network), and MUST always be called on the mExecutor thread in order to ensure 2980 * consistency of the Ikev2VpnRunner fields. 2981 */ onChildMigrated( int token, @NonNull IpSecTransform inTransform, @NonNull IpSecTransform outTransform)2982 public void onChildMigrated( 2983 int token, 2984 @NonNull IpSecTransform inTransform, 2985 @NonNull IpSecTransform outTransform) { 2986 if (!isActiveToken(token)) { 2987 Log.d(TAG, "onChildMigrated for obsolete token " + token); 2988 return; 2989 } 2990 2991 // The actual network of this IKE session has migrated to is 2992 // mIkeConnectionInfo.getNetwork() instead of mActiveNetwork because mActiveNetwork 2993 // might have been updated after the migration was triggered. 2994 final Network network = mIkeConnectionInfo.getNetwork(); 2995 2996 try { 2997 synchronized (Vpn.this) { 2998 // Ignore stale runner. 2999 if (mVpnRunner != this) return; 3000 3001 mConfig.underlyingNetworks = new Network[] {network}; 3002 mNetworkCapabilities = 3003 new NetworkCapabilities.Builder(mNetworkCapabilities) 3004 .setUnderlyingNetworks(Collections.singletonList(network)) 3005 .build(); 3006 doSetUnderlyingNetworks(mNetworkAgent, Collections.singletonList(network)); 3007 } 3008 3009 mTunnelIface.setUnderlyingNetwork(network); 3010 3011 // Transforms do not need to be persisted; the IkeSession will keep them alive for 3012 // us 3013 mIpSecManager.applyTunnelModeTransform( 3014 mTunnelIface, IpSecManager.DIRECTION_IN, inTransform); 3015 mIpSecManager.applyTunnelModeTransform( 3016 mTunnelIface, IpSecManager.DIRECTION_OUT, outTransform); 3017 } catch (IOException e) { 3018 Log.d(TAG, "Transform application failed for token " + token, e); 3019 onSessionLost(token, e); 3020 } 3021 } 3022 3023 /** 3024 * Called when a new default network is connected. 3025 * 3026 * <p>The Ikev2VpnRunner will unconditionally switch to the new network. If the IKE session 3027 * has mobility, Ikev2VpnRunner will migrate the existing IkeSession to the new network. 3028 * Otherwise, Ikev2VpnRunner will kill the old IKE state, and start a new IkeSession 3029 * instance. 3030 * 3031 * <p>This method MUST always be called on the mExecutor thread in order to ensure 3032 * consistency of the Ikev2VpnRunner fields. 3033 */ onDefaultNetworkChanged(@onNull Network network)3034 public void onDefaultNetworkChanged(@NonNull Network network) { 3035 Log.d(TAG, "onDefaultNetworkChanged: " + network); 3036 3037 // If there is a new default network brought up, cancel the retry task to prevent 3038 // establishing an unnecessary IKE session. 3039 cancelRetryNewIkeSessionFuture(); 3040 3041 // If there is a new default network brought up, cancel the obsolete reset and retry 3042 // task. 3043 cancelHandleNetworkLostTimeout(); 3044 3045 if (!mIsRunning) { 3046 Log.d(TAG, "onDefaultNetworkChanged after exit"); 3047 return; // VPN has been shut down. 3048 } 3049 3050 mActiveNetwork = network; 3051 mRetryCount = 0; 3052 3053 startOrMigrateIkeSession(network); 3054 } 3055 3056 /** 3057 * Start a new IKE session. 3058 * 3059 * <p>This method MUST always be called on the mExecutor thread in order to ensure 3060 * consistency of the Ikev2VpnRunner fields. 3061 * 3062 * @param underlyingNetwork if the value is {@code null}, which means there is no active 3063 * network can be used, do nothing and return immediately. Otherwise, use the 3064 * given network to start a new IKE session. 3065 */ startOrMigrateIkeSession(@ullable Network underlyingNetwork)3066 private void startOrMigrateIkeSession(@Nullable Network underlyingNetwork) { 3067 if (underlyingNetwork == null) { 3068 Log.d(TAG, "There is no active network for starting an IKE session"); 3069 return; 3070 } 3071 3072 try { 3073 if (mSession != null && mMobikeEnabled) { 3074 // IKE session can schedule a migration event only when IKE AUTH is finished 3075 // and mMobikeEnabled is true. 3076 Log.d( 3077 TAG, 3078 "Migrate IKE Session with token " 3079 + mCurrentToken 3080 + " to network " 3081 + underlyingNetwork); 3082 mSession.setNetwork(underlyingNetwork); 3083 return; 3084 } 3085 3086 Log.d(TAG, "Start new IKE session on network " + underlyingNetwork); 3087 3088 // Clear mInterface to prevent Ikev2VpnRunner being cleared when 3089 // interfaceRemoved() is called. 3090 synchronized (Vpn.this) { 3091 // Ignore stale runner. 3092 if (mVpnRunner != this) return; 3093 3094 mInterface = null; 3095 } 3096 // Without MOBIKE, we have no way to seamlessly migrate. Close on old 3097 // (non-default) network, and start the new one. 3098 resetIkeState(); 3099 3100 // Get Ike options from IkeTunnelConnectionParams if it's available in the 3101 // profile. 3102 final IkeTunnelConnectionParams ikeTunConnParams = 3103 mProfile.getIkeTunnelConnectionParams(); 3104 final IkeSessionParams ikeSessionParams; 3105 final ChildSessionParams childSessionParams; 3106 if (ikeTunConnParams != null) { 3107 final IkeSessionParams.Builder builder = new IkeSessionParams.Builder( 3108 ikeTunConnParams.getIkeSessionParams()).setNetwork(underlyingNetwork); 3109 ikeSessionParams = builder.build(); 3110 childSessionParams = ikeTunConnParams.getTunnelModeChildSessionParams(); 3111 } else { 3112 ikeSessionParams = VpnIkev2Utils.buildIkeSessionParams( 3113 mContext, mProfile, underlyingNetwork); 3114 childSessionParams = VpnIkev2Utils.buildChildSessionParams( 3115 mProfile.getAllowedAlgorithms()); 3116 } 3117 3118 // TODO: Remove the need for adding two unused addresses with 3119 // IPsec tunnels. 3120 final InetAddress address = InetAddress.getLocalHost(); 3121 3122 // When onChildOpened is called and transforms are applied, it is 3123 // guaranteed that the underlying network is still "network", because the 3124 // all the network switch events will be deferred before onChildOpened is 3125 // called. Thus it is safe to build a mTunnelIface before IKE setup. 3126 mTunnelIface = 3127 mIpSecManager.createIpSecTunnelInterface( 3128 address /* unused */, address /* unused */, underlyingNetwork); 3129 NetdUtils.setInterfaceUp(mNetd, mTunnelIface.getInterfaceName()); 3130 3131 final int token = ++mCurrentToken; 3132 mSession = 3133 mIkev2SessionCreator.createIkeSession( 3134 mContext, 3135 ikeSessionParams, 3136 childSessionParams, 3137 mExecutor, 3138 new VpnIkev2Utils.IkeSessionCallbackImpl( 3139 TAG, IkeV2VpnRunner.this, token), 3140 new VpnIkev2Utils.ChildSessionCallbackImpl( 3141 TAG, IkeV2VpnRunner.this, token)); 3142 Log.d(TAG, "IKE session started for token " + token); 3143 } catch (Exception e) { 3144 Log.i(TAG, "Setup failed for token " + mCurrentToken + ". Aborting", e); 3145 onSessionLost(mCurrentToken, e); 3146 } 3147 } 3148 scheduleRetryNewIkeSession()3149 private void scheduleRetryNewIkeSession() { 3150 final long retryDelay = mDeps.getNextRetryDelaySeconds(mRetryCount++); 3151 Log.d(TAG, "Retry new IKE session after " + retryDelay + " seconds."); 3152 // If the default network is lost during the retry delay, the mActiveNetwork will be 3153 // null, and the new IKE session won't be established until there is a new default 3154 // network bringing up. 3155 mScheduledHandleRetryIkeSessionFuture = 3156 mExecutor.schedule(() -> { 3157 startOrMigrateIkeSession(mActiveNetwork); 3158 3159 // Reset mScheduledHandleRetryIkeSessionFuture since it's already run on 3160 // executor thread. 3161 mScheduledHandleRetryIkeSessionFuture = null; 3162 }, retryDelay, TimeUnit.SECONDS); 3163 } 3164 3165 /** Called when the NetworkCapabilities of underlying network is changed */ onDefaultNetworkCapabilitiesChanged(@onNull NetworkCapabilities nc)3166 public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) { 3167 mUnderlyingNetworkCapabilities = nc; 3168 } 3169 3170 /** Called when the LinkProperties of underlying network is changed */ onDefaultNetworkLinkPropertiesChanged(@onNull LinkProperties lp)3171 public void onDefaultNetworkLinkPropertiesChanged(@NonNull LinkProperties lp) { 3172 mUnderlyingLinkProperties = lp; 3173 } 3174 3175 /** 3176 * Handles loss of the default underlying network 3177 * 3178 * <p>If the IKE Session has mobility, Ikev2VpnRunner will schedule a teardown event with a 3179 * delay so that the IKE Session can migrate if a new network is available soon. Otherwise, 3180 * Ikev2VpnRunner will kill the IKE session and reset the VPN. 3181 * 3182 * <p>This method MUST always be called on the mExecutor thread in order to ensure 3183 * consistency of the Ikev2VpnRunner fields. 3184 */ onDefaultNetworkLost(@onNull Network network)3185 public void onDefaultNetworkLost(@NonNull Network network) { 3186 // If the default network is torn down, there is no need to call 3187 // startOrMigrateIkeSession() since it will always check if there is an active network 3188 // can be used or not. 3189 cancelRetryNewIkeSessionFuture(); 3190 3191 if (!isActiveNetwork(network)) { 3192 Log.d(TAG, "onDefaultNetworkLost called for obsolete network " + network); 3193 3194 // Do nothing; this signals that either: (1) a new/better Network was found, 3195 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in 3196 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited, 3197 // or an error was encountered somewhere else). In both cases, all resources and 3198 // sessions are torn down via resetIkeState(). 3199 return; 3200 } else { 3201 mActiveNetwork = null; 3202 } 3203 3204 if (mScheduledHandleNetworkLostFuture != null) { 3205 final IllegalStateException exception = 3206 new IllegalStateException( 3207 "Found a pending mScheduledHandleNetworkLostFuture"); 3208 Log.i( 3209 TAG, 3210 "Unexpected error in onDefaultNetworkLost. Tear down session", 3211 exception); 3212 handleSessionLost(exception, network); 3213 return; 3214 } 3215 3216 if (mSession != null && mMobikeEnabled) { 3217 Log.d( 3218 TAG, 3219 "IKE Session has mobility. Delay handleSessionLost for losing network " 3220 + network 3221 + " on session with token " 3222 + mCurrentToken); 3223 3224 final int token = mCurrentToken; 3225 // Delay the teardown in case a new network will be available soon. For example, 3226 // during handover between two WiFi networks, Android will disconnect from the 3227 // first WiFi and then connects to the second WiFi. 3228 mScheduledHandleNetworkLostFuture = 3229 mExecutor.schedule( 3230 () -> { 3231 if (isActiveToken(token)) { 3232 handleSessionLost(null /* exception */, network); 3233 } else { 3234 Log.d( 3235 TAG, 3236 "Scheduled handleSessionLost fired for " 3237 + "obsolete token " 3238 + token); 3239 } 3240 3241 // Reset mScheduledHandleNetworkLostFuture since it's 3242 // already run on executor thread. 3243 mScheduledHandleNetworkLostFuture = null; 3244 }, 3245 NETWORK_LOST_TIMEOUT_MS, 3246 TimeUnit.MILLISECONDS); 3247 } else { 3248 Log.d(TAG, "Call handleSessionLost for losing network " + network); 3249 handleSessionLost(null /* exception */, network); 3250 } 3251 } 3252 cancelHandleNetworkLostTimeout()3253 private void cancelHandleNetworkLostTimeout() { 3254 if (mScheduledHandleNetworkLostFuture != null) { 3255 // It does not matter what to put in #cancel(boolean), because it is impossible 3256 // that the task tracked by mScheduledHandleNetworkLostFuture is 3257 // in-progress since both that task and onDefaultNetworkChanged are submitted to 3258 // mExecutor who has only one thread. 3259 Log.d(TAG, "Cancel the task for handling network lost timeout"); 3260 mScheduledHandleNetworkLostFuture.cancel(false /* mayInterruptIfRunning */); 3261 mScheduledHandleNetworkLostFuture = null; 3262 } 3263 } 3264 cancelRetryNewIkeSessionFuture()3265 private void cancelRetryNewIkeSessionFuture() { 3266 if (mScheduledHandleRetryIkeSessionFuture != null) { 3267 // It does not matter what to put in #cancel(boolean), because it is impossible 3268 // that the task tracked by mScheduledHandleRetryIkeSessionFuture is 3269 // in-progress since both that task and onDefaultNetworkChanged are submitted to 3270 // mExecutor who has only one thread. 3271 Log.d(TAG, "Cancel the task for handling new ike session timeout"); 3272 mScheduledHandleRetryIkeSessionFuture.cancel(false /* mayInterruptIfRunning */); 3273 mScheduledHandleRetryIkeSessionFuture = null; 3274 } 3275 } 3276 3277 /** Marks the state as FAILED, and disconnects. */ markFailedAndDisconnect(Exception exception)3278 private void markFailedAndDisconnect(Exception exception) { 3279 synchronized (Vpn.this) { 3280 // Ignore stale runner. 3281 if (mVpnRunner != this) return; 3282 3283 updateState(DetailedState.FAILED, exception.getMessage()); 3284 } 3285 3286 disconnectVpnRunner(); 3287 } 3288 3289 /** 3290 * Handles loss of a session 3291 * 3292 * <p>The loss of a session might be due to an onLost() call, the IKE session getting torn 3293 * down for any reason, or an error in updating state (transform application, VPN setup) 3294 * 3295 * <p>This method MUST always be called on the mExecutor thread in order to ensure 3296 * consistency of the Ikev2VpnRunner fields. 3297 */ onSessionLost(int token, @Nullable Exception exception)3298 public void onSessionLost(int token, @Nullable Exception exception) { 3299 Log.d(TAG, "onSessionLost() called for token " + token); 3300 3301 if (!isActiveToken(token)) { 3302 Log.d(TAG, "onSessionLost() called for obsolete token " + token); 3303 3304 // Do nothing; this signals that either: (1) a new/better Network was found, 3305 // and the Ikev2VpnRunner has switched to it by restarting a new IKE session in 3306 // onDefaultNetworkChanged, or (2) this IKE session was already shut down (exited, 3307 // or an error was encountered somewhere else). In both cases, all resources and 3308 // sessions are torn down via resetIkeState(). 3309 return; 3310 } 3311 3312 handleSessionLost(exception, mActiveNetwork); 3313 } 3314 handleSessionLost(@ullable Exception exception, @Nullable Network network)3315 private void handleSessionLost(@Nullable Exception exception, @Nullable Network network) { 3316 // Cancel mScheduledHandleNetworkLostFuture if the session it is going to terminate is 3317 // already terminated due to other failures. 3318 cancelHandleNetworkLostTimeout(); 3319 3320 String category = null; 3321 int errorClass = -1; 3322 int errorCode = -1; 3323 if (exception instanceof IllegalArgumentException) { 3324 // Failed to build IKE/ChildSessionParams; fatal profile configuration error 3325 markFailedAndDisconnect(exception); 3326 return; 3327 } 3328 3329 if (exception instanceof IkeProtocolException) { 3330 final IkeProtocolException ikeException = (IkeProtocolException) exception; 3331 category = VpnManager.CATEGORY_EVENT_IKE_ERROR; 3332 errorCode = ikeException.getErrorType(); 3333 3334 switch (ikeException.getErrorType()) { 3335 case IkeProtocolException.ERROR_TYPE_NO_PROPOSAL_CHOSEN: // Fallthrough 3336 case IkeProtocolException.ERROR_TYPE_INVALID_KE_PAYLOAD: // Fallthrough 3337 case IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED: // Fallthrough 3338 case IkeProtocolException.ERROR_TYPE_SINGLE_PAIR_REQUIRED: // Fallthrough 3339 case IkeProtocolException.ERROR_TYPE_FAILED_CP_REQUIRED: // Fallthrough 3340 case IkeProtocolException.ERROR_TYPE_TS_UNACCEPTABLE: 3341 // All the above failures are configuration errors, and are terminal 3342 errorClass = VpnManager.ERROR_CLASS_NOT_RECOVERABLE; 3343 break; 3344 // All other cases possibly recoverable. 3345 default: 3346 errorClass = VpnManager.ERROR_CLASS_RECOVERABLE; 3347 } 3348 } else if (exception instanceof IkeNetworkLostException) { 3349 category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR; 3350 errorClass = VpnManager.ERROR_CLASS_RECOVERABLE; 3351 errorCode = VpnManager.ERROR_CODE_NETWORK_LOST; 3352 } else if (exception instanceof IkeNonProtocolException) { 3353 category = VpnManager.CATEGORY_EVENT_NETWORK_ERROR; 3354 errorClass = VpnManager.ERROR_CLASS_RECOVERABLE; 3355 if (exception.getCause() instanceof UnknownHostException) { 3356 errorCode = VpnManager.ERROR_CODE_NETWORK_UNKNOWN_HOST; 3357 } else if (exception.getCause() instanceof IkeTimeoutException) { 3358 errorCode = VpnManager.ERROR_CODE_NETWORK_PROTOCOL_TIMEOUT; 3359 } else if (exception.getCause() instanceof IOException) { 3360 errorCode = VpnManager.ERROR_CODE_NETWORK_IO; 3361 } 3362 } else if (exception != null) { 3363 Log.wtf(TAG, "onSessionLost: exception = " + exception); 3364 } 3365 3366 synchronized (Vpn.this) { 3367 // Ignore stale runner. 3368 if (mVpnRunner != this) return; 3369 3370 // TODO(b/230548427): Remove SDK check once VPN related stuff are 3371 // decoupled from ConnectivityServiceTest. 3372 if (SdkLevel.isAtLeastT() && category != null && isVpnApp(mPackage)) { 3373 sendEventToVpnManagerApp(category, errorClass, errorCode, 3374 getPackage(), mSessionKey, makeVpnProfileStateLocked(), 3375 mActiveNetwork, 3376 getRedactedNetworkCapabilities(mUnderlyingNetworkCapabilities), 3377 getRedactedLinkProperties(mUnderlyingLinkProperties)); 3378 } 3379 } 3380 3381 if (errorClass == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) { 3382 markFailedAndDisconnect(exception); 3383 return; 3384 } else { 3385 scheduleRetryNewIkeSession(); 3386 } 3387 3388 mUnderlyingNetworkCapabilities = null; 3389 mUnderlyingLinkProperties = null; 3390 3391 // Close all obsolete state, but keep VPN alive incase a usable network comes up. 3392 // (Mirrors VpnService behavior) 3393 Log.d(TAG, "Resetting state for token: " + mCurrentToken); 3394 3395 synchronized (Vpn.this) { 3396 // Ignore stale runner. 3397 if (mVpnRunner != this) return; 3398 3399 // Since this method handles non-fatal errors only, set mInterface to null to 3400 // prevent the NetworkManagementEventObserver from killing this VPN based on the 3401 // interface going down (which we expect). 3402 mInterface = null; 3403 if (mConfig != null) { 3404 mConfig.interfaze = null; 3405 3406 // Set as unroutable to prevent traffic leaking while the interface is down. 3407 if (mConfig.routes != null) { 3408 final List<RouteInfo> oldRoutes = new ArrayList<>(mConfig.routes); 3409 3410 mConfig.routes.clear(); 3411 for (final RouteInfo route : oldRoutes) { 3412 mConfig.routes.add(new RouteInfo(route.getDestination(), 3413 null /*gateway*/, null /*iface*/, RTN_UNREACHABLE)); 3414 } 3415 if (mNetworkAgent != null) { 3416 doSendLinkProperties(mNetworkAgent, makeLinkProperties()); 3417 } 3418 } 3419 } 3420 } 3421 3422 resetIkeState(); 3423 } 3424 3425 /** 3426 * Cleans up all IKE state 3427 * 3428 * <p>This method MUST always be called on the mExecutor thread in order to ensure 3429 * consistency of the Ikev2VpnRunner fields. 3430 */ resetIkeState()3431 private void resetIkeState() { 3432 if (mTunnelIface != null) { 3433 // No need to call setInterfaceDown(); the IpSecInterface is being fully torn down. 3434 mTunnelIface.close(); 3435 mTunnelIface = null; 3436 } 3437 if (mSession != null) { 3438 mSession.kill(); // Kill here to make sure all resources are released immediately 3439 mSession = null; 3440 } 3441 mIkeConnectionInfo = null; 3442 mMobikeEnabled = false; 3443 } 3444 3445 /** 3446 * Disconnects and shuts down this VPN. 3447 * 3448 * <p>This method resets all internal Ikev2VpnRunner state, but unless called via 3449 * VpnRunner#exit(), this Ikev2VpnRunner will still be listed as the active VPN of record 3450 * until the next VPN is started, or the Ikev2VpnRunner is explicitly exited. This is 3451 * necessary to ensure that the detailed state is shown in the Settings VPN menus; if the 3452 * active VPN is cleared, Settings VPNs will not show the resultant state or errors. 3453 * 3454 * <p>This method MUST always be called on the mExecutor thread in order to ensure 3455 * consistency of the Ikev2VpnRunner fields. 3456 */ disconnectVpnRunner()3457 private void disconnectVpnRunner() { 3458 mActiveNetwork = null; 3459 mUnderlyingNetworkCapabilities = null; 3460 mUnderlyingLinkProperties = null; 3461 mIsRunning = false; 3462 3463 resetIkeState(); 3464 3465 mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); 3466 3467 mExecutor.shutdown(); 3468 } 3469 3470 @Override exitVpnRunner()3471 public void exitVpnRunner() { 3472 try { 3473 mExecutor.execute(() -> { 3474 disconnectVpnRunner(); 3475 }); 3476 } catch (RejectedExecutionException ignored) { 3477 // The Ikev2VpnRunner has already shut down. 3478 } 3479 } 3480 } 3481 3482 /** 3483 * Bringing up a VPN connection takes time, and that is all this thread 3484 * does. Here we have plenty of time. The only thing we need to take 3485 * care of is responding to interruptions as soon as possible. Otherwise 3486 * requests will pile up. This could be done in a Handler as a state 3487 * machine, but it is much easier to read in the current form. 3488 */ 3489 private class LegacyVpnRunner extends VpnRunner { 3490 private static final String TAG = "LegacyVpnRunner"; 3491 3492 private final String[] mDaemons; 3493 private final String[][] mArguments; 3494 private final LocalSocket[] mSockets; 3495 private final String mOuterInterface; 3496 private final AtomicInteger mOuterConnection = 3497 new AtomicInteger(ConnectivityManager.TYPE_NONE); 3498 private final VpnProfile mProfile; 3499 3500 private long mBringupStartTime = -1; 3501 3502 /** 3503 * Watch for the outer connection (passing in the constructor) going away. 3504 */ 3505 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { 3506 @Override 3507 public void onReceive(Context context, Intent intent) { 3508 if (!mEnableTeardown) return; 3509 3510 if (intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) { 3511 if (intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, 3512 ConnectivityManager.TYPE_NONE) == mOuterConnection.get()) { 3513 NetworkInfo info = (NetworkInfo)intent.getExtra( 3514 ConnectivityManager.EXTRA_NETWORK_INFO); 3515 if (info != null && !info.isConnectedOrConnecting()) { 3516 try { 3517 mObserver.interfaceStatusChanged(mOuterInterface, false); 3518 } catch (RemoteException e) {} 3519 } 3520 } 3521 } 3522 } 3523 }; 3524 LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd, VpnProfile profile)3525 LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd, VpnProfile profile) { 3526 super(TAG); 3527 if (racoon == null && mtpd == null) { 3528 throw new IllegalArgumentException( 3529 "Arguments to racoon and mtpd must not both be null"); 3530 } 3531 mConfig = config; 3532 mDaemons = new String[] {"racoon", "mtpd"}; 3533 // TODO: clear arguments from memory once launched 3534 mArguments = new String[][] {racoon, mtpd}; 3535 mSockets = new LocalSocket[mDaemons.length]; 3536 3537 // This is the interface which VPN is running on, 3538 // mConfig.interfaze will change to point to OUR 3539 // internal interface soon. TODO - add inner/outer to mconfig 3540 // TODO - we have a race - if the outer iface goes away/disconnects before we hit this 3541 // we will leave the VPN up. We should check that it's still there/connected after 3542 // registering 3543 mOuterInterface = mConfig.interfaze; 3544 3545 mProfile = profile; 3546 3547 if (!TextUtils.isEmpty(mOuterInterface)) { 3548 for (Network network : mConnectivityManager.getAllNetworks()) { 3549 final LinkProperties lp = mConnectivityManager.getLinkProperties(network); 3550 if (lp != null && lp.getAllInterfaceNames().contains(mOuterInterface)) { 3551 final NetworkInfo netInfo = mConnectivityManager.getNetworkInfo(network); 3552 if (netInfo != null) { 3553 mOuterConnection.set(netInfo.getType()); 3554 break; 3555 } 3556 } 3557 } 3558 } 3559 3560 IntentFilter filter = new IntentFilter(); 3561 filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); 3562 mContext.registerReceiver(mBroadcastReceiver, filter); 3563 } 3564 3565 /** 3566 * Checks if the parameter matches the underlying interface 3567 * 3568 * <p>If the underlying interface is torn down, the LegacyVpnRunner also should be. It has 3569 * no ability to migrate between interfaces (or Networks). 3570 */ exitIfOuterInterfaceIs(String interfaze)3571 public void exitIfOuterInterfaceIs(String interfaze) { 3572 if (interfaze.equals(mOuterInterface)) { 3573 Log.i(TAG, "Legacy VPN is going down with " + interfaze); 3574 exitVpnRunner(); 3575 } 3576 } 3577 3578 /** Tears down this LegacyVpn connection */ 3579 @Override exitVpnRunner()3580 public void exitVpnRunner() { 3581 // We assume that everything is reset after stopping the daemons. 3582 interrupt(); 3583 3584 // Always disconnect. This may be called again in cleanupVpnStateLocked() if 3585 // exitVpnRunner() was called from exit(), but it will be a no-op. 3586 agentDisconnect(); 3587 try { 3588 mContext.unregisterReceiver(mBroadcastReceiver); 3589 } catch (IllegalArgumentException e) {} 3590 } 3591 3592 @Override run()3593 public void run() { 3594 // Wait for the previous thread since it has been interrupted. 3595 Log.v(TAG, "Waiting"); 3596 synchronized (TAG) { 3597 Log.v(TAG, "Executing"); 3598 try { 3599 bringup(); 3600 waitForDaemonsToStop(); 3601 interrupted(); // Clear interrupt flag if execute called exit. 3602 } catch (InterruptedException e) { 3603 } finally { 3604 for (LocalSocket socket : mSockets) { 3605 IoUtils.closeQuietly(socket); 3606 } 3607 // This sleep is necessary for racoon to successfully complete sending delete 3608 // message to server. 3609 try { 3610 Thread.sleep(50); 3611 } catch (InterruptedException e) { 3612 } 3613 for (String daemon : mDaemons) { 3614 mDeps.stopService(daemon); 3615 } 3616 } 3617 agentDisconnect(); 3618 } 3619 } 3620 checkInterruptAndDelay(boolean sleepLonger)3621 private void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException { 3622 long now = SystemClock.elapsedRealtime(); 3623 if (now - mBringupStartTime <= 60000) { 3624 Thread.sleep(sleepLonger ? 200 : 1); 3625 } else { 3626 updateState(DetailedState.FAILED, "checkpoint"); 3627 throw new IllegalStateException("VPN bringup took too long"); 3628 } 3629 } 3630 checkAndFixupArguments(@onNull final InetAddress endpointAddress)3631 private void checkAndFixupArguments(@NonNull final InetAddress endpointAddress) { 3632 final String endpointAddressString = endpointAddress.getHostAddress(); 3633 // Perform some safety checks before inserting the address in place. 3634 // Position 0 in mDaemons and mArguments must be racoon, and position 1 must be mtpd. 3635 if (!"racoon".equals(mDaemons[0]) || !"mtpd".equals(mDaemons[1])) { 3636 throw new IllegalStateException("Unexpected daemons order"); 3637 } 3638 3639 // Respectively, the positions at which racoon and mtpd take the server address 3640 // argument are 1 and 2. Not all types of VPN require both daemons however, and 3641 // in that case the corresponding argument array is null. 3642 if (mArguments[0] != null) { 3643 if (!mProfile.server.equals(mArguments[0][1])) { 3644 throw new IllegalStateException("Invalid server argument for racoon"); 3645 } 3646 mArguments[0][1] = endpointAddressString; 3647 } 3648 3649 if (mArguments[1] != null) { 3650 if (!mProfile.server.equals(mArguments[1][2])) { 3651 throw new IllegalStateException("Invalid server argument for mtpd"); 3652 } 3653 mArguments[1][2] = endpointAddressString; 3654 } 3655 } 3656 bringup()3657 private void bringup() { 3658 // Catch all exceptions so we can clean up a few things. 3659 try { 3660 // resolve never returns null. If it does because of some bug, it will be 3661 // caught by the catch() block below and cleanup gracefully. 3662 final InetAddress endpointAddress = mDeps.resolve(mProfile.server); 3663 3664 // Big hack : dynamically replace the address of the server in the arguments 3665 // with the resolved address. 3666 checkAndFixupArguments(endpointAddress); 3667 3668 // Initialize the timer. 3669 mBringupStartTime = SystemClock.elapsedRealtime(); 3670 3671 // Wait for the daemons to stop. 3672 for (String daemon : mDaemons) { 3673 while (!mDeps.isServiceStopped(daemon)) { 3674 checkInterruptAndDelay(true); 3675 } 3676 } 3677 3678 // Clear the previous state. 3679 final File state = mDeps.getStateFile(); 3680 state.delete(); 3681 if (state.exists()) { 3682 throw new IllegalStateException("Cannot delete the state"); 3683 } 3684 new File("/data/misc/vpn/abort").delete(); 3685 3686 updateState(DetailedState.CONNECTING, "execute"); 3687 3688 // Start the daemon with arguments. 3689 for (int i = 0; i < mDaemons.length; ++i) { 3690 String[] arguments = mArguments[i]; 3691 if (arguments == null) { 3692 continue; 3693 } 3694 3695 // Start the daemon. 3696 String daemon = mDaemons[i]; 3697 mDeps.startService(daemon); 3698 3699 // Wait for the daemon to start. 3700 while (!mDeps.isServiceRunning(daemon)) { 3701 checkInterruptAndDelay(true); 3702 } 3703 3704 // Create the control socket. 3705 mSockets[i] = new LocalSocket(); 3706 3707 // Wait for the socket to connect and send over the arguments. 3708 mDeps.sendArgumentsToDaemon(daemon, mSockets[i], arguments, 3709 this::checkInterruptAndDelay); 3710 } 3711 3712 // Wait for the daemons to create the new state. 3713 while (!state.exists()) { 3714 // Check if a running daemon is dead. 3715 for (int i = 0; i < mDaemons.length; ++i) { 3716 String daemon = mDaemons[i]; 3717 if (mArguments[i] != null && !mDeps.isServiceRunning(daemon)) { 3718 throw new IllegalStateException(daemon + " is dead"); 3719 } 3720 } 3721 checkInterruptAndDelay(true); 3722 } 3723 3724 // Now we are connected. Read and parse the new state. 3725 String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); 3726 if (parameters.length != 7) { 3727 throw new IllegalStateException("Cannot parse the state: '" 3728 + String.join("', '", parameters) + "'"); 3729 } 3730 3731 // Set the interface and the addresses in the config. 3732 mConfig.interfaze = parameters[0].trim(); 3733 3734 mConfig.addLegacyAddresses(parameters[1]); 3735 // Set the routes if they are not set in the config. 3736 if (mConfig.routes == null || mConfig.routes.isEmpty()) { 3737 mConfig.addLegacyRoutes(parameters[2]); 3738 } 3739 3740 // Set the DNS servers if they are not set in the config. 3741 if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) { 3742 String dnsServers = parameters[3].trim(); 3743 if (!dnsServers.isEmpty()) { 3744 mConfig.dnsServers = Arrays.asList(dnsServers.split(" ")); 3745 } 3746 } 3747 3748 // Set the search domains if they are not set in the config. 3749 if (mConfig.searchDomains == null || mConfig.searchDomains.size() == 0) { 3750 String searchDomains = parameters[4].trim(); 3751 if (!searchDomains.isEmpty()) { 3752 mConfig.searchDomains = Arrays.asList(searchDomains.split(" ")); 3753 } 3754 } 3755 3756 // Add a throw route for the VPN server endpoint, if one was specified. 3757 if (endpointAddress instanceof Inet4Address) { 3758 mConfig.routes.add(new RouteInfo( 3759 new IpPrefix(endpointAddress, 32), null /*gateway*/, 3760 null /*iface*/, RTN_THROW)); 3761 } else if (endpointAddress instanceof Inet6Address) { 3762 mConfig.routes.add(new RouteInfo( 3763 new IpPrefix(endpointAddress, 128), null /*gateway*/, 3764 null /*iface*/, RTN_THROW)); 3765 } else { 3766 Log.e(TAG, "Unknown IP address family for VPN endpoint: " 3767 + endpointAddress); 3768 } 3769 3770 // Here is the last step and it must be done synchronously. 3771 synchronized (Vpn.this) { 3772 // Set the start time 3773 mConfig.startTime = SystemClock.elapsedRealtime(); 3774 3775 // Check if the thread was interrupted while we were waiting on the lock. 3776 checkInterruptAndDelay(false); 3777 3778 // Check if the interface is gone while we are waiting. 3779 if (!mDeps.isInterfacePresent(Vpn.this, mConfig.interfaze)) { 3780 throw new IllegalStateException(mConfig.interfaze + " is gone"); 3781 } 3782 3783 // Now INetworkManagementEventObserver is watching our back. 3784 mInterface = mConfig.interfaze; 3785 prepareStatusIntent(); 3786 3787 agentConnect(); 3788 3789 Log.i(TAG, "Connected!"); 3790 } 3791 } catch (Exception e) { 3792 Log.i(TAG, "Aborting", e); 3793 updateState(DetailedState.FAILED, e.getMessage()); 3794 exitVpnRunner(); 3795 } 3796 } 3797 3798 /** 3799 * Check all daemons every two seconds. Return when one of them is stopped. 3800 * The caller will move to the disconnected state when this function returns, 3801 * which can happen if a daemon failed or if the VPN was torn down. 3802 */ waitForDaemonsToStop()3803 private void waitForDaemonsToStop() throws InterruptedException { 3804 if (!mNetworkInfo.isConnected()) { 3805 return; 3806 } 3807 while (true) { 3808 Thread.sleep(2000); 3809 for (int i = 0; i < mDaemons.length; i++) { 3810 if (mArguments[i] != null && mDeps.isServiceStopped(mDaemons[i])) { 3811 return; 3812 } 3813 } 3814 } 3815 } 3816 } 3817 verifyCallingUidAndPackage(String packageName)3818 private void verifyCallingUidAndPackage(String packageName) { 3819 final int callingUid = Binder.getCallingUid(); 3820 if (getAppUid(packageName, mUserId) != callingUid) { 3821 throw new SecurityException(packageName + " does not belong to uid " + callingUid); 3822 } 3823 } 3824 3825 @VisibleForTesting getProfileNameForPackage(String packageName)3826 String getProfileNameForPackage(String packageName) { 3827 return Credentials.PLATFORM_VPN + mUserId + "_" + packageName; 3828 } 3829 3830 @VisibleForTesting validateRequiredFeatures(VpnProfile profile)3831 void validateRequiredFeatures(VpnProfile profile) { 3832 switch (profile.type) { 3833 case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: 3834 case VpnProfile.TYPE_IKEV2_IPSEC_PSK: 3835 case VpnProfile.TYPE_IKEV2_IPSEC_RSA: 3836 case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: 3837 if (!mContext.getPackageManager().hasSystemFeature( 3838 PackageManager.FEATURE_IPSEC_TUNNELS)) { 3839 throw new UnsupportedOperationException( 3840 "Ikev2VpnProfile(s) requires PackageManager.FEATURE_IPSEC_TUNNELS"); 3841 } 3842 break; 3843 default: 3844 return; 3845 } 3846 } 3847 3848 /** 3849 * Stores an app-provisioned VPN profile and returns whether the app is already prepared. 3850 * 3851 * @param packageName the package name of the app provisioning this profile 3852 * @param profile the profile to be stored and provisioned 3853 * @returns whether or not the app has already been granted user consent 3854 */ provisionVpnProfile( @onNull String packageName, @NonNull VpnProfile profile)3855 public synchronized boolean provisionVpnProfile( 3856 @NonNull String packageName, @NonNull VpnProfile profile) { 3857 requireNonNull(packageName, "No package name provided"); 3858 requireNonNull(profile, "No profile provided"); 3859 3860 verifyCallingUidAndPackage(packageName); 3861 enforceNotRestrictedUser(); 3862 validateRequiredFeatures(profile); 3863 3864 if (profile.isRestrictedToTestNetworks) { 3865 mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS, 3866 "Test-mode profiles require the MANAGE_TEST_NETWORKS permission"); 3867 } 3868 3869 final byte[] encodedProfile = profile.encode(); 3870 if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) { 3871 throw new IllegalArgumentException("Profile too big"); 3872 } 3873 3874 // Permissions checked during startVpnProfile() 3875 final long token = Binder.clearCallingIdentity(); 3876 try { 3877 getVpnProfileStore().put(getProfileNameForPackage(packageName), encodedProfile); 3878 } finally { 3879 Binder.restoreCallingIdentity(token); 3880 } 3881 3882 // TODO: if package has CONTROL_VPN, grant the ACTIVATE_PLATFORM_VPN appop. 3883 // This mirrors the prepareAndAuthorize that is used by VpnService. 3884 3885 // Return whether the app is already pre-consented 3886 return isVpnProfilePreConsented(mContext, packageName); 3887 } 3888 isCurrentIkev2VpnLocked(@onNull String packageName)3889 private boolean isCurrentIkev2VpnLocked(@NonNull String packageName) { 3890 return isCurrentPreparedPackage(packageName) && isIkev2VpnRunner(); 3891 } 3892 3893 /** 3894 * Deletes an app-provisioned VPN profile. 3895 * 3896 * @param packageName the package name of the app provisioning this profile 3897 */ deleteVpnProfile( @onNull String packageName)3898 public synchronized void deleteVpnProfile( 3899 @NonNull String packageName) { 3900 requireNonNull(packageName, "No package name provided"); 3901 3902 verifyCallingUidAndPackage(packageName); 3903 enforceNotRestrictedUser(); 3904 3905 final long token = Binder.clearCallingIdentity(); 3906 try { 3907 // If this profile is providing the current VPN, turn it off, disabling 3908 // always-on as well if enabled. 3909 if (isCurrentIkev2VpnLocked(packageName)) { 3910 if (mAlwaysOn) { 3911 // Will transitively call prepareInternal(VpnConfig.LEGACY_VPN). 3912 setAlwaysOnPackage(null, false, null); 3913 } else { 3914 prepareInternal(VpnConfig.LEGACY_VPN); 3915 } 3916 } 3917 3918 getVpnProfileStore().remove(getProfileNameForPackage(packageName)); 3919 } finally { 3920 Binder.restoreCallingIdentity(token); 3921 } 3922 } 3923 3924 /** 3925 * Retrieves the VpnProfile. 3926 * 3927 * <p>Must be used only as SYSTEM_UID, otherwise the key/UID pair will not match anything in the 3928 * keystore. 3929 */ 3930 @VisibleForTesting 3931 @Nullable getVpnProfilePrivileged(@onNull String packageName)3932 VpnProfile getVpnProfilePrivileged(@NonNull String packageName) { 3933 if (!mDeps.isCallerSystem()) { 3934 Log.wtf(TAG, "getVpnProfilePrivileged called as non-System UID "); 3935 return null; 3936 } 3937 3938 final byte[] encoded = getVpnProfileStore().get(getProfileNameForPackage(packageName)); 3939 if (encoded == null) return null; 3940 3941 return VpnProfile.decode("" /* Key unused */, encoded); 3942 } 3943 isIkev2VpnRunner()3944 private boolean isIkev2VpnRunner() { 3945 return (mVpnRunner instanceof IkeV2VpnRunner); 3946 } 3947 3948 @GuardedBy("this") 3949 @Nullable getSessionKeyLocked()3950 private String getSessionKeyLocked() { 3951 return isIkev2VpnRunner() ? ((IkeV2VpnRunner) mVpnRunner).mSessionKey : null; 3952 } 3953 3954 /** 3955 * Starts an already provisioned VPN Profile, keyed by package name. 3956 * 3957 * <p>This method is meant to be called by apps (via VpnManager and ConnectivityService). 3958 * Privileged (system) callers should use startVpnProfilePrivileged instead. Otherwise the UIDs 3959 * will not match during appop checks. 3960 * 3961 * @param packageName the package name of the app provisioning this profile 3962 */ startVpnProfile(@onNull String packageName)3963 public synchronized String startVpnProfile(@NonNull String packageName) { 3964 requireNonNull(packageName, "No package name provided"); 3965 3966 enforceNotRestrictedUser(); 3967 3968 // Prepare VPN for startup 3969 if (!prepare(packageName, null /* newPackage */, VpnManager.TYPE_VPN_PLATFORM)) { 3970 throw new SecurityException("User consent not granted for package " + packageName); 3971 } 3972 3973 final long token = Binder.clearCallingIdentity(); 3974 try { 3975 final VpnProfile profile = getVpnProfilePrivileged(packageName); 3976 if (profile == null) { 3977 throw new IllegalArgumentException("No profile found for " + packageName); 3978 } 3979 3980 startVpnProfilePrivileged(profile, packageName); 3981 if (!isIkev2VpnRunner()) { 3982 throw new IllegalStateException("mVpnRunner shouldn't be null and should also be " 3983 + "an instance of Ikev2VpnRunner"); 3984 } 3985 return getSessionKeyLocked(); 3986 } finally { 3987 Binder.restoreCallingIdentity(token); 3988 } 3989 } 3990 startVpnProfilePrivileged( @onNull VpnProfile profile, @NonNull String packageName)3991 private synchronized void startVpnProfilePrivileged( 3992 @NonNull VpnProfile profile, @NonNull String packageName) { 3993 // Make sure VPN is prepared. This method can be called by user apps via startVpnProfile(), 3994 // by the Setting app via startLegacyVpn(), or by ConnectivityService via 3995 // startAlwaysOnVpn(), so this is the common place to prepare the VPN. This also has the 3996 // nice property of ensuring there are no other VpnRunner instances running. 3997 prepareInternal(packageName); 3998 updateState(DetailedState.CONNECTING, "startPlatformVpn"); 3999 4000 try { 4001 // Build basic config 4002 mConfig = new VpnConfig(); 4003 if (VpnConfig.LEGACY_VPN.equals(packageName)) { 4004 mConfig.legacy = true; 4005 mConfig.session = profile.name; 4006 mConfig.user = profile.key; 4007 4008 // TODO: Add support for configuring meteredness via Settings. Until then, use a 4009 // safe default. 4010 mConfig.isMetered = true; 4011 } else { 4012 mConfig.user = packageName; 4013 mConfig.isMetered = profile.isMetered; 4014 } 4015 mConfig.startTime = SystemClock.elapsedRealtime(); 4016 mConfig.proxyInfo = profile.proxy; 4017 mConfig.requiresInternetValidation = profile.requiresInternetValidation; 4018 mConfig.excludeLocalRoutes = profile.excludeLocalRoutes; 4019 mConfig.allowBypass = profile.isBypassable; 4020 4021 switch (profile.type) { 4022 case VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS: 4023 case VpnProfile.TYPE_IKEV2_IPSEC_PSK: 4024 case VpnProfile.TYPE_IKEV2_IPSEC_RSA: 4025 case VpnProfile.TYPE_IKEV2_FROM_IKE_TUN_CONN_PARAMS: 4026 mVpnRunner = 4027 new IkeV2VpnRunner( 4028 Ikev2VpnProfile.fromVpnProfile(profile), 4029 mDeps.newScheduledThreadPoolExecutor()); 4030 mVpnRunner.start(); 4031 break; 4032 default: 4033 updateState(DetailedState.FAILED, "Invalid platform VPN type"); 4034 Log.d(TAG, "Unknown VPN profile type: " + profile.type); 4035 break; 4036 } 4037 4038 // Record that the VPN connection is established by an app which uses VpnManager API. 4039 if (!VpnConfig.LEGACY_VPN.equals(packageName)) { 4040 mAppOpsManager.startOp( 4041 AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, mOwnerUID, mPackage, null, 4042 null); 4043 } 4044 } catch (GeneralSecurityException e) { 4045 // Reset mConfig 4046 mConfig = null; 4047 4048 updateState(DetailedState.FAILED, "VPN startup failed"); 4049 throw new IllegalArgumentException("VPN startup failed", e); 4050 } 4051 } 4052 4053 @GuardedBy("this") stopVpnRunnerAndNotifyAppLocked(@onNull String packageName)4054 private void stopVpnRunnerAndNotifyAppLocked(@NonNull String packageName) { 4055 // Build intent first because the sessionKey will be reset after performing 4056 // VpnRunner.exit(). Also, cache mOwnerUID even if ownerUID will not be changed in 4057 // VpnRunner.exit() to prevent design being changed in the future. 4058 // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from 4059 // ConnectivityServiceTest. 4060 final int ownerUid = mOwnerUID; 4061 Intent intent = null; 4062 if (SdkLevel.isAtLeastT() && isVpnApp(packageName)) { 4063 intent = buildVpnManagerEventIntent( 4064 VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER, 4065 -1 /* errorClass */, -1 /* errorCode*/, packageName, 4066 getSessionKeyLocked(), makeVpnProfileStateLocked(), 4067 null /* underlyingNetwork */, null /* nc */, null /* lp */); 4068 } 4069 // cleanupVpnStateLocked() is called from mVpnRunner.exit() 4070 mVpnRunner.exit(); 4071 if (intent != null && isVpnApp(packageName)) { 4072 notifyVpnManagerVpnStopped(packageName, ownerUid, intent); 4073 } 4074 } 4075 4076 /** 4077 * Stops an already running VPN Profile for the given package. 4078 * 4079 * <p>This method is meant to be called by apps (via VpnManager and ConnectivityService). 4080 * Privileged (system) callers should (re-)prepare the LEGACY_VPN instead. 4081 * 4082 * @param packageName the package name of the app provisioning this profile 4083 */ stopVpnProfile(@onNull String packageName)4084 public synchronized void stopVpnProfile(@NonNull String packageName) { 4085 requireNonNull(packageName, "No package name provided"); 4086 4087 enforceNotRestrictedUser(); 4088 4089 // To stop the VPN profile, the caller must be the current prepared package and must be 4090 // running an Ikev2VpnProfile. 4091 if (isCurrentIkev2VpnLocked(packageName)) { 4092 stopVpnRunnerAndNotifyAppLocked(packageName); 4093 } 4094 } 4095 notifyVpnManagerVpnStopped(String packageName, int ownerUID, Intent intent)4096 private synchronized void notifyVpnManagerVpnStopped(String packageName, int ownerUID, 4097 Intent intent) { 4098 mAppOpsManager.finishOp( 4099 AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, ownerUID, packageName, null); 4100 // The underlying network, NetworkCapabilities and LinkProperties are not 4101 // necessary to send to VPN app since the purpose of this event is to notify 4102 // VPN app that VPN is deactivated by the user. 4103 // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from 4104 // ConnectivityServiceTest. 4105 if (SdkLevel.isAtLeastT()) { 4106 sendEventToVpnManagerApp(intent, packageName); 4107 } 4108 } 4109 storeAppExclusionList(@onNull String packageName, @NonNull List<String> excludedApps)4110 private boolean storeAppExclusionList(@NonNull String packageName, 4111 @NonNull List<String> excludedApps) { 4112 byte[] data; 4113 try { 4114 final PersistableBundle bundle = PersistableBundleUtils.fromList( 4115 excludedApps, PersistableBundleUtils.STRING_SERIALIZER); 4116 data = PersistableBundleUtils.toDiskStableBytes(bundle); 4117 } catch (IOException e) { 4118 Log.e(TAG, "problem writing into stream", e); 4119 return false; 4120 } 4121 4122 final long oldId = Binder.clearCallingIdentity(); 4123 try { 4124 getVpnProfileStore().put(getVpnAppExcludedForPackage(packageName), data); 4125 } finally { 4126 Binder.restoreCallingIdentity(oldId); 4127 } 4128 return true; 4129 } 4130 4131 @VisibleForTesting getVpnAppExcludedForPackage(String packageName)4132 String getVpnAppExcludedForPackage(String packageName) { 4133 return VPN_APP_EXCLUDED + mUserId + "_" + packageName; 4134 } 4135 4136 /** 4137 * Set the application exclusion list for the specified VPN profile. 4138 * 4139 * @param packageName the package name of the app provisioning this profile 4140 * @param excludedApps the list of excluded packages 4141 * 4142 * @return whether setting the list is successful or not 4143 */ setAppExclusionList(@onNull String packageName, @NonNull List<String> excludedApps)4144 public synchronized boolean setAppExclusionList(@NonNull String packageName, 4145 @NonNull List<String> excludedApps) { 4146 enforceNotRestrictedUser(); 4147 if (!storeAppExclusionList(packageName, excludedApps)) return false; 4148 4149 updateAppExclusionList(excludedApps); 4150 4151 return true; 4152 } 4153 4154 /** 4155 * Triggers an update of the VPN network's excluded UIDs if a VPN is running. 4156 */ refreshPlatformVpnAppExclusionList()4157 public synchronized void refreshPlatformVpnAppExclusionList() { 4158 updateAppExclusionList(getAppExclusionList(mPackage)); 4159 } 4160 updateAppExclusionList(@onNull List<String> excludedApps)4161 private synchronized void updateAppExclusionList(@NonNull List<String> excludedApps) { 4162 // Re-build and update NetworkCapabilities via NetworkAgent. 4163 if (mNetworkAgent != null) { 4164 // Only update the platform VPN 4165 if (isIkev2VpnRunner()) { 4166 mConfig.disallowedApplications = List.copyOf(excludedApps); 4167 mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) 4168 .setUids(createUserAndRestrictedProfilesRanges( 4169 mUserId, null /* allowedApplications */, excludedApps)) 4170 .build(); 4171 doSendNetworkCapabilities(mNetworkAgent, mNetworkCapabilities); 4172 } 4173 } 4174 } 4175 4176 /** 4177 * Gets the application exclusion list for the specified VPN profile. 4178 * 4179 * @param packageName the package name of the app provisioning this profile 4180 * @return the list of excluded packages for the specified VPN profile or empty list if there is 4181 * no provisioned VPN profile. 4182 */ 4183 @NonNull getAppExclusionList(@onNull String packageName)4184 public synchronized List<String> getAppExclusionList(@NonNull String packageName) { 4185 final long oldId = Binder.clearCallingIdentity(); 4186 try { 4187 final byte[] bytes = getVpnProfileStore().get(getVpnAppExcludedForPackage(packageName)); 4188 4189 if (bytes == null || bytes.length == 0) return new ArrayList<>(); 4190 4191 final PersistableBundle bundle = PersistableBundleUtils.fromDiskStableBytes(bytes); 4192 return PersistableBundleUtils.toList(bundle, STRING_DESERIALIZER); 4193 } catch (IOException e) { 4194 Log.e(TAG, "problem reading from stream", e); 4195 } finally { 4196 Binder.restoreCallingIdentity(oldId); 4197 } 4198 4199 return new ArrayList<>(); 4200 } 4201 getStateFromLegacyState(int legacyState)4202 private @VpnProfileState.State int getStateFromLegacyState(int legacyState) { 4203 switch (legacyState) { 4204 case LegacyVpnInfo.STATE_CONNECTING: 4205 return VpnProfileState.STATE_CONNECTING; 4206 case LegacyVpnInfo.STATE_CONNECTED: 4207 return VpnProfileState.STATE_CONNECTED; 4208 case LegacyVpnInfo.STATE_DISCONNECTED: 4209 return VpnProfileState.STATE_DISCONNECTED; 4210 case LegacyVpnInfo.STATE_FAILED: 4211 return VpnProfileState.STATE_FAILED; 4212 default: 4213 Log.wtf(TAG, "Unhandled state " + legacyState 4214 + ", treat it as STATE_DISCONNECTED"); 4215 return VpnProfileState.STATE_DISCONNECTED; 4216 } 4217 } 4218 4219 @GuardedBy("this") 4220 @NonNull makeVpnProfileStateLocked()4221 private VpnProfileState makeVpnProfileStateLocked() { 4222 return new VpnProfileState(getStateFromLegacyState(mLegacyState), 4223 isIkev2VpnRunner() ? getSessionKeyLocked() : null, mAlwaysOn, mLockdown); 4224 } 4225 4226 @NonNull makeDisconnectedVpnProfileState()4227 private VpnProfileState makeDisconnectedVpnProfileState() { 4228 return new VpnProfileState(VpnProfileState.STATE_DISCONNECTED, null /* sessionKey */, 4229 false /* alwaysOn */, false /* lockdown */); 4230 } 4231 4232 /** 4233 * Retrieve the VpnProfileState for the profile provisioned by the given package. 4234 * 4235 * @return the VpnProfileState with current information, or null if there was no profile 4236 * provisioned by the given package. 4237 */ 4238 @Nullable getProvisionedVpnProfileState( @onNull String packageName)4239 public synchronized VpnProfileState getProvisionedVpnProfileState( 4240 @NonNull String packageName) { 4241 requireNonNull(packageName, "No package name provided"); 4242 enforceNotRestrictedUser(); 4243 return isCurrentIkev2VpnLocked(packageName) ? makeVpnProfileStateLocked() : null; 4244 } 4245 4246 /** Proxy to allow different testing setups */ 4247 // TODO: b/240492694 Remove VpnNetworkAgentWrapper and this method when 4248 // NetworkAgent#sendLinkProperties can be un-finalized. doSendLinkProperties( @onNull NetworkAgent agent, @NonNull LinkProperties lp)4249 private static void doSendLinkProperties( 4250 @NonNull NetworkAgent agent, @NonNull LinkProperties lp) { 4251 if (agent instanceof VpnNetworkAgentWrapper) { 4252 ((VpnNetworkAgentWrapper) agent).doSendLinkProperties(lp); 4253 } else { 4254 agent.sendLinkProperties(lp); 4255 } 4256 } 4257 4258 /** Proxy to allow different testing setups */ 4259 // TODO: b/240492694 Remove VpnNetworkAgentWrapper and this method when 4260 // NetworkAgent#sendNetworkCapabilities can be un-finalized. doSendNetworkCapabilities( @onNull NetworkAgent agent, @NonNull NetworkCapabilities nc)4261 private static void doSendNetworkCapabilities( 4262 @NonNull NetworkAgent agent, @NonNull NetworkCapabilities nc) { 4263 if (agent instanceof VpnNetworkAgentWrapper) { 4264 ((VpnNetworkAgentWrapper) agent).doSendNetworkCapabilities(nc); 4265 } else { 4266 agent.sendNetworkCapabilities(nc); 4267 } 4268 } 4269 4270 /** Proxy to allow different testing setups */ 4271 // TODO: b/240492694 Remove VpnNetworkAgentWrapper and this method when 4272 // NetworkAgent#setUnderlyingNetworks can be un-finalized. doSetUnderlyingNetworks( @onNull NetworkAgent agent, @NonNull List<Network> networks)4273 private static void doSetUnderlyingNetworks( 4274 @NonNull NetworkAgent agent, @NonNull List<Network> networks) { 4275 if (agent instanceof VpnNetworkAgentWrapper) { 4276 ((VpnNetworkAgentWrapper) agent).doSetUnderlyingNetworks(networks); 4277 } else { 4278 agent.setUnderlyingNetworks(networks); 4279 } 4280 } 4281 4282 /** 4283 * Proxy to allow testing 4284 * 4285 * @hide 4286 */ 4287 // TODO: b/240492694 Remove VpnNetworkAgentWrapper when NetworkAgent's methods can be 4288 // un-finalized. 4289 @VisibleForTesting 4290 public static class VpnNetworkAgentWrapper extends NetworkAgent { 4291 /** Create an VpnNetworkAgentWrapper */ VpnNetworkAgentWrapper( @onNull Context context, @NonNull Looper looper, @NonNull String logTag, @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, @NonNull NetworkScore score, @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider)4292 public VpnNetworkAgentWrapper( 4293 @NonNull Context context, 4294 @NonNull Looper looper, 4295 @NonNull String logTag, 4296 @NonNull NetworkCapabilities nc, 4297 @NonNull LinkProperties lp, 4298 @NonNull NetworkScore score, 4299 @NonNull NetworkAgentConfig config, 4300 @Nullable NetworkProvider provider) { 4301 super(context, looper, logTag, nc, lp, score, config, provider); 4302 } 4303 4304 /** Update the LinkProperties */ doSendLinkProperties(@onNull LinkProperties lp)4305 public void doSendLinkProperties(@NonNull LinkProperties lp) { 4306 sendLinkProperties(lp); 4307 } 4308 4309 /** Update the NetworkCapabilities */ doSendNetworkCapabilities(@onNull NetworkCapabilities nc)4310 public void doSendNetworkCapabilities(@NonNull NetworkCapabilities nc) { 4311 sendNetworkCapabilities(nc); 4312 } 4313 4314 /** Set the underlying networks */ doSetUnderlyingNetworks(@onNull List<Network> networks)4315 public void doSetUnderlyingNetworks(@NonNull List<Network> networks) { 4316 setUnderlyingNetworks(networks); 4317 } 4318 4319 @Override onNetworkUnwanted()4320 public void onNetworkUnwanted() { 4321 // We are user controlled, not driven by NetworkRequest. 4322 } 4323 } 4324 4325 /** 4326 * Proxy to allow testing 4327 * 4328 * @hide 4329 */ 4330 @VisibleForTesting 4331 public static class IkeSessionWrapper { 4332 private final IkeSession mImpl; 4333 4334 /** Create an IkeSessionWrapper */ IkeSessionWrapper(IkeSession session)4335 public IkeSessionWrapper(IkeSession session) { 4336 mImpl = session; 4337 } 4338 4339 /** Update the underlying network of the IKE Session */ setNetwork(@onNull Network network)4340 public void setNetwork(@NonNull Network network) { 4341 mImpl.setNetwork(network); 4342 } 4343 4344 /** Forcibly terminate the IKE Session */ kill()4345 public void kill() { 4346 mImpl.kill(); 4347 } 4348 } 4349 4350 /** 4351 * Proxy to allow testing 4352 * 4353 * @hide 4354 */ 4355 @VisibleForTesting 4356 public static class Ikev2SessionCreator { 4357 /** Creates a IKE session */ createIkeSession( @onNull Context context, @NonNull IkeSessionParams ikeSessionParams, @NonNull ChildSessionParams firstChildSessionParams, @NonNull Executor userCbExecutor, @NonNull IkeSessionCallback ikeSessionCallback, @NonNull ChildSessionCallback firstChildSessionCallback)4358 public IkeSessionWrapper createIkeSession( 4359 @NonNull Context context, 4360 @NonNull IkeSessionParams ikeSessionParams, 4361 @NonNull ChildSessionParams firstChildSessionParams, 4362 @NonNull Executor userCbExecutor, 4363 @NonNull IkeSessionCallback ikeSessionCallback, 4364 @NonNull ChildSessionCallback firstChildSessionCallback) { 4365 return new IkeSessionWrapper( 4366 new IkeSession( 4367 context, 4368 ikeSessionParams, 4369 firstChildSessionParams, 4370 userCbExecutor, 4371 ikeSessionCallback, 4372 firstChildSessionCallback)); 4373 } 4374 } 4375 4376 /** 4377 * Returns the entire range of UIDs available to a macro-user. This is something like 0-99999. 4378 */ 4379 @VisibleForTesting createUidRangeForUser(int userId)4380 static Range<Integer> createUidRangeForUser(int userId) { 4381 return new Range<Integer>(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1); 4382 } 4383 } 4384