From 357ed6d3e440dd3f56f651dae3a203e03add38c7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Sep 2018 13:42:37 -0700 Subject: [PATCH] Add basic functionality tests for IPsec tunnel mode This change adds test for creation and address additions of IPsec tunnel mode. Bug: 72458318 Test: Ran on aosp_taimen-eng Change-Id: If9d7e5ef35d37242d452eb7386cd5f5b80f6351f --- .../src/android/net/cts/IpSecBaseTest.java | 3 + .../src/android/net/cts/IpSecManagerTest.java | 19 +-- .../net/cts/IpSecManagerTunnelTest.java | 150 ++++++++++++++++++ 3 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java diff --git a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java index 7132ecf685..35d0f485e0 100644 --- a/tests/cts/net/src/android/net/cts/IpSecBaseTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecBaseTest.java @@ -19,6 +19,7 @@ package android.net.cts; import static org.junit.Assert.assertArrayEquals; import android.content.Context; +import android.net.ConnectivityManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; @@ -66,11 +67,13 @@ public class IpSecBaseTest extends AndroidTestCase { protected static final byte[] AUTH_KEY = getKey(256); protected static final byte[] CRYPT_KEY = getKey(256); + protected ConnectivityManager mCM; protected IpSecManager mISM; protected void setUp() throws Exception { super.setUp(); mISM = (IpSecManager) getContext().getSystemService(Context.IPSEC_SERVICE); + mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); } protected static byte[] getKey(int bitLength) { diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java index a18b2f08e0..3387064d41 100644 --- a/tests/cts/net/src/android/net/cts/IpSecManagerTest.java +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTest.java @@ -21,8 +21,6 @@ import static android.system.OsConstants.IPPROTO_UDP; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertTrue; -import android.content.Context; -import android.net.ConnectivityManager; import android.net.IpSecAlgorithm; import android.net.IpSecManager; import android.net.IpSecTransform; @@ -37,25 +35,15 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.Inet6Address; import java.net.InetAddress; -import java.net.UnknownHostException; import java.util.Arrays; public class IpSecManagerTest extends IpSecBaseTest { private static final String TAG = IpSecManagerTest.class.getSimpleName(); - private ConnectivityManager mCM; - - private static InetAddress IpAddress(String addrString) { - try { - return InetAddress.getByName(addrString); - } catch (UnknownHostException e) { - throw new IllegalArgumentException("Invalid IP address: " + e); - } - } - - private static final InetAddress GOOGLE_DNS_4 = IpAddress("8.8.8.8"); - private static final InetAddress GOOGLE_DNS_6 = IpAddress("2001:4860:4860::8888"); + private static final InetAddress GOOGLE_DNS_4 = InetAddress.parseNumericAddress("8.8.8.8"); + private static final InetAddress GOOGLE_DNS_6 = + InetAddress.parseNumericAddress("2001:4860:4860::8888"); private static final InetAddress[] GOOGLE_DNS_LIST = new InetAddress[] {GOOGLE_DNS_4, GOOGLE_DNS_6}; @@ -78,7 +66,6 @@ public class IpSecManagerTest extends IpSecBaseTest { protected void setUp() throws Exception { super.setUp(); - mCM = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE); } /* diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java new file mode 100644 index 0000000000..5c80e33054 --- /dev/null +++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2018 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 android.net.cts; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import android.net.IpSecAlgorithm; +import android.net.IpSecManager; +import android.net.IpSecTransform; +import android.net.Network; + +import com.android.compatibility.common.util.SystemUtil; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; + +public class IpSecManagerTunnelTest extends IpSecBaseTest { + + private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName(); + private static final int IP4_PREFIX_LEN = 24; + private static final int IP6_PREFIX_LEN = 48; + private static final InetAddress OUTER_ADDR4 = InetAddress.parseNumericAddress("192.0.2.0"); + private static final InetAddress OUTER_ADDR6 = + InetAddress.parseNumericAddress("2001:db8:f00d::1"); + private static final InetAddress INNER_ADDR4 = InetAddress.parseNumericAddress("10.0.0.1"); + private static final InetAddress INNER_ADDR6 = + InetAddress.parseNumericAddress("2001:db8:d00d::1"); + + private Network mUnderlyingNetwork; + private Network mIpSecNetwork; + + protected void setUp() throws Exception { + super.setUp(); + setAppop(true); + } + + protected void tearDown() { + setAppop(false); + } + + private void setAppop(boolean allow) { + // Under normal circumstances, the MANAGE_IPSEC_TUNNELS appop would be auto-granted by the + // telephony framework, and the only permission that is sufficient is NETWORK_STACK. So we + // shell out the appop manager, to give us the right appop permissions. + String cmd = + "appops set " + + mContext.getPackageName() + + " MANAGE_IPSEC_TUNNELS " + + (allow ? "allow" : "deny"); + SystemUtil.runShellCommand(cmd); + } + + private void checkTunnel(InetAddress inner, InetAddress outer, boolean useEncap) + throws Exception { + int innerPrefixLen = inner instanceof Inet6Address ? IP6_PREFIX_LEN : IP4_PREFIX_LEN; + + try (IpSecManager.SecurityParameterIndex spi = mISM.allocateSecurityParameterIndex(outer); + IpSecManager.IpSecTunnelInterface tunnelIntf = + mISM.createIpSecTunnelInterface(outer, outer, mCM.getActiveNetwork()); + IpSecManager.UdpEncapsulationSocket encapSocket = + mISM.openUdpEncapsulationSocket()) { + + IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(mContext); + transformBuilder.setEncryption( + new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY)); + transformBuilder.setAuthentication( + new IpSecAlgorithm( + IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4)); + + if (useEncap) { + transformBuilder.setIpv4Encapsulation(encapSocket, encapSocket.getPort()); + } + + // Check transform application + try (IpSecTransform transform = transformBuilder.buildTunnelModeTransform(outer, spi)) { + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_IN, transform); + mISM.applyTunnelModeTransform(tunnelIntf, IpSecManager.DIRECTION_OUT, transform); + + // TODO: Test to ensure that send/receive works with these transforms. + } + + // Check interface was created + NetworkInterface netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); + assertTrue(netIntf.isPointToPoint()); + assertNotNull(netIntf); + + // Add addresses and check + tunnelIntf.addAddress(inner, innerPrefixLen); + for (InterfaceAddress intfAddr : netIntf.getInterfaceAddresses()) { + assertEquals(intfAddr.getAddress(), inner); + assertEquals(intfAddr.getNetworkPrefixLength(), innerPrefixLen); + } + + // Remove addresses and check + tunnelIntf.removeAddress(inner, innerPrefixLen); + assertTrue(netIntf.getInterfaceAddresses().isEmpty()); + + // Check interface was cleaned up + tunnelIntf.close(); + netIntf = NetworkInterface.getByName(tunnelIntf.getInterfaceName()); + assertNull(netIntf); + } + } + + /* + * Create, add and remove addresses, then teardown tunnel + */ + public void testTunnelV4InV4() throws Exception { + checkTunnel(INNER_ADDR4, OUTER_ADDR4, false); + } + + public void testTunnelV4InV4UdpEncap() throws Exception { + checkTunnel(INNER_ADDR4, OUTER_ADDR4, true); + } + + public void testTunnelV4InV6() throws Exception { + checkTunnel(INNER_ADDR4, OUTER_ADDR6, false); + } + + public void testTunnelV6InV4() throws Exception { + checkTunnel(INNER_ADDR6, OUTER_ADDR4, false); + } + + public void testTunnelV6InV4UdpEncap() throws Exception { + checkTunnel(INNER_ADDR6, OUTER_ADDR4, true); + } + + public void testTunnelV6InV6() throws Exception { + checkTunnel(INNER_ADDR6, OUTER_ADDR6, false); + } +}