Home | History | Annotate | Download | only in server
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.junit.Assert.assertNotNull;
     21 import static org.junit.Assert.fail;
     22 import static org.mockito.Matchers.anyInt;
     23 import static org.mockito.Matchers.anyString;
     24 import static org.mockito.Matchers.eq;
     25 import static org.mockito.Mockito.mock;
     26 import static org.mockito.Mockito.times;
     27 import static org.mockito.Mockito.verify;
     28 import static org.mockito.Mockito.when;
     29 
     30 import android.app.AppOpsManager;
     31 import android.content.Context;
     32 import android.net.INetd;
     33 import android.net.IpSecAlgorithm;
     34 import android.net.IpSecConfig;
     35 import android.net.IpSecManager;
     36 import android.net.IpSecSpiResponse;
     37 import android.net.IpSecTransformResponse;
     38 import android.net.IpSecTunnelInterfaceResponse;
     39 import android.net.LinkAddress;
     40 import android.net.Network;
     41 import android.net.NetworkUtils;
     42 import android.os.Binder;
     43 import android.os.ParcelFileDescriptor;
     44 import android.test.mock.MockContext;
     45 import android.support.test.filters.SmallTest;
     46 import android.system.Os;
     47 
     48 import java.net.Socket;
     49 import java.util.Arrays;
     50 import java.util.Collection;
     51 
     52 import org.junit.Before;
     53 import org.junit.Test;
     54 import org.junit.runner.RunWith;
     55 import org.junit.runners.Parameterized;
     56 
     57 /** Unit tests for {@link IpSecService}. */
     58 @SmallTest
     59 @RunWith(Parameterized.class)
     60 public class IpSecServiceParameterizedTest {
     61 
     62     private static final int TEST_SPI = 0xD1201D;
     63 
     64     private final String mDestinationAddr;
     65     private final String mSourceAddr;
     66     private final LinkAddress mLocalInnerAddress;
     67 
     68     @Parameterized.Parameters
     69     public static Collection ipSecConfigs() {
     70         return Arrays.asList(
     71                 new Object[][] {
     72                 {"1.2.3.4", "8.8.4.4", "10.0.1.1/24"},
     73                 {"2601::2", "2601::10", "2001:db8::1/64"}
     74         });
     75     }
     76 
     77     private static final byte[] AEAD_KEY = {
     78         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     79         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
     80         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     81         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
     82         0x73, 0x61, 0x6C, 0x74
     83     };
     84     private static final byte[] CRYPT_KEY = {
     85         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
     86         0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
     87         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
     88         0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
     89     };
     90     private static final byte[] AUTH_KEY = {
     91         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     92         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
     93         0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     94         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F
     95     };
     96 
     97     AppOpsManager mMockAppOps = mock(AppOpsManager.class);
     98 
     99     MockContext mMockContext = new MockContext() {
    100         @Override
    101         public Object getSystemService(String name) {
    102             switch(name) {
    103                 case Context.APP_OPS_SERVICE:
    104                     return mMockAppOps;
    105                 default:
    106                     return null;
    107             }
    108         }
    109 
    110         @Override
    111         public void enforceCallingOrSelfPermission(String permission, String message) {
    112             if (permission == android.Manifest.permission.MANAGE_IPSEC_TUNNELS) {
    113                 return;
    114             }
    115             throw new SecurityException("Unavailable permission requested");
    116         }
    117     };
    118 
    119     INetd mMockNetd;
    120     IpSecService.IpSecServiceConfiguration mMockIpSecSrvConfig;
    121     IpSecService mIpSecService;
    122     Network fakeNetwork = new Network(0xAB);
    123 
    124     private static final IpSecAlgorithm AUTH_ALGO =
    125             new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4);
    126     private static final IpSecAlgorithm CRYPT_ALGO =
    127             new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
    128     private static final IpSecAlgorithm AEAD_ALGO =
    129             new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
    130 
    131     public IpSecServiceParameterizedTest(
    132             String sourceAddr, String destAddr, String localInnerAddr) {
    133         mSourceAddr = sourceAddr;
    134         mDestinationAddr = destAddr;
    135         mLocalInnerAddress = new LinkAddress(localInnerAddr);
    136     }
    137 
    138     @Before
    139     public void setUp() throws Exception {
    140         mMockNetd = mock(INetd.class);
    141         mMockIpSecSrvConfig = mock(IpSecService.IpSecServiceConfiguration.class);
    142         mIpSecService = new IpSecService(mMockContext, mMockIpSecSrvConfig);
    143 
    144         // Injecting mock netd
    145         when(mMockIpSecSrvConfig.getNetdInstance()).thenReturn(mMockNetd);
    146         // A package granted the AppOp for MANAGE_IPSEC_TUNNELS will be MODE_ALLOWED.
    147         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("blessedPackage")))
    148             .thenReturn(AppOpsManager.MODE_ALLOWED);
    149         // A system package will not be granted the app op, so this should fall back to
    150         // a permissions check, which should pass.
    151         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("systemPackage")))
    152             .thenReturn(AppOpsManager.MODE_DEFAULT);
    153         // A mismatch between the package name and the UID will return MODE_IGNORED.
    154         when(mMockAppOps.noteOp(anyInt(), anyInt(), eq("badPackage")))
    155             .thenReturn(AppOpsManager.MODE_IGNORED);
    156     }
    157 
    158     @Test
    159     public void testIpSecServiceReserveSpi() throws Exception {
    160         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
    161                 .thenReturn(TEST_SPI);
    162 
    163         IpSecSpiResponse spiResp =
    164                 mIpSecService.allocateSecurityParameterIndex(
    165                         mDestinationAddr, TEST_SPI, new Binder());
    166         assertEquals(IpSecManager.Status.OK, spiResp.status);
    167         assertEquals(TEST_SPI, spiResp.spi);
    168     }
    169 
    170     @Test
    171     public void testReleaseSecurityParameterIndex() throws Exception {
    172         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
    173                 .thenReturn(TEST_SPI);
    174 
    175         IpSecSpiResponse spiResp =
    176                 mIpSecService.allocateSecurityParameterIndex(
    177                         mDestinationAddr, TEST_SPI, new Binder());
    178 
    179         mIpSecService.releaseSecurityParameterIndex(spiResp.resourceId);
    180 
    181         verify(mMockNetd)
    182                 .ipSecDeleteSecurityAssociation(
    183                         eq(spiResp.resourceId),
    184                         anyString(),
    185                         anyString(),
    186                         eq(TEST_SPI),
    187                         anyInt(),
    188                         anyInt());
    189 
    190         // Verify quota and RefcountedResource objects cleaned up
    191         IpSecService.UserRecord userRecord =
    192                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    193         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
    194         try {
    195             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
    196             fail("Expected IllegalArgumentException on attempt to access deleted resource");
    197         } catch (IllegalArgumentException expected) {
    198 
    199         }
    200     }
    201 
    202     @Test
    203     public void testSecurityParameterIndexBinderDeath() throws Exception {
    204         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), eq(mDestinationAddr), eq(TEST_SPI)))
    205                 .thenReturn(TEST_SPI);
    206 
    207         IpSecSpiResponse spiResp =
    208                 mIpSecService.allocateSecurityParameterIndex(
    209                         mDestinationAddr, TEST_SPI, new Binder());
    210 
    211         IpSecService.UserRecord userRecord =
    212                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    213         IpSecService.RefcountedResource refcountedRecord =
    214                 userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
    215 
    216         refcountedRecord.binderDied();
    217 
    218         verify(mMockNetd)
    219                 .ipSecDeleteSecurityAssociation(
    220                         eq(spiResp.resourceId),
    221                         anyString(),
    222                         anyString(),
    223                         eq(TEST_SPI),
    224                         anyInt(),
    225                         anyInt());
    226 
    227         // Verify quota and RefcountedResource objects cleaned up
    228         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
    229         try {
    230             userRecord.mSpiRecords.getRefcountedResourceOrThrow(spiResp.resourceId);
    231             fail("Expected IllegalArgumentException on attempt to access deleted resource");
    232         } catch (IllegalArgumentException expected) {
    233 
    234         }
    235     }
    236 
    237     private int getNewSpiResourceId(String remoteAddress, int returnSpi) throws Exception {
    238         when(mMockNetd.ipSecAllocateSpi(anyInt(), anyString(), anyString(), anyInt()))
    239                 .thenReturn(returnSpi);
    240 
    241         IpSecSpiResponse spi =
    242                 mIpSecService.allocateSecurityParameterIndex(
    243                         NetworkUtils.numericToInetAddress(remoteAddress).getHostAddress(),
    244                         IpSecManager.INVALID_SECURITY_PARAMETER_INDEX,
    245                         new Binder());
    246         return spi.resourceId;
    247     }
    248 
    249     private void addDefaultSpisAndRemoteAddrToIpSecConfig(IpSecConfig config) throws Exception {
    250         config.setSpiResourceId(getNewSpiResourceId(mDestinationAddr, TEST_SPI));
    251         config.setSourceAddress(mSourceAddr);
    252         config.setDestinationAddress(mDestinationAddr);
    253     }
    254 
    255     private void addAuthAndCryptToIpSecConfig(IpSecConfig config) throws Exception {
    256         config.setEncryption(CRYPT_ALGO);
    257         config.setAuthentication(AUTH_ALGO);
    258     }
    259 
    260     @Test
    261     public void testCreateTransform() throws Exception {
    262         IpSecConfig ipSecConfig = new IpSecConfig();
    263         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    264         addAuthAndCryptToIpSecConfig(ipSecConfig);
    265 
    266         IpSecTransformResponse createTransformResp =
    267                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    268         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
    269 
    270         verify(mMockNetd)
    271                 .ipSecAddSecurityAssociation(
    272                         eq(createTransformResp.resourceId),
    273                         anyInt(),
    274                         anyString(),
    275                         anyString(),
    276                         anyInt(),
    277                         eq(TEST_SPI),
    278                         anyInt(),
    279                         anyInt(),
    280                         eq(IpSecAlgorithm.AUTH_HMAC_SHA256),
    281                         eq(AUTH_KEY),
    282                         anyInt(),
    283                         eq(IpSecAlgorithm.CRYPT_AES_CBC),
    284                         eq(CRYPT_KEY),
    285                         anyInt(),
    286                         eq(""),
    287                         eq(new byte[] {}),
    288                         eq(0),
    289                         anyInt(),
    290                         anyInt(),
    291                         anyInt());
    292     }
    293 
    294     @Test
    295     public void testCreateTransformAead() throws Exception {
    296         IpSecConfig ipSecConfig = new IpSecConfig();
    297         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    298 
    299         ipSecConfig.setAuthenticatedEncryption(AEAD_ALGO);
    300 
    301         IpSecTransformResponse createTransformResp =
    302                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    303         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
    304 
    305         verify(mMockNetd)
    306                 .ipSecAddSecurityAssociation(
    307                         eq(createTransformResp.resourceId),
    308                         anyInt(),
    309                         anyString(),
    310                         anyString(),
    311                         anyInt(),
    312                         eq(TEST_SPI),
    313                         anyInt(),
    314                         anyInt(),
    315                         eq(""),
    316                         eq(new byte[] {}),
    317                         eq(0),
    318                         eq(""),
    319                         eq(new byte[] {}),
    320                         eq(0),
    321                         eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
    322                         eq(AEAD_KEY),
    323                         anyInt(),
    324                         anyInt(),
    325                         anyInt(),
    326                         anyInt());
    327     }
    328 
    329     @Test
    330     public void testCreateTwoTransformsWithSameSpis() throws Exception {
    331         IpSecConfig ipSecConfig = new IpSecConfig();
    332         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    333         addAuthAndCryptToIpSecConfig(ipSecConfig);
    334 
    335         IpSecTransformResponse createTransformResp =
    336                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    337         assertEquals(IpSecManager.Status.OK, createTransformResp.status);
    338 
    339         // Attempting to create transform a second time with the same SPIs should throw an error...
    340         try {
    341                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    342                 fail("IpSecService should have thrown an error for reuse of SPI");
    343         } catch (IllegalStateException expected) {
    344         }
    345 
    346         // ... even if the transform is deleted
    347         mIpSecService.deleteTransform(createTransformResp.resourceId);
    348         try {
    349                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    350                 fail("IpSecService should have thrown an error for reuse of SPI");
    351         } catch (IllegalStateException expected) {
    352         }
    353     }
    354 
    355     @Test
    356     public void testReleaseOwnedSpi() throws Exception {
    357         IpSecConfig ipSecConfig = new IpSecConfig();
    358         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    359         addAuthAndCryptToIpSecConfig(ipSecConfig);
    360 
    361         IpSecTransformResponse createTransformResp =
    362                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    363         IpSecService.UserRecord userRecord =
    364                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    365         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
    366         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
    367         verify(mMockNetd, times(0))
    368                 .ipSecDeleteSecurityAssociation(
    369                         eq(createTransformResp.resourceId),
    370                         anyString(),
    371                         anyString(),
    372                         eq(TEST_SPI),
    373                         anyInt(),
    374                         anyInt());
    375         // quota is not released until the SPI is released by the Transform
    376         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
    377     }
    378 
    379     @Test
    380     public void testDeleteTransform() throws Exception {
    381         IpSecConfig ipSecConfig = new IpSecConfig();
    382         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    383         addAuthAndCryptToIpSecConfig(ipSecConfig);
    384 
    385         IpSecTransformResponse createTransformResp =
    386                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    387         mIpSecService.deleteTransform(createTransformResp.resourceId);
    388 
    389         verify(mMockNetd, times(1))
    390                 .ipSecDeleteSecurityAssociation(
    391                         eq(createTransformResp.resourceId),
    392                         anyString(),
    393                         anyString(),
    394                         eq(TEST_SPI),
    395                         anyInt(),
    396                         anyInt());
    397 
    398         // Verify quota and RefcountedResource objects cleaned up
    399         IpSecService.UserRecord userRecord =
    400                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    401         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
    402         assertEquals(1, userRecord.mSpiQuotaTracker.mCurrent);
    403 
    404         mIpSecService.releaseSecurityParameterIndex(ipSecConfig.getSpiResourceId());
    405         // Verify that ipSecDeleteSa was not called when the SPI was released because the
    406         // ownedByTransform property should prevent it; (note, the called count is cumulative).
    407         verify(mMockNetd, times(1))
    408                 .ipSecDeleteSecurityAssociation(
    409                         anyInt(),
    410                         anyString(),
    411                         anyString(),
    412                         anyInt(),
    413                         anyInt(),
    414                         anyInt());
    415         assertEquals(0, userRecord.mSpiQuotaTracker.mCurrent);
    416 
    417         try {
    418             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
    419                     createTransformResp.resourceId);
    420             fail("Expected IllegalArgumentException on attempt to access deleted resource");
    421         } catch (IllegalArgumentException expected) {
    422 
    423         }
    424     }
    425 
    426     @Test
    427     public void testTransportModeTransformBinderDeath() throws Exception {
    428         IpSecConfig ipSecConfig = new IpSecConfig();
    429         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    430         addAuthAndCryptToIpSecConfig(ipSecConfig);
    431 
    432         IpSecTransformResponse createTransformResp =
    433                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    434 
    435         IpSecService.UserRecord userRecord =
    436                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    437         IpSecService.RefcountedResource refcountedRecord =
    438                 userRecord.mTransformRecords.getRefcountedResourceOrThrow(
    439                         createTransformResp.resourceId);
    440 
    441         refcountedRecord.binderDied();
    442 
    443         verify(mMockNetd)
    444                 .ipSecDeleteSecurityAssociation(
    445                         eq(createTransformResp.resourceId),
    446                         anyString(),
    447                         anyString(),
    448                         eq(TEST_SPI),
    449                         anyInt(),
    450                         anyInt());
    451 
    452         // Verify quota and RefcountedResource objects cleaned up
    453         assertEquals(0, userRecord.mTransformQuotaTracker.mCurrent);
    454         try {
    455             userRecord.mTransformRecords.getRefcountedResourceOrThrow(
    456                     createTransformResp.resourceId);
    457             fail("Expected IllegalArgumentException on attempt to access deleted resource");
    458         } catch (IllegalArgumentException expected) {
    459 
    460         }
    461     }
    462 
    463     @Test
    464     public void testApplyTransportModeTransform() throws Exception {
    465         IpSecConfig ipSecConfig = new IpSecConfig();
    466         addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig);
    467         addAuthAndCryptToIpSecConfig(ipSecConfig);
    468 
    469         IpSecTransformResponse createTransformResp =
    470                 mIpSecService.createTransform(ipSecConfig, new Binder(), "blessedPackage");
    471         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
    472 
    473         int resourceId = createTransformResp.resourceId;
    474         mIpSecService.applyTransportModeTransform(pfd, IpSecManager.DIRECTION_OUT, resourceId);
    475 
    476         verify(mMockNetd)
    477                 .ipSecApplyTransportModeTransform(
    478                         eq(pfd.getFileDescriptor()),
    479                         eq(resourceId),
    480                         eq(IpSecManager.DIRECTION_OUT),
    481                         anyString(),
    482                         anyString(),
    483                         eq(TEST_SPI));
    484     }
    485 
    486     @Test
    487     public void testRemoveTransportModeTransform() throws Exception {
    488         ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(new Socket());
    489         mIpSecService.removeTransportModeTransforms(pfd);
    490 
    491         verify(mMockNetd).ipSecRemoveTransportModeTransform(pfd.getFileDescriptor());
    492     }
    493 
    494     private IpSecTunnelInterfaceResponse createAndValidateTunnel(
    495             String localAddr, String remoteAddr, String pkgName) {
    496         IpSecTunnelInterfaceResponse createTunnelResp =
    497                 mIpSecService.createTunnelInterface(
    498                         mSourceAddr, mDestinationAddr, fakeNetwork, new Binder(), pkgName);
    499 
    500         assertNotNull(createTunnelResp);
    501         assertEquals(IpSecManager.Status.OK, createTunnelResp.status);
    502         return createTunnelResp;
    503     }
    504 
    505     @Test
    506     public void testCreateTunnelInterface() throws Exception {
    507         IpSecTunnelInterfaceResponse createTunnelResp =
    508                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
    509 
    510         // Check that we have stored the tracking object, and retrieve it
    511         IpSecService.UserRecord userRecord =
    512                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    513         IpSecService.RefcountedResource refcountedRecord =
    514                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
    515                         createTunnelResp.resourceId);
    516 
    517         assertEquals(1, userRecord.mTunnelQuotaTracker.mCurrent);
    518         verify(mMockNetd)
    519                 .addVirtualTunnelInterface(
    520                         eq(createTunnelResp.interfaceName),
    521                         eq(mSourceAddr),
    522                         eq(mDestinationAddr),
    523                         anyInt(),
    524                         anyInt());
    525     }
    526 
    527     @Test
    528     public void testDeleteTunnelInterface() throws Exception {
    529         IpSecTunnelInterfaceResponse createTunnelResp =
    530                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
    531 
    532         IpSecService.UserRecord userRecord =
    533                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    534 
    535         mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, "blessedPackage");
    536 
    537         // Verify quota and RefcountedResource objects cleaned up
    538         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
    539         verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
    540         try {
    541             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
    542                     createTunnelResp.resourceId);
    543             fail("Expected IllegalArgumentException on attempt to access deleted resource");
    544         } catch (IllegalArgumentException expected) {
    545         }
    546     }
    547 
    548     @Test
    549     public void testTunnelInterfaceBinderDeath() throws Exception {
    550         IpSecTunnelInterfaceResponse createTunnelResp =
    551                 createAndValidateTunnel(mSourceAddr, mDestinationAddr, "blessedPackage");
    552 
    553         IpSecService.UserRecord userRecord =
    554                 mIpSecService.mUserResourceTracker.getUserRecord(Os.getuid());
    555         IpSecService.RefcountedResource refcountedRecord =
    556                 userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
    557                         createTunnelResp.resourceId);
    558 
    559         refcountedRecord.binderDied();
    560 
    561         // Verify quota and RefcountedResource objects cleaned up
    562         assertEquals(0, userRecord.mTunnelQuotaTracker.mCurrent);
    563         verify(mMockNetd).removeVirtualTunnelInterface(eq(createTunnelResp.interfaceName));
    564         try {
    565             userRecord.mTunnelInterfaceRecords.getRefcountedResourceOrThrow(
    566                     createTunnelResp.resourceId);
    567             fail("Expected IllegalArgumentException on attempt to access deleted resource");
    568         } catch (IllegalArgumentException expected) {
    569         }
    570     }
    571 
    572     @Test
    573     public void testAddRemoveAddressFromTunnelInterface() throws Exception {
    574         for (String pkgName : new String[]{"blessedPackage", "systemPackage"}) {
    575             IpSecTunnelInterfaceResponse createTunnelResp =
    576                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, pkgName);
    577             mIpSecService.addAddressToTunnelInterface(
    578                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
    579             verify(mMockNetd, times(1))
    580                     .interfaceAddAddress(
    581                             eq(createTunnelResp.interfaceName),
    582                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
    583                             eq(mLocalInnerAddress.getPrefixLength()));
    584             mIpSecService.removeAddressFromTunnelInterface(
    585                     createTunnelResp.resourceId, mLocalInnerAddress, pkgName);
    586             verify(mMockNetd, times(1))
    587                     .interfaceDelAddress(
    588                             eq(createTunnelResp.interfaceName),
    589                             eq(mLocalInnerAddress.getAddress().getHostAddress()),
    590                             eq(mLocalInnerAddress.getPrefixLength()));
    591             mIpSecService.deleteTunnelInterface(createTunnelResp.resourceId, pkgName);
    592         }
    593     }
    594 
    595     @Test
    596     public void testAddTunnelFailsForBadPackageName() throws Exception {
    597         try {
    598             IpSecTunnelInterfaceResponse createTunnelResp =
    599                     createAndValidateTunnel(mSourceAddr, mDestinationAddr, "badPackage");
    600             fail("Expected a SecurityException for badPackage.");
    601         } catch (SecurityException expected) {
    602         }
    603     }
    604 }
    605