diff --git a/src/banman.cpp b/src/banman.cpp --- a/src/banman.cpp +++ b/src/banman.cpp @@ -199,7 +199,7 @@ while (it != m_banned.end()) { CSubNet sub_net = (*it).first; CBanEntry ban_entry = (*it).second; - if (now > ban_entry.nBanUntil) { + if (!sub_net.IsValid() || now > ban_entry.nBanUntil) { m_banned.erase(it++); m_is_dirty = true; notify_ui = true; diff --git a/src/netaddress.h b/src/netaddress.h --- a/src/netaddress.h +++ b/src/netaddress.h @@ -296,6 +296,8 @@ /// Is this value valid? (only used to signal parse errors) bool valid; + bool SanityCheck() const; + public: CSubNet(); CSubNet(const CNetAddr &addr, uint8_t mask); @@ -316,7 +318,20 @@ friend bool operator<(const CSubNet &a, const CSubNet &b); SERIALIZE_METHODS(CSubNet, obj) { - READWRITE(obj.network, obj.netmask, obj.valid); + READWRITE(obj.network); + if (obj.network.IsIPv4()) { + // Before D9176, CSubNet used the last 4 bytes of netmask to store + // the relevant bytes for an IPv4 mask. For compatiblity reasons, + // keep doing so in serialized form. + uint8_t dummy[12] = {0}; + READWRITE(dummy); + READWRITE(MakeSpan(obj.netmask).first(4)); + } else { + READWRITE(obj.netmask); + } + READWRITE(obj.valid); + // Mark invalid if the result doesn't pass sanity checking. + SER_READ(obj, if (obj.valid) obj.valid = obj.SanityCheck()); } }; diff --git a/src/netaddress.cpp b/src/netaddress.cpp --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -927,6 +927,20 @@ return valid; } +bool CSubNet::SanityCheck() const { + if (!(network.IsIPv4() || network.IsIPv6())) { + return false; + } + + for (size_t x = 0; x < network.m_addr.size(); ++x) { + if (network.m_addr[x] & ~netmask[x]) { + return false; + } + } + + return true; +} + bool operator==(const CSubNet &a, const CSubNet &b) { return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);