Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115562
D9519.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
7 KB
Subscribers
None
D9519.diff
View Options
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
@@ -28,6 +28,9 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import hex_str_to_bytes
+MSG_LIMIT = 2 * 1024 * 1024 # 2MB, per MAX_PROTOCOL_MESSAGE_LENGTH
+VALID_DATA_LIMIT = MSG_LIMIT - 5 # Account for the 5-byte length prefix
+
class msg_unrecognized:
"""Nonsensical message. Modeled after similar types in test_framework.messages."""
@@ -55,16 +58,6 @@
self.setup_clean_chain = True
def run_test(self):
- """
- . Test msg header
- 0. Send a bunch of large (2MB) messages of an unrecognized type. Check to see
- that it isn't an effective DoS against the node.
-
- 1. Send an oversized (2MB+) message and check that we're disconnected.
-
- 2. Send a few messages with an incorrect data size in the header, ensure the
- messages are ignored.
- """
self.test_magic_bytes()
self.test_checksum()
self.test_size()
@@ -75,101 +68,7 @@
self.test_addrv2_unrecognized_network()
self.test_large_inv()
self.test_unsolicited_ava_messages()
-
- node = self.nodes[0]
- self.node = node
- node.add_p2p_connection(P2PDataStore())
- conn2 = node.add_p2p_connection(P2PDataStore())
-
- # 2MB, per MAX_PROTOCOL_MESSAGE_LENGTH
- msg_limit = 2 * 1024 * 1024
- # Account for the 4-byte length prefix
- valid_data_limit = msg_limit - 5
-
- #
- # 0.
- #
- # Send as large a message as is valid, ensure we aren't disconnected but
- # also can't exhaust resources.
- #
- msg_at_size = msg_unrecognized(str_data="b" * valid_data_limit)
- assert len(msg_at_size.serialize()) == msg_limit
-
- self.log.info(
- "Sending a bunch of large, junk messages to test memory exhaustion. May take a bit...")
-
- # Run a bunch of times to test for memory exhaustion.
- for _ in range(80):
- node.p2p.send_message(msg_at_size)
-
- # Check that, even though the node is being hammered by nonsense from one
- # connection, it can still service other peers in a timely way.
- for _ in range(20):
- conn2.sync_with_ping(timeout=2)
-
- # Peer 1, despite serving up a bunch of nonsense, should still be
- # connected.
- self.log.info("Waiting for node to drop junk messages.")
- node.p2p.sync_with_ping(timeout=320)
- assert node.p2p.is_connected
-
- #
- # 1.
- #
- # Send an oversized message, ensure we're disconnected.
- #
- msg_over_size = msg_unrecognized(str_data="b" * (valid_data_limit + 1))
- assert len(msg_over_size.serialize()) == (msg_limit + 1)
-
- with node.assert_debug_log(["Oversized header detected"]):
- # An unknown message type (or *any* message type) over
- # MAX_PROTOCOL_MESSAGE_LENGTH should result in a disconnect.
- node.p2p.send_message(msg_over_size)
- node.p2p.wait_for_disconnect(timeout=4)
-
- node.disconnect_p2ps()
- conn = node.add_p2p_connection(P2PDataStore())
- conn.wait_for_verack()
-
- #
- # 2.
- #
- # Send messages with an incorrect data size in the header.
- #
- actual_size = 100
- msg = msg_unrecognized(str_data="b" * actual_size)
-
- # TODO: handle larger-than cases. I haven't been able to pin down what
- # behavior to expect.
- for wrong_size in (2, 77, 78, 79):
- self.log.info(
- "Sending a message with incorrect size of {}".format(wrong_size))
-
- # Unmodified message should submit okay.
- node.p2p.send_and_ping(msg)
-
- # A message lying about its data size results in a disconnect when the incorrect
- # data size is less than the actual size.
- #
- # TODO: why does behavior change at 78 bytes?
- #
- node.p2p.send_raw_message(
- self._tweak_msg_data_size(
- msg, wrong_size))
-
- # For some reason unknown to me, we sometimes have to push additional data to the
- # peer in order for it to realize a disconnect.
- try:
- node.p2p.send_message(msg_ping(nonce=123123))
- except IOError:
- pass
-
- node.p2p.wait_for_disconnect(timeout=10)
- node.disconnect_p2ps()
- node.add_p2p_connection(P2PDataStore())
-
- # Node is still up.
- conn = node.add_p2p_connection(P2PDataStore())
+ self.test_resource_exhaustion()
def test_magic_bytes(self):
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
@@ -212,16 +111,9 @@
def test_size(self):
conn = self.nodes[0].add_p2p_connection(P2PDataStore())
with self.nodes[0].assert_debug_log(['']):
- msg = conn.build_message(msg_unrecognized(str_data="d"))
- cut_len = (
- # magic
- 4 +
- # command
- 12
- )
- # modify len to MAX_SIZE + 1
- msg = msg[:cut_len] + \
- struct.pack("<I", 0x02000000 + 1) + msg[cut_len + 4:]
+ # Create a message with oversized payload
+ msg = msg_unrecognized(str_data="d" * (VALID_DATA_LIMIT + 1))
+ msg = conn.build_message(msg)
self.nodes[0].p2p.send_raw_message(msg)
conn.wait_for_disconnect(timeout=1)
self.nodes[0].disconnect_p2ps()
@@ -374,25 +266,30 @@
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
- the message header.
- """
- raw_msg = self.node.p2p.build_message(message)
+ def test_resource_exhaustion(self):
+ conn = self.nodes[0].add_p2p_connection(P2PDataStore())
+ conn2 = self.nodes[0].add_p2p_connection(P2PDataStore())
+ msg_at_size = msg_unrecognized(str_data="b" * VALID_DATA_LIMIT)
+ assert len(msg_at_size.serialize()) == MSG_LIMIT
+
+ self.log.info(
+ "Sending a bunch of large, junk messages to test memory exhaustion. May take a bit...")
- bad_size_bytes = struct.pack("<I", wrong_size)
- num_header_bytes_before_size = 4 + 12
+ # Run a bunch of times to test for memory exhaustion.
+ for _ in range(80):
+ conn.send_message(msg_at_size)
- # Replace the correct data size in the message with an incorrect one.
- raw_msg_with_wrong_size = (
- raw_msg[:num_header_bytes_before_size] +
- bad_size_bytes +
- raw_msg[(num_header_bytes_before_size + len(bad_size_bytes)):]
- )
- assert len(raw_msg) == len(raw_msg_with_wrong_size)
+ # Check that, even though the node is being hammered by nonsense from one
+ # connection, it can still service other peers in a timely way.
+ for _ in range(20):
+ conn2.sync_with_ping(timeout=2)
- return raw_msg_with_wrong_size
+ # Peer 1, despite being served up a bunch of nonsense, should still be
+ # connected.
+ self.log.info("Waiting for node to drop junk messages.")
+ conn.sync_with_ping(timeout=400)
+ assert conn.is_connected
+ self.nodes[0].disconnect_p2ps()
if __name__ == '__main__':
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Mar 1, 11:25 (8 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187591
Default Alt Text
D9519.diff (7 KB)
Attached To
D9519: [backport#19177] test: Fix and clean p2p_invalid_messages functional tests
Event Timeline
Log In to Comment