@@ -16,7 +16,7 @@ class msg_unrecognized:
16
16
17
17
command = b'badmsg'
18
18
19
- def __init__ (self , str_data ):
19
+ def __init__ (self , * , str_data ):
20
20
self .str_data = str_data .encode () if not isinstance (str_data , bytes ) else str_data
21
21
22
22
def serialize (self ):
@@ -26,30 +26,27 @@ def __repr__(self):
26
26
return "{}(data={})" .format (self .command , self .str_data )
27
27
28
28
29
- class msg_nametoolong (msg_unrecognized ):
30
-
31
- command = b'thisnameiswayyyyyyyyytoolong'
32
-
33
-
34
29
class InvalidMessagesTest (BitcoinTestFramework ):
35
-
36
30
def set_test_params (self ):
37
31
self .num_nodes = 1
38
32
self .setup_clean_chain = True
39
33
40
34
def run_test (self ):
41
35
"""
36
+ . Test msg header
42
37
0. Send a bunch of large (4MB) messages of an unrecognized type. Check to see
43
38
that it isn't an effective DoS against the node.
44
39
45
40
1. Send an oversized (4MB+) message and check that we're disconnected.
46
41
47
42
2. Send a few messages with an incorrect data size in the header, ensure the
48
43
messages are ignored.
49
-
50
- 3. Send an unrecognized message with a command name longer than 12 characters.
51
-
52
44
"""
45
+ self .test_magic_bytes ()
46
+ self .test_checksum ()
47
+ self .test_size ()
48
+ self .test_command ()
49
+
53
50
node = self .nodes [0 ]
54
51
self .node = node
55
52
node .add_p2p_connection (P2PDataStore ())
@@ -64,7 +61,7 @@ def run_test(self):
64
61
# Send as large a message as is valid, ensure we aren't disconnected but
65
62
# also can't exhaust resources.
66
63
#
67
- msg_at_size = msg_unrecognized ("b" * valid_data_limit )
64
+ msg_at_size = msg_unrecognized (str_data = "b" * valid_data_limit )
68
65
assert len (msg_at_size .serialize ()) == msg_limit
69
66
70
67
increase_allowed = 0.5
@@ -94,10 +91,10 @@ def run_test(self):
94
91
#
95
92
# Send an oversized message, ensure we're disconnected.
96
93
#
97
- msg_over_size = msg_unrecognized ("b" * (valid_data_limit + 1 ))
94
+ msg_over_size = msg_unrecognized (str_data = "b" * (valid_data_limit + 1 ))
98
95
assert len (msg_over_size .serialize ()) == (msg_limit + 1 )
99
96
100
- with node .assert_debug_log (["Oversized message from peer=0 , disconnecting" ]):
97
+ with node .assert_debug_log (["Oversized message from peer=4 , disconnecting" ]):
101
98
# An unknown message type (or *any* message type) over
102
99
# MAX_PROTOCOL_MESSAGE_LENGTH should result in a disconnect.
103
100
node .p2p .send_message (msg_over_size )
@@ -113,7 +110,7 @@ def run_test(self):
113
110
# Send messages with an incorrect data size in the header.
114
111
#
115
112
actual_size = 100
116
- msg = msg_unrecognized ("b" * actual_size )
113
+ msg = msg_unrecognized (str_data = "b" * actual_size )
117
114
118
115
# TODO: handle larger-than cases. I haven't been able to pin down what behavior to expect.
119
116
for wrong_size in (2 , 77 , 78 , 79 ):
@@ -140,18 +137,58 @@ def run_test(self):
140
137
node .disconnect_p2ps ()
141
138
node .add_p2p_connection (P2PDataStore ())
142
139
143
- #
144
- # 3.
145
- #
146
- # Send a message with a too-long command name.
147
- #
148
- node .p2p .send_message (msg_nametoolong ("foobar" ))
149
- node .p2p .wait_for_disconnect (timeout = 4 )
150
-
151
140
# Node is still up.
152
141
conn = node .add_p2p_connection (P2PDataStore ())
153
142
conn .sync_with_ping ()
154
143
144
+ def test_magic_bytes (self ):
145
+ conn = self .nodes [0 ].add_p2p_connection (P2PDataStore ())
146
+ conn .magic_bytes = b'\x00 \x11 \x22 \x32 '
147
+ with self .nodes [0 ].assert_debug_log (['PROCESSMESSAGE: INVALID MESSAGESTART ping' ]):
148
+ conn .send_message (messages .msg_ping (nonce = 0xff ))
149
+ conn .wait_for_disconnect (timeout = 1 )
150
+ self .nodes [0 ].disconnect_p2ps ()
151
+
152
+ def test_checksum (self ):
153
+ conn = self .nodes [0 ].add_p2p_connection (P2PDataStore ())
154
+ with self .nodes [0 ].assert_debug_log (['ProcessMessages(badmsg, 2 bytes): CHECKSUM ERROR expected 78df0a04 was ffffffff' ]):
155
+ msg = conn .build_message (msg_unrecognized (str_data = "d" ))
156
+ cut_len = (
157
+ 4 + # magic
158
+ 12 + # command
159
+ 4 #len
160
+ )
161
+ # modify checksum
162
+ msg = msg [:cut_len ] + b'\xff ' * 4 + msg [cut_len + 4 :]
163
+ self .nodes [0 ].p2p .send_raw_message (msg )
164
+ conn .sync_with_ping (timeout = 1 )
165
+ self .nodes [0 ].disconnect_p2ps ()
166
+
167
+ def test_size (self ):
168
+ conn = self .nodes [0 ].add_p2p_connection (P2PDataStore ())
169
+ with self .nodes [0 ].assert_debug_log (['' ]):
170
+ msg = conn .build_message (msg_unrecognized (str_data = "d" ))
171
+ cut_len = (
172
+ 4 + # magic
173
+ 12 # command
174
+ )
175
+ # modify len to MAX_SIZE + 1
176
+ msg = msg [:cut_len ] + struct .pack ("<I" , 0x02000000 + 1 ) + msg [cut_len + 4 :]
177
+ self .nodes [0 ].p2p .send_raw_message (msg )
178
+ conn .wait_for_disconnect (timeout = 1 )
179
+ self .nodes [0 ].disconnect_p2ps ()
180
+
181
+ def test_command (self ):
182
+ conn = self .nodes [0 ].add_p2p_connection (P2PDataStore ())
183
+ with self .nodes [0 ].assert_debug_log (['PROCESSMESSAGE: ERRORS IN HEADER' ]):
184
+ msg = msg_unrecognized (str_data = "d" )
185
+ msg .command = b'\xff ' * 12
186
+ msg = conn .build_message (msg )
187
+ # Modify command
188
+ msg = msg [:7 ] + b'\x00 ' + msg [7 + 1 :]
189
+ self .nodes [0 ].p2p .send_raw_message (msg )
190
+ conn .sync_with_ping (timeout = 1 )
191
+ self .nodes [0 ].disconnect_p2ps ()
155
192
156
193
def _tweak_msg_data_size (self , message , wrong_size ):
157
194
"""
0 commit comments