aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2015-06-25 10:47:34 +0200
committerJonas Schnelli <jonas.schnelli@include7.ch>2015-09-16 16:50:19 +0200
commite2b8028e4c60708a8d49b17d9d49dda10aaecc51 (patch)
tree2b8bcb0c6f61d3fef5f957306be35672dfbb3946
parent9e521c173586257f57764b479beb5923c33ed0eb (diff)
net: Fix CIDR notation in ToString()
Only use CIDR notation if the netmask can be represented as such.
-rw-r--r--src/netbase.cpp58
-rw-r--r--src/test/netbase_tests.cpp6
2 files changed, 54 insertions, 10 deletions
diff --git a/src/netbase.cpp b/src/netbase.cpp
index 4163b18086..c3d56d9184 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 f0333d8687..8e853cc288 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)