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
17package com.android.server;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertNotNull;
21import static org.junit.Assert.fail;
22import static org.mockito.Matchers.anyInt;
23import static org.mockito.Matchers.anyString;
24import static org.mockito.Matchers.eq;
25import static org.mockito.Mockito.mock;
26import static org.mockito.Mockito.times;
27import static org.mockito.Mockito.verify;
28import static org.mockito.Mockito.when;
29
30import android.app.AppOpsManager;
31import android.content.Context;
32import android.net.INetd;
33import android.net.IpSecAlgorithm;
34import android.net.IpSecConfig;
35import android.net.IpSecManager;
36import android.net.IpSecSpiResponse;
37import android.net.IpSecTransformResponse;
38import android.net.IpSecTunnelInterfaceResponse;
39import android.net.LinkAddress;
40import android.net.Network;
41import android.net.NetworkUtils;
42import android.os.Binder;
43import android.os.ParcelFileDescriptor;
44import android.test.mock.MockContext;
45import android.support.test.filters.SmallTest;
46import android.system.Os;
47
48import java.net.Socket;
49import java.util.Arrays;
50import java.util.Collection;
51
52import org.junit.Before;
53import org.junit.Test;
54import org.junit.runner.RunWith;
55import org.junit.runners.Parameterized;
56
57/** Unit tests for {@link IpSecService}. */
58@SmallTest
59@RunWith(Parameterized.class)
60public 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