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