Line data Source code
1 : #include "fd_quic_sandbox.h"
2 : #include "../fd_quic_private.h"
3 :
4 : /* fd_quic_sandbox_capture_pkt captures a single outgoing packet sent by
5 : fd_quic. */
6 :
7 : static void
8 : fd_quic_sandbox_capture_pkt( fd_quic_sandbox_t * sandbox,
9 1206805 : fd_aio_pkt_info_t const * pkt ) {
10 :
11 1206805 : ulong seq = sandbox->pkt_seq_w;
12 1206805 : fd_frag_meta_t * mcache = sandbox->pkt_mcache;
13 1206805 : void * dcache = sandbox->pkt_dcache;
14 1206805 : ulong mtu = sandbox->pkt_mtu;
15 1206805 : ulong chunk = sandbox->pkt_chunk;
16 1206805 : ulong chunk0 = fd_dcache_compact_chunk0( sandbox, dcache );
17 1206805 : ulong wmark = fd_dcache_compact_wmark ( sandbox, dcache, mtu );
18 1206805 : ulong depth = fd_mcache_depth( mcache );
19 1206805 : ulong sz = pkt->buf_sz;
20 1206805 : uchar * data = fd_chunk_to_laddr( sandbox, chunk );
21 1206805 : ulong ctl = fd_frag_meta_ctl( /* orig */ 0, /* som */ 1, /* eom */ 1, /* err */ 0 );
22 1206805 : ulong ts = sandbox->wallclock;
23 :
24 1206805 : fd_memcpy( data, pkt->buf, sz );
25 1206805 : fd_mcache_publish( mcache, depth, seq, 0UL, chunk, sz, ctl, ts, ts );
26 :
27 1206805 : sandbox->pkt_seq_w = fd_seq_inc( seq, 1UL );
28 1206805 : sandbox->pkt_chunk = fd_dcache_compact_next( chunk, pkt->buf_sz, chunk0, wmark );
29 1206805 : }
30 :
31 : /* fd_quic_sandbox_aio_send implements fd_aio_send_func_t. Called by
32 : the sandbox fd_quic to capture response packets into the sandbox
33 : capture ring. */
34 :
35 : static int
36 : fd_quic_sandbox_aio_send( void * ctx,
37 : fd_aio_pkt_info_t const * batch,
38 : ulong batch_cnt,
39 : ulong * opt_batch_idx,
40 2413610 : int flush ) {
41 :
42 2413610 : fd_quic_sandbox_t * sandbox = (fd_quic_sandbox_t *)ctx;
43 :
44 3620415 : for( ulong j=0UL; j<batch_cnt; j++ ) {
45 1206805 : fd_quic_sandbox_capture_pkt( sandbox, batch + j );
46 1206805 : }
47 :
48 2413610 : ulong _batch_idx[1];
49 2413610 : opt_batch_idx = opt_batch_idx ? opt_batch_idx : _batch_idx;
50 2413610 : *opt_batch_idx = batch_cnt;
51 :
52 2413610 : (void)flush;
53 2413610 : return FD_AIO_SUCCESS;
54 2413610 : }
55 :
56 : fd_frag_meta_t const *
57 0 : fd_quic_sandbox_next_packet( fd_quic_sandbox_t * sandbox ) {
58 0 : fd_frag_meta_t * mcache = sandbox->pkt_mcache;
59 :
60 0 : ulong depth = fd_mcache_depth( mcache );
61 0 : ulong seq = sandbox->pkt_seq_r;
62 0 : ulong mline = fd_mcache_line_idx( seq, depth );
63 :
64 0 : fd_frag_meta_t * frag = mcache + mline;
65 0 : if( FD_UNLIKELY( fd_seq_lt( frag->seq, seq ) ) ) return NULL;
66 0 : if( FD_UNLIKELY( fd_seq_gt( frag->seq, seq ) ) ) {
67 : /* Occurs if the fd_quic published 'depth' packets in succession
68 : without any reads via this function. */
69 0 : FD_LOG_WARNING(( "overrun detected, some captured packets were lost" ));
70 0 : seq = frag->seq;
71 0 : }
72 :
73 0 : sandbox->pkt_seq_r = fd_seq_inc( seq, 1UL );
74 :
75 0 : return frag;
76 0 : }
77 :
78 : uchar const fd_quic_sandbox_self_ed25519_keypair[64] =
79 : { /* private key */
80 : 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
81 : 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
82 : 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
83 : 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
84 : /* public key */
85 : 0xdb, 0x99, 0x5f, 0xe2, 0x51, 0x69, 0xd1, 0x41,
86 : 0xca, 0xb9, 0xbb, 0xba, 0x92, 0xba, 0xa0, 0x1f,
87 : 0x9f, 0x2e, 0x1e, 0xce, 0x7d, 0xf4, 0xcb, 0x2a,
88 : 0xc0, 0x51, 0x90, 0xf3, 0x7f, 0xcc, 0x1f, 0x9d };
89 :
90 :
91 : uchar const fd_quic_sandbox_peer_ed25519_keypair[64] =
92 : { /* private key */
93 : 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
94 : 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
95 : 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
96 : 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42,
97 : /* public key */
98 : 0x21, 0x52, 0xf8, 0xd1, 0x9b, 0x79, 0x1d, 0x24,
99 : 0x45, 0x32, 0x42, 0xe1, 0x5f, 0x2e, 0xab, 0x6c,
100 : 0xb7, 0xcf, 0xfa, 0x7b, 0x6a, 0x5e, 0xd3, 0x00,
101 : 0x97, 0x96, 0x0e, 0x06, 0x98, 0x81, 0xdb, 0x12 };
102 :
103 : uchar const fd_quic_sandbox_aes128_key[16] =
104 : { 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43,
105 : 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43 };
106 :
107 : uchar const fd_quic_sandbox_aes128_iv[12] =
108 : { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 : 0x00, 0x00, 0x00, 0x00 };
110 :
111 : static ulong
112 0 : fd_quic_sandbox_now_cb( void * context ) {
113 0 : fd_quic_sandbox_t * sandbox = context;
114 0 : return sandbox->wallclock;
115 0 : }
116 :
117 : ulong
118 15 : fd_quic_sandbox_align( void ) {
119 15 : return fd_ulong_max( fd_ulong_max( fd_ulong_max( fd_ulong_max(
120 15 : alignof(fd_quic_sandbox_t),
121 15 : fd_quic_align() ),
122 15 : fd_mcache_align() ),
123 15 : fd_dcache_align() ),
124 15 : FD_CHUNK_ALIGN );
125 15 : }
126 :
127 : ulong
128 : fd_quic_sandbox_footprint( fd_quic_limits_t const * quic_limits,
129 : ulong pkt_cnt,
130 6 : ulong mtu ) {
131 :
132 6 : ulong root_align = fd_quic_sandbox_align();
133 6 : ulong quic_fp = fd_quic_footprint( quic_limits );
134 6 : ulong mcache_fp = fd_mcache_footprint( pkt_cnt, 0UL );
135 6 : ulong dcache_fp = fd_dcache_footprint( fd_dcache_req_data_sz( mtu, pkt_cnt, 1UL, 1 ), 0UL );
136 :
137 6 : if( FD_UNLIKELY( !quic_fp ) ) return 0UL;
138 6 : if( FD_UNLIKELY( !mcache_fp ) ) return 0UL;
139 6 : if( FD_UNLIKELY( !dcache_fp ) ) return 0UL;
140 :
141 6 : ulong l = FD_LAYOUT_INIT;
142 6 : l = FD_LAYOUT_APPEND( l, root_align, sizeof(fd_quic_sandbox_t) );
143 6 : l = FD_LAYOUT_APPEND( l, fd_quic_align(), quic_fp );
144 6 : l = FD_LAYOUT_APPEND( l, fd_mcache_align(), mcache_fp );
145 6 : l = FD_LAYOUT_APPEND( l, fd_dcache_align(), dcache_fp );
146 6 : return FD_LAYOUT_FINI( l, root_align );
147 6 : }
148 :
149 : void *
150 : fd_quic_sandbox_new( void * mem,
151 : fd_quic_limits_t const * quic_limits,
152 : ulong pkt_cnt,
153 3 : ulong mtu ) {
154 :
155 3 : if( FD_UNLIKELY( !mem ) ) {
156 0 : FD_LOG_WARNING(( "NULL mem" ));
157 0 : return NULL;
158 0 : }
159 :
160 3 : if( FD_UNLIKELY( !fd_ulong_is_aligned( (ulong)mem, fd_quic_sandbox_align() ) ) ) {
161 0 : FD_LOG_WARNING(( "misaligned mem" ));
162 0 : return NULL;
163 0 : }
164 :
165 3 : ulong fp = fd_quic_sandbox_footprint( quic_limits, pkt_cnt, mtu );
166 3 : if( FD_UNLIKELY( !fp ) ) {
167 0 : FD_LOG_WARNING(( "invalid params" ));
168 0 : return NULL;
169 0 : }
170 :
171 3 : ulong root_align = fd_quic_sandbox_align();
172 3 : ulong quic_fp = fd_quic_footprint( quic_limits );
173 3 : ulong mcache_fp = fd_mcache_footprint( pkt_cnt, 0UL );
174 3 : ulong dcache_data_sz = fd_dcache_req_data_sz( mtu, pkt_cnt, 1UL, 1 );
175 3 : ulong dcache_fp = fd_dcache_footprint( dcache_data_sz, 0UL );
176 :
177 3 : FD_SCRATCH_ALLOC_INIT( l, mem );
178 3 : fd_quic_sandbox_t * sandbox = FD_SCRATCH_ALLOC_APPEND( l, root_align, sizeof(fd_quic_sandbox_t) );
179 3 : void * quic_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_quic_align(), quic_fp );
180 3 : void * mcache_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_mcache_align(), mcache_fp );
181 3 : void * dcache_mem = FD_SCRATCH_ALLOC_APPEND( l, fd_dcache_align(), dcache_fp );
182 3 : FD_SCRATCH_ALLOC_FINI( l, root_align );
183 :
184 3 : ulong seq0 = 0UL; /* the first packet in the capture always has sequence number 0 */
185 :
186 3 : *sandbox = (fd_quic_sandbox_t) {
187 3 : .quic = fd_quic_join ( fd_quic_new( quic_mem, quic_limits ) ),
188 3 : .pkt_mcache = fd_mcache_join( fd_mcache_new( mcache_mem, pkt_cnt, 0UL, seq0 ) ),
189 3 : .pkt_dcache = fd_dcache_join( fd_dcache_new( dcache_mem, dcache_data_sz, 0UL ) ),
190 3 : .pkt_seq_r = seq0,
191 3 : .pkt_mtu = mtu
192 3 : };
193 :
194 3 : FD_COMPILER_MFENCE();
195 3 : sandbox->magic = FD_QUIC_SANDBOX_MAGIC;
196 3 : FD_COMPILER_MFENCE();
197 :
198 3 : return sandbox;
199 3 : }
200 :
201 : fd_quic_sandbox_t *
202 3 : fd_quic_sandbox_join( void * mem ) {
203 :
204 3 : if( FD_UNLIKELY( !mem ) ) {
205 0 : FD_LOG_WARNING(( "NULL mem" ));
206 0 : return NULL;
207 0 : }
208 :
209 3 : fd_quic_sandbox_t * sandbox = (fd_quic_sandbox_t *)mem;
210 3 : if( FD_UNLIKELY( sandbox->magic != FD_QUIC_SANDBOX_MAGIC ) ) {
211 0 : FD_LOG_WARNING(( "invalid magic" ));
212 0 : return NULL;
213 0 : }
214 :
215 3 : return sandbox;
216 3 : }
217 :
218 : fd_quic_sandbox_t *
219 : fd_quic_sandbox_init( fd_quic_sandbox_t * sandbox,
220 3 : int role ) {
221 :
222 3 : fd_quic_t * quic = sandbox->quic;
223 3 : fd_quic_config_t * quic_cfg = &quic->config;
224 :
225 3 : quic_cfg->role = role;
226 3 : quic_cfg->idle_timeout = FD_QUIC_SANDBOX_IDLE_TIMEOUT;
227 3 : quic_cfg->net.ip_addr = FD_QUIC_SANDBOX_SELF_IP4;
228 3 : quic_cfg->net.listen_udp_port = FD_QUIC_SANDBOX_SELF_PORT;
229 3 : quic_cfg->net.ephem_udp_port.lo = FD_QUIC_SANDBOX_SELF_PORT;
230 3 : quic_cfg->net.ephem_udp_port.hi = FD_QUIC_SANDBOX_SELF_PORT + 1;
231 3 : quic_cfg->initial_rx_max_stream_data = 512UL; /* arbitrary */
232 3 : memcpy( quic_cfg->identity_public_key, fd_quic_sandbox_self_ed25519_keypair + 32, 32 );
233 3 : memset( &quic->metrics, 0, sizeof(fd_quic_metrics_t) );
234 :
235 3 : fd_aio_t aio_tx = {
236 3 : .send_func = fd_quic_sandbox_aio_send,
237 3 : .ctx = sandbox
238 3 : };
239 3 : fd_quic_set_aio_net_tx( quic, &aio_tx );
240 :
241 3 : quic->cb.now_ctx = sandbox;
242 3 : quic->cb.now = fd_quic_sandbox_now_cb;
243 :
244 3 : if( FD_UNLIKELY( !fd_quic_init( quic ) ) ) {
245 0 : FD_LOG_WARNING(( "fd_quic_init failed" ));
246 0 : return NULL;
247 0 : }
248 :
249 3 : sandbox->wallclock = 0UL;
250 3 : sandbox->pkt_seq_r = 0UL;
251 3 : sandbox->pkt_seq_w = 0UL;
252 3 : sandbox->pkt_mcache[0].seq = ULONG_MAX; /* mark first entry as unpublished */
253 3 : sandbox->pkt_chunk = fd_dcache_compact_chunk0( sandbox, sandbox->pkt_dcache );
254 :
255 3 : return sandbox;
256 3 : }
257 :
258 : void *
259 3 : fd_quic_sandbox_leave( fd_quic_sandbox_t * sandbox ) {
260 3 : return (void *)sandbox;
261 3 : }
262 :
263 : void *
264 3 : fd_quic_sandbox_delete( void * mem ) {
265 :
266 3 : if( FD_UNLIKELY( !mem ) ) {
267 0 : FD_LOG_WARNING(( "NULL mem" ));
268 0 : return NULL;
269 0 : }
270 :
271 3 : fd_quic_sandbox_t * sandbox = (fd_quic_sandbox_t *)mem;
272 3 : if( FD_UNLIKELY( sandbox->magic != FD_QUIC_SANDBOX_MAGIC ) ) {
273 0 : FD_LOG_WARNING(( "invalid magic" ));
274 0 : return NULL;
275 0 : }
276 :
277 3 : FD_COMPILER_MFENCE();
278 3 : sandbox->magic = 0UL;
279 3 : FD_COMPILER_MFENCE();
280 :
281 3 : fd_quic_delete ( fd_quic_leave ( sandbox->quic ) );
282 3 : fd_mcache_delete( fd_mcache_leave( sandbox->pkt_mcache ) );
283 3 : fd_dcache_delete( fd_dcache_leave( sandbox->pkt_dcache ) );
284 :
285 3 : return mem;
286 3 : }
287 :
288 : fd_quic_conn_t *
289 : fd_quic_sandbox_new_conn_established( fd_quic_sandbox_t * sandbox,
290 300000 : fd_rng_t * rng ) {
291 :
292 300000 : fd_quic_t * quic = sandbox->quic;
293 :
294 : /* fd_quic_t conn IDs are always 8 bytes */
295 300000 : ulong our_conn_id_u64 = fd_rng_ulong( rng );
296 :
297 : /* the peer may choose a conn ID size 1 to 16 bytes
298 : For now, pick 8 bytes too */
299 300000 : ulong peer_conn_id_u64 = fd_rng_ulong( rng );
300 300000 : fd_quic_conn_id_t peer_conn_id = fd_quic_conn_id_new( &peer_conn_id_u64, 8UL );
301 :
302 300000 : fd_quic_conn_t * conn = fd_quic_conn_create(
303 300000 : /* quic */ quic,
304 300000 : /* our_conn_id */ our_conn_id_u64,
305 300000 : /* peer_conn_id */ &peer_conn_id,
306 : /* dst_ip_addr */ FD_QUIC_SANDBOX_PEER_IP4,
307 : /* dst_udp_addr */ FD_QUIC_SANDBOX_PEER_PORT,
308 300000 : /* server */ quic->config.role == FD_QUIC_ROLE_SERVER );
309 300000 : if( FD_UNLIKELY( !conn ) ) {
310 0 : FD_LOG_WARNING(( "fd_quic_conn_create failed" ));
311 0 : return NULL;
312 0 : }
313 :
314 300000 : conn->state = FD_QUIC_CONN_STATE_ACTIVE;
315 300000 : conn->established = 1;
316 :
317 : /* Mock a completed handshake */
318 300000 : conn->handshake_complete = 1;
319 300000 : conn->hs_data_empty = 1;
320 300000 : conn->peer_enc_level = fd_quic_enc_level_appdata_id;
321 :
322 300000 : conn->idle_timeout = FD_QUIC_SANDBOX_IDLE_TIMEOUT;
323 300000 : conn->last_activity = sandbox->wallclock;
324 :
325 : /* Reset flow control limits */
326 300000 : conn->tx_max_data = 0UL;
327 300000 : conn->tx_tot_data = 0UL;
328 300000 : conn->rx_max_data = 0UL;
329 300000 : conn->rx_tot_data = 0UL;
330 300000 : conn->rx_max_data_ackd = 0UL;
331 300000 : conn->tx_initial_max_stream_data_uni = 0UL;
332 :
333 : /* TODO set a realistic packet number */
334 :
335 300000 : return conn;
336 300000 : }
337 :
338 : void
339 : fd_quic_sandbox_send_frame( fd_quic_sandbox_t * sandbox,
340 : fd_quic_conn_t * conn,
341 : fd_quic_pkt_t * pkt_meta,
342 : uchar const * frame_ptr,
343 25161723 : ulong frame_sz ) {
344 :
345 : /* TODO consider crafting a real app packet instead of bypassing
346 : packet processing checks */
347 :
348 25161723 : fd_quic_t * quic = sandbox->quic;
349 :
350 : /* set pkt_type to FD_QUIC_PKT_TYPE_ONE_RTT as it allows all
351 : * frame types */
352 25161723 : uint pkt_type = FD_QUIC_PKT_TYPE_ONE_RTT;
353 :
354 25161723 : ulong rc = fd_quic_handle_v1_frame( quic, conn, pkt_meta, pkt_type, frame_ptr, frame_sz );
355 25161723 : if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return;
356 25161723 : if( FD_UNLIKELY( rc==0UL || rc>frame_sz ) ) {
357 0 : fd_quic_conn_error( conn, FD_QUIC_CONN_REASON_PROTOCOL_VIOLATION, __LINE__ );
358 0 : return;
359 0 : }
360 :
361 25161723 : }
362 :
363 : void
364 : fd_quic_sandbox_send_lone_frame( fd_quic_sandbox_t * sandbox,
365 : fd_quic_conn_t * conn,
366 : uchar const * frame,
367 25161723 : ulong frame_sz ) {
368 :
369 25161723 : FD_TEST( frame_sz <= sandbox->pkt_mtu );
370 :
371 25161723 : ulong pkt_num = conn->exp_pkt_number[2]++;
372 :
373 25161723 : ulong quic_pkt_sz = frame_sz; /* TODO mock some QUIC packetization overhead */
374 :
375 25161723 : fd_quic_pkt_t pkt_meta = {
376 25161723 : .ip4 = {{
377 25161723 : .verihl = FD_IP4_VERIHL(4,5),
378 25161723 : .net_tot_len = (ushort)( 20 + 8 + quic_pkt_sz ),
379 25161723 : .net_frag_off = 0x4000u, /* don't fragment */
380 25161723 : .ttl = 64,
381 25161723 : .protocol = FD_IP4_HDR_PROTOCOL_UDP,
382 25161723 : }},
383 25161723 : .udp = {{
384 25161723 : .net_sport = FD_QUIC_SANDBOX_PEER_PORT,
385 25161723 : .net_dport = FD_QUIC_SANDBOX_SELF_PORT,
386 25161723 : .net_len = (ushort)( 8 + quic_pkt_sz ),
387 25161723 : }},
388 25161723 : .pkt_number = pkt_num,
389 25161723 : .rcv_time = sandbox->wallclock,
390 25161723 : .enc_level = fd_quic_enc_level_appdata_id,
391 25161723 : };
392 :
393 25161723 : fd_quic_sandbox_send_frame( sandbox, conn, &pkt_meta, frame, frame_sz );
394 :
395 25161723 : fd_quic_lazy_ack_pkt( sandbox->quic, conn, &pkt_meta );
396 :
397 25161723 : }
|