Add tunnel-mode calls to netd in IpSecService

Adds calls to relevant netd methods in IpSecService, enabling Tunnel
mode functionality.

Bug: 63588681
Test: Compiles, passing CTS + unit tests
Change-Id: I6deb68584cddb03f21bd76370d4ef69cadc1bf16
This commit is contained in:
Benedict Wong
2018-01-19 17:36:02 -08:00
parent e02b700032
commit 8edc557ede

View File

@@ -65,7 +65,6 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import libcore.io.IoUtils;
@@ -596,6 +595,10 @@ public class IpSecService extends IIpSecService.Stub {
return mSpi;
}
public EncapSocketRecord getSocketRecord() {
return mSocket;
}
/** always guarded by IpSecService#this */
@Override
public void freeUnderlyingResources() {
@@ -806,9 +809,29 @@ public class IpSecService extends IIpSecService.Stub {
/** always guarded by IpSecService#this */
@Override
public void freeUnderlyingResources() {
// TODO: Add calls to netd
// Calls to netd
// Teardown VTI
// Delete global policies
try {
mSrvConfig.getNetdInstance().removeVirtualTunnelInterface(mInterfaceName);
for (int direction : DIRECTIONS) {
int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey;
mSrvConfig
.getNetdInstance()
.ipSecDeleteSecurityPolicy(
0, direction, mLocalAddress, mRemoteAddress, mark, 0xffffffff);
}
} catch (ServiceSpecificException e) {
// FIXME: get the error code and throw is at an IOException from Errno Exception
} catch (RemoteException e) {
Log.e(
TAG,
"Failed to delete VTI with interface name: "
+ mInterfaceName
+ " and id: "
+ mResourceId);
}
getResourceTracker().give();
releaseNetId(mIkey);
@@ -1229,10 +1252,29 @@ public class IpSecService extends IIpSecService.Stub {
final int okey = reserveNetId();
String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId);
// TODO: Add calls to netd:
try {
// Calls to netd:
// Create VTI
// Add inbound/outbound global policies
// (use reqid = 0)
mSrvConfig
.getNetdInstance()
.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey);
for (int direction : DIRECTIONS) {
int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey;
mSrvConfig
.getNetdInstance()
.ipSecAddSecurityPolicy(
0, // Use 0 for reqId
direction,
"",
"",
0,
mark,
0xffffffff);
}
userRecord.mTunnelInterfaceRecords.put(
resourceId,
@@ -1247,6 +1289,20 @@ public class IpSecService extends IIpSecService.Stub {
okey),
binder));
return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
} catch (RemoteException e) {
// Release keys if we got an error.
releaseNetId(ikey);
releaseNetId(okey);
throw e.rethrowFromSystemServer();
} catch (ServiceSpecificException e) {
// FIXME: get the error code and throw is at an IOException from Errno Exception
}
// If we make it to here, then something has gone wrong and we couldn't create a VTI.
// Release the keys that we reserved, and return an error status.
releaseNetId(ikey);
releaseNetId(okey);
return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
/**
@@ -1381,37 +1437,12 @@ public class IpSecService extends IIpSecService.Stub {
}
}
/**
* Create a transport mode transform, which represent two security associations (one in each
* direction) in the kernel. The transform will be cached by the system server and must be freed
* when no longer needed. It is possible to free one, deleting the SA from underneath sockets
* that are using it, which will result in all of those sockets becoming unable to send or
* receive data.
*/
@Override
public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
private void createOrUpdateTransform(
IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)
throws RemoteException {
checkIpSecConfig(c);
checkNotNull(binder, "Null Binder passed to createTransform");
final int resourceId = mNextResourceId++;
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
List<RefcountedResource> dependencies = new ArrayList<>();
if (!userRecord.mTransformQuotaTracker.isAvailable()) {
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
int encapType, encapLocalPort = 0, encapRemotePort = 0;
EncapSocketRecord socketRecord = null;
encapType = c.getEncapType();
int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0;
if (encapType != IpSecTransform.ENCAP_NONE) {
RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
c.getEncapSocketResourceId());
dependencies.add(refcountedSocketRecord);
socketRecord = refcountedSocketRecord.getResource();
encapLocalPort = socketRecord.getPort();
encapRemotePort = c.getEncapRemotePort();
}
@@ -1420,12 +1451,6 @@ public class IpSecService extends IIpSecService.Stub {
IpSecAlgorithm crypt = c.getEncryption();
IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
RefcountedResource<SpiRecord> refcountedSpiRecord =
userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
dependencies.add(refcountedSpiRecord);
SpiRecord spiRecord = refcountedSpiRecord.getResource();
try {
mSrvConfig
.getNetdInstance()
.ipSecAddSecurityAssociation(
@@ -1449,11 +1474,50 @@ public class IpSecService extends IIpSecService.Stub {
encapType,
encapLocalPort,
encapRemotePort);
}
/**
* Create a IPsec transform, which represents a single security association in the kernel. The
* transform will be cached by the system server and must be freed when no longer needed. It is
* possible to free one, deleting the SA from underneath sockets that are using it, which will
* result in all of those sockets becoming unable to send or receive data.
*/
@Override
public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
throws RemoteException {
checkIpSecConfig(c);
checkNotNull(binder, "Null Binder passed to createTransform");
final int resourceId = mNextResourceId++;
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
List<RefcountedResource> dependencies = new ArrayList<>();
if (!userRecord.mTransformQuotaTracker.isAvailable()) {
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
EncapSocketRecord socketRecord = null;
if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
c.getEncapSocketResourceId());
dependencies.add(refcountedSocketRecord);
socketRecord = refcountedSocketRecord.getResource();
}
RefcountedResource<SpiRecord> refcountedSpiRecord =
userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
dependencies.add(refcountedSpiRecord);
SpiRecord spiRecord = refcountedSpiRecord.getResource();
try {
createOrUpdateTransform(c, resourceId, spiRecord, socketRecord);
} catch (ServiceSpecificException e) {
// FIXME: get the error code and throw is at an IOException from Errno Exception
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
}
// Both SAs were created successfully, time to construct a record and lock it away
// SA was created successfully, time to construct a record and lock it away
userRecord.mTransformRecords.put(
resourceId,
new RefcountedResource<TransformRecord>(
@@ -1561,14 +1625,48 @@ public class IpSecService extends IIpSecService.Stub {
c.getMode() == IpSecTransform.MODE_TUNNEL,
"Transform mode was not Tunnel mode; cannot be applied to a tunnel interface");
EncapSocketRecord socketRecord = null;
if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
socketRecord =
userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId());
}
SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId());
int mark =
(direction == IpSecManager.DIRECTION_IN)
? tunnelInterfaceInfo.getIkey()
: tunnelInterfaceInfo.getOkey();
// TODO: Add calls to netd:
try {
c.setMarkValue(mark);
c.setMarkMask(0xffffffff);
if (direction == IpSecManager.DIRECTION_OUT) {
// Set output mark via underlying network (output only)
c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork());
// If outbound, also add SPI to the policy.
mSrvConfig
.getNetdInstance()
.ipSecUpdateSecurityPolicy(
0, // Use 0 for reqId
direction,
"",
"",
transformInfo.getSpiRecord().getSpi(),
mark,
0xffffffff);
}
// Update SA with tunnel mark (ikey or okey based on direction)
// If outbound, add SPI to policy
createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord);
} catch (ServiceSpecificException e) {
if (e.errorCode == EINVAL) {
throw new IllegalArgumentException(e.toString());
} else {
throw e;
}
}
}
@Override