diff --git a/src/net_processing.cpp b/src/net_processing.cpp --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3945,8 +3945,11 @@ return; } - if (msg_type == NetMsgType::AVAHELLO && g_avalanche && - gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { + if (msg_type == NetMsgType::AVAHELLO && g_avalanche) { + if (!gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { + Misbehaving(pfrom, 20, "unsolicited-avahello"); + return; + } if (!pfrom.m_avalanche_state) { pfrom.m_avalanche_state = std::make_unique(); } @@ -3970,8 +3973,11 @@ // Ignore avalanche requests while importing if (msg_type == NetMsgType::AVAPOLL && !fImporting && !fReindex && - g_avalanche && - gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { + g_avalanche) { + if (!gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { + Misbehaving(pfrom, 20, "unsolicited-avapoll"); + return; + } auto now = std::chrono::steady_clock::now(); int64_t cooldown = gArgs.GetArg("-avacooldown", AVALANCHE_DEFAULT_COOLDOWN); @@ -4080,8 +4086,11 @@ // Ignore avalanche requests while importing if (msg_type == NetMsgType::AVARESPONSE && !fImporting && !fReindex && - g_avalanche && - gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { + g_avalanche) { + if (!gArgs.GetBoolArg("-enableavalanche", AVALANCHE_DEFAULT_ENABLED)) { + Misbehaving(pfrom, 20, "unsolicited-avaresponse"); + return; + } // As long as QUIC is not implemented, we need to sign response and // verify response's signatures in order to avoid any manipulation of // messages at the transport level. diff --git a/test/functional/p2p_invalid_messages.py b/test/functional/p2p_invalid_messages.py --- a/test/functional/p2p_invalid_messages.py +++ b/test/functional/p2p_invalid_messages.py @@ -10,6 +10,9 @@ from test_framework.messages import ( CBlockHeader, CInv, + msg_avahello, + msg_avapoll, + msg_avaresponse, msg_getdata, msg_headers, msg_inv, @@ -71,6 +74,7 @@ self.test_addrv2_too_long_address() self.test_addrv2_unrecognized_network() self.test_large_inv() + self.test_unsolicited_ava_messages() node = self.nodes[0] self.node = node @@ -350,6 +354,26 @@ conn.send_and_ping(msg) self.nodes[0].disconnect_p2ps() + def test_unsolicited_ava_messages(self): + """Node 0 has avalanche disabled by default. If a node does not + advertise the avalanche service flag, it does not expect to receive + any avalanche related message and should consider it as spam. + """ + conn = self.nodes[0].add_p2p_connection(P2PInterface()) + with self.nodes[0].assert_debug_log( + ['Misbehaving', 'peer=9 (0 -> 20): unsolicited-avahello']): + msg = msg_avahello() + conn.send_and_ping(msg) + with self.nodes[0].assert_debug_log( + ['Misbehaving', 'peer=9 (20 -> 40): unsolicited-avapoll']): + msg = msg_avapoll() + conn.send_and_ping(msg) + with self.nodes[0].assert_debug_log( + ['Misbehaving', 'peer=9 (40 -> 60): unsolicited-avaresponse']): + msg = msg_avaresponse() + conn.send_and_ping(msg) + self.nodes[0].disconnect_p2ps() + def _tweak_msg_data_size(self, message, wrong_size): """ Return a raw message based on another message but with an incorrect data size in diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py --- a/test/functional/test_framework/messages.py +++ b/test/functional/test_framework/messages.py @@ -27,6 +27,8 @@ import struct import time +from typing import List + from test_framework.siphash import siphash256 from test_framework.util import hex_str_to_bytes, assert_equal @@ -948,8 +950,8 @@ __slots__ = ("proofid", "levels") def __init__(self, proofid=0, levels=None): - self.proofid = proofid - self.levels = levels + self.proofid: int = proofid + self.levels: List[AvalancheDelegationLevel] = levels or [] def deserialize(self, f): self.proofid = deser_uint256(f)