Add tests for ip address manipulation functions

This commit is contained in:
Piotr Wójcik 2024-03-25 15:21:48 +01:00
commit b652bf016f
3 changed files with 93 additions and 7 deletions

View file

@ -57,3 +57,88 @@ TEST (network_functions, network_range_ipv4)
auto address2_subnet (nano::transport::map_address_to_subnetwork (address2)); auto address2_subnet (nano::transport::map_address_to_subnetwork (address2));
ASSERT_EQ (subnet2.network (), address2_subnet); ASSERT_EQ (subnet2.network (), address2_subnet);
} }
TEST (network_functions, ipv4_address_or_ipv6_subnet)
{
// IPv4 mapped as IPv6 address should return the original IPv4 address
boost::asio::ip::address addr1 = boost::asio::ip::address::from_string ("192.168.1.1");
boost::asio::ip::address addr2 = boost::asio::ip::address::from_string ("::ffff:192.168.1.1");
ASSERT_EQ (nano::transport::ipv4_address_or_ipv6_subnet (addr1), addr2);
// IPv6 address within the same /48 subnet should return the network prefix
boost::asio::ip::address addr3 = boost::asio::ip::address::from_string ("2001:0db8:85a3:0000:0000:8a2e:0370:7334");
boost::asio::ip::address addr4 = boost::asio::ip::address::from_string ("2001:0db8:85a3::");
ASSERT_EQ (nano::transport::ipv4_address_or_ipv6_subnet (addr3), addr4);
// Different IPv6 address outside the /48 subnet should not match
boost::asio::ip::address addr5 = boost::asio::ip::address::from_string ("2001:0db8:85a4:0001:0000:8a2e:0370:7334");
ASSERT_NE (nano::transport::ipv4_address_or_ipv6_subnet (addr3), nano::transport::ipv4_address_or_ipv6_subnet (addr5));
}
TEST (network_functions, is_same_ip)
{
// Same IPv4 addresses
boost::asio::ip::address ipv4_addr1 = boost::asio::ip::address::from_string ("192.168.1.1");
ASSERT_TRUE (nano::transport::is_same_ip (ipv4_addr1, ipv4_addr1));
// IPv4 and its IPv6 mapped form
boost::asio::ip::address ipv6_mapped_ipv4 = boost::asio::ip::address::from_string ("::ffff:192.168.1.1");
ASSERT_TRUE (nano::transport::is_same_ip (ipv4_addr1, ipv6_mapped_ipv4));
}
TEST (network_functions, is_same_ipv4)
{
// Same IPv4 addresses
boost::asio::ip::address ipv4_addr1 = boost::asio::ip::address::from_string ("192.168.1.1");
ASSERT_TRUE (nano::transport::is_same_ip (ipv4_addr1, ipv4_addr1));
// IPv4 and its IPv6 mapped form
boost::asio::ip::address ipv6_mapped_ipv4 = boost::asio::ip::address::from_string ("::ffff:192.168.1.1");
ASSERT_TRUE (nano::transport::is_same_ip (ipv4_addr1, ipv6_mapped_ipv4));
}
TEST (network_functions, is_same_ipv6)
{
// Two different IPv6 addresses within the same /48 subnet
boost::asio::ip::address ipv6_addr1 = boost::asio::ip::address::from_string ("2001:db8::1");
boost::asio::ip::address ipv6_addr2 = boost::asio::ip::address::from_string ("2001:db8::2");
ASSERT_TRUE (nano::transport::is_same_ip (ipv6_addr1, ipv6_addr2));
// Two different IPv6 addresses in different /48 subnets
boost::asio::ip::address ipv6_addr3 = boost::asio::ip::address::from_string ("2001:db8:1::1");
ASSERT_FALSE (nano::transport::is_same_ip (ipv6_addr1, ipv6_addr3));
}
TEST (network_functions, is_different_ip_family)
{
boost::asio::ip::address addr1 = boost::asio::ip::address::from_string ("192.168.1.1");
boost::asio::ip::address addr2 = boost::asio::ip::address::from_string ("::1");
ASSERT_FALSE (nano::transport::is_same_ip (addr1, addr2));
}
TEST (network_functions, is_same_ip_v4_mapped)
{
boost::asio::ip::address addr1 = boost::asio::ip::address::from_string ("::ffff:192.168.1.1");
boost::asio::ip::address addr2 = boost::asio::ip::address::from_string ("192.168.1.1");
ASSERT_TRUE (nano::transport::is_same_ip (addr1, addr2));
boost::asio::ip::address addr3 = boost::asio::ip::address::from_string ("10.0.0.1");
ASSERT_FALSE (nano::transport::is_same_ip (addr1, addr3));
}
TEST (network_functions, map_ipv4_address_to_subnetwork)
{
boost::asio::ip::address addr = boost::asio::ip::address::from_string ("192.168.1.100");
auto subnetwork = nano::transport::map_address_to_subnetwork (addr);
// Assuming a /24 subnet mask for IPv4, all addresses in 192.168.1.x should map to the same network
// Automatically maps to IPv6
ASSERT_EQ (subnetwork.to_string (), "::ffff:192.168.1.0");
}
TEST (network_functions, map_ipv6_address_to_subnetwork)
{
boost::asio::ip::address addr = boost::asio::ip::address::from_string ("2001:db8:abcd:0012::0");
auto subnetwork = nano::transport::map_address_to_subnetwork (addr);
// Assuming a /32 subnet mask for IPv6
ASSERT_EQ (subnetwork.to_string (), "2001:db8::");
}

