Skip to content

Commit e3b474c

Browse files
committed
Merge #20140: Restore compatibility with old CSubNet serialization
886be97 Ignore incorrectly-serialized banlist.dat entries (Pieter Wuille) 883cea7 Restore compatibility with old CSubNet serialization (Pieter Wuille) Pull request description: #19628 changed CSubNet for IPv4 netmasks, using the first 4 bytes of `netmask` rather than the last 4 to store the actual mask. Unfortunately, CSubNet objects are serialized on disk in banlist.dat, breaking compatibility with existing banlists (and bringing them into an inconsistent state where entries reported in `listbanned` cannot be removed). Fix this by reverting to the old format (just for serialization). Also add a sanity check to the deserializer so that nonsensical banlist.dat entries are ignored (which would otherwise be possible if someone added IPv4 entries after #19628 but without this PR). Reported by Greg Maxwell. ACKs for top commit: laanwj: Code review ACK 886be97 vasild: ACK 886be97 Tree-SHA512: d3fb91e8ecd933406e527187974f22770374ee2e12a233e7870363f52ecda471fb0b7bae72420e8ff6b6b1594e3037a5115984c023dbadf38f86aeaffcd681e7
2 parents 3956165 + 886be97 commit e3b474c

File tree

3 files changed

+31
-2
lines changed

3 files changed

+31
-2
lines changed

src/banman.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ void BanMan::SweepBanned()
184184
while (it != m_banned.end()) {
185185
CSubNet sub_net = (*it).first;
186186
CBanEntry ban_entry = (*it).second;
187-
if (now > ban_entry.nBanUntil) {
187+
if (!sub_net.IsValid() || now > ban_entry.nBanUntil) {
188188
m_banned.erase(it++);
189189
m_is_dirty = true;
190190
notify_ui = true;

src/netaddress.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,6 +1109,17 @@ bool CSubNet::IsValid() const
11091109
return valid;
11101110
}
11111111

1112+
bool CSubNet::SanityCheck() const
1113+
{
1114+
if (!(network.IsIPv4() || network.IsIPv6())) return false;
1115+
1116+
for (size_t x = 0; x < network.m_addr.size(); ++x) {
1117+
if (network.m_addr[x] & ~netmask[x]) return false;
1118+
}
1119+
1120+
return true;
1121+
}
1122+
11121123
bool operator==(const CSubNet& a, const CSubNet& b)
11131124
{
11141125
return a.valid == b.valid && a.network == b.network && !memcmp(a.netmask, b.netmask, 16);

src/netaddress.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ class CSubNet
459459
/// Is this value valid? (only used to signal parse errors)
460460
bool valid;
461461

462+
bool SanityCheck() const;
463+
462464
public:
463465
CSubNet();
464466
CSubNet(const CNetAddr& addr, uint8_t mask);
@@ -476,7 +478,23 @@ class CSubNet
476478
friend bool operator!=(const CSubNet& a, const CSubNet& b) { return !(a == b); }
477479
friend bool operator<(const CSubNet& a, const CSubNet& b);
478480

479-
SERIALIZE_METHODS(CSubNet, obj) { READWRITE(obj.network, obj.netmask, obj.valid); }
481+
SERIALIZE_METHODS(CSubNet, obj)
482+
{
483+
READWRITE(obj.network);
484+
if (obj.network.IsIPv4()) {
485+
// Before commit 102867c587f5f7954232fb8ed8e85cda78bb4d32, CSubNet used the last 4 bytes of netmask
486+
// to store the relevant bytes for an IPv4 mask. For compatiblity reasons, keep doing so in
487+
// serialized form.
488+
unsigned char dummy[12] = {0};
489+
READWRITE(dummy);
490+
READWRITE(MakeSpan(obj.netmask).first(4));
491+
} else {
492+
READWRITE(obj.netmask);
493+
}
494+
READWRITE(obj.valid);
495+
// Mark invalid if the result doesn't pass sanity checking.
496+
SER_READ(obj, if (obj.valid) obj.valid = obj.SanityCheck());
497+
}
480498
};
481499

482500
/** A combination of a network address (CNetAddr) and a (TCP) port */

0 commit comments

Comments
 (0)