From 793bd07c99861deb4c0a72f5838434aab5500ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wo=CC=81jcik?= <3044353+pwojcikdev@users.noreply.github.com> Date: Mon, 25 Mar 2024 15:21:48 +0100 Subject: [PATCH] Add tests for ip address manipulation functions --- nano/core_test/network_functions.cpp | 85 ++++++++++++++++++++++++++++ nano/node/transport/transport.cpp | 13 +++-- nano/node/transport/transport.hpp | 4 +- 3 files changed, 94 insertions(+), 8 deletions(-) diff --git a/nano/core_test/network_functions.cpp b/nano/core_test/network_functions.cpp index d0a8ae5b22..ed45a6f06f 100644 --- a/nano/core_test/network_functions.cpp +++ b/nano/core_test/network_functions.cpp @@ -57,3 +57,88 @@ TEST (network_functions, network_range_ipv4) auto address2_subnet (nano::transport::map_address_to_subnetwork (address2)); 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::"); +} \ No newline at end of file diff --git a/nano/node/transport/transport.cpp b/nano/node/transport/transport.cpp index 7522de853a..7a7fbac5b9 100644 --- a/nano/node/transport/transport.cpp +++ b/nano/node/transport/transport.cpp @@ -26,17 +26,18 @@ nano::tcp_endpoint nano::transport::map_endpoint_to_tcp (nano::endpoint const & 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 ()); - 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 + address_a = mapped_from_v4_or_v6 (address_a); + static short const ipv6_subnet_prefix_length = 32; // Equivalent to network ipv6 prefix /32. + 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 (); } -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 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 (); } diff --git a/nano/node/transport/transport.hpp b/nano/node/transport/transport.hpp index 88a225b64e..434f362c94 100644 --- a/nano/node/transport/transport.hpp +++ b/nano/node/transport/transport.hpp @@ -14,8 +14,8 @@ namespace nano::transport nano::endpoint map_endpoint_to_v6 (nano::endpoint const &); nano::endpoint map_tcp_to_endpoint (nano::tcp_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 ipv4_address_or_ipv6_subnet (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); 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 &); bool is_ipv4_or_v4_mapped_address (boost::asio::ip::address const &);