Line data Source code
1 : #define _GNU_SOURCE /* memmem */
2 : #include <errno.h>
3 : #include <stdio.h> /* fputs, fprintf */
4 : #include <stdlib.h> /* aligned_alloc */
5 : #include <unistd.h> /* pread */
6 :
7 : #include "fd_quic.h"
8 : #include "../../ballet/hex/fd_hex.h"
9 : #include "../../waltz/quic/fd_quic_proto.h"
10 : #include "../../waltz/quic/fd_quic_proto.c"
11 : #include "../../waltz/quic/templ/fd_quic_parse_util.h"
12 : #include "../../util/net/fd_pcap.h"
13 : #include "../../util/net/fd_pcapng.h"
14 : #include "../../util/net/fd_pcapng_private.h" /* FIXME */
15 : #include "../../util/net/fd_ip4.h"
16 : #include "../../util/net/fd_udp.h"
17 :
18 : #define MAX_KEYS_DEFAULT 1024
19 :
20 : static void
21 0 : usage_short( void ) {
22 0 : fputs( "Usage: fd_quic_pcap [COMMAND] [FLAGS] {FILE.PCAPNG}\n", stderr );
23 0 : }
24 :
25 : static void
26 0 : usage( void ) {
27 0 : usage_short();
28 : /* FIXME uncomment when tool is ready
29 : fprintf( stderr,
30 : "\n"
31 : "Tool to analyze Solana network QUIC traffic captures.\n"
32 : "\n"
33 : "Supported file formats: tcpdump pcap (little endian) and pcap-ng\n"
34 : "Supported pcap-ng blocks: SPB, EPB, DSB (inline TLS keys)\n"
35 : "Supported cipher suites: TLS_AES_128_GCM_SHA256\n"
36 : "Supported link layers: Ethernet, Linux SLL\n"
37 : "Assumes that conn IDs are 8 bytes long.\n"
38 : "\n"
39 : "Commands:\n"
40 : " tpu-stat Print Solana TPU traffic statistics\n"
41 : " tpu-peer-stat Print Solana TPU traffic per-peer statistics\n"
42 : " tpu-trace Trace Solana TPU traffic metadata to CSV format\n"
43 : "\n"
44 : "Optional flags:\n"
45 : // TODO " --key-file Path to TLS key log txt file (SSKEYLOGFILE format)\n"
46 : " --key-max Max concurrent TLS key count (default " FD_STRINGIFY( MAX_KEYS_DEFAULT ) ")\n"
47 : "\n" );
48 : */
49 0 : }
50 :
51 : static void
52 0 : usage_invalid( void ) {
53 0 : fputs( "Invalid arguments!\n", stderr );
54 0 : usage_short();
55 0 : }
56 :
57 : static void
58 : reject_unknown_flags( int * pargc,
59 0 : char *** pargv ) {
60 0 : int expect_flag = 1;
61 0 : int new_argc = 0;
62 0 : int arg;
63 0 : for( arg=0; arg<(*pargc); arg++ ) {
64 0 : if( !expect_flag || 0!=strncmp( (*pargv)[arg], "--", 2 ) ) {
65 0 : (*pargv)[new_argc++] = (*pargv)[arg];
66 0 : } else if( (++arg)<(*pargc) ) {
67 0 : if( (*pargv)[arg][2] == '0' ) {
68 0 : expect_flag = 0;
69 0 : } else {
70 0 : FD_LOG_ERR(( "Unsupported flag: %s", (*pargv)[arg] ));
71 0 : }
72 0 : }
73 0 : }
74 0 : }
75 :
76 : /* Helper for maps with 32 byte keys */
77 :
78 : union key32 {
79 : uchar key[32];
80 : ulong ul[4];
81 : };
82 : typedef union key32 key32_t;
83 :
84 : static ulong map_seed;
85 0 : __attribute__((constructor)) static void random_seeds( void ) {
86 0 : if( FD_UNLIKELY( !fd_rng_secure( &map_seed, sizeof(map_seed) ) ) ) {
87 0 : FD_LOG_WARNING(( "fd_rng_secure failed" ));
88 0 : }
89 0 : }
90 :
91 : /* Declare a map resolving Client Random => encryption keys */
92 :
93 : struct key_map {
94 : key32_t client_random;
95 : /* FIXME support a ring buffer of multiple keys */
96 : uchar server_app_secret[32];
97 : uchar client_app_secret[32];
98 : };
99 :
100 : typedef struct key_map key_map_t;
101 :
102 : #define MAP_NAME key_map
103 0 : #define MAP_T key_map_t
104 0 : #define MAP_HASH_T ulong
105 0 : #define MAP_KEY client_random
106 0 : #define MAP_KEY_T key32_t
107 0 : #define MAP_KEY_NULL ((key32_t){.ul={0,0,0,0}})
108 0 : #define MAP_KEY_EQUAL(k0,k1) (0==memcmp((k0).key,(k1).key,32))
109 : #define MAP_KEY_EQUAL_IS_SLOW 0
110 0 : #define MAP_KEY_HASH(key) fd_hash( map_seed, key.key, 32 )
111 0 : #define MAP_KEY_INVAL(k) ((0==k.ul[0]) & (0==k.ul[1]) & (0==k.ul[2]) & (0==k.ul[3]))
112 : #define MAP_MEMOIZE 0
113 : #include "../../util/tmpl/fd_map_dynamic.c"
114 :
115 : /* Declare a map resolving conn ID => Client Random */
116 :
117 : struct conn_map {
118 : ulong conn_id;
119 : uchar client_random[32];
120 : };
121 :
122 : typedef struct conn_map conn_map_t;
123 :
124 : #define MAP_NAME conn_map
125 0 : #define MAP_T conn_map_t
126 0 : #define MAP_KEY conn_id
127 : #define MAP_MEMOIZE 0
128 : #include "../../util/tmpl/fd_map_dynamic.c"
129 :
130 :
131 : struct quic_pcap_params {
132 : char const * pcap_path;
133 : ulong key_max;
134 : };
135 :
136 : typedef struct quic_pcap_params quic_pcap_params_t;
137 :
138 : struct quic_pcap_iter {
139 : FILE * pcap_file;
140 : conn_map_t * conn_map;
141 : key_map_t * key_map;
142 : ulong key_max;
143 : ulong key_cnt;
144 : ulong key_ignore_cnt;
145 : };
146 :
147 : typedef struct quic_pcap_iter quic_pcap_iter_t;
148 :
149 : static quic_pcap_iter_t *
150 : quic_pcap_iter_new( quic_pcap_iter_t * iter,
151 0 : quic_pcap_params_t const * params ) {
152 0 : int lg_slot_cnt = fd_ulong_find_msb_w_default( fd_ulong_pow2_up( params->key_max*4 ), 0 );
153 :
154 0 : void * key_map_mem = aligned_alloc( key_map_align(), key_map_footprint( lg_slot_cnt ) );
155 0 : key_map_t * key_map = key_map_join( key_map_new( key_map_mem, lg_slot_cnt ) );
156 0 : if( FD_UNLIKELY( !key_map ) ) FD_LOG_ERR(( "key_map alloc failed" ));
157 :
158 0 : void * conn_map_mem = aligned_alloc( conn_map_align(), conn_map_footprint( lg_slot_cnt ) );
159 0 : conn_map_t * conn_map = conn_map_join( conn_map_new( conn_map_mem, lg_slot_cnt ) );
160 0 : if( FD_UNLIKELY( !conn_map ) ) FD_LOG_ERR(( "conn_map alloc failed" ));
161 :
162 0 : FILE * pcap_file = fopen( params->pcap_path, "rb" );
163 0 : if( FD_UNLIKELY( !pcap_file ) ) {
164 0 : FD_LOG_ERR(( "fopen(%s) failed (%d-%s)", params->pcap_path, errno, fd_io_strerror( errno ) ));
165 0 : }
166 :
167 0 : *iter = (quic_pcap_iter_t) {
168 0 : .pcap_file = pcap_file,
169 0 : .conn_map = conn_map,
170 0 : .key_map = key_map,
171 0 : .key_max = params->key_max
172 0 : };
173 0 : return iter;
174 0 : }
175 :
176 : static void
177 : quic_pcap_iter_add_one_key( quic_pcap_iter_t * iter,
178 : char const * str,
179 0 : ulong str_sz ) {
180 :
181 : /* Silently ignore tiny lines, those are probably just whitespace */
182 0 : if( str_sz<6 ) return;
183 :
184 : /* Copy into mutable buffer */
185 0 : char line[ 512 ];
186 0 : if( FD_UNLIKELY( str_sz>=sizeof(line) ) ) {
187 0 : FD_LOG_WARNING(( "Ignoring oversz TLS key log line" ));
188 0 : FD_LOG_HEXDUMP_DEBUG(( "Oversz TLS key log line", str, str_sz ));
189 0 : return;
190 0 : }
191 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( line ), str, str_sz ) );
192 :
193 : /* Tokenize */
194 0 : char * tokens[3];
195 0 : ulong tok_cnt = fd_cstr_tokenize( tokens, 3, line, ' ' );
196 0 : if( FD_UNLIKELY( tok_cnt!=3 ) ) {
197 0 : FD_LOG_WARNING(( "Ignoring malformed TLS key log line" ));
198 0 : FD_LOG_HEXDUMP_DEBUG(( "Malformed TLS key log line", str, str_sz ));
199 0 : return;
200 0 : }
201 :
202 : /* Parse client random */
203 0 : if( FD_UNLIKELY( strlen( tokens[1] )!=64UL ) ) {
204 0 : FD_LOG_WARNING(( "Ignoring odd sized client random in TLS key log" ));
205 0 : return;
206 0 : }
207 0 : key32_t client_random;
208 0 : if( FD_UNLIKELY( fd_hex_decode( client_random.key, tokens[1], 32UL )!=32UL ) ) {
209 0 : FD_LOG_WARNING(( "Ignoring malformed client random in TLS key log" ));
210 0 : return;
211 0 : }
212 :
213 : /* Parse encryption key */
214 0 : if( FD_UNLIKELY( strlen( tokens[2] )!=64UL ) ) {
215 0 : FD_LOG_WARNING(( "Ignoring odd sized encryption key in TLS key log" ));
216 0 : return;
217 0 : }
218 0 : uchar encryption_key[32];
219 0 : if( FD_UNLIKELY( fd_hex_decode( encryption_key, tokens[2], 32UL )!=32UL ) ) {
220 0 : FD_LOG_WARNING(( "Ignoring malformed encryption key in TLS key log" ));
221 0 : return;
222 0 : }
223 :
224 : /* Upsert record */
225 0 : key_map_t * record = key_map_query( iter->key_map, client_random, NULL );
226 0 : if( !record ) {
227 0 : if( FD_UNLIKELY( key_map_key_cnt( iter->key_map ) >= iter->key_max ) ) {
228 0 : iter->key_ignore_cnt++;
229 0 : static int warned = 0;
230 0 : if( !warned ) {
231 0 : FD_LOG_WARNING(( "Reached TLS key limit (%lu), ignoring new connections", iter->key_max ));
232 0 : warned = 1;
233 0 : }
234 0 : return;
235 0 : }
236 0 : record = key_map_insert( iter->key_map, client_random );
237 0 : *record = (key_map_t) { .client_random = client_random };
238 0 : }
239 :
240 : /* Extract decryption key
241 : For now, ignore handshake keys */
242 0 : if( strncmp( tokens[0], "CLIENT_TRAFFIC_SECRET_", 22UL ) ||
243 0 : strncmp( tokens[0], "SERVER_TRAFFIC_SECRET_", 22UL ) ) {
244 :
245 0 : int is_client = ( tokens[0][0] == 'C' );
246 0 : ulong key_idx = fd_cstr_to_ulong( tokens[0] + 22UL );
247 0 : if( key_idx!=0 ) {
248 0 : iter->key_ignore_cnt++;
249 0 : FD_LOG_DEBUG(( "Ignoring key rotation" ));
250 0 : return;
251 0 : }
252 :
253 0 : uchar * dst = ( is_client ? record->client_app_secret : record->server_app_secret );
254 0 : memcpy( dst, encryption_key, 32 );
255 0 : iter->key_cnt++;
256 :
257 0 : } else {
258 0 : iter->key_ignore_cnt++;
259 0 : }
260 :
261 0 : }
262 :
263 : static void
264 : quic_pcap_iter_add_keys( quic_pcap_iter_t * iter,
265 : char const * str,
266 0 : ulong str_sz ) {
267 0 : while( str_sz ) {
268 0 : char const * crlf = memmem( str, str_sz, "\r\n", 2UL );
269 0 : char const * lf = memchr( str, '\n', str_sz );
270 0 : char const * eol = ( crlf ? crlf+2 : ( lf ? lf+1 : str+str_sz ) );
271 0 : quic_pcap_iter_add_one_key( iter, str, str_sz );
272 0 : str_sz -= (ulong)( eol - str );
273 0 : }
274 0 : }
275 :
276 : static void
277 : quic_pcap_iter_deliver_initial(
278 : quic_pcap_iter_t * iter,
279 : uint ip4_saddr,
280 : uchar * data,
281 : ulong data_sz,
282 : ulong * out_pkt_sz
283 0 : ) {
284 0 : (void)iter;
285 0 : (void)ip4_saddr;
286 0 : (void)out_pkt_sz;
287 :
288 0 : fd_quic_initial_t initial[1];
289 0 : ulong rc = fd_quic_decode_initial( initial, data, data_sz );
290 0 : if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return;
291 0 : ulong pnoff = initial->pkt_num_pnoff;
292 0 : ulong tot_sz = pnoff + initial->len;
293 0 : if( FD_UNLIKELY( tot_sz>data_sz ) ) return;
294 0 : *out_pkt_sz = tot_sz;
295 0 : data_sz = tot_sz;
296 :
297 0 : fd_quic_crypto_secrets_t secrets[1];
298 0 : fd_quic_gen_initial_secret( secrets, initial->dst_conn_id, initial->dst_conn_id_len );
299 0 : fd_quic_gen_secrets( secrets, fd_quic_enc_level_initial_id );
300 :
301 0 : fd_quic_crypto_keys_t keys[1];
302 0 : fd_quic_gen_keys( keys, secrets->secret[ fd_quic_enc_level_initial_id ][ 0 ] );
303 :
304 : /* Undo initial packet protection */
305 : /* FIXME does this support QUIC retries? */
306 :
307 0 : if( FD_UNLIKELY(
308 0 : fd_quic_crypto_decrypt_hdr( data, tot_sz, pnoff, keys )
309 0 : != FD_QUIC_SUCCESS ) ) {
310 0 : FD_LOG_WARNING(( "Failed to decrypt initial" ));
311 0 : return;
312 0 : }
313 :
314 0 : uint pkt_number_sz = fd_quic_h0_pkt_num_len( data[0] ) + 1u;
315 0 : ulong pkt_number = fd_quic_pktnum_decode( data+pnoff, pkt_number_sz );
316 :
317 0 : if( FD_UNLIKELY(
318 0 : fd_quic_crypto_decrypt( data, tot_sz, pnoff, pkt_number, keys )
319 0 : != FD_QUIC_SUCCESS ) ) {
320 0 : FD_LOG_WARNING(( "Failed to decrypt initial" ));
321 0 : return;
322 0 : }
323 :
324 : /* Expect first frame to be a CRYPTO frame */
325 :
326 0 : data += (rc+pkt_number_sz);
327 0 : data_sz -= (rc+pkt_number_sz);
328 0 : if( FD_UNLIKELY( data_sz<1 ) ) return;
329 0 : if( data[0]!=0x06 ) return;
330 :
331 0 : fd_quic_crypto_frame_t crypto[1];
332 0 : rc = fd_quic_decode_crypto_frame( crypto, data, data_sz );
333 0 : if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return;
334 0 : data += rc;
335 0 : data_sz -= rc;
336 0 : ulong left = fd_ulong_min( crypto->length, data_sz );
337 :
338 : /* Expect first TLS message to be a ClientHello */
339 :
340 0 : if( FD_UNLIKELY( left < 6+32 ) ) return;
341 0 : if( data[0] != 0x01 ) return; /* ClientHello */
342 0 : uchar const * client_random = data + 6;
343 0 : FD_LOG_HEXDUMP_WARNING(( "ClientRandom", client_random, 32 ));
344 :
345 0 : }
346 :
347 : static void
348 : quic_pcap_iter_deliver_handshake(
349 : quic_pcap_iter_t * iter,
350 : uint ip4_saddr,
351 : uchar const * const data,
352 : ulong data_sz,
353 : ulong * out_pkt_sz
354 0 : ) {
355 0 : (void)iter;
356 0 : (void)ip4_saddr;
357 0 : (void)data;
358 0 : (void)data_sz;
359 0 : (void)out_pkt_sz;
360 0 : }
361 :
362 : static void
363 : quic_pcap_iter_deliver_1rtt(
364 : quic_pcap_iter_t * iter,
365 : uint ip4_saddr,
366 : uchar const * const data,
367 : ulong data_sz
368 0 : ) {
369 0 : (void)iter;
370 0 : (void)ip4_saddr;
371 0 : (void)data;
372 0 : (void)data_sz;
373 0 : }
374 :
375 : static void
376 : quic_pcap_iter_deliver_datagram(
377 : quic_pcap_iter_t * iter,
378 : uint ip4_saddr,
379 : uchar * data,
380 : ulong data_sz
381 0 : ) {
382 :
383 : //FD_LOG_HEXDUMP_NOTICE(( "datagram", data, data_sz ));
384 0 : while( data_sz ) {
385 :
386 0 : int is_long = fd_quic_h0_hdr_form( data[0] );
387 0 : if( is_long ) {
388 :
389 0 : int pkt_type = fd_quic_h0_long_packet_type( data[0] );
390 0 : ulong out_pkt_sz = data_sz;
391 0 : switch( pkt_type ) {
392 0 : case FD_QUIC_PKT_TYPE_INITIAL:
393 0 : quic_pcap_iter_deliver_initial( iter, ip4_saddr, data, data_sz, &out_pkt_sz );
394 0 : break;
395 0 : case FD_QUIC_PKT_TYPE_HANDSHAKE:
396 0 : quic_pcap_iter_deliver_handshake( iter, ip4_saddr, data, data_sz, &out_pkt_sz );
397 0 : break;
398 0 : }
399 0 : data += out_pkt_sz;
400 0 : data_sz -= out_pkt_sz;
401 :
402 0 : } else {
403 :
404 0 : quic_pcap_iter_deliver_1rtt( iter, ip4_saddr, data, data_sz );
405 0 : data_sz = 0UL;
406 0 : break;
407 :
408 0 : }
409 :
410 0 : }
411 :
412 0 : (void)iter;
413 0 : (void)ip4_saddr;
414 0 : }
415 :
416 : static void
417 : quic_pcap_iter_deliver_ethernet( quic_pcap_iter_t * iter,
418 : uchar * const data,
419 0 : ulong const data_sz ) {
420 0 : uchar * cur = data;
421 0 : uchar * end = data+data_sz;
422 :
423 0 : fd_eth_hdr_t const * eth_hdr = fd_type_pun_const( data );
424 0 : cur += sizeof(fd_eth_hdr_t);
425 0 : if( FD_UNLIKELY( cur>end ) ) return;
426 0 : if( FD_UNLIKELY( fd_ushort_bswap( eth_hdr->net_type )!=FD_ETH_HDR_TYPE_IP ) ) return;
427 :
428 0 : fd_ip4_hdr_t const * ip4_hdr = fd_type_pun_const( cur );
429 0 : if( FD_UNLIKELY( cur+sizeof(fd_ip4_hdr_t) > end ) ) return;
430 0 : cur += FD_IP4_GET_LEN( *ip4_hdr );
431 0 : if( FD_UNLIKELY( cur>end ) ) return;
432 0 : if( FD_UNLIKELY( ip4_hdr->protocol!=FD_IP4_HDR_PROTOCOL_UDP ) ) return;
433 :
434 0 : fd_udp_hdr_t const * udp_hdr = fd_type_pun_const( cur );
435 0 : if( FD_UNLIKELY( cur+sizeof(fd_udp_hdr_t) > end ) ) return;
436 0 : cur += sizeof(fd_udp_hdr_t);
437 0 : if( FD_UNLIKELY( cur>end ) ) return;
438 0 : (void)udp_hdr;
439 :
440 0 : uint ip4_saddr = fd_uint_load_4( ip4_hdr->saddr_c );
441 0 : quic_pcap_iter_deliver_datagram( iter, ip4_saddr, cur, (ulong)( end-cur ) );
442 0 : }
443 :
444 : struct fd_sll_hdr {
445 : ushort packet_type;
446 : ushort arphrd_type;
447 : ushort ll_addr_sz;
448 : uchar ll_addr[8];
449 : ushort protocol_type;
450 : };
451 :
452 : typedef struct fd_sll_hdr fd_sll_hdr_t;
453 :
454 : static void
455 : quic_pcap_iter_deliver_cooked( quic_pcap_iter_t * iter,
456 : uchar const * const data,
457 0 : ulong const data_sz ) {
458 0 : (void)iter; (void)data; (void)data_sz;
459 0 : FD_LOG_ERR(( "Linux SLL captures not yet supported" ));
460 0 : }
461 :
462 : static void
463 0 : quic_pcap_iter_run_pcap( quic_pcap_iter_t * iter ) {
464 :
465 0 : fd_pcap_iter_t * pcap = fd_pcap_iter_new( iter->pcap_file );
466 0 : if( FD_UNLIKELY( !pcap ) ) FD_LOG_ERR(( "Failed to read pcap" ));
467 :
468 0 : ulong pcap_iter_type = fd_pcap_iter_type( pcap );
469 0 : int is_cooked;
470 0 : switch( pcap_iter_type ) {
471 0 : case FD_PCAP_ITER_TYPE_ETHERNET: is_cooked = 0; break;
472 0 : case FD_PCAP_ITER_TYPE_COOKED: is_cooked = 1; break;
473 0 : default:
474 0 : FD_LOG_ERR(( "Unsupported pcap link type (%lu)", pcap_iter_type ));
475 0 : }
476 :
477 0 : for(;;) {
478 0 : uchar pkt[ 8192 ];
479 0 : long ts;
480 0 : ulong sz = fd_pcap_iter_next( pcap, pkt, sizeof(pkt), &ts );
481 0 : if( FD_UNLIKELY( !sz ) ) break;
482 0 : if( is_cooked ) {
483 0 : quic_pcap_iter_deliver_ethernet( iter, pkt, sz );
484 0 : } else {
485 0 : quic_pcap_iter_deliver_cooked( iter, pkt, sz );
486 0 : }
487 0 : }
488 :
489 0 : (void)fd_pcap_iter_delete( pcap );
490 :
491 0 : }
492 :
493 : static void
494 0 : quic_pcap_iter_run_pcapng( quic_pcap_iter_t * iter ) {
495 :
496 0 : void * pcap_iter_mem = aligned_alloc( fd_pcapng_iter_align(), fd_pcapng_iter_footprint() );
497 0 : fd_pcapng_iter_t * pcap = NULL;
498 :
499 0 : while( !feof( iter->pcap_file ) ) {
500 :
501 0 : if( !pcap ) {
502 0 : pcap = fd_pcapng_iter_new( pcap_iter_mem, iter->pcap_file );
503 0 : if( FD_UNLIKELY( !pcap ) ) FD_LOG_ERR(( "fd_pcapng_iter_new failed" ));
504 0 : }
505 :
506 0 : fd_pcapng_frame_t * frame = fd_pcapng_iter_next( pcap );
507 0 : if( FD_UNLIKELY( !frame ) ) {
508 0 : int err = fd_pcapng_iter_err( pcap );
509 0 : if( FD_LIKELY( err==-1 ) ) {
510 0 : (void)fd_pcapng_iter_delete( pcap );
511 0 : pcap = NULL;
512 0 : continue;
513 0 : }
514 0 : FD_LOG_ERR(( "Failed to read pcapng (%d-%s)", err, fd_io_strerror( err ) ));
515 0 : }
516 :
517 0 : if( frame->type==FD_PCAPNG_FRAME_TLSKEYS ) {
518 0 : quic_pcap_iter_add_keys( iter, (char const *)frame->data, frame->data_sz );
519 0 : continue;
520 0 : }
521 0 : if( frame->type!=FD_PCAPNG_FRAME_SIMPLE && frame->type!=FD_PCAPNG_FRAME_ENHANCED ) {
522 0 : continue;
523 0 : }
524 :
525 0 : uint link_type = pcap->iface[ frame->if_idx ].link_type;
526 0 : switch( link_type ) {
527 0 : case FD_PCAPNG_LINKTYPE_ETHERNET:
528 0 : quic_pcap_iter_deliver_ethernet( iter, (void *)frame->data, frame->data_sz );
529 0 : break;
530 0 : case FD_PCAPNG_LINKTYPE_COOKED:
531 0 : quic_pcap_iter_deliver_cooked( iter, frame->data, frame->data_sz );
532 0 : break;
533 0 : default:
534 0 : FD_LOG_NOTICE(( "Unsupported link type %#x", link_type ));
535 0 : }
536 :
537 0 : }
538 :
539 0 : }
540 :
541 : static void
542 0 : quic_pcap_iter_run( quic_pcap_iter_t * iter ) {
543 :
544 0 : uint magic;
545 0 : if( FD_UNLIKELY( pread( fileno( iter->pcap_file ), &magic, sizeof(uint), 0 )!=sizeof(uint) ) ) {
546 0 : FD_LOG_ERR(( "Failed to detect pcap version (%d-%s)", errno, fd_io_strerror( errno ) ));
547 0 : }
548 :
549 0 : switch( magic ) {
550 0 : case 0xa1b2c3d4U:
551 0 : case 0xa1b23c4dU:
552 0 : quic_pcap_iter_run_pcap( iter );
553 0 : break;
554 0 : case 0x0a0d0d0aU:
555 0 : quic_pcap_iter_run_pcapng( iter );
556 0 : break;
557 0 : default:
558 0 : FD_LOG_ERR(( "Unsupported packet capture file format" ));
559 0 : }
560 :
561 0 : }
562 :
563 : int
564 : main( int argc,
565 : char ** argv ) {
566 :
567 : for( int i=1; i<argc; i++ ) {
568 : if( 0==strcmp( argv[i], "--help" ) ) {
569 : usage();
570 : return 0;
571 : }
572 : }
573 :
574 : setenv( "FD_LOG_PATH", "", 1 ); /* suppress logs for tools */
575 : fd_boot( &argc, &argv );
576 :
577 : //char const * key_file = fd_env_strip_cmdline_cstr ( &argc, &argv, "--key-file", NULL, NULL );
578 : ulong key_max = fd_env_strip_cmdline_ulong( &argc, &argv, "--key-max", NULL, MAX_KEYS_DEFAULT );
579 : reject_unknown_flags( &argc, &argv );
580 :
581 : argc--; argv++;
582 : if( FD_UNLIKELY( argc!=2 ) ) {
583 : usage_invalid();
584 : return 1;
585 : }
586 :
587 : char const * command = argv[0];
588 : char const * pcap_path = argv[1];
589 :
590 : quic_pcap_params_t params = {
591 : .pcap_path = pcap_path,
592 : .key_max = key_max
593 : };
594 : quic_pcap_iter_t iter_[1];
595 : quic_pcap_iter_t * iter = quic_pcap_iter_new( iter_, ¶ms );
596 : if( FD_UNLIKELY( !iter ) ) {
597 : FD_LOG_ERR(( "Failed to initialize. Aborting" ));
598 : }
599 :
600 : (void)command;
601 :
602 : quic_pcap_iter_run( iter );
603 :
604 : /* Don't bother to close files on application exit */
605 : fd_halt();
606 : return 0;
607 : }
|