1414 from bcc import BPF , USDT # type: ignore[import]
1515except ImportError :
1616 pass
17- from test_framework .messages import msg_version
17+ from test_framework .messages import CBlockHeader , MAX_HEADERS_RESULTS , msg_headers , msg_version
1818from test_framework .p2p import P2PInterface
1919from test_framework .test_framework import BitcoinTestFramework
2020from test_framework .util import assert_equal
2323MAX_PEER_ADDR_LENGTH = 68
2424MAX_PEER_CONN_TYPE_LENGTH = 20
2525MAX_MSG_TYPE_LENGTH = 20
26+ MAX_MISBEHAVING_MESSAGE_LENGTH = 128
2627# We won't process messages larger than 150 byte in this test. For reading
2728# larger messanges see contrib/tracing/log_raw_p2p_msgs.py
2829MAX_MSG_DATA_LENGTH = 150
4041#define MAX_PEER_CONN_TYPE_LENGTH {}
4142#define MAX_MSG_TYPE_LENGTH {}
4243#define MAX_MSG_DATA_LENGTH {}
44+ #define MAX_MISBEHAVING_MESSAGE_LENGTH {}
4345""" .format (
4446 MAX_PEER_ADDR_LENGTH ,
4547 MAX_PEER_CONN_TYPE_LENGTH ,
4648 MAX_MSG_TYPE_LENGTH ,
47- MAX_MSG_DATA_LENGTH
49+ MAX_MSG_DATA_LENGTH ,
50+ MAX_MISBEHAVING_MESSAGE_LENGTH ,
4851) + """
4952// A min() macro. Prefixed with _TRACEPOINT_TEST to avoid collision with other MIN macros.
5053#define _TRACEPOINT_TEST_MIN(a,b) ({ __typeof__ (a) _a = (a); __typeof__ (b) _b = (b); _a < _b ? _a : _b; })
7982 u64 time_established;
8083};
8184
85+ struct MisbehavingConnection
86+ {
87+ u64 id;
88+ char message[MAX_MISBEHAVING_MESSAGE_LENGTH];
89+ };
90+
8291BPF_PERF_OUTPUT(inbound_messages);
8392int trace_inbound_message(struct pt_regs *ctx) {
8493 struct p2p_message msg = {};
150159 return 0;
151160};
152161
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+ };
153172"""
154173
155174
@@ -183,6 +202,17 @@ class ClosedConnection(ctypes.Structure):
183202 def __repr__ (self ):
184203 return f"ClosedConnection(conn={ self .conn } , time_established={ self .time_established } )"
185204
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+
186216class NetTracepointTest (BitcoinTestFramework ):
187217 def set_test_params (self ):
188218 self .num_nodes = 1
@@ -199,6 +229,7 @@ def run_test(self):
199229 self .inbound_conn_tracepoint_test ()
200230 self .outbound_conn_tracepoint_test ()
201231 self .evicted_inbound_conn_tracepoint_test ()
232+ self .misbehaving_conn_tracepoint_test ()
202233
203234 def p2p_message_tracepoint_test (self ):
204235 # Tests the net:inbound_message and net:outbound_message tracepoints
@@ -392,5 +423,39 @@ def handle_evicted_inbound_connection(_, data, __):
392423 for node in testnodes :
393424 node .peer_disconnect ()
394425
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+
395460if __name__ == '__main__' :
396461 NetTracepointTest (__file__ ).main ()
0 commit comments