Skip to content

Commit e2b8028

Browse files
laanwjjonasschnelli
authored andcommitted
net: Fix CIDR notation in ToString()
Only use CIDR notation if the netmask can be represented as such.
1 parent 9e521c1 commit e2b8028

File tree

2 files changed

+54
-10
lines changed

2 files changed

+54
-10
lines changed

src/netbase.cpp

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,20 +1311,58 @@ bool CSubNet::Match(const CNetAddr &addr) const
13111311
return true;
13121312
}
13131313

1314+
static inline int NetmaskBits(uint8_t x)
1315+
{
1316+
switch(x) {
1317+
case 0x00: return 0; break;
1318+
case 0x80: return 1; break;
1319+
case 0xc0: return 2; break;
1320+
case 0xe0: return 3; break;
1321+
case 0xf0: return 4; break;
1322+
case 0xf8: return 5; break;
1323+
case 0xfc: return 6; break;
1324+
case 0xfe: return 7; break;
1325+
case 0xff: return 8; break;
1326+
default: return -1; break;
1327+
}
1328+
}
1329+
13141330
std::string CSubNet::ToString() const
13151331
{
1316-
std::string strNetmask;
1332+
/* Parse binary 1{n}0{N-n} to see if mask can be represented as /n */
13171333
int cidr = 0;
1318-
for (int n = network.IsIPv4() ? 12 : 0 ; n < 16; ++n)
1319-
{
1320-
uint8_t netmaskpart = netmask[n];
1321-
while (netmaskpart)
1322-
{
1323-
cidr += ( netmaskpart & 0x01 );
1324-
netmaskpart >>= 1;
1325-
}
1334+
bool valid_cidr = true;
1335+
int n = network.IsIPv4() ? 12 : 0;
1336+
for (; n < 16 && netmask[n] == 0xff; ++n)
1337+
cidr += 8;
1338+
if (n < 16) {
1339+
int bits = NetmaskBits(netmask[n]);
1340+
if (bits < 0)
1341+
valid_cidr = false;
1342+
else
1343+
cidr += bits;
1344+
++n;
13261345
}
1327-
return network.ToString() + strprintf("/%u", cidr);
1346+
for (; n < 16 && valid_cidr; ++n)
1347+
if (netmask[n] != 0x00)
1348+
valid_cidr = false;
1349+
1350+
/* Format output */
1351+
std::string strNetmask;
1352+
if (valid_cidr) {
1353+
strNetmask = strprintf("%u", cidr);
1354+
} else {
1355+
if (network.IsIPv4())
1356+
strNetmask = strprintf("%u.%u.%u.%u", netmask[12], netmask[13], netmask[14], netmask[15]);
1357+
else
1358+
strNetmask = strprintf("%x:%x:%x:%x:%x:%x:%x:%x",
1359+
netmask[0] << 8 | netmask[1], netmask[2] << 8 | netmask[3],
1360+
netmask[4] << 8 | netmask[5], netmask[6] << 8 | netmask[7],
1361+
netmask[8] << 8 | netmask[9], netmask[10] << 8 | netmask[11],
1362+
netmask[12] << 8 | netmask[13], netmask[14] << 8 | netmask[15]);
1363+
}
1364+
1365+
return network.ToString() + "/" + strNetmask;
13281366
}
13291367

13301368
bool CSubNet::IsValid() const

src/test/netbase_tests.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,12 @@ BOOST_AUTO_TEST_CASE(subnet_test)
229229
BOOST_CHECK_EQUAL(subnet.ToString(), "1::/16");
230230
subnet = CSubNet("1:2:3:4:5:6:7:8/0000:0000:0000:0000:0000:0000:0000:0000");
231231
BOOST_CHECK_EQUAL(subnet.ToString(), "::/0");
232+
subnet = CSubNet("1.2.3.4/255.255.232.0");
233+
BOOST_CHECK_EQUAL(subnet.ToString(), "1.2.0.0/255.255.232.0");
234+
subnet = CSubNet("1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
235+
BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:8/ffff:ffff:ffff:fffe:ffff:ffff:ffff:ff0f");
236+
subnet = CSubNet("1:2:3:4:5:6:7:8/fff:ffff:ffff:ffff:ffff:ffff:ffff:fff0");
237+
BOOST_CHECK_EQUAL(subnet.ToString(), "1:2:3:4:5:6:7:0/fff:ffff:ffff:ffff:ffff:ffff:ffff:fff0");
232238
}
233239

234240
BOOST_AUTO_TEST_CASE(netbase_getgroup)

0 commit comments

Comments
 (0)