refactor: overhaul tr_address special address checks (#7818)

* refactor: rewrite is_martian_addr() with tr_address methods

- Fix broken check for IPv4 multicast address in is_martian_address()

* refactor: rewrite is_global_unicast_address()

- Rewrite using new tr_address methods
- Add missing IPv4 loopback check
- Follow RFC 4291 IPv6 global unicast definition
- Fix and update existing tests

* chore: reorganise methods and add comments

* fix: check for teredo and 6to4

* test: tests for new methods
This commit is contained in:
Yat Ho
2025-11-22 08:09:38 +08:00
committed by GitHub
parent 40e1bd660d
commit 25d2ebf8fc
9 changed files with 920 additions and 193 deletions

View File

@@ -141,7 +141,7 @@ TEST_F(IPCacheTest, setGlobalAddr)
static auto constexpr AddrStr = std::array{
"8.8.8.8"sv, "192.168.133.133"sv, "172.16.241.133"sv, "2001:1890:1112:1::20"sv, "fd12:3456:789a:1::1"sv,
};
static auto constexpr AddrTests = std::array{ true, false, false, true, false };
static auto constexpr AddrTests = std::array{ true, false, false, true, true };
static_assert(TR_AF_INET == 0);
static_assert(TR_AF_INET6 == 1);
static_assert(NUM_TR_AF_INET_TYPES == 2);
@@ -154,7 +154,7 @@ TEST_F(IPCacheTest, setGlobalAddr)
{
auto const addr = tr_address::from_string(AddrStr[i]);
ASSERT_TRUE(addr.has_value());
EXPECT_EQ(ip_cache_->set_global_addr(*addr), AddrTests[i]);
EXPECT_EQ(ip_cache_->set_global_addr(*addr), AddrTests[i]) << AddrStr[i];
if (auto const val = ip_cache_->global_addr(addr->type); val && AddrTests[i])
{
EXPECT_EQ(val->display_name(), AddrStr[i]);
@@ -213,11 +213,13 @@ TEST_F(IPCacheTest, globalSourceIPv6)
TEST_F(IPCacheTest, onResponseIPQuery)
{
static auto constexpr AddrStr = std::array{
"8.8.8.8"sv, "192.168.133.133"sv, "172.16.241.133"sv, "2001:1890:1112:1::20"sv, "fd12:3456:789a:1::1"sv,
"91.121.74.28"sv, "2001:1890:1112:1::20"sv
"8.8.8.8"sv, "192.168.133.133"sv, "172.16.241.133"sv, "2001:1890:1112:1::20"sv, "fd12:3456:789a:1::1"sv,
"91.121.74.28"sv, "2001:1890:1112:1::20"sv,
};
static auto constexpr AddrTests = std::array{
std::array{ true, false, false, false, false, true, false /* IPv4 */ },
std::array{ false, false, false, true, true, false, true /* IPv6 */ },
};
static auto constexpr AddrTests = std::array{ std::array{ true, false, false, false, false, true, false /* IPv4 */ },
std::array{ false, false, false, true, false, false, true /* IPv6 */ } };
static_assert(TR_AF_INET == 0);
static_assert(TR_AF_INET6 == 1);
static_assert(NUM_TR_AF_INET_TYPES == 2);
@@ -228,8 +230,9 @@ TEST_F(IPCacheTest, onResponseIPQuery)
{
void fetch(tr_web::FetchOptions&& options) override // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
{
auto response = tr_web::FetchResponse{ http_code, std::string{ AddrStr[k_] }, std::string{}, true,
false, options.done_func_user_data };
auto response = tr_web::FetchResponse{
http_code, std::string{ AddrStr[k_] }, std::string{}, true, false, options.done_func_user_data,
};
options.done_func(response);
}
@@ -256,7 +259,8 @@ TEST_F(IPCacheTest, onResponseIPQuery)
ip_cache_->update_global_addr(type);
auto const global_addr = ip_cache_->global_addr(type);
EXPECT_EQ(!!global_addr, j == 200 /* HTTP_OK */ && AddrTests[i][k]);
EXPECT_EQ(!!global_addr, j == 200 /* HTTP_OK */ && AddrTests[i][k])
<< "i = " << i << ", j = "sv << j << ", addr = "sv << AddrStr[k];
if (global_addr)
{
EXPECT_EQ(global_addr->display_name(), AddrStr[k]);

View File

@@ -5,7 +5,6 @@
#include <algorithm>
#include <array>
#include <cassert>
#include <cstddef> // std::byte, size_t
#include <string_view>
#include <tuple>
@@ -32,8 +31,7 @@ TEST_F(NetTest, conversionsIPv4)
static auto constexpr AddrStr = "127.0.0.1"sv;
auto addr = tr_address::from_string(AddrStr);
EXPECT_TRUE(addr.has_value());
assert(addr.has_value());
ASSERT_TRUE(addr.has_value());
EXPECT_EQ(AddrStr, addr->display_name());
auto [ss, sslen] = tr_socket_address::to_sockaddr(*addr, Port);
@@ -191,23 +189,729 @@ TEST_F(NetTest, isGlobalUnicastAddress)
{ "100.64.0.0"sv, false },
{ "100.128.0.0"sv, true },
{ "126.0.0.0"sv, true },
{ "127.0.0.0"sv, true },
{ "127.0.0.0"sv, false },
{ "169.253.255.255"sv, true },
{ "169.254.0.0"sv, false },
{ "169.254.255.255"sv, false },
{ "169.255.0.0"sv, true },
{ "223.0.0.0"sv, true },
{ "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1", false },
{ "2001:0:0eab:dead::a0:abcd:4e", true },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, true },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
EXPECT_TRUE(address.has_value());
assert(address.has_value());
EXPECT_EQ(expected, address->is_global_unicast_address()) << presentation;
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_global_unicast()) << presentation;
}
}
TEST_F(NetTest, isIPv4CurrentNetwork)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 19>{ {
{ "0.0.0.0"sv, true },
{ "0.25.37.132"sv, true },
{ "0.255.255.255"sv, true },
{ "1.0.0.0"sv, false },
{ "10.0.0.0"sv, false },
{ "10.255.0.0"sv, false },
{ "10.255.0.255"sv, false },
{ "100.64.0.0"sv, false },
{ "100.128.0.0"sv, false },
{ "126.0.0.0"sv, false },
{ "127.0.0.0"sv, false },
{ "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false },
{ "169.254.255.255"sv, false },
{ "169.255.0.0"sv, false },
{ "223.0.0.0"sv, false },
{ "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_current_network()) << presentation;
}
}
TEST_F(NetTest, isIPv4And10Private)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 18>{ {
{ "0.0.0.0"sv, false },
{ "9.255.255.255"sv, false },
{ "10.0.0.0"sv, true },
{ "10.255.0.0"sv, true },
{ "10.255.0.255"sv, true },
{ "10.255.255.255"sv, true },
{ "11.0.0.0"sv, false },
{ "100.128.0.0"sv, false },
{ "126.0.0.0"sv, false },
{ "127.0.0.0"sv, false },
{ "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false },
{ "169.254.255.255"sv, false },
{ "169.255.0.0"sv, false },
{ "223.0.0.0"sv, false },
{ "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_10_private()) << presentation;
}
}
TEST_F(NetTest, isIPv4CarrierGradeNAT)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 19>{ {
{ "0.0.0.0"sv, false },
{ "1.0.0.0"sv, false },
{ "10.0.0.0"sv, false },
{ "10.255.0.0"sv, false },
{ "100.63.255.255"sv, false },
{ "100.64.0.0"sv, true },
{ "100.100.32.0"sv, true },
{ "100.127.255.255"sv, true },
{ "100.128.0.0"sv, false },
{ "126.0.0.0"sv, false },
{ "127.0.0.0"sv, false },
{ "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false },
{ "169.254.255.255"sv, false },
{ "169.255.0.0"sv, false },
{ "223.0.0.0"sv, false },
{ "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_carrier_grade_nat()) << presentation;
}
}
TEST_F(NetTest, isIPv4Loopback)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 19>{ {
{ "0.0.0.0"sv, false },
{ "1.0.0.0"sv, false },
{ "10.0.0.0"sv, false },
{ "10.255.0.0"sv, false },
{ "10.255.0.255"sv, false },
{ "100.64.0.0"sv, false },
{ "100.128.0.0"sv, false },
{ "126.255.255.255"sv, false },
{ "127.0.0.0"sv, true },
{ "127.12.12.57"sv, true },
{ "127.255.255.255"sv, true },
{ "128.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "169.254.255.255"sv, false },
{ "169.255.0.0"sv, false },
{ "223.0.0.0"sv, false },
{ "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_loopback()) << presentation;
}
}
TEST_F(NetTest, isIPv4LinkLocal)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 18>{ {
{ "0.0.0.0"sv, false },
{ "1.0.0.0"sv, false },
{ "10.0.0.0"sv, false },
{ "10.255.0.0"sv, false },
{ "10.255.0.255"sv, false },
{ "100.64.0.0"sv, false },
{ "100.128.0.0"sv, false },
{ "126.0.0.0"sv, false },
{ "127.0.0.0"sv, false },
{ "169.253.255.255"sv, false },
{ "169.254.0.0"sv, true },
{ "169.254.235.12"sv, true },
{ "169.254.255.255"sv, true },
{ "169.255.0.0"sv, false },
{ "223.0.0.0"sv, false },
{ "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_link_local()) << presentation;
}
}
TEST_F(NetTest, isIPv4And172Private)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.0"sv, false }, { "10.255.0.255"sv, false },
{ "100.64.0.0"sv, false }, { "100.128.0.0"sv, false },
{ "126.0.0.0"sv, false }, { "127.0.0.0"sv, false },
{ "169.253.255.255"sv, false }, { "169.254.0.0"sv, false },
{ "169.254.255.255"sv, false }, { "172.15.255.255"sv, false },
{ "172.16.0.0"sv, true }, { "172.17.78.245"sv, true },
{ "172.31.255.255"sv, true }, { "172.32.0.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_172_private()) << presentation;
}
}
TEST_F(NetTest, isIPv4IetfProtocolAssignment)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "191.255.255.255"sv, false },
{ "192.0.0.0"sv, true }, { "192.0.0.14"sv, true },
{ "192.0.0.255"sv, true }, { "192.0.1.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_ietf_protocol_assignment()) << presentation;
}
}
TEST_F(NetTest, isIPv4TestNet1)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "192.0.1.255"sv, false },
{ "192.0.2.0"sv, true }, { "192.0.2.14"sv, true },
{ "192.0.2.225"sv, true }, { "192.0.3.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_test_net_1()) << presentation;
}
}
TEST_F(NetTest, isIPv4And6to4Relay)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "192.88.98.255"sv, false },
{ "192.88.99.0"sv, true }, { "192.88.99.14"sv, true },
{ "192.88.99.225"sv, true }, { "192.88.100.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_6to4_relay()) << presentation;
}
}
TEST_F(NetTest, isIPv4And192Private)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "192.167.255.255"sv, false },
{ "192.168.0.0"sv, true }, { "192.168.99.14"sv, true },
{ "192.168.255.225"sv, true }, { "192.169.0.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_192_168_private()) << presentation;
}
}
TEST_F(NetTest, isIPv4Benchmark)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "198.17.255.255"sv, false },
{ "198.18.0.0"sv, true }, { "198.19.99.14"sv, true },
{ "198.19.255.225"sv, true }, { "198.20.0.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_benchmark()) << presentation;
}
}
TEST_F(NetTest, isIPv4TestNet2)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "198.51.99.255"sv, false },
{ "198.51.100.0"sv, true }, { "198.51.100.45"sv, true },
{ "198.51.100.255"sv, true }, { "198.51.101.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_test_net_2()) << presentation;
}
}
TEST_F(NetTest, isIPv4TestNet3)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "203.0.112.255"sv, false },
{ "203.0.113.0"sv, true }, { "203.0.113.45"sv, true },
{ "203.0.113.255"sv, true }, { "203.0.114.0"sv, false },
{ "223.0.0.0"sv, false }, { "224.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_test_net_3()) << presentation;
}
}
TEST_F(NetTest, isIPv4Multicast)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "203.0.113.255"sv, false },
{ "203.0.114.0"sv, false }, { "223.255.255.255"sv, false },
{ "224.0.0.0"sv, true }, { "230.124.45.18"sv, true },
{ "239.255.255.255"sv, true }, { "240.0.0.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_multicast()) << presentation;
}
}
TEST_F(NetTest, isIPv4McastTestNet)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "203.0.113.255"sv, false },
{ "203.0.114.0"sv, false }, { "233.251.255.255"sv, false },
{ "233.252.0.0"sv, true }, { "233.252.0.18"sv, true },
{ "233.252.0.255"sv, true }, { "233.252.1.0"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_mcast_test_net()) << presentation;
}
}
TEST_F(NetTest, isIPv4ReservedClassE)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "203.0.113.255"sv, false },
{ "203.0.114.0"sv, false }, { "239.255.255.255"sv, false },
{ "240.0.0.0"sv, true }, { "247.252.0.18"sv, true },
{ "255.255.255.254"sv, true }, { "255.255.255.255"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_reserved_class_e()) << presentation;
}
}
TEST_F(NetTest, isIPv4LimitedBroadcast)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 20>{ {
{ "0.0.0.0"sv, false }, { "10.0.0.0"sv, false },
{ "10.255.0.255"sv, false }, { "100.64.0.0"sv, false },
{ "127.0.0.0"sv, false }, { "169.253.255.255"sv, false },
{ "169.254.0.0"sv, false }, { "169.254.255.255"sv, false },
{ "172.16.0.0"sv, false }, { "172.17.78.245"sv, false },
{ "172.31.255.255"sv, false }, { "203.0.113.255"sv, false },
{ "203.0.114.0"sv, false }, { "239.255.255.255"sv, false },
{ "240.0.0.0"sv, false }, { "247.252.0.18"sv, false },
{ "255.255.255.254"sv, false }, { "255.255.255.255"sv, true },
{ "0:0:0:0:0:0:0:1"sv, false }, { "2001:0:0eab:dead::a0:abcd:4e"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv4_limited_broadcast()) << presentation;
}
}
TEST_F(NetTest, isIPv6Unspecified)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, true },
{ "0:0:0:0:0:0:0:0"sv, true },
{ "::1"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, false },
{ "::ffff:255.255.255.255"sv, false },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, false },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2003::"sv, false },
{ "fe80::"sv, false },
{ "fe80::1234:5678:9876:5432"sv, false },
{ "fe80::ffff:ffff:ffff:ffff"sv, false },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, false },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_unspecified()) << presentation;
}
}
TEST_F(NetTest, isIPv6Loopback)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, false },
{ "0:0:0:0:0:0:0:0"sv, false },
{ "::1"sv, true },
{ "0:0:0:0:0:0:0:1"sv, true },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, false },
{ "::ffff:255.255.255.255"sv, false },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, false },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2003::"sv, false },
{ "fe80::"sv, false },
{ "fe80::1234:5678:9876:5432"sv, false },
{ "fe80::ffff:ffff:ffff:ffff"sv, false },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, false },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_loopback()) << presentation;
}
}
TEST_F(NetTest, isIPv6IPv4Mapped)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, false },
{ "0:0:0:0:0:0:0:0"sv, false },
{ "::1"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, true },
{ "::ffff:255.255.255.255"sv, true },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, false },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2003::"sv, false },
{ "fe80::"sv, false },
{ "fe80::1234:5678:9876:5432"sv, false },
{ "fe80::ffff:ffff:ffff:ffff"sv, false },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, false },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_ipv4_mapped()) << presentation;
}
}
TEST_F(NetTest, isIPv6Teredo)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, false },
{ "0:0:0:0:0:0:0:0"sv, false },
{ "::1"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, false },
{ "::ffff:255.255.255.255"sv, false },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, true },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, true },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, true },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, false },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2003::"sv, false },
{ "fe80::"sv, false },
{ "fe80::1234:5678:9876:5432"sv, false },
{ "fe80::ffff:ffff:ffff:ffff"sv, false },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, false },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_teredo()) << presentation;
}
}
TEST_F(NetTest, isIPv6And6to4)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, false },
{ "0:0:0:0:0:0:0:0"sv, false },
{ "::1"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, false },
{ "::ffff:255.255.255.255"sv, false },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, true },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, true },
{ "2003::"sv, false },
{ "fe80::"sv, false },
{ "fe80::1234:5678:9876:5432"sv, false },
{ "fe80::ffff:ffff:ffff:ffff"sv, false },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, false },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_6to4()) << presentation;
}
}
TEST_F(NetTest, isIPv6LinkLocal)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, false },
{ "0:0:0:0:0:0:0:0"sv, false },
{ "::1"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, false },
{ "::ffff:255.255.255.255"sv, false },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, false },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2003::"sv, false },
{ "fe80::"sv, true },
{ "fe80::1234:5678:9876:5432"sv, true },
{ "fe80::ffff:ffff:ffff:ffff"sv, true },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, false },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_link_local()) << presentation;
}
}
TEST_F(NetTest, isIPv6Multicast)
{
static auto constexpr Tests = std::array<std::pair<std::string_view, bool>, 26>{ {
{ "0.0.0.0"sv, false },
{ "169.254.0.0"sv, false },
{ "::"sv, false },
{ "0:0:0:0:0:0:0:0"sv, false },
{ "::1"sv, false },
{ "0:0:0:0:0:0:0:1"sv, false },
{ "0:0:0:0:0:0:0:2"sv, false },
{ "::fffe:ffff:ffff"sv, false },
{ "::ffff:0:0"sv, false },
{ "::ffff:255.255.255.255"sv, false },
{ "::1:0:0:0"sv, false },
{ "2000:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001::"sv, false },
{ "2001:0:0eab:dead::a0:abcd:4e"sv, false },
{ "2001:0:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2001:1::"sv, false },
{ "2001:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2002::"sv, false },
{ "2002:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "2003::"sv, false },
{ "fe80::"sv, false },
{ "fe80::1234:5678:9876:5432"sv, false },
{ "fe80::ffff:ffff:ffff:ffff"sv, false },
{ "feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, false },
{ "ff00::"sv, true },
{ "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"sv, true },
} };
for (auto const& [presentation, expected] : Tests)
{
auto const address = tr_address::from_string(presentation);
ASSERT_TRUE(address.has_value());
EXPECT_EQ(expected, address->is_ipv6_multicast()) << presentation;
}
}