diff --git a/include/libtorrent/address.hpp b/include/libtorrent/address.hpp index 62018dea5..a292fbf84 100644 --- a/include/libtorrent/address.hpp +++ b/include/libtorrent/address.hpp @@ -74,6 +74,15 @@ namespace libtorrent { // internal inline address_v6 make_address_v6(string_view str, boost::system::error_code& ec) { return address_v6::from_string(str.data(), ec); } + // internal + inline address make_address(string_view str) + { return address::from_string(str.data()); } + // internal + inline address_v4 make_address_v4(string_view str) + { return address_v4::from_string(str.data()); } + // internal + inline address_v6 make_address_v6(string_view str) + { return address_v6::from_string(str.data()); } #endif } diff --git a/include/libtorrent/enum_net.hpp b/include/libtorrent/enum_net.hpp index 439889b1a..23758836c 100644 --- a/include/libtorrent/enum_net.hpp +++ b/include/libtorrent/enum_net.hpp @@ -89,6 +89,11 @@ namespace libtorrent { TORRENT_EXTRA_EXPORT bool match_addr_mask(address const& a1 , address const& a2, address const& mask); + // return a netmask with the specified address family and the specified + // number of prefix bit set, of the most significant bits in the resulting + // netmask + TORRENT_EXTRA_EXPORT address build_netmask(int bits, int family); + // returns true if the specified address is on the same // local network as us TORRENT_EXTRA_EXPORT bool in_local_network(io_service& ios, address const& addr diff --git a/src/enum_net.cpp b/src/enum_net.cpp index 84e675762..d4bbf41ed 100644 --- a/src/enum_net.cpp +++ b/src/enum_net.cpp @@ -165,48 +165,6 @@ namespace { ); } -#if TORRENT_USE_GETIPFORWARDTABLE || TORRENT_USE_NETLINK - address build_netmask(int bits, int const family) - { - if (family == AF_INET) - { - address_v4::bytes_type b; - b.fill(0xff); - for (int i = int(b.size()) - 1; i >= 0; --i) - { - if (bits < 8) - { - b[std::size_t(i)] <<= bits; - break; - } - b[std::size_t(i)] = 0; - bits -= 8; - } - return address_v4(b); - } - else if (family == AF_INET6) - { - address_v6::bytes_type b; - b.fill(0xff); - for (int i = int(b.size()) - 1; i >= 0; --i) - { - if (bits < 8) - { - b[std::size_t(i)] <<= bits; - break; - } - b[std::size_t(i)] = 0; - bits -= 8; - } - return address_v6(b); - } - else - { - return address(); - } - } -#endif - #if TORRENT_USE_NETLINK int read_nl_sock(int sock, span buf, std::uint32_t const seq, std::uint32_t const pid) @@ -353,36 +311,7 @@ namespace { return false; ip_info->preferred = (addr_msg->ifa_flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0; - - if (addr_msg->ifa_family == AF_INET6) - { - TORRENT_ASSERT(addr_msg->ifa_prefixlen <= 128); - if (addr_msg->ifa_prefixlen > 0) - { - address_v6::bytes_type mask = {}; - auto it = mask.begin(); - if (addr_msg->ifa_prefixlen > 64) - { - detail::write_uint64(0xffffffffffffffffULL, it); - addr_msg->ifa_prefixlen -= 64; - } - if (addr_msg->ifa_prefixlen > 0) - { - std::uint64_t const m = ~((1ULL << (64 - addr_msg->ifa_prefixlen)) - 1); - detail::write_uint64(m, it); - } - ip_info->netmask = address_v6(mask); - } - } - else - { - TORRENT_ASSERT(addr_msg->ifa_prefixlen <= 32); - if (addr_msg->ifa_prefixlen != 0) - { - std::uint32_t const m = ~((1U << (32 - addr_msg->ifa_prefixlen)) - 1); - ip_info->netmask = address_v4(m); - } - } + ip_info->netmask = build_netmask(addr_msg->ifa_prefixlen, addr_msg->ifa_family); ip_info->interface_address = address(); int rt_len = int(IFA_PAYLOAD(nl_hdr)); @@ -492,8 +421,47 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl } #endif + void build_netmask_impl(span mask, int prefix_bits) + { + TORRENT_ASSERT(prefix_bits <= mask.size() * 8); + int i = 0; + while (prefix_bits >= 8) + { + mask[i] = 0xff; + prefix_bits -= 8; + ++i; + } + if (i < mask.size()) + { + mask[i] = (0xff << (8 - prefix_bits)) & 0xff; + ++i; + while (i < mask.size()) + { + mask[i] = 0; + ++i; + } + } + } + } // + address build_netmask(int prefix_bits, int const family) + { + if (family == AF_INET) + { + address_v4::bytes_type b; + build_netmask_impl(b, prefix_bits); + return address_v4(b); + } + else if (family == AF_INET6) + { + address_v6::bytes_type b; + build_netmask_impl(b, prefix_bits); + return address_v6(b); + } + return {}; + } + // return (a1 & mask) == (a2 & mask) bool match_addr_mask(address const& a1, address const& a2, address const& mask) { diff --git a/test/test_enum_net.cpp b/test/test_enum_net.cpp index e2989fbff..49c3fedc2 100644 --- a/test/test_enum_net.cpp +++ b/test/test_enum_net.cpp @@ -104,3 +104,63 @@ TORRENT_TEST(is_ip_address) TEST_EQUAL(is_ip_address("::1"), true); TEST_EQUAL(is_ip_address("2001:db8:85a3:0:0:8a2e:370:7334"), true); } + +TORRENT_TEST(build_netmask_v4) +{ + TEST_CHECK(build_netmask(0, AF_INET) == make_address("0.0.0.0")); + TEST_CHECK(build_netmask(1, AF_INET) == make_address("128.0.0.0")); + TEST_CHECK(build_netmask(2, AF_INET) == make_address("192.0.0.0")); + TEST_CHECK(build_netmask(3, AF_INET) == make_address("224.0.0.0")); + TEST_CHECK(build_netmask(4, AF_INET) == make_address("240.0.0.0")); + TEST_CHECK(build_netmask(5, AF_INET) == make_address("248.0.0.0")); + TEST_CHECK(build_netmask(6, AF_INET) == make_address("252.0.0.0")); + TEST_CHECK(build_netmask(7, AF_INET) == make_address("254.0.0.0")); + TEST_CHECK(build_netmask(8, AF_INET) == make_address("255.0.0.0")); + TEST_CHECK(build_netmask(9, AF_INET) == make_address("255.128.0.0")); + TEST_CHECK(build_netmask(10, AF_INET) == make_address("255.192.0.0")); + TEST_CHECK(build_netmask(11, AF_INET) == make_address("255.224.0.0")); + + TEST_CHECK(build_netmask(22, AF_INET) == make_address("255.255.252.0")); + TEST_CHECK(build_netmask(23, AF_INET) == make_address("255.255.254.0")); + TEST_CHECK(build_netmask(24, AF_INET) == make_address("255.255.255.0")); + TEST_CHECK(build_netmask(25, AF_INET) == make_address("255.255.255.128")); + TEST_CHECK(build_netmask(26, AF_INET) == make_address("255.255.255.192")); + TEST_CHECK(build_netmask(27, AF_INET) == make_address("255.255.255.224")); + TEST_CHECK(build_netmask(28, AF_INET) == make_address("255.255.255.240")); + TEST_CHECK(build_netmask(29, AF_INET) == make_address("255.255.255.248")); + TEST_CHECK(build_netmask(30, AF_INET) == make_address("255.255.255.252")); + TEST_CHECK(build_netmask(31, AF_INET) == make_address("255.255.255.254")); + TEST_CHECK(build_netmask(32, AF_INET) == make_address("255.255.255.255")); +} + +TORRENT_TEST(build_netmask_v6) +{ + TEST_CHECK(build_netmask(0, AF_INET6) == make_address("::")); + TEST_CHECK(build_netmask(1, AF_INET6) == make_address("8000::")); + TEST_CHECK(build_netmask(2, AF_INET6) == make_address("c000::")); + TEST_CHECK(build_netmask(3, AF_INET6) == make_address("e000::")); + TEST_CHECK(build_netmask(4, AF_INET6) == make_address("f000::")); + TEST_CHECK(build_netmask(5, AF_INET6) == make_address("f800::")); + TEST_CHECK(build_netmask(6, AF_INET6) == make_address("fc00::")); + TEST_CHECK(build_netmask(7, AF_INET6) == make_address("fe00::")); + TEST_CHECK(build_netmask(8, AF_INET6) == make_address("ff00::")); + TEST_CHECK(build_netmask(9, AF_INET6) == make_address("ff80::")); + TEST_CHECK(build_netmask(10, AF_INET6) == make_address("ffc0::")); + TEST_CHECK(build_netmask(11, AF_INET6) == make_address("ffe0::")); + + TEST_CHECK(build_netmask(119, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00")); + TEST_CHECK(build_netmask(120, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00")); + TEST_CHECK(build_netmask(121, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80")); + TEST_CHECK(build_netmask(122, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0")); + TEST_CHECK(build_netmask(123, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0")); + TEST_CHECK(build_netmask(124, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0")); + TEST_CHECK(build_netmask(125, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8")); + TEST_CHECK(build_netmask(126, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc")); + TEST_CHECK(build_netmask(127, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")); + TEST_CHECK(build_netmask(128, AF_INET6) == make_address("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")); +} + +TORRENT_TEST(build_netmask_unknown) +{ + TEST_CHECK(build_netmask(0, -1) == address{}); +}