From 72f770c4ad644ad49371531ac030196eff32076b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 4 Jan 2019 15:00:28 +0900 Subject: Test clatd methods that affect interface IP addresses. Depend on tun_interface so we can add tests to clatd_test that use a real interface instead of mocking everything out. Add a simple test for determining the clat IPv6 address. Test: atest clatd_test Change-Id: I1f10c372388a7c663bebab3c45b206036a264673 --- clatd_test.cpp | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/clatd_test.cpp b/clatd_test.cpp index 2a10101..4f998ea 100644 --- a/clatd_test.cpp +++ b/clatd_test.cpp @@ -24,17 +24,22 @@ #include #include +#include "tun_interface.h" extern "C" { #include "checksum.h" #include "clatd.h" #include "config.h" +#include "getaddr.h" #include "translate.h" +#include "tun.h" } // For convenience. #define ARRAYSIZE(x) sizeof((x)) / sizeof((x)[0]) +using android::net::TunInterface; + // Default translation parameters. static const char kIPv4LocalAddr[] = "192.0.0.4"; static const char kIPv6LocalAddr[] = "2001:db8:0:b11::464"; @@ -557,15 +562,26 @@ struct clat_config Global_Clatd_Config; class ClatdTest : public ::testing::Test { protected: + static TunInterface sTun; + virtual void SetUp() { inet_pton(AF_INET, kIPv4LocalAddr, &Global_Clatd_Config.ipv4_local_subnet); inet_pton(AF_INET6, kIPv6PlatSubnet, &Global_Clatd_Config.plat_subnet); - inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet); + memset(&Global_Clatd_Config.ipv6_local_subnet, 0, sizeof(in6_addr)); Global_Clatd_Config.ipv6_host_id = in6addr_any; Global_Clatd_Config.use_dynamic_iid = 1; + Global_Clatd_Config.default_pdp_interface = const_cast(sTun.name().c_str()); } + + // Static because setting up the tun interface takes about 40ms. + static void SetUpTestCase() { ASSERT_EQ(0, sTun.init()); } + + // Closing the socket removes the interface and IP addresses. + static void TearDownTestCase() { sTun.destroy(); } }; +TunInterface ClatdTest::sTun; + void expect_ipv6_addr_equal(struct in6_addr *expected, struct in6_addr *actual) { if (!IN6_ARE_ADDR_EQUAL(expected, actual)) { char expected_str[INET6_ADDRSTRLEN], actual_str[INET6_ADDRSTRLEN]; @@ -868,6 +884,9 @@ TEST_F(ClatdTest, AdjustChecksum) { } TEST_F(ClatdTest, Translate) { + // This test uses hardcoded packets so the clatd address must be fixed. + inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet); + uint8_t udp_ipv4[] = { IPV4_UDP_HEADER UDP_HEADER PAYLOAD }; uint8_t udp_ipv6[] = { IPV6_UDP_HEADER UDP_HEADER PAYLOAD }; fix_udp_checksum(udp_ipv4); @@ -886,6 +905,9 @@ TEST_F(ClatdTest, Translate) { } TEST_F(ClatdTest, Fragmentation) { + // This test uses hardcoded packets so the clatd address must be fixed. + inet_pton(AF_INET6, kIPv6LocalAddr, &Global_Clatd_Config.ipv6_local_subnet); + check_fragment_translation(kIPv4Fragments, kIPv4FragLengths, kIPv6Fragments, kIPv6FragLengths, ARRAYSIZE(kIPv4Fragments), "IPv4->IPv6 fragment translation"); @@ -914,7 +936,7 @@ TEST_F(ClatdTest, TranslateChecksumNeutral) { ASSERT_TRUE(inet_pton(AF_INET6, "2001:db8:1:2:f076:ae99:124e:aa54", &Global_Clatd_Config.ipv6_local_subnet)); config_generate_local_ipv6_subnet(&Global_Clatd_Config.ipv6_local_subnet); - ASSERT_NE((uint32_t)0x00000464, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); + ASSERT_NE(htonl((uint32_t)0x00000464), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); ASSERT_NE((uint32_t)0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); // Check that translating UDP packets is checksum-neutral. First, IPv4. @@ -932,3 +954,39 @@ TEST_F(ClatdTest, TranslateChecksumNeutral) { check_translate_checksum_neutral(udp_ipv4, sizeof(udp_ipv4), sizeof(udp_ipv4) + 20, "UDP/IPv4 -> UDP/IPv6 checksum neutral"); } + +TEST_F(ClatdTest, GetInterfaceIp) { + union anyip *ip = getinterface_ip(sTun.name().c_str(), AF_INET6); + ASSERT_NE(nullptr, ip); + in6_addr expected = sTun.srcAddr(); + in6_addr actual = ip->ip6; + expect_ipv6_addr_equal(&expected, &actual); +} + +TEST_F(ClatdTest, UpdateIpv6Address) { + // Create some fake but realistic-looking sockets so update_clat_ipv6_address doesn't balk. + struct tun_data tunnel = { + .write_fd6 = socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW), + .read_fd6 = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)), + }; + + // Run update_clat_ipv6_address with no local IID yet picked. + ASSERT_TRUE(IN6_IS_ADDR_UNSPECIFIED(&Global_Clatd_Config.ipv6_local_subnet)); + ASSERT_EQ(1, update_clat_ipv6_address(&tunnel, sTun.name().c_str())); + + // Check that it generated an IID in the same prefix as the address assigned to the interface, + // and that the IID is not the default IID. + in6_addr addr = sTun.srcAddr(); + EXPECT_TRUE(ipv6_prefix_equal(&Global_Clatd_Config.ipv6_local_subnet, &addr)); + EXPECT_FALSE(IN6_ARE_ADDR_EQUAL(&Global_Clatd_Config.ipv6_local_subnet, &addr)); + EXPECT_NE(htonl((uint32_t)0x00000464), Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); + EXPECT_NE((uint32_t)0, Global_Clatd_Config.ipv6_local_subnet.s6_addr32[3]); + + // 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(tunnel.read_fd6, reinterpret_cast(&sll), &len)); + EXPECT_EQ(htons(ETH_P_IPV6), sll.sll_protocol); + EXPECT_EQ(sll.sll_ifindex, sTun.ifindex()); +} -- cgit v1.2.3