Add version control for packet address translation design

This commit adds the version control for keepalive packet address
translation design to prevent device crash if the network stack
is not updated to a newer version. This commit also adds a
DeviceConfig to control the design in newer module version.

Bug: 291870956
Test: atest FrameworksNetTests CtsNetTestCases
Change-Id: Id4efbf51dae9154d2bc3a1ee405e2139d5c91e36
This commit is contained in:
chiachangwang
2023-07-31 14:30:47 +00:00
parent ebdda22240
commit 144dd51761
3 changed files with 65 additions and 6 deletions

View File

@@ -34,6 +34,8 @@ import static android.net.SocketKeepalive.NO_KEEPALIVE;
import static android.net.SocketKeepalive.SUCCESS;
import static android.net.SocketKeepalive.SUCCESS_PAUSED;
import static com.android.net.module.util.FeatureVersions.FEATURE_CLAT_ADDRESS_TRANSLATE;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
@@ -59,6 +61,7 @@ import android.util.Pair;
import com.android.connectivity.resources.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.HexDump;
import com.android.net.module.util.IpUtils;
@@ -86,6 +89,9 @@ public class KeepaliveTracker {
public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
private static final String CONFIG_DISABLE_CLAT_ADDRESS_TRANSLATE =
"disable_clat_address_translate";
/** Keeps track of keepalive requests. */
private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
new HashMap<> ();
@@ -113,7 +119,7 @@ public class KeepaliveTracker {
}
@VisibleForTesting
KeepaliveTracker(Context context, Handler handler, TcpKeepaliveController tcpController,
public KeepaliveTracker(Context context, Handler handler, TcpKeepaliveController tcpController,
Dependencies deps) {
mTcpController = tcpController;
mContext = context;
@@ -553,6 +559,8 @@ public class KeepaliveTracker {
private KeepaliveInfo handleUpdateKeepaliveForClat(KeepaliveInfo ki)
throws InvalidSocketException, InvalidPacketException {
if (!mDependencies.isAddressTranslationEnabled(mContext)) return ki;
// Translation applies to only NAT-T keepalive
if (ki.mType != KeepaliveInfo.TYPE_NATT) return ki;
// Only try to translate address if the packet source address is the clat's source address.
@@ -973,5 +981,20 @@ public class KeepaliveTracker {
public ConnectivityResources createConnectivityResources(@NonNull Context context) {
return new ConnectivityResources(context);
}
/**
* Return if keepalive address translation with clat feature is supported or not.
*
* This is controlled by both isFeatureSupported() and isFeatureEnabled(). The
* isFeatureSupported() checks whether device contains the minimal required module
* version for FEATURE_CLAT_ADDRESS_TRANSLATE. The isTetheringFeatureForceDisabled()
* checks the DeviceConfig flag that can be updated via DeviceConfig push to control
* the overall feature.
*/
public boolean isAddressTranslationEnabled(@NonNull Context context) {
return DeviceConfigUtils.isFeatureSupported(context, FEATURE_CLAT_ADDRESS_TRANSLATE)
&& !DeviceConfigUtils.isTetheringFeatureForceDisabled(
CONFIG_DISABLE_CLAT_ADDRESS_TRANSLATE);
}
}
}

View File

@@ -402,6 +402,7 @@ import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
import com.android.server.connectivity.ClatCoordinator;
import com.android.server.connectivity.ConnectivityFlags;
import com.android.server.connectivity.ConnectivityResources;
import com.android.server.connectivity.KeepaliveTracker;
import com.android.server.connectivity.MultinetworkPolicyTracker;
import com.android.server.connectivity.MultinetworkPolicyTrackerTestDependencies;
import com.android.server.connectivity.Nat464Xlat;
@@ -410,6 +411,7 @@ import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
import com.android.server.connectivity.ProxyTracker;
import com.android.server.connectivity.QosCallbackTracker;
import com.android.server.connectivity.TcpKeepaliveController;
import com.android.server.connectivity.UidRangeUtils;
import com.android.server.connectivity.Vpn;
import com.android.server.connectivity.VpnProfileStore;
@@ -627,6 +629,7 @@ public class ConnectivityServiceTest {
@Mock ActivityManager mActivityManager;
@Mock DestroySocketsWrapper mDestroySocketsWrapper;
@Mock SubscriptionManager mSubscriptionManager;
@Mock KeepaliveTracker.Dependencies mMockKeepaliveTrackerDependencies;
// BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the
// underlying binder calls.
@@ -1898,6 +1901,12 @@ public class ConnectivityServiceTest {
doReturn(mResources).when(mockResContext).getResources();
ConnectivityResources.setResourcesContextForTest(mockResContext);
mDeps = new ConnectivityServiceDependencies(mockResContext);
doReturn(true).when(mMockKeepaliveTrackerDependencies)
.isAddressTranslationEnabled(mServiceContext);
doReturn(new ConnectivityResources(mockResContext)).when(mMockKeepaliveTrackerDependencies)
.createConnectivityResources(mServiceContext);
doReturn(new int[] {1, 3, 0, 0}).when(mMockKeepaliveTrackerDependencies)
.getSupportedKeepalives(mServiceContext);
mAutoOnOffKeepaliveDependencies =
new AutomaticOnOffKeepaliveTrackerDependencies(mServiceContext);
mService = new ConnectivityService(mServiceContext,
@@ -2297,6 +2306,12 @@ public class ConnectivityServiceTest {
// Assuming enabled here to focus on ConnectivityService tests.
return true;
}
public KeepaliveTracker newKeepaliveTracker(@NonNull Context context,
@NonNull Handler connectivityserviceHander) {
return new KeepaliveTracker(context, connectivityserviceHander,
new TcpKeepaliveController(connectivityserviceHander),
mMockKeepaliveTrackerDependencies);
}
}
private static void initAlarmManager(final AlarmManager am, final Handler alarmHandler) {

View File

@@ -78,7 +78,6 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.connectivity.resources.R;
import com.android.server.connectivity.AutomaticOnOffKeepaliveTracker.AutomaticOnOffKeepalive;
import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
import com.android.testutils.DevSdkIgnoreRule;
@@ -96,6 +95,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
@@ -128,7 +128,7 @@ public class AutomaticOnOffKeepaliveTrackerTest {
@Mock AlarmManager mAlarmManager;
@Mock NetworkAgentInfo mNai;
@Mock SubscriptionManager mSubscriptionManager;
@Mock KeepaliveTracker.Dependencies mKeepaliveTrackerDeps;
KeepaliveStatsTracker mKeepaliveStatsTracker;
TestKeepaliveTracker mKeepaliveTracker;
AOOTestHandler mTestHandler;
@@ -267,7 +267,7 @@ public class AutomaticOnOffKeepaliveTrackerTest {
TestKeepaliveTracker(@NonNull final Context context, @NonNull final Handler handler,
@NonNull final TcpKeepaliveController tcpController) {
super(context, handler, tcpController, new Dependencies());
super(context, handler, tcpController, mKeepaliveTrackerDeps);
}
public void setReturnedKeepaliveInfo(@NonNull final KeepaliveInfo ki) {
@@ -336,8 +336,6 @@ public class AutomaticOnOffKeepaliveTrackerTest {
anyInt() /* pid */, anyInt() /* uid */);
ConnectivityResources.setResourcesContextForTest(mCtx);
final Resources mockResources = mock(Resources.class);
doReturn(new String[] { "0,3", "3,3" }).when(mockResources)
.getStringArray(R.array.config_networkSupportedKeepaliveCount);
doReturn(mockResources).when(mCtx).getResources();
doReturn(mNetd).when(mDependencies).getNetd();
doReturn(mAlarmManager).when(mDependencies).getAlarmManager(any());
@@ -345,6 +343,10 @@ public class AutomaticOnOffKeepaliveTrackerTest {
.getFwmarkForNetwork(TEST_NETID);
doNothing().when(mDependencies).sendRequest(any(), any());
doReturn(true).when(mKeepaliveTrackerDeps).isAddressTranslationEnabled(mCtx);
doReturn(new ConnectivityResources(mCtx)).when(mKeepaliveTrackerDeps)
.createConnectivityResources(mCtx);
doReturn(new int[] {3, 0, 0, 3}).when(mKeepaliveTrackerDeps).getSupportedKeepalives(mCtx);
mHandlerThread = new HandlerThread("KeepaliveTrackerTest");
mHandlerThread.start();
@@ -658,6 +660,25 @@ public class AutomaticOnOffKeepaliveTrackerTest {
assertEquals(srcAddr, tpd.getSrcAddress());
}
@Test
public void testStartNattKeepalive_addressTranslationOnClatNotSupported() throws Exception {
// Disable address translation feature and verify the behavior
doReturn(false).when(mKeepaliveTrackerDeps).isAddressTranslationEnabled(mCtx);
setupTestNaiForClat(InetAddresses.parseNumericAddress("2001:db8::1"),
InetAddresses.parseNumericAddress("2001:db8::2"));
doStartNattKeepalive();
final ArgumentCaptor<NattKeepalivePacketData> kpdCaptor =
ArgumentCaptor.forClass(NattKeepalivePacketData.class);
verify(mNai).onStartNattSocketKeepalive(
eq(TEST_SLOT), eq(TEST_KEEPALIVE_INTERVAL_SEC), kpdCaptor.capture());
// Verify that address translation is not triggered so the addresses are still v4.
final NattKeepalivePacketData kpd = kpdCaptor.getValue();
assertTrue(kpd.getSrcAddress() instanceof Inet4Address);
assertTrue(kpd.getDstAddress() instanceof Inet4Address);
}
@Test
public void testStartNattKeepalive_addressTranslationOnClat() throws Exception {
final InetAddress v6AddrSrc = InetAddresses.parseNumericAddress("2001:db8::1");