Loading tests/integration/src/android/net/util/NetworkStackUtilsIntegrationTest.kt +70 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.net.util import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.content.Context import android.content.Context import android.net.InetAddresses.parseNumericAddress import android.net.InetAddresses.parseNumericAddress import android.net.IpPrefix import android.net.MacAddress import android.net.MacAddress import android.net.TestNetworkInterface import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.TestNetworkManager Loading @@ -26,12 +27,22 @@ import android.net.dhcp.DhcpPacket import android.os.HandlerThread import android.os.HandlerThread import android.system.Os import android.system.Os import android.system.OsConstants.AF_INET import android.system.OsConstants.AF_INET import android.system.OsConstants.AF_PACKET import android.system.OsConstants.ARPHRD_ETHER import android.system.OsConstants.ETH_P_IPV6 import android.system.OsConstants.IPPROTO_UDP import android.system.OsConstants.IPPROTO_UDP import android.system.OsConstants.SOCK_DGRAM import android.system.OsConstants.SOCK_DGRAM import android.system.OsConstants.SOCK_NONBLOCK import android.system.OsConstants.SOCK_NONBLOCK import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry import android.system.OsConstants.SOCK_RAW import android.system.OsConstants.SOL_SOCKET import android.system.OsConstants.SO_RCVTIMEO import android.system.StructTimeval import com.android.net.module.util.Ipv6Utils import com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN import com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST import com.android.net.module.util.structs.PrefixInformationOption import com.android.testutils.ArpRequestFilter import com.android.testutils.ArpRequestFilter import com.android.testutils.ETHER_HEADER_LENGTH import com.android.testutils.ETHER_HEADER_LENGTH import com.android.testutils.IPV4_HEADER_LENGTH import com.android.testutils.IPV4_HEADER_LENGTH Loading @@ -42,9 +53,13 @@ import org.junit.After import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertArrayEquals import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import java.io.FileDescriptor import java.net.Inet4Address import java.net.Inet4Address import kotlin.reflect.KClass import kotlin.reflect.KClass import java.net.Inet6Address import java.nio.ByteBuffer import kotlin.test.assertEquals import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlin.test.fail import kotlin.test.fail class NetworkStackUtilsIntegrationTest { class NetworkStackUtilsIntegrationTest { Loading @@ -52,8 +67,12 @@ class NetworkStackUtilsIntegrationTest { private val context by lazy { inst.context } private val context by lazy { inst.context } private val TEST_TIMEOUT_MS = 10_000L private val TEST_TIMEOUT_MS = 10_000L private val TEST_MTU = 1500 private val TEST_TARGET_IPV4_ADDR = parseNumericAddress("192.0.2.42") as Inet4Address private val TEST_TARGET_IPV4_ADDR = parseNumericAddress("192.0.2.42") as Inet4Address private val TEST_SRC_MAC = MacAddress.fromString("BA:98:76:54:32:10") private val TEST_TARGET_MAC = MacAddress.fromString("01:23:45:67:89:0A") private val TEST_TARGET_MAC = MacAddress.fromString("01:23:45:67:89:0A") private val TEST_INET6ADDR_1 = parseNumericAddress("2001:db8::1") as Inet6Address private val TEST_INET6ADDR_2 = parseNumericAddress("2001:db8::2") as Inet6Address private val readerHandler = HandlerThread( private val readerHandler = HandlerThread( NetworkStackUtilsIntegrationTest::class.java.simpleName) NetworkStackUtilsIntegrationTest::class.java.simpleName) Loading Loading @@ -103,8 +122,7 @@ class NetworkStackUtilsIntegrationTest { null /* hostname */, false /* metered */, 1500 /* mtu */, null /* hostname */, false /* metered */, 1500 /* mtu */, null /* captivePortalUrl */) null /* captivePortalUrl */) // Not using .array as per errorprone "ByteBufferBackingArray" recommendation // Not using .array as per errorprone "ByteBufferBackingArray" recommendation val originalPacket = ByteArray(buffer.limit()) val originalPacket = buffer.readAsArray() buffer.get(originalPacket) Os.sendto(socket, originalPacket, 0 /* bytesOffset */, originalPacket.size /* bytesCount */, Os.sendto(socket, originalPacket, 0 /* bytesOffset */, originalPacket.size /* bytesCount */, 0 /* flags */, TEST_TARGET_IPV4_ADDR, DhcpPacket.DHCP_CLIENT.toInt() /* port */) 0 /* flags */, TEST_TARGET_IPV4_ADDR, DhcpPacket.DHCP_CLIENT.toInt() /* port */) Loading @@ -112,7 +130,7 @@ class NetworkStackUtilsIntegrationTest { // Verify the packet was sent to the mac address specified in the ARP entry // Verify the packet was sent to the mac address specified in the ARP entry // Also accept ARP requests, but expect that none is sent before the UDP packet // Also accept ARP requests, but expect that none is sent before the UDP packet // IPv6 NS may be sent on the interface but will be filtered out // IPv6 NS may be sent on the interface but will be filtered out val sentPacket = reader.popPacket(TEST_TIMEOUT_MS, IPv4UdpFilter().or(ArpRequestFilter())) val sentPacket = reader.poll(TEST_TIMEOUT_MS, IPv4UdpFilter().or(ArpRequestFilter())) ?: fail("Packet was not sent on the interface") ?: fail("Packet was not sent on the interface") val sentTargetAddr = MacAddress.fromBytes(sentPacket.copyOfRange(0, ETHER_ADDR_LEN)) val sentTargetAddr = MacAddress.fromBytes(sentPacket.copyOfRange(0, ETHER_ADDR_LEN)) Loading @@ -123,6 +141,54 @@ class NetworkStackUtilsIntegrationTest { assertArrayEquals("Sent packet != original packet", originalPacket, sentDhcpPacket) assertArrayEquals("Sent packet != original packet", originalPacket, sentDhcpPacket) } } @Test fun testAttachRaFilter() { val socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6) val ifParams = InterfaceParams.getByName(iface.interfaceName) ?: fail("Could not obtain interface params for ${iface.interfaceName}") val socketAddr = SocketUtils.makePacketSocketAddress(ETH_P_IPV6, ifParams.index) Os.bind(socket, socketAddr) Os.setsockoptTimeval(socket, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(TEST_TIMEOUT_MS)) // Verify that before setting any filter, the socket receives pings val echo = Ipv6Utils.buildEchoRequestPacket(TEST_SRC_MAC, TEST_TARGET_MAC, TEST_INET6ADDR_1, TEST_INET6ADDR_2) reader.sendResponse(echo) echo.rewind() assertNextPacketEquals(socket, echo.readAsArray(), "ICMPv6 echo") NetworkStackUtils.attachRaFilter(socket, ARPHRD_ETHER) // Send another echo, then an RA. After setting the filter expect only the RA. echo.rewind() reader.sendResponse(echo) val pio = PrefixInformationOption.build(IpPrefix("2001:db8:1::/64"), 0.toByte() /* flags */, 3600 /* validLifetime */, 1800 /* preferredLifetime */) val ra = Ipv6Utils.buildRaPacket(TEST_SRC_MAC, TEST_TARGET_MAC, TEST_INET6ADDR_1 /* routerAddr */, IPV6_ADDR_ALL_NODES_MULTICAST, 0.toByte() /* flags */, 1800 /* lifetime */, 0 /* reachableTime */, 0 /* retransTimer */, pio) reader.sendResponse(ra) ra.rewind() assertNextPacketEquals(socket, ra.readAsArray(), "ICMPv6 RA") } private fun assertNextPacketEquals(socket: FileDescriptor, expected: ByteArray, descr: String) { val buffer = ByteArray(TEST_MTU) val readPacket = Os.read(socket, buffer, 0 /* byteOffset */, buffer.size) assertTrue(readPacket > 0, "$descr not received") assertEquals(expected.size, readPacket, "Received packet size does not match for $descr") assertArrayEquals("Received packet != expected $descr", expected, buffer.copyOfRange(0, readPacket)) } } private fun ByteBuffer.readAsArray(): ByteArray { val out = ByteArray(remaining()) get(out) return out } } private fun <T : Any> Context.assertHasService(manager: KClass<T>) = getSystemService(manager.java) private fun <T : Any> Context.assertHasService(manager: KClass<T>) = getSystemService(manager.java) Loading Loading
tests/integration/src/android/net/util/NetworkStackUtilsIntegrationTest.kt +70 −4 Original line number Original line Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.net.util import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.Manifest.permission.MANAGE_TEST_NETWORKS import android.content.Context import android.content.Context import android.net.InetAddresses.parseNumericAddress import android.net.InetAddresses.parseNumericAddress import android.net.IpPrefix import android.net.MacAddress import android.net.MacAddress import android.net.TestNetworkInterface import android.net.TestNetworkInterface import android.net.TestNetworkManager import android.net.TestNetworkManager Loading @@ -26,12 +27,22 @@ import android.net.dhcp.DhcpPacket import android.os.HandlerThread import android.os.HandlerThread import android.system.Os import android.system.Os import android.system.OsConstants.AF_INET import android.system.OsConstants.AF_INET import android.system.OsConstants.AF_PACKET import android.system.OsConstants.ARPHRD_ETHER import android.system.OsConstants.ETH_P_IPV6 import android.system.OsConstants.IPPROTO_UDP import android.system.OsConstants.IPPROTO_UDP import android.system.OsConstants.SOCK_DGRAM import android.system.OsConstants.SOCK_DGRAM import android.system.OsConstants.SOCK_NONBLOCK import android.system.OsConstants.SOCK_NONBLOCK import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry import android.system.OsConstants.SOCK_RAW import android.system.OsConstants.SOL_SOCKET import android.system.OsConstants.SO_RCVTIMEO import android.system.StructTimeval import com.android.net.module.util.Ipv6Utils import com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN import com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY import com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST import com.android.net.module.util.structs.PrefixInformationOption import com.android.testutils.ArpRequestFilter import com.android.testutils.ArpRequestFilter import com.android.testutils.ETHER_HEADER_LENGTH import com.android.testutils.ETHER_HEADER_LENGTH import com.android.testutils.IPV4_HEADER_LENGTH import com.android.testutils.IPV4_HEADER_LENGTH Loading @@ -42,9 +53,13 @@ import org.junit.After import org.junit.Assert.assertArrayEquals import org.junit.Assert.assertArrayEquals import org.junit.Before import org.junit.Before import org.junit.Test import org.junit.Test import java.io.FileDescriptor import java.net.Inet4Address import java.net.Inet4Address import kotlin.reflect.KClass import kotlin.reflect.KClass import java.net.Inet6Address import java.nio.ByteBuffer import kotlin.test.assertEquals import kotlin.test.assertEquals import kotlin.test.assertTrue import kotlin.test.fail import kotlin.test.fail class NetworkStackUtilsIntegrationTest { class NetworkStackUtilsIntegrationTest { Loading @@ -52,8 +67,12 @@ class NetworkStackUtilsIntegrationTest { private val context by lazy { inst.context } private val context by lazy { inst.context } private val TEST_TIMEOUT_MS = 10_000L private val TEST_TIMEOUT_MS = 10_000L private val TEST_MTU = 1500 private val TEST_TARGET_IPV4_ADDR = parseNumericAddress("192.0.2.42") as Inet4Address private val TEST_TARGET_IPV4_ADDR = parseNumericAddress("192.0.2.42") as Inet4Address private val TEST_SRC_MAC = MacAddress.fromString("BA:98:76:54:32:10") private val TEST_TARGET_MAC = MacAddress.fromString("01:23:45:67:89:0A") private val TEST_TARGET_MAC = MacAddress.fromString("01:23:45:67:89:0A") private val TEST_INET6ADDR_1 = parseNumericAddress("2001:db8::1") as Inet6Address private val TEST_INET6ADDR_2 = parseNumericAddress("2001:db8::2") as Inet6Address private val readerHandler = HandlerThread( private val readerHandler = HandlerThread( NetworkStackUtilsIntegrationTest::class.java.simpleName) NetworkStackUtilsIntegrationTest::class.java.simpleName) Loading Loading @@ -103,8 +122,7 @@ class NetworkStackUtilsIntegrationTest { null /* hostname */, false /* metered */, 1500 /* mtu */, null /* hostname */, false /* metered */, 1500 /* mtu */, null /* captivePortalUrl */) null /* captivePortalUrl */) // Not using .array as per errorprone "ByteBufferBackingArray" recommendation // Not using .array as per errorprone "ByteBufferBackingArray" recommendation val originalPacket = ByteArray(buffer.limit()) val originalPacket = buffer.readAsArray() buffer.get(originalPacket) Os.sendto(socket, originalPacket, 0 /* bytesOffset */, originalPacket.size /* bytesCount */, Os.sendto(socket, originalPacket, 0 /* bytesOffset */, originalPacket.size /* bytesCount */, 0 /* flags */, TEST_TARGET_IPV4_ADDR, DhcpPacket.DHCP_CLIENT.toInt() /* port */) 0 /* flags */, TEST_TARGET_IPV4_ADDR, DhcpPacket.DHCP_CLIENT.toInt() /* port */) Loading @@ -112,7 +130,7 @@ class NetworkStackUtilsIntegrationTest { // Verify the packet was sent to the mac address specified in the ARP entry // Verify the packet was sent to the mac address specified in the ARP entry // Also accept ARP requests, but expect that none is sent before the UDP packet // Also accept ARP requests, but expect that none is sent before the UDP packet // IPv6 NS may be sent on the interface but will be filtered out // IPv6 NS may be sent on the interface but will be filtered out val sentPacket = reader.popPacket(TEST_TIMEOUT_MS, IPv4UdpFilter().or(ArpRequestFilter())) val sentPacket = reader.poll(TEST_TIMEOUT_MS, IPv4UdpFilter().or(ArpRequestFilter())) ?: fail("Packet was not sent on the interface") ?: fail("Packet was not sent on the interface") val sentTargetAddr = MacAddress.fromBytes(sentPacket.copyOfRange(0, ETHER_ADDR_LEN)) val sentTargetAddr = MacAddress.fromBytes(sentPacket.copyOfRange(0, ETHER_ADDR_LEN)) Loading @@ -123,6 +141,54 @@ class NetworkStackUtilsIntegrationTest { assertArrayEquals("Sent packet != original packet", originalPacket, sentDhcpPacket) assertArrayEquals("Sent packet != original packet", originalPacket, sentDhcpPacket) } } @Test fun testAttachRaFilter() { val socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6) val ifParams = InterfaceParams.getByName(iface.interfaceName) ?: fail("Could not obtain interface params for ${iface.interfaceName}") val socketAddr = SocketUtils.makePacketSocketAddress(ETH_P_IPV6, ifParams.index) Os.bind(socket, socketAddr) Os.setsockoptTimeval(socket, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(TEST_TIMEOUT_MS)) // Verify that before setting any filter, the socket receives pings val echo = Ipv6Utils.buildEchoRequestPacket(TEST_SRC_MAC, TEST_TARGET_MAC, TEST_INET6ADDR_1, TEST_INET6ADDR_2) reader.sendResponse(echo) echo.rewind() assertNextPacketEquals(socket, echo.readAsArray(), "ICMPv6 echo") NetworkStackUtils.attachRaFilter(socket, ARPHRD_ETHER) // Send another echo, then an RA. After setting the filter expect only the RA. echo.rewind() reader.sendResponse(echo) val pio = PrefixInformationOption.build(IpPrefix("2001:db8:1::/64"), 0.toByte() /* flags */, 3600 /* validLifetime */, 1800 /* preferredLifetime */) val ra = Ipv6Utils.buildRaPacket(TEST_SRC_MAC, TEST_TARGET_MAC, TEST_INET6ADDR_1 /* routerAddr */, IPV6_ADDR_ALL_NODES_MULTICAST, 0.toByte() /* flags */, 1800 /* lifetime */, 0 /* reachableTime */, 0 /* retransTimer */, pio) reader.sendResponse(ra) ra.rewind() assertNextPacketEquals(socket, ra.readAsArray(), "ICMPv6 RA") } private fun assertNextPacketEquals(socket: FileDescriptor, expected: ByteArray, descr: String) { val buffer = ByteArray(TEST_MTU) val readPacket = Os.read(socket, buffer, 0 /* byteOffset */, buffer.size) assertTrue(readPacket > 0, "$descr not received") assertEquals(expected.size, readPacket, "Received packet size does not match for $descr") assertArrayEquals("Received packet != expected $descr", expected, buffer.copyOfRange(0, readPacket)) } } private fun ByteBuffer.readAsArray(): ByteArray { val out = ByteArray(remaining()) get(out) return out } } private fun <T : Any> Context.assertHasService(manager: KClass<T>) = getSystemService(manager.java) private fun <T : Any> Context.assertHasService(manager: KClass<T>) = getSystemService(manager.java) Loading