Skip to content

Commit 60a5094

Browse files
committed
Fix node protection logic false positives
We could be reading multiple messages from a socket buffer at once _without actually processing them yet_ which means that `fSuccessfullyConnected` might not be switched to `true` at the time we already parsed `VERACK` message and started to parse the next one. This is basically a false positive and we drop a legit node as a result even though the order of messages sent by this node was completely fine. To fix this I partially reverted #2790 (where the issue was initially introduced) and moved the logic for tracking the first message into ProcessMessage instead.
1 parent 9166ecd commit 60a5094

File tree

2 files changed

+14
-28
lines changed

2 files changed

+14
-28
lines changed

src/net.cpp

+1-19
Original file line numberDiff line numberDiff line change
@@ -768,24 +768,6 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
768768
int handled;
769769
if (!msg.in_data) {
770770
handled = msg.readHeader(pch, nBytes);
771-
if (msg.in_data && nTimeFirstMessageReceived == 0) {
772-
if (fSuccessfullyConnected) {
773-
// First message after VERSION/VERACK.
774-
// We record the time when the header is fully received and not when the full message is received.
775-
// otherwise a peer might send us a very large message as first message after VERSION/VERACK and fill
776-
// up our memory with multiple parallel connections doing this.
777-
nTimeFirstMessageReceived = nTimeMicros;
778-
fFirstMessageIsMNAUTH = msg.hdr.GetCommand() == NetMsgType::MNAUTH;
779-
} else {
780-
// We're still in the VERSION/VERACK handshake process, so any message received in this state is
781-
// expected to be very small. This protects against attackers filling up memory by sending oversized
782-
// VERSION messages while the incoming connection is still protected against eviction
783-
if (msg.hdr.nMessageSize > 1024) {
784-
LogPrint(BCLog::NET, "Oversized VERSION/VERACK message from peer=%i, disconnecting\n", GetId());
785-
return false;
786-
}
787-
}
788-
}
789771
} else {
790772
handled = msg.readData(pch, nBytes);
791773
}
@@ -1032,7 +1014,7 @@ bool CConnman::AttemptToEvictConnection()
10321014
if (fMasternodeMode) {
10331015
// This handles eviction protected nodes. Nodes are always protected for a short time after the connection
10341016
// was accepted. This short time is meant for the VERSION/VERACK exchange and the possible MNAUTH that might
1035-
// follow when the incoming connection is from another masternode. When another message then MNAUTH
1017+
// follow when the incoming connection is from another masternode. When a message other than MNAUTH
10361018
// is received after VERSION/VERACK, the protection is lifted immediately.
10371019
bool isProtected = GetSystemTimeInSeconds() - node->nTimeConnected < INBOUND_EVICTION_PROTECTION_TIME;
10381020
if (node->nTimeFirstMessageReceived != 0 && !node->fFirstMessageIsMNAUTH) {

src/net_processing.cpp

+13-9
Original file line numberDiff line numberDiff line change
@@ -1788,10 +1788,10 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
17881788
}
17891789
LogPrint(BCLog::NET, "Reject %s\n", SanitizeString(ss.str()));
17901790
}
1791+
return true;
17911792
}
17921793

1793-
else if (strCommand == NetMsgType::VERSION)
1794-
{
1794+
if (strCommand == NetMsgType::VERSION) {
17951795
// Each connection can only send one version message
17961796
if (pfrom->nVersion != 0)
17971797
{
@@ -1961,9 +1961,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
19611961
return true;
19621962
}
19631963

1964-
1965-
else if (pfrom->nVersion == 0)
1966-
{
1964+
if (pfrom->nVersion == 0) {
19671965
// Must have a version message before anything else
19681966
LOCK(cs_main);
19691967
Misbehaving(pfrom->GetId(), 1);
@@ -2028,18 +2026,24 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr
20282026
}
20292027

20302028
pfrom->fSuccessfullyConnected = true;
2029+
return true;
20312030
}
20322031

2033-
else if (!pfrom->fSuccessfullyConnected)
2034-
{
2032+
if (!pfrom->fSuccessfullyConnected) {
20352033
// Must have a verack message before anything else
20362034
LOCK(cs_main);
20372035
Misbehaving(pfrom->GetId(), 1);
20382036
return false;
20392037
}
20402038

2041-
else if (strCommand == NetMsgType::ADDR)
2042-
{
2039+
if (pfrom->nTimeFirstMessageReceived == 0) {
2040+
// First message after VERSION/VERACK
2041+
pfrom->nTimeFirstMessageReceived = GetTimeMicros();
2042+
pfrom->fFirstMessageIsMNAUTH = strCommand == NetMsgType::MNAUTH;
2043+
// Note: do not break the flow here
2044+
}
2045+
2046+
if (strCommand == NetMsgType::ADDR) {
20432047
std::vector<CAddress> vAddr;
20442048
vRecv >> vAddr;
20452049

0 commit comments

Comments
 (0)