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 : sixty seconds is eligible to be pinged, except nodes with at least
19 : FD_GOSSIP_STAKED_THRESHOLD lamports of stake which are exempt from
20 : ping requirements.
21 :
22 : Once a peer has been pinged, we wait up to twenty seconds for a
23 : response before trying again. We repeatedly retry pinging the peer
24 : every 20s for a minute until the peer responds, or their most recent
25 : message becomes older than sixty seconds.
26 :
27 : Once a peer is validated by responding to a ping with a valid pong,
28 : it is considered valid for 20 minutes. After 18 minutes, we will
29 : begin pinging the peer again, every twenty seconds, to refresh the
30 : peer. */
31 :
32 : #include "fd_gossip_message.h"
33 : #include "../../util/rng/fd_rng.h"
34 : #include "../../util/net/fd_net_headers.h"
35 :
36 63 : #define FD_PING_TRACKER_ALIGN (128UL)
37 :
38 21 : #define FD_PING_TRACKER_MAGIC (0xF17EDA2CE0113100) /* FIREDANCE PINGT V0 */
39 :
40 21 : #define FD_PING_TRACKER_MAX (65536UL)
41 :
42 : struct fd_ping_tracker_private;
43 : typedef struct fd_ping_tracker_private fd_ping_tracker_t;
44 :
45 : struct fd_ping_tracker_metrics {
46 : ulong unpinged_cnt;
47 : ulong invalid_cnt;
48 : ulong valid_cnt;
49 : ulong refreshing_cnt;
50 :
51 : ulong peers_evicted;
52 :
53 : ulong tracked_cnt;
54 : ulong stake_changed_cnt;
55 : ulong address_changed_cnt;
56 :
57 : ulong pong_result[ 6UL ];
58 : };
59 :
60 : typedef struct fd_ping_tracker_metrics fd_ping_tracker_metrics_t;
61 :
62 18 : #define FD_PING_TRACKER_CHANGE_TYPE_ACTIVE (0)
63 24 : #define FD_PING_TRACKER_CHANGE_TYPE_INACTIVE (1)
64 0 : #define FD_PING_TRACKER_CHANGE_TYPE_INACTIVE_STAKED (2)
65 :
66 : typedef void (*fd_ping_tracker_change_fn)( void * ctx,
67 : uchar const * peer_pubkey,
68 : fd_ip4_port_t peer_address,
69 : long now,
70 : int change_type );
71 :
72 : FD_PROTOTYPES_BEGIN
73 :
74 : FD_FN_CONST ulong
75 : fd_ping_tracker_align( void );
76 :
77 : FD_FN_CONST ulong
78 : fd_ping_tracker_footprint( ulong entrypoints_len );
79 :
80 : void *
81 : fd_ping_tracker_new( void * shmem,
82 : fd_rng_t * rng,
83 : ulong entrypoints_len,
84 : fd_ip4_port_t const * entrypoints,
85 : fd_ping_tracker_change_fn change_fn,
86 : void * change_fn_ctx );
87 :
88 : fd_ping_tracker_t *
89 : fd_ping_tracker_join( void * shpt );
90 :
91 : /* fd_ping_tracker_track marks a peer for ping tracking. This should be
92 : called every time a peer sends us a valid gossip contact info message
93 : so that we can start pinging them.
94 :
95 : The tracker is idempotent, and will only refresh and update
96 : information about the peer, based on knowledge that it sent us a new
97 : message and is still alive. It is valid to register a peer pubkey
98 : with a new stake amount, or peer address, and the tracker will
99 : internally update the information. */
100 :
101 : void
102 : fd_ping_tracker_track( fd_ping_tracker_t * ping_tracker,
103 : uchar const * peer_pubkey,
104 : ulong peer_stake,
105 : fd_ip4_port_t peer_address,
106 : long now );
107 :
108 : /* fd_ping_tracker_register registers a response pong from a peer so
109 : that they can be considered as valid. It should be called any time
110 : a peer sends a valid-looking pong. Valid looking, because it might
111 : not be ponging an actual ping token we sent, but this function will
112 : validate that before marking the peer as active. */
113 :
114 : void
115 : fd_ping_tracker_register( fd_ping_tracker_t * ping_tracker,
116 : uchar const * peer_pubkey,
117 : ulong peer_stake,
118 : fd_ip4_port_t peer_address,
119 : uchar const * pong_token,
120 : long now );
121 :
122 : /* fd_ping_tracker_active returns 1 if the peer is currently active and
123 : valid to send messages to, or 0 if the peer is not active. */
124 :
125 : int
126 : fd_ping_tracker_active( fd_ping_tracker_t * ping_tracker,
127 : uchar const * peer_pubkey,
128 : fd_ip4_port_t peer_address );
129 :
130 : /* fd_ping_tracker_remove removes a peer from the ping tracker by
131 : pubkey. If the peer was active (VALID or VALID_REFRESHING), the
132 : change_fn callback is fired with INACTIVE change type. If the peer
133 : is not in the tracker, this is a no-op. */
134 :
135 : void
136 : fd_ping_tracker_remove( fd_ping_tracker_t * ping_tracker,
137 : uchar const * peer_pubkey,
138 : long now );
139 :
140 : /* fd_ping_tracker_pop_request informs the caller if a ping request
141 : needs to be sent to a peer. If a ping request needs to be sent, the
142 : peer pubkey is returned in out_peer_pubkey. The caller should send a
143 : ping message to the peer. The structure assumes the ping will be
144 : sent, and updates internal state accordingly.
145 :
146 : Returns 1 if a ping request needs to be sent, or 0 if no ping request
147 : is needed.
148 :
149 : The out_peer_pubkey is only valid if the return value is 1, and
150 : should only be used immediately. The out_peer_pubkey is invalidated
151 : by any other call to the ping tracker, and using it after that is
152 : undefined behavior. */
153 :
154 : int
155 : fd_ping_tracker_pop_request( fd_ping_tracker_t * ping_tracker,
156 : long now,
157 : uchar const ** out_peer_pubkey,
158 : fd_ip4_port_t const ** out_peer_address,
159 : uchar const ** out_token );
160 :
161 : fd_ping_tracker_metrics_t const *
162 : fd_ping_tracker_metrics( fd_ping_tracker_t const * ping_tracker );
163 :
164 : #endif /* HEADER_fd_src_flamenco_gossip_fd_ping_tracker_h */
|