net: allow CSubNet of non-IP networks

Allow creation of valid `CSubNet` objects of non-IP networks and only
match the single address they were created from (like /32 for IPv4 or
/128 for IPv6).

This fixes a deficiency in `CConnman::DisconnectNode(const CNetAddr& addr)`
and in `BanMan` which assume that creating a subnet from any address
using the `CSubNet(CNetAddr)` constructor would later match that address
only. Before this change a non-IP subnet would be invalid and would not
match any address.
This commit is contained in:
Vasil Dimov
2021-01-04 18:37:52 +01:00
parent bc8ada1c15
commit 94d335da7f
3 changed files with 107 additions and 19 deletions

View File

@@ -1068,15 +1068,24 @@ CSubNet::CSubNet(const CNetAddr& addr, const CNetAddr& mask) : CSubNet()
CSubNet::CSubNet(const CNetAddr& addr) : CSubNet()
{
valid = addr.IsIPv4() || addr.IsIPv6();
if (!valid) {
switch (addr.m_net) {
case NET_IPV4:
case NET_IPV6:
valid = true;
assert(addr.m_addr.size() <= sizeof(netmask));
memset(netmask, 0xFF, addr.m_addr.size());
break;
case NET_ONION:
case NET_I2P:
case NET_CJDNS:
valid = true;
break;
case NET_INTERNAL:
case NET_UNROUTABLE:
case NET_MAX:
return;
}
assert(addr.m_addr.size() <= sizeof(netmask));
memset(netmask, 0xFF, addr.m_addr.size());
network = addr;
}
@@ -1088,6 +1097,21 @@ bool CSubNet::Match(const CNetAddr &addr) const
{
if (!valid || !addr.IsValid() || network.m_net != addr.m_net)
return false;
switch (network.m_net) {
case NET_IPV4:
case NET_IPV6:
break;
case NET_ONION:
case NET_I2P:
case NET_CJDNS:
case NET_INTERNAL:
return addr == network;
case NET_UNROUTABLE:
case NET_MAX:
return false;
}
assert(network.m_addr.size() == addr.m_addr.size());
for (size_t x = 0; x < addr.m_addr.size(); ++x) {
if ((addr.m_addr[x] & netmask[x]) != network.m_addr[x]) {
@@ -1099,18 +1123,35 @@ bool CSubNet::Match(const CNetAddr &addr) const
std::string CSubNet::ToString() const
{
assert(network.m_addr.size() <= sizeof(netmask));
std::string suffix;
uint8_t cidr = 0;
switch (network.m_net) {
case NET_IPV4:
case NET_IPV6: {
assert(network.m_addr.size() <= sizeof(netmask));
for (size_t i = 0; i < network.m_addr.size(); ++i) {
if (netmask[i] == 0x00) {
break;
uint8_t cidr = 0;
for (size_t i = 0; i < network.m_addr.size(); ++i) {
if (netmask[i] == 0x00) {
break;
}
cidr += NetmaskBits(netmask[i]);
}
cidr += NetmaskBits(netmask[i]);
suffix = strprintf("/%u", cidr);
break;
}
case NET_ONION:
case NET_I2P:
case NET_CJDNS:
case NET_INTERNAL:
case NET_UNROUTABLE:
case NET_MAX:
break;
}
return network.ToString() + strprintf("/%u", cidr);
return network.ToString() + suffix;
}
bool CSubNet::IsValid() const
@@ -1120,7 +1161,19 @@ bool CSubNet::IsValid() const
bool CSubNet::SanityCheck() const
{
if (!(network.IsIPv4() || network.IsIPv6())) return false;
switch (network.m_net) {
case NET_IPV4:
case NET_IPV6:
break;
case NET_ONION:
case NET_I2P:
case NET_CJDNS:
return true;
case NET_INTERNAL:
case NET_UNROUTABLE:
case NET_MAX:
return false;
}
for (size_t x = 0; x < network.m_addr.size(); ++x) {
if (network.m_addr[x] & ~netmask[x]) return false;