Skip to content

Commit deb5271

Browse files
committed
Remove header checks out of net_processing
This moves header size and netmagic checking out of net_processing and into net. This check now runs in ReadHeader, so that net can exit early out of receiving bytes from the peer. IsValid is now slimmed down, so it no longer needs a MessageStartChars& parameter. Additionally this removes the rest of the m_valid_* members from CNetMessage.
1 parent 52d4ae4 commit deb5271

File tree

8 files changed

+32
-62
lines changed

8 files changed

+32
-62
lines changed

src/net.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
605605
// absorb network data
606606
int handled = m_deserializer->Read(pch, nBytes);
607607
if (handled < 0) {
608+
// Serious header problem, disconnect from the peer.
608609
return false;
609610
}
610611

@@ -616,6 +617,7 @@ bool CNode::ReceiveMsgBytes(const char *pch, unsigned int nBytes, bool& complete
616617
uint32_t out_err_raw_size{0};
617618
Optional<CNetMessage> result{m_deserializer->GetMessage(time, out_err_raw_size)};
618619
if (!result) {
620+
// Message deserialization failed. Drop the message but don't disconnect the peer.
619621
// store the size of the corrupt message
620622
mapRecvBytesPerMsgCmd.find(NET_MESSAGE_COMMAND_OTHER)->second += out_err_raw_size;
621623
continue;
@@ -657,11 +659,19 @@ int V1TransportDeserializer::readHeader(const char *pch, unsigned int nBytes)
657659
hdrbuf >> hdr;
658660
}
659661
catch (const std::exception&) {
662+
LogPrint(BCLog::NET, "HEADER ERROR - UNABLE TO DESERIALIZE, peer=%d\n", m_node_id);
663+
return -1;
664+
}
665+
666+
// Check start string, network magic
667+
if (memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) != 0) {
668+
LogPrint(BCLog::NET, "HEADER ERROR - MESSAGESTART (%s, %u bytes), received %s, peer=%d\n", hdr.GetCommand(), hdr.nMessageSize, HexStr(hdr.pchMessageStart), m_node_id);
660669
return -1;
661670
}
662671

663672
// reject messages larger than MAX_SIZE or MAX_PROTOCOL_MESSAGE_LENGTH
664673
if (hdr.nMessageSize > MAX_SIZE || hdr.nMessageSize > MAX_PROTOCOL_MESSAGE_LENGTH) {
674+
LogPrint(BCLog::NET, "HEADER ERROR - SIZE (%s, %u bytes), peer=%d\n", hdr.GetCommand(), hdr.nMessageSize, m_node_id);
665675
return -1;
666676
}
667677

