From 8ff032b990d514ead8ea7ea06bd412fcd0289248 Mon Sep 17 00:00:00 2001 From: Hungming Chen Date: Fri, 17 Dec 2021 21:12:53 +0800 Subject: [PATCH] [CLATJ#6] libclat: move configure_packet_socket() from netd to apex configure_packet_socket() is moved from ClatdController. Only change the failure return value from errno to -errno. The remaining parts are the same. The test is modified from ClatdControllerTest::ConfigureIpv6Address. Simply set socket filter to an interface and check that the packet socket is bound to the interface. We can't check the socket filter because there is no way to fetch it from the kernel. Bug: 212345928 Test: build and boot atest libclat_test Change-Id: Ia33c21051b040829c7d2aa55ed5b7de8766c98c5 --- service/native/libs/libclat/Android.bp | 7 ++- service/native/libs/libclat/clatutils.cpp | 60 +++++++++++++++++++ .../native/libs/libclat/clatutils_test.cpp | 27 +++++++++ .../libs/libclat/include/libclat/clatutils.h | 1 + 4 files changed, 94 insertions(+), 1 deletion(-) diff --git a/service/native/libs/libclat/Android.bp b/service/native/libs/libclat/Android.bp index 9fe441ac70..85407871f2 100644 --- a/service/native/libs/libclat/Android.bp +++ b/service/native/libs/libclat/Android.bp @@ -39,6 +39,11 @@ cc_test { "libbase", "libclat", "libip_checksum", + "libnetd_test_tun_interface", ], - shared_libs: ["liblog"], + shared_libs: [ + "liblog", + "libnetutils", + ], + require_root: true, } \ No newline at end of file diff --git a/service/native/libs/libclat/clatutils.cpp b/service/native/libs/libclat/clatutils.cpp index 8f037ad07e..4a125ba9ff 100644 --- a/service/native/libs/libclat/clatutils.cpp +++ b/service/native/libs/libclat/clatutils.cpp @@ -17,6 +17,9 @@ #include "libclat/clatutils.h" #include +#include +#include +#include #include #include #include @@ -26,6 +29,10 @@ extern "C" { #include "checksum.h" } +// Sync from external/android-clat/clatd.h +#define MAXMTU 65536 +#define PACKETLEN (MAXMTU + sizeof(struct tun_pi)) + // Sync from system/netd/include/netid_client.h. #define MARK_UNSET 0u @@ -203,6 +210,59 @@ int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_ return mtu; } +/* function: configure_packet_socket + * Binds the packet socket and attaches the receive filter to it. + * sock - the socket to configure + * addr - the IP address to filter + * ifindex - index of interface to add the filter to + * returns: 0 on success, -errno on failure + */ +int configure_packet_socket(int sock, in6_addr* addr, int ifindex) { + uint32_t* ipv6 = addr->s6_addr32; + + // clang-format off + struct sock_filter filter_code[] = { + // Load the first four bytes of the IPv6 destination address (starts 24 bytes in). + // Compare it against the first four bytes of our IPv6 address, in host byte order (BPF loads + // are always in host byte order). If it matches, continue with next instruction (JMP 0). If it + // doesn't match, jump ahead to statement that returns 0 (ignore packet). Repeat for the other + // three words of the IPv6 address, and if they all match, return PACKETLEN (accept packet). + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 24), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[0]), 0, 7), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 28), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[1]), 0, 5), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 32), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[2]), 0, 3), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, 36), + BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, htonl(ipv6[3]), 0, 1), + BPF_STMT(BPF_RET | BPF_K, PACKETLEN), + BPF_STMT(BPF_RET | BPF_K, 0), + }; + // clang-format on + struct sock_fprog filter = {sizeof(filter_code) / sizeof(filter_code[0]), filter_code}; + + if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))) { + int res = errno; + ALOGE("attach packet filter failed: %s", strerror(errno)); + return -res; + } + + struct sockaddr_ll sll = { + .sll_family = AF_PACKET, + .sll_protocol = htons(ETH_P_IPV6), + .sll_ifindex = ifindex, + .sll_pkttype = + PACKET_OTHERHOST, // The 464xlat IPv6 address is not assigned to the kernel. + }; + if (bind(sock, (struct sockaddr*)&sll, sizeof(sll))) { + int res = errno; + ALOGE("binding packet socket: %s", strerror(errno)); + return -res; + } + + return 0; +} + } // namespace clat } // namespace net } // namespace android diff --git a/service/native/libs/libclat/clatutils_test.cpp b/service/native/libs/libclat/clatutils_test.cpp index bb9678d665..4153e19d37 100644 --- a/service/native/libs/libclat/clatutils_test.cpp +++ b/service/native/libs/libclat/clatutils_test.cpp @@ -17,6 +17,9 @@ #include #include #include +#include +#include +#include "tun_interface.h" extern "C" { #include "checksum.h" @@ -29,6 +32,7 @@ namespace android { namespace net { namespace clat { +using android::net::TunInterface; using base::StringPrintf; class ClatUtils : public ::testing::Test {}; @@ -155,6 +159,29 @@ TEST_F(ClatUtils, DetectMtu) { ASSERT_EQ(detect_mtu(&in6addr_loopback, htonl(1), 0 /*MARK_UNSET*/), 65536); } +TEST_F(ClatUtils, ConfigurePacketSocket) { + // Create an interface for configure_packet_socket to attach socket filter to. + TunInterface v6Iface; + ASSERT_EQ(0, v6Iface.init()); + + int s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, htons(ETH_P_IPV6)); + EXPECT_LE(0, s); + struct in6_addr addr6; + EXPECT_EQ(1, inet_pton(AF_INET6, "2001:db8::f00", &addr6)); + EXPECT_EQ(0, configure_packet_socket(s, &addr6, v6Iface.ifindex())); + + // Check that the packet socket is bound to the interface. We can't check the socket filter + // because there is no way to fetch it from the kernel. + sockaddr_ll sll; + socklen_t len = sizeof(sll); + ASSERT_EQ(0, getsockname(s, reinterpret_cast(&sll), &len)); + EXPECT_EQ(htons(ETH_P_IPV6), sll.sll_protocol); + EXPECT_EQ(sll.sll_ifindex, v6Iface.ifindex()); + + close(s); + v6Iface.destroy(); +} + } // namespace clat } // namespace net } // namespace android diff --git a/service/native/libs/libclat/include/libclat/clatutils.h b/service/native/libs/libclat/include/libclat/clatutils.h index c8f83f16b4..812c86eb21 100644 --- a/service/native/libs/libclat/include/libclat/clatutils.h +++ b/service/native/libs/libclat/include/libclat/clatutils.h @@ -26,6 +26,7 @@ void makeChecksumNeutral(in6_addr* v6, const in_addr v4, const in6_addr& nat64Pr int generateIpv6Address(const char* iface, const in_addr v4, const in6_addr& nat64Prefix, in6_addr* v6); int detect_mtu(const struct in6_addr* plat_subnet, uint32_t plat_suffix, uint32_t mark); +int configure_packet_socket(int sock, in6_addr* addr, int ifindex); // For testing typedef bool (*isIpv4AddrFreeFn)(in_addr_t);