Line data Source code
1 : #ifndef HEADER_fd_src_flamenco_gossip_fd_ping_tracker_h
2 : #define HEADER_fd_src_flamenco_gossip_fd_ping_tracker_h
3 :
4 : /* The gossip network amplifies inbound traffic. For example, a node
5 : can send us a small pull request, with an empty bloom filter and then
6 : get back a very large set of pull responses.
7 :
8 : This is not good because an attacker can use it as a reflection
9 : vector for a DDoS attack. To prevent this, we enforce a rule that we
10 : can only send data to peers that have responded to a ping request.
11 :
12 : The fd_ping_tracker maintains a metadata about the peers available to
13 : ping, who has been pinged, and who has responded, so that we can
14 : quickly determine before sending a message if we should send it or
15 : not.
16 :
17 : Any peer which has tried to send us a gossip message within the last
18 : two minutes is eligible to be pinged, except nodes with at least one
19 : SOL of stake which are exempt from ping requirements.
20 :
21 : Once a peer has been pinged, we wait up to twenty seconds for a
22 : response before trying again. We repeatedly retry pinging the peer
23 : until the peer responds, or their most recent message becomes older
24 : than two minutes.
25 :
26 : Once a peer is validated by responding to a ping with a valid pong,
27 : it is considered valid for 20 minutes. After 18 minutes, we will
28 : begin pinging the peer again, every twenty seconds, to refresh the
29 : peer. */
30 :
31 : #include "../../util/rng/fd_rng.h"
32 : #include "../../util/net/fd_net_headers.h"
33 :
34 45 : #define FD_PING_TRACKER_ALIGN (128UL)
35 :
36 15 : #define FD_PING_TRACKER_MAGIC (0xF17EDA2CE0113100) /* FIREDANCE PINGT V0 */
37 :
38 15 : #define FD_PING_TRACKER_MAX (65536UL)
39 :
40 : struct fd_ping_tracker_private;
41 : typedef struct fd_ping_tracker_private fd_ping_tracker_t;
42 :
43 : struct fd_ping_tracker_metrics {
44 : ulong unpinged_cnt;
45 : ulong invalid_cnt;
46 : ulong valid_cnt;
47 : ulong refreshing_cnt;
48 :
49 : ulong peers_evicted;
50 :
51 : ulong tracked_cnt;
52 : ulong stake_changed_cnt;
53 : ulong address_changed_cnt;
54 :
55 : ulong pong_result[ 6UL ];
56 : };
57 :
58 : typedef struct fd_ping_tracker_metrics fd_ping_tracker_metrics_t;
59 :
60 9 : #define FD_PING_TRACKER_CHANGE_TYPE_ACTIVE (0)
61 6 : #define FD_PING_TRACKER_CHANGE_TYPE_INACTIVE (1)
62 0 : #define FD_PING_TRACKER_CHANGE_TYPE_INACTIVE_STAKED (2)
63 :
64 : typedef void (*fd_ping_tracker_change_fn)( void * ctx,
65 : uchar const * peer_pubkey,
66 : fd_ip4_port_t peer_address,
67 : long now,
68 : int change_type );
69 :
70 : FD_PROTOTYPES_BEGIN
71 :
72 : FD_FN_CONST ulong
73 : fd_ping_tracker_align( void );
74 :
75 : FD_FN_CONST ulong
76 : fd_ping_tracker_footprint( ulong entrypoints_len );
77 :
78 : void *
79 : fd_ping_tracker_new( void * shmem,
80 : fd_rng_t * rng,
81 : ulong entrypoints_len,
82 : fd_ip4_port_t const * entrypoints,
83 : fd_ping_tracker_change_fn change_fn,
84 : void * change_fn_ctx );
85 :
86 : fd_ping_tracker_t *
87 : fd_ping_tracker_join( void * shpt );
88 :
89 : /* fd_ping_tracker_track marks a peer for ping tracking. This should be
90 : called every time a peer sends us a valid gossip contact info message
91 : so that we can start pinging them.
92 :
93 : The tracker is idempotent, and will only refresh and update
94 : information about the peer, based on knowledge that it sent us a new
95 : message and is still alive. It is valid to register a peer pubkey
96 : with a new stake amount, or peer address, and the tracker will
97 : internally update the information. */
98 :
99 : void
100 : fd_ping_tracker_track( fd_ping_tracker_t * ping_tracker,
101 : uchar const * peer_pubkey,
102 : ulong peer_stake,
103 : fd_ip4_port_t peer_address,
104 : long now );
105 :
106 : /* fd_ping_tracker_register registers a response pong from a peer so
107 : that they can be considered as valid. It should be called any time
108 : a peer sends a valid-looking pong. Valid looking, because it might
109 : not be ponging an actual ping token we sent, but this function will
110 : validate that before marking the peer as active. */
111 :
112 : void
113 : fd_ping_tracker_register( fd_ping_tracker_t * ping_tracker,
114 : uchar const * peer_pubkey,
115 : ulong peer_stake,
116 : fd_ip4_port_t peer_address,
117 : uchar const * pong_token,
118 : long now );
119 :
120 : /* fd_ping_tracker_pop_request informs the caller if a ping request
121 : needs to be sent to a peer. If a ping request needs to be sent, the
122 : peer pubkey is returned in out_peer_pubkey. The caller should send a
123 : ping message to the peer. The structure assumes the ping will be
124 : sent, and updates internal state accordingly.
125 :
126 : Returns 1 if a ping request needs to be sent, or 0 if no ping request
127 : is needed.
128 :
129 : The out_peer_pubkey is only valid if the return value is 1, and
130 : should only be used immediately. The out_peer_pubkey is invalidated
131 : by any other call to the ping tracker, and using it after that is
132 : undefined behavior. */
133 :
134 : int
135 : fd_ping_tracker_pop_request( fd_ping_tracker_t * ping_tracker,
136 : long now,
137 : uchar const ** out_peer_pubkey,
138 : fd_ip4_port_t const ** out_peer_address,
139 : uchar const ** out_token );
140 :
141 : fd_ping_tracker_metrics_t const *
142 : fd_ping_tracker_metrics( fd_ping_tracker_t const * ping_tracker );
143 :
144 : #endif /* HEADER_fd_src_flamenco_gossip_fd_ping_tracker_h */
|