@@ -701,10 +711,6 @@ Optional<CNetMessage> V1TransportDeserializer::GetMessage(const std::chrono::mic
701711
// decompose a single CNetMessage from the TransportDeserializer
702712
Optional<CNetMessage> msg(std::move(vRecv));
703713

704-
// store state about valid header, netmagic and checksum
705-
msg->m_valid_header = hdr.IsValid(m_chain_params.MessageStart());
706-
msg->m_valid_netmagic = (memcmp(hdr.pchMessageStart, m_chain_params.MessageStart(), CMessageHeader::MESSAGE_START_SIZE) == 0);
707-
708714
// store command string, time, and sizes
709715
msg->m_command = hdr.GetCommand();
710716
msg->m_time = time;
@@ -716,6 +722,7 @@ Optional<CNetMessage> V1TransportDeserializer::GetMessage(const std::chrono::mic
716722
// We just received a message off the wire, harvest entropy from the time (and the message checksum)
717723
RandAddEvent(ReadLE32(hash.begin()));
718724

725+
// Check checksum and header command string
719726
if (memcmp(hash.begin(), hdr.pchChecksum, CMessageHeader::CHECKSUM_SIZE) != 0) {
720727
LogPrint(BCLog::NET, "CHECKSUM ERROR (%s, %u bytes), expected %s was %s, peer=%d\n",
721728
SanitizeString(msg->m_command), msg->m_message_size,
@@ -724,6 +731,11 @@ Optional<CNetMessage> V1TransportDeserializer::GetMessage(const std::chrono::mic
724731
m_node_id);
725732
out_err_raw_size = msg->m_raw_message_size;
726733
msg = nullopt;
734+
} else if (!hdr.IsCommandValid()) {
735+
LogPrint(BCLog::NET, "HEADER ERROR - COMMAND (%s, %u bytes), peer=%d\n",
736+
hdr.GetCommand(), msg->m_message_size, m_node_id);
737+
out_err_raw_size = msg->m_raw_message_size;
738+
msg = nullopt;
727739
}
728740

729741
// Always reset the network deserializer (prepare for the next message)

src/net.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -706,10 +706,8 @@ class CNetMessage {
706706
public:
707707
CDataStream m_recv; //!< received message data
708708
std::chrono::microseconds m_time{0}; //!< time of message receipt
709-
bool m_valid_netmagic = false;
710-
bool m_valid_header = false;
711-
uint32_t m_message_size{0}; //!< size of the payload
712-
uint32_t m_raw_message_size{0}; //!< used wire size of the message (including header/checksum)
709+
uint32_t m_message_size{0}; //!< size of the payload
710+
uint32_t m_raw_message_size{0}; //!< used wire size of the message (including header/checksum)
713711
std::string m_command;
714712

715713
CNetMessage(CDataStream&& recv_in) : m_recv(std::move(recv_in)) {}

src/net_processing.cpp

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3820,14 +3820,6 @@ bool PeerManager::MaybeDiscourageAndDisconnect(CNode& pnode)
38203820

38213821
bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgProc)
38223822
{
3823-
//
3824-
// Message format
3825-
// (4) message start
3826-
// (12) command
3827-
// (4) size
3828-
// (4) checksum
3829-
// (x) data
3830-
//
38313823
bool fMoreWork = false;
38323824

38333825
if (!pfrom->vRecvGetData.empty())
@@ -3868,19 +3860,6 @@ bool PeerManager::ProcessMessages(CNode* pfrom, std::atomic<bool>& interruptMsgP
38683860
CNetMessage& msg(msgs.front());
38693861

38703862
msg.SetVersion(pfrom->GetCommonVersion());
3871-
// Check network magic
3872-
if (!msg.m_valid_netmagic) {
3873-
LogPrint(BCLog::NET, "PROCESSMESSAGE: INVALID MESSAGESTART %s peer=%d\n", SanitizeString(msg.m_command), pfrom->GetId());
3874-
pfrom->fDisconnect = true;
3875-
return false;
3876-
}
3877-
3878-
// Check header
3879-
if (!msg.m_valid_header)
3880-
{
3881-
LogPrint(BCLog::NET, "PROCESSMESSAGE: ERRORS IN HEADER %s peer=%d\n", SanitizeString(msg.m_command), pfrom->GetId());
3882-
return fMoreWork;
3883-
}
38843863
const std::string& msg_type = msg.m_command;
38853864

38863865
// Message size

src/protocol.cpp

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -111,31 +111,20 @@ std::string CMessageHeader::GetCommand() const
111111
return std::string(pchCommand, pchCommand + strnlen(pchCommand, COMMAND_SIZE));
112112
}
113113

114-
bool CMessageHeader::IsValid(const MessageStartChars& pchMessageStartIn) const
114+
bool CMessageHeader::IsCommandValid() const
115115
{
116-
// Check start string
117-
if (memcmp(pchMessageStart, pchMessageStartIn, MESSAGE_START_SIZE) != 0)
118-
return false;
119-
120116
// Check the command string for errors
121-
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; p1++)
122-
{
123-
if (*p1 == 0)
124-
{
117+
for (const char* p1 = pchCommand; p1 < pchCommand + COMMAND_SIZE; ++p1) {
118+
if (*p1 == 0) {
125119
// Must be all zeros after the first zero
126-
for (; p1 < pchCommand + COMMAND_SIZE; p1++)
127-
if (*p1 != 0)
120+
for (; p1 < pchCommand + COMMAND_SIZE; ++p1) {
121+
if (*p1 != 0) {
128122
return false;
129-
}
130-
else if (*p1 < ' ' || *p1 > 0x7E)
123+
}
124+
}
125+
} else if (*p1 < ' ' || *p1 > 0x7E) {
131126
return false;
132-
}
133-
134-
// Message size
135-
if (nMessageSize > MAX_SIZE)
136-
{
137-
LogPrintf("CMessageHeader::IsValid(): (%s, %u bytes) nMessageSize > MAX_SIZE\n", GetCommand(), nMessageSize);
138-
return false;
127+
}
139128
}
140129

141130
return true;

src/protocol.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class CMessageHeader
4545
CMessageHeader(const MessageStartChars& pchMessageStartIn, const char* pszCommand, unsigned int nMessageSizeIn);
4646

4747
std::string GetCommand() const;
48-
bool IsValid(const MessageStartChars& messageStart) const;
48+
bool IsCommandValid() const;
4949

5050
SERIALIZE_METHODS(CMessageHeader, obj) { READWRITE(obj.pchMessageStart, obj.pchCommand, obj.nMessageSize, obj.pchChecksum); }
5151

src/test/fuzz/deserialize.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,10 +189,9 @@ void test_one_input(const std::vector<uint8_t>& buffer)
189189
DeserializeFromFuzzingInput(buffer, s);
190190
AssertEqualAfterSerializeDeserialize(s);
191191
#elif MESSAGEHEADER_DESERIALIZE
192-
const CMessageHeader::MessageStartChars pchMessageStart = {0x00, 0x00, 0x00, 0x00};
193192
CMessageHeader mh;
194193
DeserializeFromFuzzingInput(buffer, mh);
195-
(void)mh.IsValid(pchMessageStart);
194+
(void)mh.IsCommandValid();
196195
#elif ADDRESS_DESERIALIZE
197196
CAddress a;
198197
DeserializeFromFuzzingInput(buffer, a);

src/test/fuzz/p2p_transport_deserializer.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ void test_one_input(const std::vector<uint8_t>& buffer)
3939
assert(result->m_raw_message_size <= buffer.size());
4040
assert(result->m_raw_message_size == CMessageHeader::HEADER_SIZE + result->m_message_size);
4141
assert(result->m_time == m_time);
42-
if (result->m_valid_header) {
43-
assert(result->m_valid_netmagic);
44-
}
45-
if (!result->m_valid_netmagic) {
46-
assert(!result->m_valid_header);
47-
}
4842
}
4943
}
5044
}

test/functional/p2p_invalid_messages.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def test_buffer(self):
8181
def test_magic_bytes(self):
8282
self.log.info("Test message with invalid magic bytes disconnects peer")
8383
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
84-
with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: INVALID MESSAGESTART badmsg']):
84+
with self.nodes[0].assert_debug_log(['HEADER ERROR - MESSAGESTART (badmsg, 2 bytes), received ffffffff']):
8585
msg = conn.build_message(msg_unrecognized(str_data="d"))
8686
# modify magic bytes
8787
msg = b'\xff' * 4 + msg[4:]
@@ -105,7 +105,7 @@ def test_checksum(self):
105105
def test_size(self):
106106
self.log.info("Test message with oversized payload disconnects peer")
107107
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
108-
with self.nodes[0].assert_debug_log(['']):
108+
with self.nodes[0].assert_debug_log(['HEADER ERROR - SIZE (badmsg, 4000001 bytes)']):
109109
msg = msg_unrecognized(str_data="d" * (VALID_DATA_LIMIT + 1))
110110
msg = conn.build_message(msg)
111111
conn.send_raw_message(msg)
@@ -115,9 +115,8 @@ def test_size(self):
115115
def test_msgtype(self):
116116
self.log.info("Test message with invalid message type logs an error")
117117
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
118-
with self.nodes[0].assert_debug_log(['PROCESSMESSAGE: ERRORS IN HEADER']):
118+
with self.nodes[0].assert_debug_log(['HEADER ERROR - COMMAND']):
119119
msg = msg_unrecognized(str_data="d")
120-
msg.msgtype = b'\xff' * 12
121120
msg = conn.build_message(msg)
122121
# Modify msgtype
123122
msg = msg[:7] + b'\x00' + msg[7 + 1:]

0 commit comments

Comments
 (0)