From 82d4b9956d8d19db09a153b4f0ae6310dc92c441 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 16 Mar 2021 11:46:06 +0900 Subject: [PATCH] Add a test for TetheringUtils.setupNaSocket. Because most of the tethering tests are unprivileged, we cannot test this code on real sockets. So use an AF_UNIX socketpair. Bug: 154669942 Bug: 182785371 Test: test-only change Change-Id: I843fddb3aaeab33628438f3bcd6a4166062de962 --- .../android/net/util/TetheringUtilsTest.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java b/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java index 91c7771cc7..287c253b5e 100644 --- a/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java +++ b/Tethering/tests/unit/src/android/net/util/TetheringUtilsTest.java @@ -17,27 +17,49 @@ package android.net.util; import static android.net.TetheringManager.TETHERING_USB; import static android.net.TetheringManager.TETHERING_WIFI; +import static android.system.OsConstants.AF_UNIX; +import static android.system.OsConstants.EAGAIN; +import static android.system.OsConstants.SOCK_CLOEXEC; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOCK_NONBLOCK; +import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import android.net.LinkAddress; +import android.net.MacAddress; import android.net.TetheringRequestParcel; +import android.system.ErrnoException; +import android.system.Os; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.net.module.util.Ipv6Utils; +import com.android.net.module.util.NetworkStackConstants; +import com.android.net.module.util.Struct; +import com.android.net.module.util.structs.EthernetHeader; +import com.android.net.module.util.structs.Icmpv6Header; +import com.android.net.module.util.structs.Ipv6Header; import com.android.testutils.MiscAsserts; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.io.FileDescriptor; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; + @RunWith(AndroidJUnit4.class) @SmallTest public class TetheringUtilsTest { private static final LinkAddress TEST_SERVER_ADDR = new LinkAddress("192.168.43.1/24"); private static final LinkAddress TEST_CLIENT_ADDR = new LinkAddress("192.168.43.5/24"); + private static final int PACKET_SIZE = 1500; + private TetheringRequestParcel mTetheringRequest; @Before @@ -84,4 +106,74 @@ public class TetheringUtilsTest { MiscAsserts.assertFieldCountEquals(5, TetheringRequestParcel.class); } + + // Writes the specified packet to a filedescriptor, skipping the Ethernet header. + // Needed because the Ipv6Utils methods for building packets always include the Ethernet header, + // but socket filters applied by TetheringUtils expect the packet to start from the IP header. + private int writePacket(FileDescriptor fd, ByteBuffer pkt) throws Exception { + pkt.flip(); + int offset = Struct.getSize(EthernetHeader.class); + int len = pkt.capacity() - offset; + return Os.write(fd, pkt.array(), offset, len); + } + + // Reads a packet from the filedescriptor. + private ByteBuffer readIpPacket(FileDescriptor fd) throws Exception { + ByteBuffer buf = ByteBuffer.allocate(PACKET_SIZE); + Os.read(fd, buf); + return buf; + } + + private interface SocketFilter { + void apply(FileDescriptor fd) throws Exception; + } + + private ByteBuffer checkIcmpSocketFilter(ByteBuffer passed, ByteBuffer dropped, + SocketFilter filter) throws Exception { + FileDescriptor in = new FileDescriptor(); + FileDescriptor out = new FileDescriptor(); + Os.socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, in, out); + + // Before the filter is applied, it doesn't drop anything. + int len = writePacket(out, dropped); + ByteBuffer received = readIpPacket(in); + assertEquals(len, received.position()); + + // Install the socket filter. Then write two packets, the first expected to be dropped and + // the second expected to be passed. Check that only the second makes it through. + filter.apply(in); + writePacket(out, dropped); + len = writePacket(out, passed); + received = readIpPacket(in); + assertEquals(len, received.position()); + received.flip(); + + // Check there are no more packets to read. + try { + readIpPacket(in); + } catch (ErrnoException expected) { + assertEquals(EAGAIN, expected.errno); + } + + return received; + } + + @Test + public void testIcmpSocketFilters() throws Exception { + MacAddress mac1 = MacAddress.fromString("11:22:33:44:55:66"); + MacAddress mac2 = MacAddress.fromString("aa:bb:cc:dd:ee:ff"); + Inet6Address ll1 = (Inet6Address) InetAddress.getByName("fe80::1"); + Inet6Address ll2 = (Inet6Address) InetAddress.getByName("fe80::abcd"); + Inet6Address allRouters = NetworkStackConstants.IPV6_ADDR_ALL_ROUTERS_MULTICAST; + + final ByteBuffer na = Ipv6Utils.buildNaPacket(mac1, mac2, ll1, ll2, 0, ll1); + final ByteBuffer rs = Ipv6Utils.buildRsPacket(mac1, mac2, ll1, allRouters); + + ByteBuffer received = checkIcmpSocketFilter(na /* passed */, rs /* dropped */, + TetheringUtils::setupNaSocket); + + Struct.parse(Ipv6Header.class, received); // Skip IPv6 header. + Icmpv6Header icmpv6 = Struct.parse(Icmpv6Header.class, received); + assertEquals(NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT, icmpv6.type); + } }