Line data Source code
1 : #include "fd_rserve.h"
2 : #include "fd_repair.h"
3 : #include "../../ballet/sha256/fd_sha256.h"
4 :
5 : static void
6 : fd_rserve_rotation_secret( uchar out[ 32 ],
7 : uchar const master[ 32 ],
8 0 : ulong idx ) {
9 0 : uchar buf[ 40 ];
10 0 : memcpy( buf, master, 32UL );
11 0 : FD_STORE( ulong, buf+32UL, idx );
12 0 : fd_sha256_hash( buf, sizeof(buf), out );
13 0 : }
14 :
15 : static void
16 : fd_rserve_token_compute( uchar token[ 32 ],
17 : uchar const secret[ 32 ],
18 : fd_pubkey_t const * from,
19 : uint ip4,
20 0 : ushort port ) {
21 0 : memcpy( token, "SOLANA_PING_PONG", 16UL );
22 :
23 0 : uchar buf[ 32UL + 32UL + 4UL + 2UL ];
24 0 : memcpy( buf, secret, 32UL );
25 0 : memcpy( buf+32UL, from->uc, 32UL );
26 0 : FD_STORE( uint, buf+64UL, ip4 );
27 0 : FD_STORE( ushort, buf+68UL, port );
28 :
29 0 : uchar mac[ 32 ];
30 0 : fd_sha256_hash( buf, sizeof(buf), mac );
31 0 : memcpy( token+16UL, mac, 16UL );
32 0 : }
33 :
34 : ulong
35 0 : fd_rserve_footprint( ulong ping_cache_entries ) {
36 0 : if( FD_UNLIKELY( !ping_cache_entries ) ) return 0UL;
37 :
38 0 : ulong ping_max = fd_ulong_pow2_up( ping_cache_entries );
39 :
40 0 : ulong l = FD_LAYOUT_INIT;
41 0 : l = FD_LAYOUT_APPEND( l, alignof(fd_rserve_t), sizeof(fd_rserve_t) );
42 0 : l = FD_LAYOUT_APPEND( l, ping_pool_align(), ping_pool_footprint( ping_max ) );
43 0 : l = FD_LAYOUT_APPEND( l, ping_map_align(), ping_map_footprint( ping_map_chain_cnt_est( ping_max ) ) );
44 0 : l = FD_LAYOUT_APPEND( l, ping_dlist_align(), ping_dlist_footprint() );
45 0 : return FD_LAYOUT_FINI( l, fd_rserve_align() );
46 0 : }
47 :
48 : void *
49 : fd_rserve_new( void * shmem,
50 : ulong ping_cache_entries,
51 : ulong seed,
52 0 : uchar const secret[ 32 ] ) {
53 0 : if( FD_UNLIKELY( !shmem ) ) {
54 0 : FD_LOG_WARNING(( "NULL mem" ));
55 0 : return NULL;
56 0 : }
57 :
58 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shmem, fd_rserve_align() ) ) ) {
59 0 : FD_LOG_WARNING(( "misaligned mem" ));
60 0 : return NULL;
61 0 : }
62 :
63 0 : ulong footprint = fd_rserve_footprint( ping_cache_entries );
64 0 : if( FD_UNLIKELY( !footprint ) ) {
65 0 : FD_LOG_WARNING(( "bad ping cache size (%lu)", ping_cache_entries ));
66 0 : return NULL;
67 0 : }
68 :
69 0 : ulong ping_max = fd_ulong_pow2_up( ping_cache_entries );
70 :
71 0 : FD_SCRATCH_ALLOC_INIT( l, shmem );
72 0 : void * rserve_mem = FD_SCRATCH_ALLOC_APPEND( l, alignof(fd_rserve_t), sizeof(fd_rserve_t) );
73 0 : void * ping_pool_mem = FD_SCRATCH_ALLOC_APPEND( l, ping_pool_align(), ping_pool_footprint( ping_max ) );
74 0 : void * ping_map_mem = FD_SCRATCH_ALLOC_APPEND( l, ping_map_align(), ping_map_footprint( ping_map_chain_cnt_est( ping_max ) ) );
75 0 : void * ping_dlist_mem = FD_SCRATCH_ALLOC_APPEND( l, ping_dlist_align(), ping_dlist_footprint() );
76 :
77 0 : fd_rserve_t * rserve = (fd_rserve_t *)rserve_mem;
78 0 : ping_pool_new( ping_pool_mem, ping_max );
79 0 : rserve->ping_pool = fd_type_pun( ping_pool_mem );
80 0 : rserve->ping_map = ping_map_join ( ping_map_new ( ping_map_mem, ping_map_chain_cnt_est( ping_max ), seed ) );
81 0 : rserve->ping_dlist = ping_dlist_join( ping_dlist_new( ping_dlist_mem ) );
82 :
83 : /* Initialize rotating token secrets. */
84 0 : rserve->seed = seed;
85 0 : rserve->token_idx = 0UL;
86 0 : rserve->last_rotate_ts = 0UL;
87 0 : memcpy( rserve->secret_master, secret, 32UL );
88 0 : fd_rserve_rotation_secret( rserve->secret_cur, rserve->secret_master, 0UL );
89 0 : memcpy( rserve->secret_prev, rserve->secret_cur, 32UL );
90 :
91 0 : FD_TEST( FD_SCRATCH_ALLOC_FINI( l, fd_rserve_align() )==(ulong)shmem + footprint );
92 :
93 0 : return shmem;
94 0 : }
95 :
96 : fd_rserve_t *
97 0 : fd_rserve_join( void * shrserve ) {
98 0 : if( FD_UNLIKELY( !shrserve ) ) {
99 0 : FD_LOG_WARNING(( "NULL rserve" ));
100 0 : return NULL;
101 0 : }
102 :
103 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)shrserve, fd_rserve_align() ) ) ) {
104 0 : FD_LOG_WARNING(( "misaligned rserve" ));
105 0 : return NULL;
106 0 : }
107 :
108 0 : fd_rserve_t * rserve = (fd_rserve_t *)shrserve;
109 0 : rserve->ping_pool = ping_pool_join ( rserve->ping_pool );
110 0 : rserve->ping_map = ping_map_join ( rserve->ping_map );
111 0 : rserve->ping_dlist = ping_dlist_join( rserve->ping_dlist );
112 :
113 0 : return (fd_rserve_t *)rserve;
114 0 : }
115 :
116 : void *
117 0 : fd_rserve_leave( fd_rserve_t const * rserve ) {
118 0 : if( FD_UNLIKELY( !rserve ) ) {
119 0 : FD_LOG_WARNING(( "NULL rserve" ));
120 0 : return NULL;
121 0 : }
122 :
123 0 : return (void *)rserve;
124 0 : }
125 :
126 : void *
127 0 : fd_rserve_delete( void * rserve ) {
128 0 : if( FD_UNLIKELY( !rserve ) ) {
129 0 : FD_LOG_WARNING(( "NULL rserve" ));
130 0 : return NULL;
131 0 : }
132 :
133 0 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)rserve, fd_rserve_align() ) ) ) {
134 0 : FD_LOG_WARNING(( "misaligned rserve" ));
135 0 : return NULL;
136 0 : }
137 :
138 0 : return rserve;
139 0 : }
140 :
141 : void
142 : fd_rserve_ping_token( fd_rserve_t const * rserve,
143 : uchar token[ 32 ],
144 : fd_pubkey_t const * from,
145 : uint ip4,
146 0 : ushort port ) {
147 0 : fd_rserve_token_compute( token, rserve->secret_cur, from, ip4, port );
148 0 : }
149 :
150 : static int
151 : fd_rserve_secret_pong_verify( uchar const secret[ 32 ],
152 : uchar const * pong_hash,
153 : fd_pubkey_t const * from,
154 : uint ip4,
155 0 : ushort port ) {
156 0 : uchar token [ 32 ];
157 0 : uchar preimage[ FD_REPAIR_PONG_PREIMAGE_SZ ];
158 0 : uchar expected[ 32 ];
159 :
160 0 : fd_rserve_token_compute( token, secret, from, ip4, port );
161 0 : preimage_pong( (fd_hash_t const *)token, preimage );
162 0 : fd_sha256_hash( preimage, FD_REPAIR_PONG_PREIMAGE_SZ, expected );
163 0 : return !memcmp( expected, pong_hash, 32UL );
164 0 : }
165 :
166 : int
167 : fd_rserve_pong_token_verify( fd_rserve_t const * rserve,
168 : uchar const * pong_hash,
169 : fd_pubkey_t const * from,
170 : uint ip4,
171 0 : ushort port ) {
172 0 : if( FD_LIKELY( fd_rserve_secret_pong_verify( rserve->secret_cur, pong_hash, from, ip4, port ) ) ) return 1;
173 0 : if( FD_LIKELY( fd_rserve_secret_pong_verify( rserve->secret_prev, pong_hash, from, ip4, port ) ) ) return 1;
174 0 : return 0;
175 0 : }
176 :
177 : void
178 : fd_rserve_maybe_rotate( fd_rserve_t * rserve,
179 0 : ulong now_ns ) {
180 0 : if( FD_UNLIKELY( now_ns-rserve->last_rotate_ts > FD_RSERVE_TOKEN_ROTATE_NS ) ) {
181 0 : rserve->last_rotate_ts = now_ns;
182 0 : rserve->token_idx++;
183 0 : memcpy( rserve->secret_prev, rserve->secret_cur, 32UL );
184 0 : fd_rserve_rotation_secret( rserve->secret_cur, rserve->secret_master, rserve->token_idx );
185 0 : }
186 0 : }
187 :
|