Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0be71aff authored by Remi NGUYEN VAN's avatar Remi NGUYEN VAN Committed by Gerrit Code Review
Browse files

Merge "Add test for NetworkStackUtils.attachRaFilter"

parents 83a64b86 3df5c234
Loading
Loading
Loading
Loading
+70 −4
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.net.util
import android.Manifest.permission.MANAGE_TEST_NETWORKS
import android.content.Context
import android.net.InetAddresses.parseNumericAddress
import android.net.IpPrefix
import android.net.MacAddress
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
@@ -26,12 +27,22 @@ import android.net.dhcp.DhcpPacket
import android.os.HandlerThread
import android.system.Os
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.SOCK_DGRAM
import android.system.OsConstants.SOCK_NONBLOCK
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.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.ETHER_HEADER_LENGTH
import com.android.testutils.IPV4_HEADER_LENGTH
@@ -42,9 +53,13 @@ import org.junit.After
import org.junit.Assert.assertArrayEquals
import org.junit.Before
import org.junit.Test
import java.io.FileDescriptor
import java.net.Inet4Address
import kotlin.reflect.KClass
import java.net.Inet6Address
import java.nio.ByteBuffer
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail

class NetworkStackUtilsIntegrationTest {
@@ -52,8 +67,12 @@ class NetworkStackUtilsIntegrationTest {
    private val context by lazy { inst.context }

    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_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_INET6ADDR_1 = parseNumericAddress("2001:db8::1") as Inet6Address
    private val TEST_INET6ADDR_2 = parseNumericAddress("2001:db8::2") as Inet6Address

    private val readerHandler = HandlerThread(
            NetworkStackUtilsIntegrationTest::class.java.simpleName)
@@ -103,8 +122,7 @@ class NetworkStackUtilsIntegrationTest {
                null /* hostname */, false /* metered */, 1500 /* mtu */,
                null /* captivePortalUrl */)
        // Not using .array as per errorprone "ByteBufferBackingArray" recommendation
        val originalPacket = ByteArray(buffer.limit())
        buffer.get(originalPacket)
        val originalPacket = buffer.readAsArray()

        Os.sendto(socket, originalPacket, 0 /* bytesOffset */, originalPacket.size /* bytesCount */,
                0 /* flags */, TEST_TARGET_IPV4_ADDR, DhcpPacket.DHCP_CLIENT.toInt() /* port */)
@@ -112,7 +130,7 @@ class NetworkStackUtilsIntegrationTest {
        // 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
        // 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")

        val sentTargetAddr = MacAddress.fromBytes(sentPacket.copyOfRange(0, ETHER_ADDR_LEN))
@@ -123,6 +141,54 @@ class NetworkStackUtilsIntegrationTest {

        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)