net: Fix CIDR notation in ToString()

Only use CIDR notation if the netmask can be represented as such.
This commit is contained in:
Wladimir J. van der Laan 2015-06-25 10:47:34 +02:00 committed by Jonas Schnelli
parent 9e521c1735
commit e2b8028e4c
2 changed files with 54 additions and 10 deletions

View file

@ -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

View file

@ -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)