diff --git a/src/netbase.cpp b/src/netbase.cpp index 4163b1808..c3d56d918 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -1311,20 +1311,58 @@ bool CSubNet::Match(const CNetAddr &addr) const return true; } +static inline int NetmaskBits(uint8_t x) +{ + switch(x) { + case 0x00: return 0; break; + case 0x80: return 1; break; + case 0xc0: return 2; break; + case 0xe0: return 3; break; + case 0xf0: return 4; break; + case 0xf8: return 5; break; + case 0xfc: return 6; break; + case 0xfe: return 7; break; + case 0xff: return 8; break; + default: return -1; break; + } +} + std::string CSubNet::ToString() const { - std::string strNetmask; + /* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */ int cidr = 0; - for (int n = network.IsIPv4() ? 12 : 0 ; n < 16; ++n) - { - uint8_t netmaskpart = netmask[n]; - while (netmaskpart) - { - cidr += ( netmaskpart & 0x01 ); - netmaskpart >>= 1; - } + bool valid_cidr = true; + int n = network.IsIPv4() ? 12 : 0; + for (; n < 16 && netmask[n] == 0xff; ++n) + cidr += 8; + if (n < 16) { + int bits = NetmaskBits(netmask[n]); + if (bits < 0) + valid_cidr = false; + else + cidr += bits; + ++n; } - return network.ToString() + strprintf("/%u", cidr); + for (; n < 16 && valid_cidr; ++n) + if (netmask[n] != 0x00) + valid_cidr = false; + + /* Format output */ + std::string strNetmask; + if (valid_cidr) { + strNetmask = strprintf("%u", cidr); + } else { + if (network.IsIPv4()) + strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]); + else + strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x", + netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3], + netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7], + netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11], + netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]); + } + + return network.ToString() + "/" + strNetmask; } bool CSubNet::IsValid() const diff --git a/src/test/netbase_tests.cpp b/src/test/netbase_tests.cpp index f0333d868..8e853cc28 100644 --- a/src/test/netbase_tests.cpp +++ b/src/test/netbase_tests.cpp @@ -229,6 +229,12 @@ BOOST_AUTO_TEST_CASE(subnet_test) BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16"); subnet = CSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000"); BOOST_CHECK_EQUAL(subnet.ToString(), "::/0"); + subnet = CSubNet("1.2.3.4/255.255.232.0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0"); + subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f"); + subnet = CSubNet("1:2:3:4:5:6:7:8/fff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"); + BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:0/fff:ffff:ffff:ffff:ffff:ffff:ffff:fff0"); } BOOST_AUTO_TEST_CASE(netbase_getgroup)