View file

@ -26,17 +26,18 @@ nano::tcp_endpoint nano::transport::map_endpoint_to_tcp (nano::endpoint const &
return { endpoint_a.address (), endpoint_a.port () }; return { endpoint_a.address (), endpoint_a.port () };
} }
boost::asio::ip::address nano::transport::map_address_to_subnetwork (boost::asio::ip::address const & address_a) boost::asio::ip::address nano::transport::map_address_to_subnetwork (boost::asio::ip::address address_a)
{ {
debug_assert (address_a.is_v6 ()); address_a = mapped_from_v4_or_v6 (address_a);
static short const ipv6_subnet_prefix_length = 32; // Equivalent to network prefix /32. static short const ipv6_subnet_prefix_length = 32; // Equivalent to network prefix /32.
static short const ipv4_subnet_prefix_length = (128 - 32) + 24; // Limits for /24 IPv4 subnetwork static short const ipv4_subnet_prefix_length = (128 - 32) + 24; // Limits for /24 IPv4 subnetwork (we're using mapped IPv4 to IPv6 addresses, hence (128 - 32))
return address_a.to_v6 ().is_v4_mapped () ? boost::asio::ip::make_network_v6 (address_a.to_v6 (), ipv4_subnet_prefix_length).network () : boost::asio::ip::make_network_v6 (address_a.to_v6 (), ipv6_subnet_prefix_length).network (); return address_a.to_v6 ().is_v4_mapped () ? boost::asio::ip::make_network_v6 (address_a.to_v6 (), ipv4_subnet_prefix_length).network () : boost::asio::ip::make_network_v6 (address_a.to_v6 (), ipv6_subnet_prefix_length).network ();
} }
boost::asio::ip::address nano::transport::ipv4_address_or_ipv6_subnet (boost::asio::ip::address const & address_a) boost::asio::ip::address nano::transport::ipv4_address_or_ipv6_subnet (boost::asio::ip::address address_a)
{ {
debug_assert (address_a.is_v6 ()); address_a = mapped_from_v4_or_v6 (address_a);
// Assuming /48 subnet prefix for IPv6 as it's relatively easy to acquire such a /48 address range
static short const ipv6_address_prefix_length = 48; // /48 IPv6 subnetwork static short const ipv6_address_prefix_length = 48; // /48 IPv6 subnetwork
return address_a.to_v6 ().is_v4_mapped () ? address_a : boost::asio::ip::make_network_v6 (address_a.to_v6 (), ipv6_address_prefix_length).network (); return address_a.to_v6 ().is_v4_mapped () ? address_a : boost::asio::ip::make_network_v6 (address_a.to_v6 (), ipv6_address_prefix_length).network ();
} }

View file

@ -14,8 +14,8 @@ namespace nano::transport
nano::endpoint map_endpoint_to_v6 (nano::endpoint const &); nano::endpoint map_endpoint_to_v6 (nano::endpoint const &);
nano::endpoint map_tcp_to_endpoint (nano::tcp_endpoint const &); nano::endpoint map_tcp_to_endpoint (nano::tcp_endpoint const &);
nano::tcp_endpoint map_endpoint_to_tcp (nano::endpoint const &); nano::tcp_endpoint map_endpoint_to_tcp (nano::endpoint const &);
boost::asio::ip::address map_address_to_subnetwork (boost::asio::ip::address const &); boost::asio::ip::address map_address_to_subnetwork (boost::asio::ip::address);
boost::asio::ip::address ipv4_address_or_ipv6_subnet (boost::asio::ip::address const &); boost::asio::ip::address ipv4_address_or_ipv6_subnet (boost::asio::ip::address);
boost::asio::ip::address_v6 mapped_from_v4_bytes (unsigned long); boost::asio::ip::address_v6 mapped_from_v4_bytes (unsigned long);
boost::asio::ip::address_v6 mapped_from_v4_or_v6 (boost::asio::ip::address const &); boost::asio::ip::address_v6 mapped_from_v4_or_v6 (boost::asio::ip::address const &);
bool is_ipv4_or_v4_mapped_address (boost::asio::ip::address const &); bool is_ipv4_or_v4_mapped_address (boost::asio::ip::address const &);