Loading services/core/java/com/android/server/IpSecService.java +159 −61 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -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); Loading Loading @@ -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, Loading @@ -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); } /** Loading Loading @@ -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(); } Loading @@ -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( Loading @@ -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>( Loading Loading @@ -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 Loading tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +2 −3 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; Loading Loading @@ -229,7 +228,7 @@ public class IpSecServiceParameterizedTest { anyInt(), anyString(), anyString(), anyLong(), anyInt(), eq(TEST_SPI), anyInt(), anyInt(), Loading Loading @@ -264,7 +263,7 @@ public class IpSecServiceParameterizedTest { anyInt(), anyString(), anyString(), anyLong(), anyInt(), eq(TEST_SPI), anyInt(), anyInt(), Loading Loading
services/core/java/com/android/server/IpSecService.java +159 −61 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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() { Loading Loading @@ -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); Loading Loading @@ -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, Loading @@ -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); } /** Loading Loading @@ -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(); } Loading @@ -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( Loading @@ -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>( Loading Loading @@ -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 Loading
tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +2 −3 Original line number Diff line number Diff line Loading @@ -19,7 +19,6 @@ package com.android.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; Loading Loading @@ -229,7 +228,7 @@ public class IpSecServiceParameterizedTest { anyInt(), anyString(), anyString(), anyLong(), anyInt(), eq(TEST_SPI), anyInt(), anyInt(), Loading Loading @@ -264,7 +263,7 @@ public class IpSecServiceParameterizedTest { anyInt(), anyString(), anyString(), anyLong(), anyInt(), eq(TEST_SPI), anyInt(), anyInt(), Loading