Support IPsec transform migration

This commit adds methods to support migrating tunnel mode
IpSecTransform to new source/destination addresses.

Bug: 169171001
Test: atest FrameworksNetTests (new tests added)
Change-Id: Ic177015fba5b62d3f73009633118109d3631086f
This commit is contained in:
Yan Yan
2021-02-16 16:29:48 -08:00
parent 236013b328
commit e114b38f07
5 changed files with 353 additions and 10 deletions

View File

@@ -36,6 +36,7 @@ import android.net.InetAddresses;
import android.net.IpSecAlgorithm;
import android.net.IpSecConfig;
import android.net.IpSecManager;
import android.net.IpSecMigrateInfoParcel;
import android.net.IpSecSpiResponse;
import android.net.IpSecTransform;
import android.net.IpSecTransformResponse;
@@ -590,14 +591,19 @@ public class IpSecService extends IIpSecService.Stub {
}
/**
* Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is
* created, the SpiRecord that originally tracked the SAs will reliquish the
* responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag.
* Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is created, the
* SpiRecord that originally tracked the SAs will reliquish the responsibility of freeing the
* underlying SA to this class via the mOwnedByTransform flag.
*
* <p>This class is not thread-safe, and expects that that users of this class will ensure
* synchronization and thread safety by holding the IpSecService.this instance lock
*/
private final class TransformRecord extends OwnedResourceRecord {
private final IpSecConfig mConfig;
private final SpiRecord mSpi;
private final EncapSocketRecord mSocket;
private String mNewSourceAddress = null;
private String mNewDestinationAddress = null;
TransformRecord(
int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) {
@@ -621,6 +627,51 @@ public class IpSecService extends IIpSecService.Stub {
return mSocket;
}
@GuardedBy("IpSecService.this")
public String getNewSourceAddress() {
return mNewSourceAddress;
}
@GuardedBy("IpSecService.this")
public String getNewDestinationAddress() {
return mNewDestinationAddress;
}
private void verifyTunnelModeOrThrow() {
if (mConfig.getMode() != IpSecTransform.MODE_TUNNEL) {
throw new UnsupportedOperationException(
"Migration requested/called on non-tunnel-mode transform");
}
}
/** Start migrating this transform to new source and destination addresses */
@GuardedBy("IpSecService.this")
public void startMigration(String newSourceAddress, String newDestinationAddress) {
verifyTunnelModeOrThrow();
Objects.requireNonNull(newSourceAddress, "newSourceAddress was null");
Objects.requireNonNull(newDestinationAddress, "newDestinationAddress was null");
mNewSourceAddress = newSourceAddress;
mNewDestinationAddress = newDestinationAddress;
}
/** Finish migration and update addresses. */
@GuardedBy("IpSecService.this")
public void finishMigration() {
verifyTunnelModeOrThrow();
mConfig.setSourceAddress(mNewSourceAddress);
mConfig.setDestinationAddress(mNewDestinationAddress);
mNewSourceAddress = null;
mNewDestinationAddress = null;
}
/** Return if this transform is going to be migrated. */
@GuardedBy("IpSecService.this")
public boolean isMigrating() {
verifyTunnelModeOrThrow();
return mNewSourceAddress != null;
}
/** always guarded by IpSecService#this */
@Override
public void freeUnderlyingResources() {
@@ -1725,6 +1776,44 @@ public class IpSecService extends IIpSecService.Stub {
return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId);
}
/**
* Migrate an active Tunnel Mode IPsec Transform to new source/destination addresses.
*
* <p>Begins the process of migrating a transform and cache the new addresses. To complete the
* migration once started, callers MUST apply the same transform to the appropriate tunnel using
* {@link #applyTunnelModeTransform}. Otherwise, the address update will not be committed and
* the transform will still only process traffic between the current source and destination
* address. One common use case is that the control plane will start the migration process and
* then hand off the transform to the IPsec caller to perform the actual migration when the
* tunnel is ready.
*
* <p>If this method is called multiple times before {@link #applyTunnelModeTransform} is
* called, when the transform is applied, it will be migrated to the addresses from the last
* call.
*
* <p>The provided source and destination addresses MUST share the same address family, but they
* can have a different family from the current addresses.
*
* <p>Transform migration is only supported for tunnel mode transforms. Calling this method on
* other types of transforms will throw an {@code UnsupportedOperationException}.
*/
@Override
public synchronized void migrateTransform(
int transformId,
String newSourceAddress,
String newDestinationAddress,
String callingPackage) {
Objects.requireNonNull(newSourceAddress, "newSourceAddress was null");
Objects.requireNonNull(newDestinationAddress, "newDestinationAddress was null");
enforceTunnelFeatureAndPermissions(callingPackage);
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
TransformRecord transformInfo =
userRecord.mTransformRecords.getResourceOrThrow(transformId);
transformInfo.startMigration(newSourceAddress, newDestinationAddress);
}
/**
* Delete a transport mode transform that was previously allocated by + registered with the
* system server. If this is called on an inactive (or non-existent) transform, it will not
@@ -1784,12 +1873,15 @@ public class IpSecService extends IIpSecService.Stub {
/**
* Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec
* security association as a correspondent policy to the provided interface
* security association as a correspondent policy to the provided interface.
*
* <p>If the transform is migrating, migrate the IPsec security association to new
* source/destination addresses, and mark the migration as finished.
*/
@Override
public synchronized void applyTunnelModeTransform(
int tunnelResourceId, int direction,
int transformResourceId, String callingPackage) throws RemoteException {
int tunnelResourceId, int direction, int transformResourceId, String callingPackage)
throws RemoteException {
enforceTunnelFeatureAndPermissions(callingPackage);
checkDirection(direction);
@@ -1868,6 +1960,24 @@ public class IpSecService extends IIpSecService.Stub {
// Update SA with tunnel mark (ikey or okey based on direction)
createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord);
if (transformInfo.isMigrating()) {
for (int selAddrFamily : ADDRESS_FAMILIES) {
final IpSecMigrateInfoParcel migrateInfo =
new IpSecMigrateInfoParcel(
Binder.getCallingUid(),
selAddrFamily,
direction,
c.getSourceAddress(),
c.getDestinationAddress(),
transformInfo.getNewSourceAddress(),
transformInfo.getNewDestinationAddress(),
c.getXfrmInterfaceId());
mNetd.ipSecMigrate(migrateInfo);
}
transformInfo.finishMigration();
}
} catch (ServiceSpecificException e) {
if (e.errorCode == EINVAL) {
throw new IllegalArgumentException(e.toString());