1015 lines
42 KiB
Java
1015 lines
42 KiB
Java
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.server;
|
|
|
|
import static android.content.pm.PackageManager.PERMISSION_DENIED;
|
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
|
import static android.net.INetd.IF_STATE_DOWN;
|
|
import static android.net.INetd.IF_STATE_UP;
|
|
import static android.net.IpSecManager.DIRECTION_FWD;
|
|
import static android.net.IpSecManager.DIRECTION_IN;
|
|
import static android.net.IpSecManager.DIRECTION_OUT;
|
|
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
|
|
import static android.system.OsConstants.AF_INET;
|
|
import static android.system.OsConstants.AF_INET6;
|
|
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.fail;
|
|
import static org.mockito.ArgumentMatchers.argThat;
|
|
import static org.mockito.Matchers.anyInt;
|
|
import static org.mockito.Matchers.anyString;
|
|
import static org.mockito.Matchers.eq;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.times;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
import android.app.AppOpsManager;
|
|
import android.content.Context;
|
|
import android.content.pm.PackageManager;
|
|
import android.net.ConnectivityManager;
|
|
import android.net.INetd;
|
|
import android.net.InetAddresses;
|
|
import android.net.InterfaceConfigurationParcel;
|
|
import android.net.IpSecAlgorithm;
|
|
import android.net.IpSecConfig;
|
|
import android.net.IpSecManager;
|
|
import android.net.IpSecSpiResponse;
|
|
import android.net.IpSecTransform;
|
|
import android.net.IpSecTransformResponse;
|
|
import android.net.IpSecTunnelInterfaceResponse;
|
|
import android.net.IpSecUdpEncapResponse;
|
|
import android.net.LinkAddress;
|
|
import android.net.LinkProperties;
|
|
import android.net.Network;
|
|
import android.os.Binder;
|
|
import android.os.Build;
|
|
import android.os.ParcelFileDescriptor;
|
|
import android.os.RemoteException;
|
|
import android.system.Os;
|
|
import android.test.mock.MockContext;
|
|
import android.util.ArraySet;
|
|
|
|
import androidx.test.filters.SmallTest;
|
|
|
|
import com.android.server.IpSecService.TunnelInterfaceRecord;
|
|
import com.android.testutils.DevSdkIgnoreRule;
|
|
|
|
import org.junit.Before;
|
|
import org.junit.Ignore;
|
|
import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.runner.RunWith;
|
|
import org.junit.runners.Parameterized;
|
|
|
|
import java.net.Inet4Address;
|
|
import java.net.Socket;
|
|
import java.util.Arrays;
|
|
import java.util.Collection;
|
|
import java.util.Set;
|
|
|
|
/** Unit tests for {@link IpSecService}. */
|
|
@SmallTest
|
|
@RunWith(Parameterized.class)
|
|
public class IpSecServiceParameterizedTest {
|
|
@Rule
|
|
public final DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule(
|
|
Build.VERSION_CODES.R /* ignoreClassUpTo */);
|
|
|
|
private static final int TEST_SPI = 0xD1201D;
|
|
|
|
private final String mSourceAddr;
|
|
private final String mDestinationAddr;
|
|
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(
|
|
new Object[][] {
|
|
{"1.2.3.4", "8.8.4.4", "10.0.1.1/24", AF_INET},
|
|
{"2601::2", "2601::10", "2001:db8::1/64", AF_INET6}
|
|
});
|
|
}
|
|
|
|
private static final byte[] AEAD_KEY = {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
|
0x73, 0x61, 0x6C, 0x74
|
|
};
|
|
private static final byte[] CRYPT_KEY = {
|
|
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
|
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
|
|
};
|
|
private static final byte[] AUTH_KEY = {
|
|
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
|
|
0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
|
|
};
|
|
|
|
AppOpsManager mMockAppOps = mock(AppOpsManager.class);
|
|
ConnectivityManager mMockConnectivityMgr = mock(ConnectivityManager.class);
|
|
|
|
TestContext mTestContext = new TestContext();
|
|
|
|
private class TestContext extends MockContext {
|
|
private Set<String> mAllowedPermissions = new ArraySet<>(Arrays.asList(
|
|
android.Manifest.permission.MANAGE_IPSEC_TUNNELS,
|
|
android.Manifest.permission.NETWORK_STACK,
|
|
PERMISSION_MAINLINE_NETWORK_STACK));
|
|
|
|
private void setAllowedPermissions(String... permissions) {
|
|
mAllowedPermissions = new ArraySet<>(permissions);
|
|
}
|
|
|
|
@Override
|
|
public Object getSystemService(String name) {
|
|
switch(name) {
|
|
case Context.APP_OPS_SERVICE:
|
|
return mMockAppOps;
|
|
case Context.CONNECTIVITY_SERVICE:
|
|
return mMockConnectivityMgr;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String getSystemServiceName(Class<?> serviceClass) {
|
|
if (ConnectivityManager.class == serviceClass) {
|
|
return Context.CONNECTIVITY_SERVICE;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public PackageManager getPackageManager() {
|
|
return mMockPkgMgr;
|
|
}
|
|
|
|
@Override
|
|
public void enforceCallingOrSelfPermission(String permission, String message) {
|
|
if (mAllowedPermissions.contains(permission)) {
|
|
return;
|
|
} else {
|
|
throw new SecurityException("Unavailable permission requested");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public int checkCallingOrSelfPermission(String permission) {
|
|
if (mAllowedPermissions.contains(permission)) {
|
|
return PERMISSION_GRANTED;
|
|
} else {
|
|
return PERMISSION_DENIED;
|
|
}
|
|
}
|
|
}
|
|
|
|
private IpSecService.Dependencies makeDependencies() throws RemoteException {
|
|
final IpSecService.Dependencies deps = mock(IpSecService.Dependencies.class);
|
|
when(deps.getNetdInstance(mTestContext)).thenReturn(mMockNetd);
|
|
return deps;
|
|
}
|
|
|
|
INetd mMockNetd;
|
|
PackageManager mMockPkgMgr;
|
|
IpSecService.Dependencies mDeps;
|
|
IpSecService mIpSecService;
|
|
Network fakeNetwork = new Network(0xAB);
|
|
int mUid = Os.getuid();
|
|
|
|
private static final IpSecAlgorithm AUTH_ALGO =
|
|
new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
|
|
private static final IpSecAlgorithm CRYPT_ALGO =
|
|
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
|
|
private static final IpSecAlgorithm AEAD_ALGO =
|
|
new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
|
|
private static final int REMOTE_ENCAP_PORT = 4500;
|
|
|
|
private static final String BLESSED_PACKAGE = "blessedPackage";
|
|
private static final String SYSTEM_PACKAGE = "systemPackage";
|
|
private static final String BAD_PACKAGE = "badPackage";
|
|
|
|
public IpSecServiceParameterizedTest(
|
|
String sourceAddr, String destAddr, String localInnerAddr, int family) {
|
|
mSourceAddr = sourceAddr;
|
|
mDestinationAddr = destAddr;
|
|
mLocalInnerAddress = new LinkAddress(localInnerAddr);
|
|
mFamily = family;
|
|
}
|
|
|
|
@Before
|
|
public void setUp() throws Exception {
|
|
mMockNetd = mock(INetd.class);
|
|
mMockPkgMgr = mock(PackageManager.class);
|
|
mDeps = makeDependencies();
|
|
mIpSecService = new IpSecService(mTestContext, mDeps);
|
|
|
|
// PackageManager should always return true (feature flag tests in IpSecServiceTest)
|
|
when(mMockPkgMgr.hasSystemFeature(anyString())).thenReturn(true);
|
|
|
|
// A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
|
|
when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BLESSED_PACKAGE)))
|
|
.thenReturn(AppOpsManager.MODE_ALLOWED);
|
|
// A system package will not be granted the app op, so this should fall back to
|
|
// a permissions check, which should pass.
|
|
when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(SYSTEM_PACKAGE)))
|
|
.thenReturn(AppOpsManager.MODE_DEFAULT);
|
|
// A mismatch between the package name and the UID will return MODE_IGNORED.
|
|
when(mMockAppOps.noteOp(anyInt(), anyInt(), eq(BAD_PACKAGE)))
|
|
.thenReturn(AppOpsManager.MODE_IGNORED);
|
|
}
|
|
|
|
//TODO: Add a test to verify SPI.
|
|
|
|
@Test
|
|
public void testIpSecServiceReserveSpi() throws Exception {
|
|
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
|
|
.thenReturn(TEST_SPI);
|
|
|
|
IpSecSpiResponse spiResp =
|
|
mIpSecService.allocateSecurityParameterIndex(
|
|
mDestinationAddr, TEST_SPI, new Binder());
|
|
assertEquals(IpSecManager.Status.OK, spiResp.status);
|
|
assertEquals(TEST_SPI, spiResp.spi);
|
|
}
|
|
|
|
@Test
|
|
public void testReleaseSecurityParameterIndex() throws Exception {
|
|
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
|
|
.thenReturn(TEST_SPI);
|
|
|
|
IpSecSpiResponse spiResp =
|
|
mIpSecService.allocateSecurityParameterIndex(
|
|
mDestinationAddr, TEST_SPI, new Binder());
|
|
|
|
mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
|
|
|
|
verify(mMockNetd)
|
|
.ipSecDeleteSecurityAssociation(
|
|
eq(mUid),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
|
|
// Verify quota and RefcountedResource objects cleaned up
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
|
|
try {
|
|
userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
|
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
|
} catch (IllegalArgumentException expected) {
|
|
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testSecurityParameterIndexBinderDeath() throws Exception {
|
|
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
|
|
.thenReturn(TEST_SPI);
|
|
|
|
IpSecSpiResponse spiResp =
|
|
mIpSecService.allocateSecurityParameterIndex(
|
|
mDestinationAddr, TEST_SPI, new Binder());
|
|
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
IpSecService.RefcountedResource refcountedRecord =
|
|
userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
|
|
|
|
refcountedRecord.binderDied();
|
|
|
|
verify(mMockNetd)
|
|
.ipSecDeleteSecurityAssociation(
|
|
eq(mUid),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
|
|
// Verify quota and RefcountedResource objects cleaned up
|
|
assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
|
|
try {
|
|
userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
|
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
|
} catch (IllegalArgumentException expected) {
|
|
|
|
}
|
|
}
|
|
|
|
private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
|
|
when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
|
|
.thenReturn(returnSpi);
|
|
|
|
IpSecSpiResponse spi =
|
|
mIpSecService.allocateSecurityParameterIndex(
|
|
InetAddresses.parseNumericAddress(remoteAddress).getHostAddress(),
|
|
IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
|
|
new Binder());
|
|
return spi.resourceId;
|
|
}
|
|
|
|
private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
|
|
config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
|
|
config.setSourceAddress(mSourceAddr);
|
|
config.setDestinationAddress(mDestinationAddr);
|
|
}
|
|
|
|
private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
|
|
config.setEncryption(CRYPT_ALGO);
|
|
config.setAuthentication(AUTH_ALGO);
|
|
}
|
|
|
|
private void addEncapSocketToIpSecConfig(int resourceId, IpSecConfig config) throws Exception {
|
|
config.setEncapType(IpSecTransform.ENCAP_ESPINUDP);
|
|
config.setEncapSocketResourceId(resourceId);
|
|
config.setEncapRemotePort(REMOTE_ENCAP_PORT);
|
|
}
|
|
|
|
private void verifyTransformNetdCalledForCreatingSA(
|
|
IpSecConfig config, IpSecTransformResponse resp) throws Exception {
|
|
verifyTransformNetdCalledForCreatingSA(config, resp, 0);
|
|
}
|
|
|
|
private void verifyTransformNetdCalledForCreatingSA(
|
|
IpSecConfig config, IpSecTransformResponse resp, int encapSocketPort) throws Exception {
|
|
IpSecAlgorithm auth = config.getAuthentication();
|
|
IpSecAlgorithm crypt = config.getEncryption();
|
|
IpSecAlgorithm authCrypt = config.getAuthenticatedEncryption();
|
|
|
|
verify(mMockNetd, times(1))
|
|
.ipSecAddSecurityAssociation(
|
|
eq(mUid),
|
|
eq(config.getMode()),
|
|
eq(config.getSourceAddress()),
|
|
eq(config.getDestinationAddress()),
|
|
eq((config.getNetwork() != null) ? config.getNetwork().netId : 0),
|
|
eq(TEST_SPI),
|
|
eq(0),
|
|
eq(0),
|
|
eq((auth != null) ? auth.getName() : ""),
|
|
eq((auth != null) ? auth.getKey() : new byte[] {}),
|
|
eq((auth != null) ? auth.getTruncationLengthBits() : 0),
|
|
eq((crypt != null) ? crypt.getName() : ""),
|
|
eq((crypt != null) ? crypt.getKey() : new byte[] {}),
|
|
eq((crypt != null) ? crypt.getTruncationLengthBits() : 0),
|
|
eq((authCrypt != null) ? authCrypt.getName() : ""),
|
|
eq((authCrypt != null) ? authCrypt.getKey() : new byte[] {}),
|
|
eq((authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0),
|
|
eq(config.getEncapType()),
|
|
eq(encapSocketPort),
|
|
eq(config.getEncapRemotePort()),
|
|
eq(config.getXfrmInterfaceId()));
|
|
}
|
|
|
|
@Test
|
|
public void testCreateTransform() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
|
|
|
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
|
|
}
|
|
|
|
@Test
|
|
public void testCreateTransformAead() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
|
|
ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
|
|
|
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
|
|
}
|
|
|
|
@Test
|
|
public void testCreateTransportModeTransformWithEncap() throws Exception {
|
|
IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
|
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
ipSecConfig.setMode(IpSecTransform.MODE_TRANSPORT);
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
|
|
|
|
if (mFamily == AF_INET) {
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
|
|
|
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
|
|
} else {
|
|
try {
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testCreateTunnelModeTransformWithEncap() throws Exception {
|
|
IpSecUdpEncapResponse udpSock = mIpSecService.openUdpEncapsulationSocket(0, new Binder());
|
|
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
addEncapSocketToIpSecConfig(udpSock.resourceId, ipSecConfig);
|
|
|
|
if (mFamily == AF_INET) {
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
|
|
|
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp, udpSock.port);
|
|
} else {
|
|
try {
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
fail("Expected IllegalArgumentException on attempt to use UDP Encap in IPv6");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testCreateTwoTransformsWithSameSpis() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
assertEquals(IpSecManager.Status.OK, createTransformResp.status);
|
|
|
|
// Attempting to create transform a second time with the same SPIs should throw an error...
|
|
try {
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
fail("IpSecService should have thrown an error for reuse of SPI");
|
|
} catch (IllegalStateException expected) {
|
|
}
|
|
|
|
// ... even if the transform is deleted
|
|
mIpSecService.deleteTransform(createTransformResp.resourceId);
|
|
try {
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
fail("IpSecService should have thrown an error for reuse of SPI");
|
|
} catch (IllegalStateException expected) {
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testReleaseOwnedSpi() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
|
|
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
|
|
verify(mMockNetd, times(0))
|
|
.ipSecDeleteSecurityAssociation(
|
|
eq(mUid),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
// quota is not released until the SPI is released by the Transform
|
|
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
|
|
}
|
|
|
|
@Test
|
|
public void testDeleteTransform() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
mIpSecService.deleteTransform(createTransformResp.resourceId);
|
|
|
|
verify(mMockNetd, times(1))
|
|
.ipSecDeleteSecurityAssociation(
|
|
eq(mUid),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
|
|
// Verify quota and RefcountedResource objects cleaned up
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
|
|
assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
|
|
|
|
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
|
|
// Verify that ipSecDeleteSa was not called when the SPI was released because the
|
|
// ownedByTransform property should prevent it; (note, the called count is cumulative).
|
|
verify(mMockNetd, times(1))
|
|
.ipSecDeleteSecurityAssociation(
|
|
anyInt(),
|
|
anyString(),
|
|
anyString(),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
|
|
|
|
try {
|
|
userRecord.mTransformRecords.getRefcountedResourceOrThrow(
|
|
createTransformResp.resourceId);
|
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
|
} catch (IllegalArgumentException expected) {
|
|
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testTransportModeTransformBinderDeath() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
IpSecService.RefcountedResource refcountedRecord =
|
|
userRecord.mTransformRecords.getRefcountedResourceOrThrow(
|
|
createTransformResp.resourceId);
|
|
|
|
refcountedRecord.binderDied();
|
|
|
|
verify(mMockNetd)
|
|
.ipSecDeleteSecurityAssociation(
|
|
eq(mUid),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
|
|
// Verify quota and RefcountedResource objects cleaned up
|
|
assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
|
|
try {
|
|
userRecord.mTransformRecords.getRefcountedResourceOrThrow(
|
|
createTransformResp.resourceId);
|
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
|
} catch (IllegalArgumentException expected) {
|
|
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTransportModeTransform() throws Exception {
|
|
verifyApplyTransportModeTransformCommon(false);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTransportModeTransformReleasedSpi() throws Exception {
|
|
verifyApplyTransportModeTransformCommon(true);
|
|
}
|
|
|
|
public void verifyApplyTransportModeTransformCommon(
|
|
boolean closeSpiBeforeApply) throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
|
|
if (closeSpiBeforeApply) {
|
|
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
|
|
}
|
|
|
|
Socket socket = new Socket();
|
|
socket.bind(null);
|
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
|
|
|
|
int resourceId = createTransformResp.resourceId;
|
|
mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
|
|
|
|
verify(mMockNetd)
|
|
.ipSecApplyTransportModeTransform(
|
|
eq(pfd),
|
|
eq(mUid),
|
|
eq(IpSecManager.DIRECTION_OUT),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI));
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTransportModeTransformWithClosedSpi() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
|
|
// Close SPI record
|
|
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
|
|
|
|
Socket socket = new Socket();
|
|
socket.bind(null);
|
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
|
|
|
|
int resourceId = createTransformResp.resourceId;
|
|
mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
|
|
|
|
verify(mMockNetd)
|
|
.ipSecApplyTransportModeTransform(
|
|
eq(pfd),
|
|
eq(mUid),
|
|
eq(IpSecManager.DIRECTION_OUT),
|
|
anyString(),
|
|
anyString(),
|
|
eq(TEST_SPI));
|
|
}
|
|
|
|
@Test
|
|
public void testRemoveTransportModeTransform() throws Exception {
|
|
Socket socket = new Socket();
|
|
socket.bind(null);
|
|
ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket);
|
|
mIpSecService.removeTransportModeTransforms(pfd);
|
|
|
|
verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd);
|
|
}
|
|
|
|
private IpSecTunnelInterfaceResponse createAndValidateTunnel(
|
|
String localAddr, String remoteAddr, String pkgName) throws Exception {
|
|
final InterfaceConfigurationParcel config = new InterfaceConfigurationParcel();
|
|
config.flags = new String[] {IF_STATE_DOWN};
|
|
when(mMockNetd.interfaceGetCfg(anyString())).thenReturn(config);
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
mIpSecService.createTunnelInterface(
|
|
mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
|
|
|
|
assertNotNull(createTunnelResp);
|
|
assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
|
|
for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT, DIRECTION_FWD}) {
|
|
for (int selAddrFamily : ADDRESS_FAMILIES) {
|
|
verify(mMockNetd).ipSecAddSecurityPolicy(
|
|
eq(mUid),
|
|
eq(selAddrFamily),
|
|
eq(direction),
|
|
anyString(),
|
|
anyString(),
|
|
eq(0),
|
|
anyInt(), // iKey/oKey
|
|
anyInt(), // mask
|
|
eq(createTunnelResp.resourceId));
|
|
}
|
|
}
|
|
|
|
return createTunnelResp;
|
|
}
|
|
|
|
@Test
|
|
public void testCreateTunnelInterface() throws Exception {
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
|
|
// Check that we have stored the tracking object, and retrieve it
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
IpSecService.RefcountedResource refcountedRecord =
|
|
userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
|
|
createTunnelResp.resourceId);
|
|
|
|
assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
|
|
verify(mMockNetd)
|
|
.ipSecAddTunnelInterface(
|
|
eq(createTunnelResp.interfaceName),
|
|
eq(mSourceAddr),
|
|
eq(mDestinationAddr),
|
|
anyInt(),
|
|
anyInt(),
|
|
anyInt());
|
|
verify(mMockNetd).interfaceSetCfg(argThat(
|
|
config -> Arrays.asList(config.flags).contains(IF_STATE_UP)));
|
|
}
|
|
|
|
@Test
|
|
public void testDeleteTunnelInterface() throws Exception {
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
|
|
mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, BLESSED_PACKAGE);
|
|
|
|
// Verify quota and RefcountedResource objects cleaned up
|
|
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
|
|
verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
|
|
try {
|
|
userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
|
|
createTunnelResp.resourceId);
|
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
|
|
private Network createFakeUnderlyingNetwork(String interfaceName) {
|
|
final Network fakeNetwork = new Network(1000);
|
|
final LinkProperties fakeLp = new LinkProperties();
|
|
fakeLp.setInterfaceName(interfaceName);
|
|
when(mMockConnectivityMgr.getLinkProperties(eq(fakeNetwork))).thenReturn(fakeLp);
|
|
return fakeNetwork;
|
|
}
|
|
|
|
@Test
|
|
public void testSetNetworkForTunnelInterface() throws Exception {
|
|
final IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
final Network newFakeNetwork = createFakeUnderlyingNetwork("newFakeNetworkInterface");
|
|
final int tunnelIfaceResourceId = createTunnelResp.resourceId;
|
|
mIpSecService.setNetworkForTunnelInterface(
|
|
tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
|
|
|
|
final IpSecService.UserRecord userRecord =
|
|
mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
|
|
|
|
final TunnelInterfaceRecord tunnelInterfaceInfo =
|
|
userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
|
|
assertEquals(newFakeNetwork, tunnelInterfaceInfo.getUnderlyingNetwork());
|
|
}
|
|
|
|
@Test
|
|
public void testSetNetworkForTunnelInterfaceFailsForInvalidResourceId() throws Exception {
|
|
final IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
final Network newFakeNetwork = new Network(1000);
|
|
|
|
try {
|
|
mIpSecService.setNetworkForTunnelInterface(
|
|
IpSecManager.INVALID_RESOURCE_ID, newFakeNetwork, BLESSED_PACKAGE);
|
|
fail("Expected an IllegalArgumentException for invalid resource ID.");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testSetNetworkForTunnelInterfaceFailsWhenSettingTunnelNetwork() throws Exception {
|
|
final IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
final int tunnelIfaceResourceId = createTunnelResp.resourceId;
|
|
final IpSecService.UserRecord userRecord =
|
|
mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
final TunnelInterfaceRecord tunnelInterfaceInfo =
|
|
userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelIfaceResourceId);
|
|
|
|
final Network newFakeNetwork =
|
|
createFakeUnderlyingNetwork(tunnelInterfaceInfo.getInterfaceName());
|
|
|
|
try {
|
|
mIpSecService.setNetworkForTunnelInterface(
|
|
tunnelIfaceResourceId, newFakeNetwork, BLESSED_PACKAGE);
|
|
fail(
|
|
"Expected an IllegalArgumentException because the underlying network is the"
|
|
+ " network being exposed by this tunnel.");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testTunnelInterfaceBinderDeath() throws Exception {
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
|
|
IpSecService.UserRecord userRecord = mIpSecService.mUserResourceTracker.getUserRecord(mUid);
|
|
IpSecService.RefcountedResource refcountedRecord =
|
|
userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
|
|
createTunnelResp.resourceId);
|
|
|
|
refcountedRecord.binderDied();
|
|
|
|
// Verify quota and RefcountedResource objects cleaned up
|
|
assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
|
|
verify(mMockNetd).ipSecRemoveTunnelInterface(eq(createTunnelResp.interfaceName));
|
|
try {
|
|
userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
|
|
createTunnelResp.resourceId);
|
|
fail("Expected IllegalArgumentException on attempt to access deleted resource");
|
|
} catch (IllegalArgumentException expected) {
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformOutbound() throws Exception {
|
|
verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformOutboundNonNetworkStack() throws Exception {
|
|
mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
|
|
verifyApplyTunnelModeTransformCommon(false /* closeSpiBeforeApply */, DIRECTION_OUT);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformOutboundReleasedSpi() throws Exception {
|
|
verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_OUT);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformInbound() throws Exception {
|
|
verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformInboundNonNetworkStack() throws Exception {
|
|
mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
|
|
verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_IN);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformForward() throws Exception {
|
|
verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
|
|
}
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformForwardNonNetworkStack() throws Exception {
|
|
mTestContext.setAllowedPermissions(android.Manifest.permission.MANAGE_IPSEC_TUNNELS);
|
|
|
|
try {
|
|
verifyApplyTunnelModeTransformCommon(true /* closeSpiBeforeApply */, DIRECTION_FWD);
|
|
fail("Expected security exception due to use of forward policies without NETWORK_STACK"
|
|
+ " or MAINLINE_NETWORK_STACK permission");
|
|
} catch (SecurityException expected) {
|
|
}
|
|
}
|
|
|
|
public void verifyApplyTunnelModeTransformCommon(boolean closeSpiBeforeApply, int direction)
|
|
throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
|
|
if (closeSpiBeforeApply) {
|
|
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
|
|
}
|
|
|
|
int transformResourceId = createTransformResp.resourceId;
|
|
int tunnelResourceId = createTunnelResp.resourceId;
|
|
mIpSecService.applyTunnelModeTransform(
|
|
tunnelResourceId, direction, transformResourceId, BLESSED_PACKAGE);
|
|
|
|
for (int selAddrFamily : ADDRESS_FAMILIES) {
|
|
verify(mMockNetd)
|
|
.ipSecUpdateSecurityPolicy(
|
|
eq(mUid),
|
|
eq(selAddrFamily),
|
|
eq(direction),
|
|
anyString(),
|
|
anyString(),
|
|
eq(direction == DIRECTION_OUT ? TEST_SPI : 0),
|
|
anyInt(), // iKey/oKey
|
|
anyInt(), // mask
|
|
eq(tunnelResourceId));
|
|
}
|
|
|
|
ipSecConfig.setXfrmInterfaceId(tunnelResourceId);
|
|
verifyTransformNetdCalledForCreatingSA(ipSecConfig, createTransformResp);
|
|
}
|
|
|
|
|
|
@Test
|
|
public void testApplyTunnelModeTransformWithClosedSpi() throws Exception {
|
|
IpSecConfig ipSecConfig = new IpSecConfig();
|
|
ipSecConfig.setMode(IpSecTransform.MODE_TUNNEL);
|
|
addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
|
|
addAuthAndCryptToIpSecConfig(ipSecConfig);
|
|
|
|
IpSecTransformResponse createTransformResp =
|
|
mIpSecService.createTransform(ipSecConfig, new Binder(), BLESSED_PACKAGE);
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BLESSED_PACKAGE);
|
|
|
|
// Close SPI record
|
|
mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
|
|
|
|
int transformResourceId = createTransformResp.resourceId;
|
|
int tunnelResourceId = createTunnelResp.resourceId;
|
|
mIpSecService.applyTunnelModeTransform(
|
|
tunnelResourceId, IpSecManager.DIRECTION_OUT, transformResourceId, BLESSED_PACKAGE);
|
|
|
|
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[] {BLESSED_PACKAGE, SYSTEM_PACKAGE}) {
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
|
|
mIpSecService.addAddressToTunnelInterface(
|
|
createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
|
|
verify(mMockNetd, times(1))
|
|
.interfaceAddAddress(
|
|
eq(createTunnelResp.interfaceName),
|
|
eq(mLocalInnerAddress.getAddress().getHostAddress()),
|
|
eq(mLocalInnerAddress.getPrefixLength()));
|
|
mIpSecService.removeAddressFromTunnelInterface(
|
|
createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
|
|
verify(mMockNetd, times(1))
|
|
.interfaceDelAddress(
|
|
eq(createTunnelResp.interfaceName),
|
|
eq(mLocalInnerAddress.getAddress().getHostAddress()),
|
|
eq(mLocalInnerAddress.getPrefixLength()));
|
|
mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
|
|
}
|
|
}
|
|
|
|
@Ignore
|
|
@Test
|
|
public void testAddTunnelFailsForBadPackageName() throws Exception {
|
|
try {
|
|
IpSecTunnelInterfaceResponse createTunnelResp =
|
|
createAndValidateTunnel(mSourceAddr, mDestinationAddr, BAD_PACKAGE);
|
|
fail("Expected a SecurityException for badPackage.");
|
|
} catch (SecurityException expected) {
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testFeatureFlagVerification() throws Exception {
|
|
when(mMockPkgMgr.hasSystemFeature(eq(PackageManager.FEATURE_IPSEC_TUNNELS)))
|
|
.thenReturn(false);
|
|
|
|
try {
|
|
String addr = Inet4Address.getLoopbackAddress().getHostAddress();
|
|
mIpSecService.createTunnelInterface(
|
|
addr, addr, new Network(0), new Binder(), BLESSED_PACKAGE);
|
|
fail("Expected UnsupportedOperationException for disabled feature");
|
|
} catch (UnsupportedOperationException expected) {
|
|
}
|
|
}
|
|
}
|