blob: 607d4245f5e634df357dddc0d7cf2a7d47dd0a51 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "addr.h"
#include <arpa/inet.h>
#include <gtest/gtest.h>
#if PACKET_SOCKETS
#include <netpacket/packet.h>
#include "api_abstraction.h"
#include "testutil.h"
#endif // PACKET_SOCKETS
#define EXPECT_NO_VALUE(expr) \
do { \
const std::optional val = expr; \
EXPECT_FALSE(val.has_value()) << val.value(); \
} while (0)
#define EXPECT_NO_VALUE_FMT(expr, format) \
do { \
const std::optional val = expr; \
EXPECT_FALSE(val.has_value()) << format(val.value()); \
} while (0)
TEST(AddrTest, TestParseFormatNoPort) {
{
std::optional addr = Parse("192.168.0.1", std::nullopt);
EXPECT_TRUE(addr.has_value());
EXPECT_EQ(addr.value().ss_family, AF_INET);
EXPECT_EQ(Format(addr.value()), "192.168.0.1");
}
{
std::optional addr = Parse("FF01:0:0:0:0:0:0:1", std::nullopt);
EXPECT_TRUE(addr.has_value());
EXPECT_EQ(addr.value().ss_family, AF_INET6);
EXPECT_EQ(Format(addr.value()), "[ff01::1]");
}
EXPECT_NO_VALUE_FMT(Parse("bad", std::nullopt), Format);
EXPECT_NO_VALUE_FMT(Parse("192.168.0.", std::nullopt), Format);
EXPECT_NO_VALUE_FMT(Parse("FF01::jk", std::nullopt), Format);
}
TEST(AddrTest, TestParseIpv4WithScopeFormat) {
{
auto [addr, id] = ParseIpv4WithScope("192.168.0.1%2");
EXPECT_TRUE(addr.has_value());
EXPECT_TRUE(id.has_value());
char buf[INET_ADDRSTRLEN] = {};
EXPECT_STREQ(inet_ntop(AF_INET, &addr.value(), buf, sizeof(buf)), "192.168.0.1");
EXPECT_EQ(id.value(), 2);
}
{
auto [addr, id] = ParseIpv4WithScope("192.168.0.1");
EXPECT_TRUE(addr.has_value());
EXPECT_NO_VALUE(id);
char buf[INET_ADDRSTRLEN] = {};
EXPECT_STREQ(inet_ntop(AF_INET, &addr.value(), buf, sizeof(buf)), "192.168.0.1");
}
{
auto [addr, id] = ParseIpv4WithScope("FF01:0:0:0:0:0:0:1%3");
char buf[INET_ADDRSTRLEN] = {};
EXPECT_FALSE(addr.has_value()) << inet_ntop(AF_INET, &addr.value(), buf, sizeof(buf));
EXPECT_TRUE(id.has_value());
EXPECT_EQ(id.value(), 3);
}
{
auto [addr, id] = ParseIpv4WithScope("192.168.0.1%abc");
EXPECT_TRUE(addr.has_value());
EXPECT_NO_VALUE(id);
char buf[INET_ADDRSTRLEN] = {};
EXPECT_STREQ(inet_ntop(AF_INET, &addr.value(), buf, sizeof(buf)), "192.168.0.1");
}
}
TEST(AddrTest, TestParseFormat) {
{
std::optional addr = Parse("192.168.0.1:2020");
EXPECT_TRUE(addr.has_value());
EXPECT_EQ(Format(addr.value()), "192.168.0.1:2020");
EXPECT_EQ(addr.value().ss_family, AF_INET);
const sockaddr_in& addr_in = *reinterpret_cast<struct sockaddr_in*>(&addr.value());
union {
uint8_t b[4];
uint32_t x;
} ip4 = {{192, 168, 0, 1}};
EXPECT_EQ(addr_in.sin_addr.s_addr, ip4.x);
EXPECT_EQ(addr_in.sin_port, htons(2020));
}
{
std::optional addr = Parse("[FF01:0:0:0:0:0:0:1]:4040");
EXPECT_TRUE(addr.has_value());
EXPECT_EQ(Format(addr.value()), "[ff01::1]:4040");
EXPECT_EQ(addr.value().ss_family, AF_INET6);
const sockaddr_in6& addr_in6 = *reinterpret_cast<struct sockaddr_in6*>(&addr.value());
const uint8_t cmp[] = {0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
EXPECT_EQ(memcmp(addr_in6.sin6_addr.s6_addr, cmp, 16), 0);
EXPECT_EQ(addr_in6.sin6_port, htons(4040));
}
{
std::optional addr = Parse("[ff02::2%100]:3");
EXPECT_TRUE(addr.has_value());
EXPECT_EQ(Format(addr.value()), "[ff02::2%100]:3");
EXPECT_EQ(addr.value().ss_family, AF_INET6);
const sockaddr_in6& addr_in6 = *reinterpret_cast<struct sockaddr_in6*>(&addr.value());
EXPECT_EQ(addr_in6.sin6_scope_id, 100u);
}
EXPECT_NO_VALUE_FMT(Parse(""), Format);
EXPECT_NO_VALUE_FMT(Parse(":0"), Format);
EXPECT_NO_VALUE_FMT(Parse("any::0"), Format);
EXPECT_NO_VALUE_FMT(Parse("[]"), Format);
EXPECT_NO_VALUE_FMT(Parse("[]:0"), Format);
EXPECT_NO_VALUE_FMT(Parse("[::]"), Format);
EXPECT_NO_VALUE_FMT(Parse("[::]::0"), Format);
}
TEST(AddrTest, TestAddrlen) {
sockaddr_storage addr_unspec;
addr_unspec.ss_family = AF_UNSPEC;
EXPECT_EQ(AddrLen(addr_unspec), sizeof(sockaddr_storage));
std::optional addr_v4 = Parse("192.168.0.1:2020");
ASSERT_TRUE(addr_v4.has_value());
ASSERT_EQ(addr_v4.value().ss_family, AF_INET);
EXPECT_EQ(AddrLen(addr_v4.value()), sizeof(sockaddr_in));
std::optional addr_v6 = Parse("[ff02::2%100]:3");
ASSERT_TRUE(addr_v6.has_value());
ASSERT_EQ(addr_v6.value().ss_family, AF_INET6);
EXPECT_EQ(AddrLen(addr_v6.value()), sizeof(sockaddr_in6));
}
#if PACKET_SOCKETS
TEST(AddrTest, TestParseSockAddrLl) {
constexpr unsigned int kIfIndex = 5;
constexpr uint16_t kIpv4Protocol = 2048;
TestApi api;
EXPECT_CALL(api, if_nametoindex(testing::_)).WillOnce([](const char* ifname) {
EXPECT_EQ(std::string(ifname), "myinterfacename");
return kIfIndex;
});
std::optional actual_addr = ParseSockAddrLlFromArg("2048:myinterfacename", &api);
const struct sockaddr_ll expected_addr = {
.sll_family = AF_PACKET,
.sll_protocol = htons(kIpv4Protocol),
.sll_ifindex = kIfIndex,
};
ASSERT_TRUE(actual_addr.has_value());
EXPECT_EQ(actual_addr->sll_family, expected_addr.sll_family);
EXPECT_EQ(actual_addr->sll_protocol, expected_addr.sll_protocol);
EXPECT_EQ(actual_addr->sll_ifindex, expected_addr.sll_ifindex);
}
TEST(AddrTest, TestFormatHardwareAddress) {
const unsigned char addr_bytes[8] = {0x00, 0x0f, 0xff, 0x12, 0x34, 0x56, 0x00, 0x00};
std::stringstream o1;
o1 << PrintHardwareAddress{6, addr_bytes};
EXPECT_EQ(o1.str(), "[00:0f:ff:12:34:56]");
std::stringstream o2;
o2 << PrintHardwareAddress{0, addr_bytes};
EXPECT_EQ(o2.str(), "[]");
}
#endif // PACKET_SOCKETS