Merge "Add tunnel-mode calls to netd in IpSecService" am: 475fe28c50
am: 02d6d81006 Change-Id: I8a3d16c8e58ad1c09d967943abe1c729fe37636a
This commit is contained in:
@@ -65,7 +65,6 @@ import java.net.InetAddress;
|
|||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.BitSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import libcore.io.IoUtils;
|
import libcore.io.IoUtils;
|
||||||
@@ -596,6 +595,10 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
return mSpi;
|
return mSpi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EncapSocketRecord getSocketRecord() {
|
||||||
|
return mSocket;
|
||||||
|
}
|
||||||
|
|
||||||
/** always guarded by IpSecService#this */
|
/** always guarded by IpSecService#this */
|
||||||
@Override
|
@Override
|
||||||
public void freeUnderlyingResources() {
|
public void freeUnderlyingResources() {
|
||||||
@@ -806,9 +809,29 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
/** always guarded by IpSecService#this */
|
/** always guarded by IpSecService#this */
|
||||||
@Override
|
@Override
|
||||||
public void freeUnderlyingResources() {
|
public void freeUnderlyingResources() {
|
||||||
// TODO: Add calls to netd
|
// Calls to netd
|
||||||
// Teardown VTI
|
// Teardown VTI
|
||||||
// Delete global policies
|
// 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();
|
getResourceTracker().give();
|
||||||
releaseNetId(mIkey);
|
releaseNetId(mIkey);
|
||||||
@@ -1229,24 +1252,57 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
final int okey = reserveNetId();
|
final int okey = reserveNetId();
|
||||||
String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId);
|
String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId);
|
||||||
|
|
||||||
// TODO: Add calls to netd:
|
try {
|
||||||
// Create VTI
|
// Calls to netd:
|
||||||
// Add inbound/outbound global policies
|
// Create VTI
|
||||||
// (use reqid = 0)
|
// Add inbound/outbound global policies
|
||||||
|
// (use reqid = 0)
|
||||||
|
mSrvConfig
|
||||||
|
.getNetdInstance()
|
||||||
|
.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey);
|
||||||
|
|
||||||
userRecord.mTunnelInterfaceRecords.put(
|
for (int direction : DIRECTIONS) {
|
||||||
resourceId,
|
int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey;
|
||||||
new RefcountedResource<TunnelInterfaceRecord>(
|
|
||||||
new TunnelInterfaceRecord(
|
mSrvConfig
|
||||||
resourceId,
|
.getNetdInstance()
|
||||||
intfName,
|
.ipSecAddSecurityPolicy(
|
||||||
underlyingNetwork,
|
0, // Use 0 for reqId
|
||||||
localAddr,
|
direction,
|
||||||
remoteAddr,
|
"",
|
||||||
ikey,
|
"",
|
||||||
okey),
|
0,
|
||||||
binder));
|
mark,
|
||||||
return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
|
0xffffffff);
|
||||||
|
}
|
||||||
|
|
||||||
|
userRecord.mTunnelInterfaceRecords.put(
|
||||||
|
resourceId,
|
||||||
|
new RefcountedResource<TunnelInterfaceRecord>(
|
||||||
|
new TunnelInterfaceRecord(
|
||||||
|
resourceId,
|
||||||
|
intfName,
|
||||||
|
underlyingNetwork,
|
||||||
|
localAddr,
|
||||||
|
remoteAddr,
|
||||||
|
ikey,
|
||||||
|
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,12 +1437,50 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createOrUpdateTransform(
|
||||||
|
IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord)
|
||||||
|
throws RemoteException {
|
||||||
|
|
||||||
|
int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0;
|
||||||
|
if (encapType != IpSecTransform.ENCAP_NONE) {
|
||||||
|
encapLocalPort = socketRecord.getPort();
|
||||||
|
encapRemotePort = c.getEncapRemotePort();
|
||||||
|
}
|
||||||
|
|
||||||
|
IpSecAlgorithm auth = c.getAuthentication();
|
||||||
|
IpSecAlgorithm crypt = c.getEncryption();
|
||||||
|
IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
|
||||||
|
|
||||||
|
mSrvConfig
|
||||||
|
.getNetdInstance()
|
||||||
|
.ipSecAddSecurityAssociation(
|
||||||
|
resourceId,
|
||||||
|
c.getMode(),
|
||||||
|
c.getSourceAddress(),
|
||||||
|
c.getDestinationAddress(),
|
||||||
|
(c.getNetwork() != null) ? c.getNetwork().netId : 0,
|
||||||
|
spiRecord.getSpi(),
|
||||||
|
c.getMarkValue(),
|
||||||
|
c.getMarkMask(),
|
||||||
|
(auth != null) ? auth.getName() : "",
|
||||||
|
(auth != null) ? auth.getKey() : new byte[] {},
|
||||||
|
(auth != null) ? auth.getTruncationLengthBits() : 0,
|
||||||
|
(crypt != null) ? crypt.getName() : "",
|
||||||
|
(crypt != null) ? crypt.getKey() : new byte[] {},
|
||||||
|
(crypt != null) ? crypt.getTruncationLengthBits() : 0,
|
||||||
|
(authCrypt != null) ? authCrypt.getName() : "",
|
||||||
|
(authCrypt != null) ? authCrypt.getKey() : new byte[] {},
|
||||||
|
(authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
|
||||||
|
encapType,
|
||||||
|
encapLocalPort,
|
||||||
|
encapRemotePort);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a transport mode transform, which represent two security associations (one in each
|
* Create a IPsec transform, which represents a single security association in the kernel. The
|
||||||
* direction) in the kernel. The transform will be cached by the system server and must be freed
|
* transform will be cached by the system server and must be freed when no longer needed. It is
|
||||||
* when no longer needed. It is possible to free one, deleting the SA from underneath sockets
|
* possible to free one, deleting the SA from underneath sockets that are using it, which will
|
||||||
* that are using it, which will result in all of those sockets becoming unable to send or
|
* result in all of those sockets becoming unable to send or receive data.
|
||||||
* receive data.
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
|
public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder)
|
||||||
@@ -1402,58 +1496,28 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
|
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int encapType, encapLocalPort = 0, encapRemotePort = 0;
|
|
||||||
EncapSocketRecord socketRecord = null;
|
EncapSocketRecord socketRecord = null;
|
||||||
encapType = c.getEncapType();
|
if (c.getEncapType() != IpSecTransform.ENCAP_NONE) {
|
||||||
if (encapType != IpSecTransform.ENCAP_NONE) {
|
|
||||||
RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
|
RefcountedResource<EncapSocketRecord> refcountedSocketRecord =
|
||||||
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
|
userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(
|
||||||
c.getEncapSocketResourceId());
|
c.getEncapSocketResourceId());
|
||||||
dependencies.add(refcountedSocketRecord);
|
dependencies.add(refcountedSocketRecord);
|
||||||
|
|
||||||
socketRecord = refcountedSocketRecord.getResource();
|
socketRecord = refcountedSocketRecord.getResource();
|
||||||
encapLocalPort = socketRecord.getPort();
|
|
||||||
encapRemotePort = c.getEncapRemotePort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IpSecAlgorithm auth = c.getAuthentication();
|
|
||||||
IpSecAlgorithm crypt = c.getEncryption();
|
|
||||||
IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption();
|
|
||||||
|
|
||||||
RefcountedResource<SpiRecord> refcountedSpiRecord =
|
RefcountedResource<SpiRecord> refcountedSpiRecord =
|
||||||
userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
|
userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId());
|
||||||
dependencies.add(refcountedSpiRecord);
|
dependencies.add(refcountedSpiRecord);
|
||||||
SpiRecord spiRecord = refcountedSpiRecord.getResource();
|
SpiRecord spiRecord = refcountedSpiRecord.getResource();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mSrvConfig
|
createOrUpdateTransform(c, resourceId, spiRecord, socketRecord);
|
||||||
.getNetdInstance()
|
|
||||||
.ipSecAddSecurityAssociation(
|
|
||||||
resourceId,
|
|
||||||
c.getMode(),
|
|
||||||
c.getSourceAddress(),
|
|
||||||
c.getDestinationAddress(),
|
|
||||||
(c.getNetwork() != null) ? c.getNetwork().netId : 0,
|
|
||||||
spiRecord.getSpi(),
|
|
||||||
c.getMarkValue(),
|
|
||||||
c.getMarkMask(),
|
|
||||||
(auth != null) ? auth.getName() : "",
|
|
||||||
(auth != null) ? auth.getKey() : new byte[] {},
|
|
||||||
(auth != null) ? auth.getTruncationLengthBits() : 0,
|
|
||||||
(crypt != null) ? crypt.getName() : "",
|
|
||||||
(crypt != null) ? crypt.getKey() : new byte[] {},
|
|
||||||
(crypt != null) ? crypt.getTruncationLengthBits() : 0,
|
|
||||||
(authCrypt != null) ? authCrypt.getName() : "",
|
|
||||||
(authCrypt != null) ? authCrypt.getKey() : new byte[] {},
|
|
||||||
(authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
|
|
||||||
encapType,
|
|
||||||
encapLocalPort,
|
|
||||||
encapRemotePort);
|
|
||||||
} catch (ServiceSpecificException e) {
|
} catch (ServiceSpecificException e) {
|
||||||
// FIXME: get the error code and throw is at an IOException from Errno Exception
|
// FIXME: get the error code and throw is at an IOException from Errno Exception
|
||||||
return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE);
|
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(
|
userRecord.mTransformRecords.put(
|
||||||
resourceId,
|
resourceId,
|
||||||
new RefcountedResource<TransformRecord>(
|
new RefcountedResource<TransformRecord>(
|
||||||
@@ -1561,14 +1625,48 @@ public class IpSecService extends IIpSecService.Stub {
|
|||||||
c.getMode() == IpSecTransform.MODE_TUNNEL,
|
c.getMode() == IpSecTransform.MODE_TUNNEL,
|
||||||
"Transform mode was not Tunnel mode; cannot be applied to a tunnel interface");
|
"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 =
|
int mark =
|
||||||
(direction == IpSecManager.DIRECTION_IN)
|
(direction == IpSecManager.DIRECTION_IN)
|
||||||
? tunnelInterfaceInfo.getIkey()
|
? tunnelInterfaceInfo.getIkey()
|
||||||
: tunnelInterfaceInfo.getOkey();
|
: tunnelInterfaceInfo.getOkey();
|
||||||
|
|
||||||
// TODO: Add calls to netd:
|
try {
|
||||||
// Update SA with tunnel mark (ikey or okey based on direction)
|
c.setMarkValue(mark);
|
||||||
// If outbound, add SPI to policy
|
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)
|
||||||
|
createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord);
|
||||||
|
} catch (ServiceSpecificException e) {
|
||||||
|
if (e.errorCode == EINVAL) {
|
||||||
|
throw new IllegalArgumentException(e.toString());
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user