From f0eb7b81183d1f896ae1e191480b619edd366898 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Wed, 22 Feb 2023 13:08:32 +0000 Subject: [PATCH 1/2] Read NAT keepalive value from carrier config Read keepalive from carrier config for Ikev2 VPN. Bug: 259000745 Bug: 269714970 Test: atest FrameworksNetTests Change-Id: I242a2d033dbc9266fd083e7242233638dd475e3d --- .../com/android/server/connectivity/Vpn.java | 105 +++++++++++++++++- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 1ce917cb78419..c39b4ffcf3522 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.CONTROL_VPN; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_VPN; import static android.net.RouteInfo.RTN_THROW; import static android.net.RouteInfo.RTN_UNREACHABLE; @@ -29,6 +30,7 @@ import static android.net.ipsec.ike.IkeSessionParams.ESP_ENCAP_TYPE_AUTO; import static android.net.ipsec.ike.IkeSessionParams.ESP_IP_VERSION_AUTO; import static android.os.PowerWhitelistManager.REASON_VPN; import static android.os.UserHandle.PER_USER_RANGE; +import static android.telephony.CarrierConfigManager.KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT; import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; import static com.android.server.vcn.util.PersistableBundleUtils.STRING_DESERIALIZER; @@ -79,7 +81,9 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkProvider; import android.net.NetworkRequest; import android.net.NetworkScore; +import android.net.NetworkSpecifier; import android.net.RouteInfo; +import android.net.TelephonyNetworkSpecifier; import android.net.UidRangeParcel; import android.net.UnderlyingNetworkInfo; import android.net.Uri; @@ -127,12 +131,16 @@ import android.security.keystore.KeyProperties; import android.system.keystore2.Domain; import android.system.keystore2.KeyDescriptor; import android.system.keystore2.KeyPermission; +import android.telephony.CarrierConfigManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; import android.util.IndentingPrintWriter; import android.util.LocalLog; import android.util.Log; import android.util.Range; +import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; @@ -268,6 +276,10 @@ public class Vpn { private final ConnectivityManager mConnectivityManager; private final AppOpsManager mAppOpsManager; private final ConnectivityDiagnosticsManager mConnectivityDiagnosticsManager; + private final TelephonyManager mTelephonyManager; + private final CarrierConfigManager mCarrierConfigManager; + private final SubscriptionManager mSubscriptionManager; + // The context is for specific user which is created from mUserId private final Context mUserIdContext; @VisibleForTesting final Dependencies mDeps; @@ -313,6 +325,14 @@ public class Vpn { private final LocalLog mUnderlyNetworkChanges = new LocalLog(MAX_EVENTS_LOGS); private final LocalLog mVpnManagerEvents = new LocalLog(MAX_EVENTS_LOGS); + /** + * Cached Map of since retrieving the PersistableBundle + * and the target value from CarrierConfigManager is somewhat expensive as it has hundreds of + * fields. This cache is cleared when the carrier config changes to ensure data freshness. + */ + @GuardedBy("this") + private final SparseArray mCachedKeepalivePerSubId = new SparseArray<>(); + /** * Whether to keep the connection active after rebooting, or upgrading or reinstalling. This * only applies to {@link VpnService} connections. @@ -626,6 +646,10 @@ public class Vpn { mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mConnectivityDiagnosticsManager = mContext.getSystemService(ConnectivityDiagnosticsManager.class); + mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class); + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class); + mDeps = deps; mNms = netService; mNetd = netd; @@ -2893,6 +2917,24 @@ public class Vpn { */ private int mRetryCount = 0; + private CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener = + new CarrierConfigManager.CarrierConfigChangeListener() { + @Override + public void onCarrierConfigChanged(int slotIndex, int subId, int carrierId, + int specificCarrierId) { + synchronized (Vpn.this) { + mCachedKeepalivePerSubId.remove(subId); + + // Ignore stale runner. + if (mVpnRunner != Vpn.IkeV2VpnRunner.this) return; + + maybeMigrateIkeSession(mActiveNetwork); + } + // TODO: update the longLivedTcpConnectionsExpensive value in the + // networkcapabilities of the VPN network. + } + }; + IkeV2VpnRunner( @NonNull Ikev2VpnProfile profile, @NonNull ScheduledThreadPoolExecutor executor) { super(TAG); @@ -2918,6 +2960,9 @@ public class Vpn { setVpnNetworkPreference(mSessionKey, createUserAndRestrictedProfilesRanges(mUserId, mConfig.allowedApplications, mConfig.disallowedApplications)); + + mCarrierConfigManager.registerCarrierConfigChangeListener(mExecutor, + mCarrierConfigChangeListener); } @Override @@ -3356,9 +3401,36 @@ public class Vpn { } private int guessNattKeepaliveTimerForNetwork() { - // TODO : guess the keepalive delay based on carrier if auto keepalive timer is - // enabled - return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + final int subId = getCellSubIdForNetworkCapabilities(mUnderlyingNetworkCapabilities); + if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { + Log.d(TAG, "Underlying network is not a cellular network"); + return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + } + + synchronized (Vpn.this) { + if (mCachedKeepalivePerSubId.contains(subId)) { + Log.d(TAG, "Get cached keepalive config"); + return mCachedKeepalivePerSubId.get(subId); + } + + final TelephonyManager perSubTm = mTelephonyManager.createForSubscriptionId(subId); + if (perSubTm.getSimApplicationState() != TelephonyManager.SIM_STATE_LOADED) { + Log.d(TAG, "SIM card is not ready on sub " + subId); + return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + } + + final PersistableBundle carrierConfig = + mCarrierConfigManager.getConfigForSubId(subId); + if (!CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) { + return AUTOMATIC_KEEPALIVE_DELAY_SECONDS; + } + + final int natKeepalive = + carrierConfig.getInt(KEY_MIN_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT); + mCachedKeepalivePerSubId.put(subId, natKeepalive); + Log.d(TAG, "Get customized keepalive=" + natKeepalive); + return natKeepalive; + } } boolean maybeMigrateIkeSession(@NonNull Network underlyingNetwork) { @@ -3456,7 +3528,15 @@ public class Vpn { /** Called when the NetworkCapabilities of underlying network is changed */ public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) { + final NetworkCapabilities oldNc = mUnderlyingNetworkCapabilities; mUnderlyingNetworkCapabilities = nc; + // The oldNc may be null when it's not assigned yet. + final boolean subIdChanged = + (oldNc == null) || !nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds()); + // Update carrierConfig. + if (subIdChanged) { + maybeMigrateIkeSession(mActiveNetwork); + } } /** Called when the LinkProperties of underlying network is changed */ @@ -3812,6 +3892,8 @@ public class Vpn { resetIkeState(); + mCarrierConfigManager.unregisterCarrierConfigChangeListener( + mCarrierConfigChangeListener); mConnectivityManager.unregisterNetworkCallback(mNetworkCallback); mConnectivityDiagnosticsManager.unregisterConnectivityDiagnosticsCallback( mDiagnosticsCallback); @@ -4804,6 +4886,8 @@ public class Vpn { pw.println("Reset session scheduled"); } } + pw.println("mCachedKeepalivePerSubId=" + mCachedKeepalivePerSubId); + pw.println("mUnderlyNetworkChanges (most recent first):"); pw.increaseIndent(); mUnderlyNetworkChanges.reverseDump(pw); @@ -4815,4 +4899,19 @@ public class Vpn { pw.decreaseIndent(); } } + + private static int getCellSubIdForNetworkCapabilities(@Nullable NetworkCapabilities nc) { + if (nc == null) return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + + if (!nc.hasTransport(TRANSPORT_CELLULAR)) { + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + final NetworkSpecifier specifier = nc.getNetworkSpecifier(); + if (specifier instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); + } + + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } } From 84dd61d2113ff6c2d044023a0396849162bf586c Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Mon, 6 Mar 2023 13:52:49 +0000 Subject: [PATCH 2/2] Prevent migrating the session from using the wrong value Migrating the IKE session requires reading the subId information from network capabilities. A new default network change will start with an onAailable callback and start the migration. But Vpn does not yet get the new network capabilities. The migration should not be processed until receiving network capabilities change. Bug: 269714970 Test: atest FrameworksNetTests Change-Id: I1d2eb9647cd3a0434ba656671926eb504abbf150 --- .../java/com/android/server/connectivity/Vpn.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index c39b4ffcf3522..6d3f8fd772329 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -3302,8 +3302,6 @@ public class Vpn { mUnderlyingLinkProperties = null; mUnderlyingNetworkCapabilities = null; mRetryCount = 0; - - startOrMigrateIkeSession(network); } @NonNull @@ -3530,11 +3528,11 @@ public class Vpn { public void onDefaultNetworkCapabilitiesChanged(@NonNull NetworkCapabilities nc) { final NetworkCapabilities oldNc = mUnderlyingNetworkCapabilities; mUnderlyingNetworkCapabilities = nc; - // The oldNc may be null when it's not assigned yet. - final boolean subIdChanged = - (oldNc == null) || !nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds()); - // Update carrierConfig. - if (subIdChanged) { + if (oldNc == null) { + // A new default network is available. + startOrMigrateIkeSession(mActiveNetwork); + } else if (!nc.getSubscriptionIds().equals(oldNc.getSubscriptionIds())) { + // Renew carrierConfig values. maybeMigrateIkeSession(mActiveNetwork); } }