diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java index df2e7a6a2e..f81a03d718 100755 --- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java +++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java @@ -24,6 +24,7 @@ import static android.content.pm.PackageManager.FEATURE_TELEPHONY; import static android.content.pm.PackageManager.FEATURE_WIFI; import static android.net.ConnectivityManager.TYPE_VPN; import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_TEST; import static android.os.Process.INVALID_UID; import static android.system.OsConstants.AF_INET; import static android.system.OsConstants.AF_INET6; @@ -72,6 +73,7 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.ConnectivityManager.NetworkCallback; +import android.net.InetAddresses; import android.net.IpSecManager; import android.net.LinkAddress; import android.net.LinkProperties; @@ -91,6 +93,7 @@ import android.net.VpnTransportInfo; import android.net.cts.util.CtsNetUtils; import android.net.util.KeepaliveUtils; import android.net.wifi.WifiManager; +import android.os.Binder; import android.os.Build; import android.os.Handler; import android.os.Looper; @@ -249,6 +252,7 @@ public class VpnTest { @Before public void setUp() throws Exception { + assumeTrue(supportedHardware()); mNetwork = null; mTestContext = getInstrumentation().getContext(); mTargetContext = getInstrumentation().getTargetContext(); @@ -879,7 +883,6 @@ public class VpnTest { @Test @IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available public void testChangeUnderlyingNetworks() throws Exception { - assumeTrue(supportedHardware()); assumeTrue(mPackageManager.hasSystemFeature(FEATURE_WIFI)); assumeTrue(mPackageManager.hasSystemFeature(FEATURE_TELEPHONY)); final TestableNetworkCallback callback = new TestableNetworkCallback(); @@ -938,7 +941,6 @@ public class VpnTest { @Test public void testDefault() throws Exception { - assumeTrue(supportedHardware()); if (!SdkLevel.isAtLeastS() && ( SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 || SystemProperties.getInt("service.adb.tcp.port", -1) > -1)) { @@ -1033,8 +1035,6 @@ public class VpnTest { @Test public void testAppAllowed() throws Exception { - assumeTrue(supportedHardware()); - FileDescriptor fd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); // Shell app must not be put in here or it would kill the ADB-over-network use case @@ -1142,8 +1142,6 @@ public class VpnTest { } private void doTestAutomaticOnOffKeepaliveMode(final boolean closeSocket) throws Exception { - assumeTrue(supportedHardware()); - // Get default network first before starting VPN final Network defaultNetwork = mCM.getActiveNetwork(); final TestableNetworkCallback cb = new TestableNetworkCallback(); @@ -1231,8 +1229,6 @@ public class VpnTest { @Test public void testAppDisallowed() throws Exception { - assumeTrue(supportedHardware()); - FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS); FileDescriptor remoteFd = openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS); @@ -1265,8 +1261,6 @@ public class VpnTest { @Test public void testSocketClosed() throws Exception { - assumeTrue(supportedHardware()); - final FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS); final List remoteFds = new ArrayList<>(); @@ -1290,7 +1284,6 @@ public class VpnTest { @Test public void testExcludedRoutes() throws Exception { - assumeTrue(supportedHardware()); assumeTrue(SdkLevel.isAtLeastT()); // Shell app must not be put in here or it would kill the ADB-over-network use case @@ -1311,8 +1304,6 @@ public class VpnTest { @Test public void testIncludedRoutes() throws Exception { - assumeTrue(supportedHardware()); - // Shell app must not be put in here or it would kill the ADB-over-network use case String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName; startVpn(new String[]{"192.0.2.2/32", "2001:db8:1:2::ffe/128"} /* addresses */, @@ -1330,7 +1321,6 @@ public class VpnTest { @Test public void testInterleavedRoutes() throws Exception { - assumeTrue(supportedHardware()); assumeTrue(SdkLevel.isAtLeastT()); // Shell app must not be put in here or it would kill the ADB-over-network use case @@ -1358,8 +1348,6 @@ public class VpnTest { @Test public void testGetConnectionOwnerUidSecurity() throws Exception { - assumeTrue(supportedHardware()); - DatagramSocket s; InetAddress address = InetAddress.getByName("localhost"); s = new DatagramSocket(); @@ -1380,7 +1368,6 @@ public class VpnTest { @Test public void testSetProxy() throws Exception { - assumeTrue(supportedHardware()); ProxyInfo initialProxy = mCM.getDefaultProxy(); // Receiver for the proxy change broadcast. BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); @@ -1420,7 +1407,6 @@ public class VpnTest { @Test public void testSetProxyDisallowedApps() throws Exception { - assumeTrue(supportedHardware()); ProxyInfo initialProxy = mCM.getDefaultProxy(); String disallowedApps = mPackageName; @@ -1446,7 +1432,6 @@ public class VpnTest { @Test public void testNoProxy() throws Exception { - assumeTrue(supportedHardware()); ProxyInfo initialProxy = mCM.getDefaultProxy(); BlockingBroadcastReceiver proxyBroadcastReceiver = new ProxyChangeBroadcastReceiver(); proxyBroadcastReceiver.register(); @@ -1481,7 +1466,6 @@ public class VpnTest { @Test public void testBindToNetworkWithProxy() throws Exception { - assumeTrue(supportedHardware()); String allowedApps = mPackageName; Network initialNetwork = mCM.getActiveNetwork(); ProxyInfo initialProxy = mCM.getDefaultProxy(); @@ -1506,9 +1490,6 @@ public class VpnTest { @Test public void testVpnMeterednessWithNoUnderlyingNetwork() throws Exception { - if (!supportedHardware()) { - return; - } // VPN is not routing any traffic i.e. its underlying networks is an empty array. ArrayList underlyingNetworks = new ArrayList<>(); String allowedApps = mPackageName; @@ -1538,9 +1519,6 @@ public class VpnTest { @Test public void testVpnMeterednessWithNullUnderlyingNetwork() throws Exception { - if (!supportedHardware()) { - return; - } Network underlyingNetwork = mCM.getActiveNetwork(); if (underlyingNetwork == null) { Log.i(TAG, "testVpnMeterednessWithNullUnderlyingNetwork cannot execute" @@ -1567,9 +1545,6 @@ public class VpnTest { @Test public void testVpnMeterednessWithNonNullUnderlyingNetwork() throws Exception { - if (!supportedHardware()) { - return; - } Network underlyingNetwork = mCM.getActiveNetwork(); if (underlyingNetwork == null) { Log.i(TAG, "testVpnMeterednessWithNonNullUnderlyingNetwork cannot execute" @@ -1609,9 +1584,6 @@ public class VpnTest { @Test public void testAlwaysMeteredVpnWithNullUnderlyingNetwork() throws Exception { - if (!supportedHardware()) { - return; - } Network underlyingNetwork = mCM.getActiveNetwork(); if (underlyingNetwork == null) { Log.i(TAG, "testAlwaysMeteredVpnWithNullUnderlyingNetwork cannot execute" @@ -1636,9 +1608,6 @@ public class VpnTest { @Test public void testAlwaysMeteredVpnWithNonNullUnderlyingNetwork() throws Exception { - if (!supportedHardware()) { - return; - } Network underlyingNetwork = mCM.getActiveNetwork(); if (underlyingNetwork == null) { Log.i(TAG, "testAlwaysMeteredVpnWithNonNullUnderlyingNetwork cannot execute" @@ -1676,9 +1645,6 @@ public class VpnTest { @Test public void testB141603906() throws Exception { - if (!supportedHardware()) { - return; - } final InetSocketAddress src = new InetSocketAddress(0); final InetSocketAddress dst = new InetSocketAddress(0); final int NUM_THREADS = 8; @@ -1786,8 +1752,6 @@ public class VpnTest { */ @Test public void testDownloadWithDownloadManagerDisallowed() throws Exception { - assumeTrue(supportedHardware()); - // Start a VPN with DownloadManager package in disallowed list. startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"}, new String[] {"192.0.2.0/24", "2001:db8::/32"}, @@ -1843,7 +1807,6 @@ public class VpnTest { @Test @IgnoreUpTo(Build.VERSION_CODES.R) public void testBlockIncomingPackets() throws Exception { - assumeTrue(supportedHardware()); final Network network = mCM.getActiveNetwork(); assertNotNull("Requires a working Internet connection", network); @@ -1912,7 +1875,6 @@ public class VpnTest { @Test public void testSetVpnDefaultForUids() throws Exception { - assumeTrue(supportedHardware()); assumeTrue(SdkLevel.isAtLeastU()); final Network defaultNetwork = mCM.getActiveNetwork(); @@ -1958,6 +1920,81 @@ public class VpnTest { }); } + /** + * Check if packets to a VPN interface's IP arriving on a non-VPN interface are dropped or not. + * If the test interface has a different address from the VPN interface, packets must be dropped + * If the test interface has the same address as the VPN interface, packets must not be + * dropped + * + * @param duplicatedAddress true to bring up the test interface with the same address as the VPN + * interface + */ + private void doTestDropPacketToVpnAddress(final boolean duplicatedAddress) + throws Exception { + final NetworkRequest request = new NetworkRequest.Builder() + .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .addTransportType(TRANSPORT_TEST) + .build(); + final CtsNetUtils.TestNetworkCallback callback = new CtsNetUtils.TestNetworkCallback(); + mCM.requestNetwork(request, callback); + final FileDescriptor srcTunFd = runWithShellPermissionIdentity(() -> { + final TestNetworkManager tnm = mTestContext.getSystemService(TestNetworkManager.class); + List linkAddresses = duplicatedAddress + ? List.of(new LinkAddress("192.0.2.2/24"), + new LinkAddress("2001:db8:1:2::ffe/64")) : + List.of(new LinkAddress("198.51.100.2/24"), + new LinkAddress("2001:db8:3:4::ffe/64")); + final TestNetworkInterface iface = tnm.createTunInterface(linkAddresses); + tnm.setupTestNetwork(iface.getInterfaceName(), new Binder()); + return iface.getFileDescriptor().getFileDescriptor(); + }, MANAGE_TEST_NETWORKS); + final Network testNetwork = callback.waitForAvailable(); + assertNotNull(testNetwork); + final DatagramSocket dstSock = new DatagramSocket(); + + testAndCleanup(() -> { + startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"} /* addresses */, + new String[]{"0.0.0.0/0", "::/0"} /* routes */, + "" /* allowedApplications */, "" /* disallowedApplications */, + null /* proxyInfo */, null /* underlyingNetworks */, + false /* isAlwaysMetered */); + + final FileDescriptor dstUdpFd = dstSock.getFileDescriptor$(); + checkBlockUdp(srcTunFd, dstUdpFd, + InetAddresses.parseNumericAddress("192.0.2.2") /* dstAddress */, + InetAddresses.parseNumericAddress("192.0.2.1") /* srcAddress */, + duplicatedAddress ? EXPECT_PASS : EXPECT_BLOCK); + checkBlockUdp(srcTunFd, dstUdpFd, + InetAddresses.parseNumericAddress("2001:db8:1:2::ffe") /* dstAddress */, + InetAddresses.parseNumericAddress("2001:db8:1:2::ffa") /* srcAddress */, + duplicatedAddress ? EXPECT_PASS : EXPECT_BLOCK); + + // Traffic on VPN should not be affected + checkTrafficOnVpn(); + }, /* cleanup */ () -> { + Os.close(srcTunFd); + dstSock.close(); + }, /* cleanup */ () -> { + runWithShellPermissionIdentity(() -> { + mTestContext.getSystemService(TestNetworkManager.class) + .teardownTestNetwork(testNetwork); + }, MANAGE_TEST_NETWORKS); + }, /* cleanup */ () -> { + mCM.unregisterNetworkCallback(callback); + }); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) + public void testDropPacketToVpnAddress_WithoutDuplicatedAddress() throws Exception { + doTestDropPacketToVpnAddress(false /* duplicatedAddress */); + } + + @Test @IgnoreUpTo(Build.VERSION_CODES.S_V2) + public void testDropPacketToVpnAddress_WithDuplicatedAddress() throws Exception { + doTestDropPacketToVpnAddress(true /* duplicatedAddress */); + } + private ByteBuffer buildIpv4UdpPacket(final Inet4Address dstAddr, final Inet4Address srcAddr, final short dstPort, final short srcPort, final byte[] payload) throws IOException { @@ -2001,7 +2038,8 @@ public class VpnTest { private void checkBlockUdp( final FileDescriptor srcTunFd, final FileDescriptor dstUdpFd, - final boolean ipv6, + final InetAddress dstAddress, + final InetAddress srcAddress, final boolean expectBlock) throws Exception { final Random random = new Random(); final byte[] sendData = new byte[100]; @@ -2009,15 +2047,15 @@ public class VpnTest { final short dstPort = (short) ((InetSocketAddress) Os.getsockname(dstUdpFd)).getPort(); ByteBuffer buf; - if (ipv6) { + if (dstAddress instanceof Inet6Address) { buf = buildIpv6UdpPacket( - (Inet6Address) TEST_IP6_DST_ADDR.getAddress(), - (Inet6Address) TEST_IP6_SRC_ADDR.getAddress(), + (Inet6Address) dstAddress, + (Inet6Address) srcAddress, dstPort, TEST_SRC_PORT, sendData); } else { buf = buildIpv4UdpPacket( - (Inet4Address) TEST_IP4_DST_ADDR.getAddress(), - (Inet4Address) TEST_IP4_SRC_ADDR.getAddress(), + (Inet4Address) dstAddress, + (Inet4Address) srcAddress, dstPort, TEST_SRC_PORT, sendData); } @@ -2043,8 +2081,10 @@ public class VpnTest { final FileDescriptor srcTunFd, final FileDescriptor dstUdpFd, final boolean expectBlock) throws Exception { - checkBlockUdp(srcTunFd, dstUdpFd, false /* ipv6 */, expectBlock); - checkBlockUdp(srcTunFd, dstUdpFd, true /* ipv6 */, expectBlock); + checkBlockUdp(srcTunFd, dstUdpFd, TEST_IP4_DST_ADDR.getAddress(), + TEST_IP4_SRC_ADDR.getAddress(), expectBlock); + checkBlockUdp(srcTunFd, dstUdpFd, TEST_IP6_DST_ADDR.getAddress(), + TEST_IP6_SRC_ADDR.getAddress(), expectBlock); } private class DetailedBlockedStatusCallback extends TestableNetworkCallback { diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java index 4f21af78a9..f0a87af803 100644 --- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java +++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java @@ -171,4 +171,16 @@ public class HostsideVpnTests extends HostsideNetworkTestCase { public void testSetVpnDefaultForUids() throws Exception { runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSetVpnDefaultForUids"); } + + @Test + public void testDropPacketToVpnAddress_WithoutDuplicatedAddress() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", + "testDropPacketToVpnAddress_WithoutDuplicatedAddress"); + } + + @Test + public void testDropPacketToVpnAddress_WithDuplicatedAddress() throws Exception { + runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", + "testDropPacketToVpnAddress_WithDuplicatedAddress"); + } }