14
14
from bcc import BPF , USDT # type: ignore[import]
15
15
except ImportError :
16
16
pass
17
- from test_framework .messages import msg_version
17
+ from test_framework .messages import CBlockHeader , MAX_HEADERS_RESULTS , msg_headers , msg_version
18
18
from test_framework .p2p import P2PInterface
19
19
from test_framework .test_framework import BitcoinTestFramework
20
20
from test_framework .util import assert_equal
23
23
MAX_PEER_ADDR_LENGTH = 68
24
24
MAX_PEER_CONN_TYPE_LENGTH = 20
25
25
MAX_MSG_TYPE_LENGTH = 20
26
+ MAX_MISBEHAVING_MESSAGE_LENGTH = 128
26
27
# We won't process messages larger than 150 byte in this test. For reading
27
28
# larger messanges see contrib/tracing/log_raw_p2p_msgs.py
28
29
MAX_MSG_DATA_LENGTH = 150
40
41
#define MAX_PEER_CONN_TYPE_LENGTH {}
41
42
#define MAX_MSG_TYPE_LENGTH {}
42
43
#define MAX_MSG_DATA_LENGTH {}
44
+ #define MAX_MISBEHAVING_MESSAGE_LENGTH {}
43
45
""" .format (
44
46
MAX_PEER_ADDR_LENGTH ,
45
47
MAX_PEER_CONN_TYPE_LENGTH ,
46
48
MAX_MSG_TYPE_LENGTH ,
47
- MAX_MSG_DATA_LENGTH
49
+ MAX_MSG_DATA_LENGTH ,
50
+ MAX_MISBEHAVING_MESSAGE_LENGTH ,
48
51
) + """
49
52
// A min() macro. Prefixed with _TRACEPOINT_TEST to avoid collision with other MIN macros.
50
53
#define _TRACEPOINT_TEST_MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
79
82
u64 time_established;
80
83
};
81
84
85
+ struct MisbehavingConnection
86
+ {
87
+ u64 id;
88
+ char message[MAX_MISBEHAVING_MESSAGE_LENGTH];
89
+ };
90
+
82
91
BPF_PERF_OUTPUT(inbound_messages);
83
92
int trace_inbound_message(struct pt_regs *ctx) {
84
93
struct p2p_message msg = {};
150
159
return 0;
151
160
};
152
161
162
+ BPF_PERF_OUTPUT(misbehaving_connections);
163
+ int trace_misbehaving_connection(struct pt_regs *ctx) {
164
+ struct MisbehavingConnection misbehaving = {};
165
+ void *message_pointer = NULL;
166
+ bpf_usdt_readarg(1, ctx, &misbehaving.id);
167
+ bpf_usdt_readarg(2, ctx, &message_pointer);
168
+ bpf_probe_read_user_str(&misbehaving.message, sizeof(misbehaving.message), message_pointer);
169
+ misbehaving_connections.perf_submit(ctx, &misbehaving, sizeof(misbehaving));
170
+ return 0;
171
+ };
153
172
"""
154
173
155
174
@@ -183,6 +202,17 @@ class ClosedConnection(ctypes.Structure):
183
202
def __repr__ (self ):
184
203
return f"ClosedConnection(conn={ self .conn } , time_established={ self .time_established } )"
185
204
205
+
206
+ class MisbehavingConnection (ctypes .Structure ):
207
+ _fields_ = [
208
+ ("id" , ctypes .c_uint64 ),
209
+ ("message" , ctypes .c_char * MAX_MISBEHAVING_MESSAGE_LENGTH ),
210
+ ]
211
+
212
+ def __repr__ (self ):
213
+ return f"MisbehavingConnection(id={ self .id } , message={ self .message } )"
214
+
215
+
186
216
class NetTracepointTest (BitcoinTestFramework ):
187
217
def set_test_params (self ):
188
218
self .num_nodes = 1
@@ -199,6 +229,7 @@ def run_test(self):
199
229
self .inbound_conn_tracepoint_test ()
200
230
self .outbound_conn_tracepoint_test ()
201
231
self .evicted_inbound_conn_tracepoint_test ()
232
+ self .misbehaving_conn_tracepoint_test ()
202
233
203
234
def p2p_message_tracepoint_test (self ):
204
235
# Tests the net:inbound_message and net:outbound_message tracepoints
@@ -392,5 +423,39 @@ def handle_evicted_inbound_connection(_, data, __):
392
423
for node in testnodes :
393
424
node .peer_disconnect ()
394
425
426
+ def misbehaving_conn_tracepoint_test (self ):
427
+ self .log .info ("hook into the net:misbehaving_connection tracepoint" )
428
+ ctx = USDT (pid = self .nodes [0 ].process .pid )
429
+ ctx .enable_probe (probe = "net:misbehaving_connection" ,
430
+ fn_name = "trace_misbehaving_connection" )
431
+ bpf = BPF (text = net_tracepoints_program , usdt_contexts = [ctx ], debug = 0 , cflags = ["-Wno-error=implicit-function-declaration" ])
432
+
433
+ EXPECTED_MISBEHAVING_CONNECTIONS = 2
434
+ misbehaving_connections = []
435
+
436
+ def handle_misbehaving_connection (_ , data , __ ):
437
+ event = ctypes .cast (data , ctypes .POINTER (MisbehavingConnection )).contents
438
+ self .log .info (f"handle_misbehaving_connection(): { event } " )
439
+ misbehaving_connections .append (event )
440
+
441
+ bpf ["misbehaving_connections" ].open_perf_buffer (handle_misbehaving_connection )
442
+
443
+ self .log .info ("connect a misbehaving P2P test nodes to our bitcoind node" )
444
+ msg = msg_headers ([CBlockHeader ()] * (MAX_HEADERS_RESULTS + 1 ))
445
+ for _ in range (EXPECTED_MISBEHAVING_CONNECTIONS ):
446
+ testnode = P2PInterface ()
447
+ self .nodes [0 ].add_p2p_connection (testnode )
448
+ testnode .send_message (msg )
449
+ bpf .perf_buffer_poll (timeout = 500 )
450
+ testnode .peer_disconnect ()
451
+
452
+ assert_equal (EXPECTED_MISBEHAVING_CONNECTIONS , len (misbehaving_connections ))
453
+ for misbehaving_connection in misbehaving_connections :
454
+ assert misbehaving_connection .id > 0
455
+ assert len (misbehaving_connection .message ) > 0
456
+ assert misbehaving_connection .message == b"headers message size = 2001"
457
+
458
+ bpf .cleanup ()
459
+
395
460
if __name__ == '__main__' :
396
461
NetTracepointTest (__file__ ).main ()
0 commit comments