OSDN Git Service

Add XFRM-I support to IpSecService
authorBenedict Wong <benedictwong@google.com>
Thu, 6 Sep 2018 18:31:25 +0000 (11:31 -0700)
committerBenedict Wong <benedictwong@google.com>
Wed, 21 Nov 2018 16:34:54 +0000 (08:34 -0800)
This change adds support for XFRM-I to all IpSecService netd calls.
Fallback logic is in netd, and thus both VTI and XFRM-I parameters are
always passed down to IpSecService.

Bug: 78589502
Test: All java, CTS tests passing
Change-Id: Ie4186f0ad7e50763b21831f6fa411b5ee436de78

core/java/android/net/IpSecConfig.java
services/core/java/com/android/server/IpSecService.java
tests/net/java/android/net/IpSecConfigTest.java
tests/net/java/com/android/server/IpSecServiceParameterizedTest.java

index c7eb2dd..3552655 100644 (file)
@@ -69,6 +69,9 @@ public final class IpSecConfig implements Parcelable {
     private int mMarkValue;
     private int mMarkMask;
 
+    // XFRM interface id
+    private int mXfrmInterfaceId;
+
     /** Set the mode for this IPsec transform */
     public void setMode(int mode) {
         mMode = mode;
@@ -145,6 +148,10 @@ public final class IpSecConfig implements Parcelable {
         mMarkMask = mask;
     }
 
+    public void setXfrmInterfaceId(int xfrmInterfaceId) {
+        mXfrmInterfaceId = xfrmInterfaceId;
+    }
+
     // Transport or Tunnel
     public int getMode() {
         return mMode;
@@ -202,6 +209,10 @@ public final class IpSecConfig implements Parcelable {
         return mMarkMask;
     }
 
+    public int getXfrmInterfaceId() {
+        return mXfrmInterfaceId;
+    }
+
     // Parcelable Methods
 
     @Override
@@ -225,6 +236,7 @@ public final class IpSecConfig implements Parcelable {
         out.writeInt(mNattKeepaliveInterval);
         out.writeInt(mMarkValue);
         out.writeInt(mMarkMask);
+        out.writeInt(mXfrmInterfaceId);
     }
 
     @VisibleForTesting
@@ -247,6 +259,7 @@ public final class IpSecConfig implements Parcelable {
         mNattKeepaliveInterval = c.mNattKeepaliveInterval;
         mMarkValue = c.mMarkValue;
         mMarkMask = c.mMarkMask;
+        mXfrmInterfaceId = c.mXfrmInterfaceId;
     }
 
     private IpSecConfig(Parcel in) {
@@ -267,6 +280,7 @@ public final class IpSecConfig implements Parcelable {
         mNattKeepaliveInterval = in.readInt();
         mMarkValue = in.readInt();
         mMarkMask = in.readInt();
+        mXfrmInterfaceId = in.readInt();
     }
 
     @Override
@@ -301,6 +315,8 @@ public final class IpSecConfig implements Parcelable {
                 .append(mMarkValue)
                 .append(", mMarkMask=")
                 .append(mMarkMask)
+                .append(", mXfrmInterfaceId=")
+                .append(mXfrmInterfaceId)
                 .append("}");
 
         return strBuilder.toString();
@@ -332,10 +348,10 @@ public final class IpSecConfig implements Parcelable {
                 && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval
                 && lhs.mSpiResourceId == rhs.mSpiResourceId
                 && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption)
-                && IpSecAlgorithm.equals(
-                        lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
+                && IpSecAlgorithm.equals(lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption)
                 && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)
                 && lhs.mMarkValue == rhs.mMarkValue
-                && lhs.mMarkMask == rhs.mMarkMask);
+                && lhs.mMarkMask == rhs.mMarkMask
+                && lhs.mXfrmInterfaceId == rhs.mXfrmInterfaceId);
     }
 }
index c4b7490..71a7a2b 100644 (file)
@@ -622,7 +622,8 @@ public class IpSecService extends IIpSecService.Stub {
                                 mConfig.getDestinationAddress(),
                                 spi,
                                 mConfig.getMarkValue(),
-                                mConfig.getMarkMask());
+                                mConfig.getMarkMask(),
+                                mConfig.getXfrmInterfaceId());
             } catch (RemoteException | ServiceSpecificException e) {
                 Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e);
             }
