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:
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user