@@ -684,7 +685,8 @@ public class IpSecService extends IIpSecService.Stub {
                     mSrvConfig
                             .getNetdInstance()
                             .ipSecDeleteSecurityAssociation(
-                                    uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0);
+                                    uid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */,
+                                    0 /* mask */, 0 /* if_id */);
                 }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e);
@@ -796,6 +798,8 @@ public class IpSecService extends IIpSecService.Stub {
         private final int mIkey;
         private final int mOkey;
 
+        private final int mIfId;
+
         TunnelInterfaceRecord(
                 int resourceId,
                 String interfaceName,
@@ -803,7 +807,8 @@ public class IpSecService extends IIpSecService.Stub {
                 String localAddr,
                 String remoteAddr,
                 int ikey,
-                int okey) {
+                int okey,
+                int intfId) {
             super(resourceId);
 
             mInterfaceName = interfaceName;
@@ -812,6 +817,7 @@ public class IpSecService extends IIpSecService.Stub {
             mRemoteAddress = remoteAddr;
             mIkey = ikey;
             mOkey = okey;
+            mIfId = intfId;
         }
 
         /** always guarded by IpSecService#this */
@@ -822,7 +828,7 @@ public class IpSecService extends IIpSecService.Stub {
             //       Delete global policies
             try {
                 final INetd netd = mSrvConfig.getNetdInstance();
-                netd.removeVirtualTunnelInterface(mInterfaceName);
+                netd.ipSecRemoveTunnelInterface(mInterfaceName);
 
                 for (int selAddrFamily : ADDRESS_FAMILIES) {
                     netd.ipSecDeleteSecurityPolicy(
@@ -830,13 +836,15 @@ public class IpSecService extends IIpSecService.Stub {
                             selAddrFamily,
                             IpSecManager.DIRECTION_OUT,
                             mOkey,
-                            0xffffffff);
+                            0xffffffff,
+                            mIfId);
                     netd.ipSecDeleteSecurityPolicy(
                             uid,
                             selAddrFamily,
                             IpSecManager.DIRECTION_IN,
                             mIkey,
-                            0xffffffff);
+                            0xffffffff,
+                            mIfId);
                 }
             } catch (ServiceSpecificException | RemoteException e) {
                 Log.e(
@@ -878,6 +886,10 @@ public class IpSecService extends IIpSecService.Stub {
             return mOkey;
         }
 
+        public int getIfId() {
+            return mIfId;
+        }
+
         @Override
         protected ResourceTracker getResourceTracker() {
             return getUserRecord().mTunnelQuotaTracker;
@@ -1287,7 +1299,7 @@ public class IpSecService extends IIpSecService.Stub {
             //       Add inbound/outbound global policies
             //              (use reqid = 0)
             final INetd netd = mSrvConfig.getNetdInstance();
-            netd.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey);
+            netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId);
 
             for (int selAddrFamily : ADDRESS_FAMILIES) {
                 // Always send down correct local/remote addresses for template.
@@ -1299,7 +1311,8 @@ public class IpSecService extends IIpSecService.Stub {
                         remoteAddr,
                         0,
                         okey,
-                        0xffffffff);
+                        0xffffffff,
+                        resourceId);
                 netd.ipSecAddSecurityPolicy(
                         callerUid,
                         selAddrFamily,
@@ -1308,7 +1321,8 @@ public class IpSecService extends IIpSecService.Stub {
                         localAddr,
                         0,
                         ikey,
-                        0xffffffff);
+                        0xffffffff,
+                        resourceId);
             }
 
             userRecord.mTunnelInterfaceRecords.put(
@@ -1321,7 +1335,8 @@ public class IpSecService extends IIpSecService.Stub {
                                     localAddr,
                                     remoteAddr,
                                     ikey,
-                                    okey),
+                                    okey,
+                                    resourceId),
                             binder));
             return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName);
         } catch (RemoteException e) {
@@ -1588,7 +1603,8 @@ public class IpSecService extends IIpSecService.Stub {
                         (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0,
                         encapType,
                         encapLocalPort,
-                        encapRemotePort);
+                        encapRemotePort,
+                        c.getXfrmInterfaceId());
     }
 
     /**
@@ -1744,6 +1760,11 @@ public class IpSecService extends IIpSecService.Stub {
                         : tunnelInterfaceInfo.getIkey();
 
         try {
+            // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip
+            // SPI matching as part of the template resolution.
+            int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX;
+            c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId());
+
             // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream
             //     (and backporting) would allow us to narrow the mark space, and ensure that the SA
             //     and SPs have matching marks (as VTI are meant to be built).
@@ -1757,20 +1778,25 @@ public class IpSecService extends IIpSecService.Stub {
                 // Set output mark via underlying network (output only)
                 c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork());
 
-                // If outbound, also add SPI to the policy.
-                for (int selAddrFamily : ADDRESS_FAMILIES) {
-                    mSrvConfig
-                            .getNetdInstance()
-                            .ipSecUpdateSecurityPolicy(
-                                    callingUid,
-                                    selAddrFamily,
-                                    direction,
-                                    tunnelInterfaceInfo.getLocalAddress(),
-                                    tunnelInterfaceInfo.getRemoteAddress(),
-                                    transformInfo.getSpiRecord().getSpi(),
-                                    mark, // Must always set policy mark; ikey/okey for VTIs
-                                    0xffffffff);
-                }
+                // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys,
+                // but want to guarantee outbound packets are sent over the new SA.
+                spi = transformInfo.getSpiRecord().getSpi();
+            }
+
+            // Always update the policy with the relevant XFRM_IF_ID
+            for (int selAddrFamily : ADDRESS_FAMILIES) {
+                mSrvConfig
+                        .getNetdInstance()
+                        .ipSecUpdateSecurityPolicy(
+                                callingUid,
+                                selAddrFamily,
+                                direction,
+                                transformInfo.getConfig().getSourceAddress(),
+                                transformInfo.getConfig().getDestinationAddress(),
+                                spi, // If outbound, also add SPI to the policy.
+                                mark, // Must always set policy mark; ikey/okey for VTIs
+                                0xffffffff,
+                                c.getXfrmInterfaceId());
             }
 
             // Update SA with tunnel mark (ikey or okey based on direction)
index 771faaf..be1a455 100644 (file)
@@ -47,6 +47,7 @@ public class IpSecConfigTest {
         assertNull(c.getEncryption());
         assertNull(c.getAuthentication());
         assertEquals(IpSecManager.INVALID_RESOURCE_ID, c.getSpiResourceId());
+        assertEquals(0, c.getXfrmInterfaceId());
     }
 
     private IpSecConfig getSampleConfig() {
@@ -77,6 +78,7 @@ public class IpSecConfigTest {
         c.setNattKeepaliveInterval(42);
         c.setMarkValue(12);
         c.setMarkMask(23);
+        c.setXfrmInterfaceId(34);
 
         return c;
     }
index 9b919ab..4dc0341 100644 (file)
@@ -71,6 +71,9 @@ public class IpSecServiceParameterizedTest {
     private final LinkAddress mLocalInnerAddress;
     private final int mFamily;
 
+    private static final int[] ADDRESS_FAMILIES =
+            new int[] {AF_INET, AF_INET6};
+
     @Parameterized.Parameters
     public static Collection ipSecConfigs() {
         return Arrays.asList(
@@ -196,6 +199,7 @@ public class IpSecServiceParameterizedTest {
                         anyString(),
                         eq(TEST_SPI),
                         anyInt(),
+                        anyInt(),
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
@@ -231,6 +235,7 @@ public class IpSecServiceParameterizedTest {
                         anyString(),
                         eq(TEST_SPI),
                         anyInt(),
+                        anyInt(),
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
@@ -304,7 +309,8 @@ public class IpSecServiceParameterizedTest {
                         eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
                         eq(config.getEncapType()),
                         eq(encapSocketPort),
-                        eq(config.getEncapRemotePort()));
+                        eq(config.getEncapRemotePort()),
+                        eq(config.getXfrmInterfaceId()));
     }
 
     @Test
@@ -430,6 +436,7 @@ public class IpSecServiceParameterizedTest {
                         anyString(),
                         eq(TEST_SPI),
                         anyInt(),
+                        anyInt(),
                         anyInt());
         // quota is not released until the SPI is released by the Transform
         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
@@ -452,6 +459,7 @@ public class IpSecServiceParameterizedTest {
                         anyString(),
                         eq(TEST_SPI),
                         anyInt(),
+                        anyInt(),
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
@@ -469,6 +477,7 @@ public class IpSecServiceParameterizedTest {
                         anyString(),
                         anyInt(),
                         anyInt(),
+                        anyInt(),
                         anyInt());
         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
 
@@ -504,6 +513,7 @@ public class IpSecServiceParameterizedTest {
                         anyString(),
                         eq(TEST_SPI),
                         anyInt(),
+                        anyInt(),
                         anyInt());
 
         // Verify quota and RefcountedResource objects cleaned up
@@ -572,11 +582,12 @@ public class IpSecServiceParameterizedTest {
 
         assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
         verify(mMockNetd)
-                .addVirtualTunnelInterface(
+                .ipSecAddTunnelInterface(
                         eq(createTunnelResp.interfaceName),
                         eq(mSourceAddr),
                         eq(mDestinationAddr),
                         anyInt(),
+                        anyInt(),
                         anyInt());
     }
 
@@ -591,7 +602,7 @@ public class IpSecServiceParameterizedTest {
 
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
-        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+        verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
         try {
             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                     createTunnelResp.resourceId);
@@ -614,7 +625,7 @@ public class IpSecServiceParameterizedTest {
 
         // Verify quota and RefcountedResource objects cleaned up
         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
-        verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
+        verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
         try {
             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
                     createTunnelResp.resourceId);
@@ -624,6 +635,41 @@ public class IpSecServiceParameterizedTest {
     }
 
     @Test
+    public void testApplyTunnelModeTransform() throws Exception {
+        IpSecConfig ipSecConfig = new IpSecConfig();
+        ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
+        addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
+        addAuthAndCryptToIpSecConfig(ipSecConfig);
+
+        IpSecTransformResponse createTransformResp =
+                mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
+        IpSecTunnelInterfaceResponse createTunnelResp =
+                createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
+
+        int transformResourceId = createTransformResp.resourceId;
+        int tunnelResourceId = createTunnelResp.resourceId;
+        mIpSecService.applyTunnelModeTransform(tunnelResourceId, IpSecManager.DIRECTION_OUT,
+                transformResourceId, "blessedPackage");
+
+        for (int selAddrFamily : ADDRESS_FAMILIES) {
+            verify(mMockNetd)
+                    .ipSecUpdateSecurityPolicy(
+                            eq(mUid),
+                            eq(selAddrFamily),
+                            eq(IpSecManager.DIRECTION_OUT),
+                            anyString(),
+                            anyString(),
+                            eq(TEST_SPI),
+                            anyInt(), // iKey/oKey
+                            anyInt(), // mask
+                            eq(tunnelResourceId));
+        }
+
+        ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
+        verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
+    }
+
+    @Test
     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
         for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
             IpSecTunnelInterfaceResponse createTunnelResp =