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 <string.h> /* memcmp */
6 : #include <unistd.h> /* pread */
7 :
8 : #include "fd_quic.h"
9 : #include "../../ballet/hex/fd_hex.h"
10 : #include "../../waltz/quic/fd_quic_proto.h"
11 : #include "../../waltz/quic/fd_quic_proto.c"
12 : #include "../../waltz/quic/templ/fd_quic_parse_util.h"
13 : #include "../../util/net/fd_pcap.h"
14 : #include "../../util/net/fd_pcapng.h"
15 : #include "../../util/net/fd_pcapng_private.h" /* FIXME */
16 : #include "../../util/net/fd_ip4.h"
17 : #include "../../util/net/fd_udp.h"
18 :
19 : #define MAX_KEYS_DEFAULT 1024
20 :
21 : static void
22 0 : usage_short( void ) {
23 0 : fputs( "Usage: fd_quic_pcap [COMMAND] [FLAGS] {FILE.PCAPNG}\n", stderr );
24 0 : }
25 :
26 : static void
27 0 : usage( void ) {
28 0 : usage_short();
29 : /* FIXME uncomment when tool is ready
30 : fprintf( stderr,
31 : "\n"
32 : "Tool to analyze Solana network QUIC traffic captures.\n"
33 : "\n"
34 : "Supported file formats: tcpdump pcap (little endian) and pcap-ng\n"
35 : "Supported pcap-ng blocks: SPB, EPB, DSB (inline TLS keys)\n"
36 : "Supported cipher suites: TLS_AES_128_GCM_SHA256\n"
37 : "Supported link layers: Ethernet, Linux SLL\n"
38 : "Assumes that conn IDs are 8 bytes long.\n"
39 : "\n"
40 : "Commands:\n"
41 : " tpu-stat Print Solana TPU traffic statistics\n"
42 : " tpu-peer-stat Print Solana TPU traffic per-peer statistics\n"
43 : " tpu-trace Trace Solana TPU traffic metadata to CSV format\n"
44 : "\n"
45 : "Optional flags:\n"
46 : // TODO " --key-file Path to TLS key log txt file (SSKEYLOGFILE format)\n"
47 : " --key-max Max concurrent TLS key count (default " FD_STRINGIFY( MAX_KEYS_DEFAULT ) ")\n"
48 : "\n" );
49 : */
50 0 : }
51 :
52 : static void
53 0 : usage_invalid( void ) {
54 0 : fputs( "Invalid arguments!\n", stderr );
55 0 : usage_short();
56 0 : }
57 :
58 : static void
59 : reject_unknown_flags( int * pargc,
60 0 : char *** pargv ) {
61 0 : int expect_flag = 1;
62 0 : int new_argc = 0;
63 0 : int arg;
64 0 : for( arg=0; arg<(*pargc); arg++ ) {
65 0 : if( !expect_flag || 0!=strncmp( (*pargv)[arg], "--", 2 ) ) {
66 0 : (*pargv)[new_argc++] = (*pargv)[arg];
67 0 : } else if( (++arg)<(*pargc) ) {
68 0 : if( (*pargv)[arg][2] == '0' ) {
69 0 : expect_flag = 0;
70 0 : } else {
71 0 : FD_LOG_ERR(( "Unsupported flag: %s", (*pargv)[arg] ));
72 0 : }
73 0 : }
74 0 : }
75 0 : }
76 :
77 : /* Helper for maps with 32 byte keys */
78 :
79 : union key32 {
80 : uchar key[32];
81 : ulong ul[4];
82 : };
83 : typedef union key32 key32_t;
84 :
85 : static ulong map_seed;
86 0 : __attribute__((constructor)) static void random_seeds( void ) {
87 0 : if( FD_UNLIKELY( !fd_rng_secure( &map_seed, sizeof(map_seed) ) ) ) {
88 0 : FD_LOG_WARNING(( "fd_rng_secure failed" ));
89 0 : }
90 0 : }
91 :
92 : /* Declare a map resolving Client Random => encryption keys */
93 :
94 : struct key_map {
95 : key32_t client_random;
96 : /* FIXME support a ring buffer of multiple keys */
97 : uchar server_app_secret[32];
98 : uchar client_app_secret[32];
99 : };
100 :
101 : typedef struct key_map key_map_t;
102 :
103 : #define MAP_NAME key_map
104 0 : #define MAP_T key_map_t
105 0 : #define MAP_HASH_T ulong
106 0 : #define MAP_KEY client_random
107 0 : #define MAP_KEY_T key32_t
108 0 : #define MAP_KEY_NULL ((key32_t){.ul={0,0,0,0}})
109 0 : #define MAP_KEY_EQUAL(k0,k1) (0==memcmp((k0).key,(k1).key,32))
110 : #define MAP_KEY_EQUAL_IS_SLOW 0
111 0 : #define MAP_KEY_HASH(key) fd_hash( map_seed, key.key, 32 )
112 0 : #define MAP_KEY_INVAL(k) ((0==k.ul[0]) & (0==k.ul[1]) & (0==k.ul[2]) & (0==k.ul[3]))
113 : #define MAP_MEMOIZE 0
114 : #include "../../util/tmpl/fd_map_dynamic.c"
115 :
116 : /* Declare a map resolving conn ID => Client Random */
117 :
118 : struct conn_map {
119 : ulong conn_id;
120 : uchar client_random[32];
121 : };
122 :
123 : typedef struct conn_map conn_map_t;
124 :
125 : #define MAP_NAME conn_map
126 0 : #define MAP_T conn_map_t
127 0 : #define MAP_KEY conn_id
128 : #define MAP_MEMOIZE 0
129 : #include "../../util/tmpl/fd_map_dynamic.c"
130 :
131 :
132 : struct quic_pcap_params {
133 : char const * pcap_path;
134 : ulong key_max;
135 : };
136 :
137 : typedef struct quic_pcap_params quic_pcap_params_t;
138 :
139 : struct quic_pcap_iter {
140 : FILE * pcap_file;
141 : conn_map_t * conn_map;
142 : key_map_t * key_map;
143 : ulong key_max;
144 : ulong key_cnt;
145 : ulong key_ignore_cnt;
146 : };
147 :
148 : typedef struct quic_pcap_iter quic_pcap_iter_t;
149 :
150 : static quic_pcap_iter_t *
151 : quic_pcap_iter_new( quic_pcap_iter_t * iter,
152 0 : quic_pcap_params_t const * params ) {
153 0 : int lg_slot_cnt = fd_ulong_find_msb_w_default( fd_ulong_pow2_up( params->key_max*4 ), 0 );
154 :
155 0 : void * key_map_mem = aligned_alloc( key_map_align(), key_map_footprint( lg_slot_cnt ) );
156 0 : key_map_t * key_map = key_map_join( key_map_new( key_map_mem, lg_slot_cnt ) );
157 0 : if( FD_UNLIKELY( !key_map ) ) FD_LOG_ERR(( "key_map alloc failed" ));
158 :
159 0 : void * conn_map_mem = aligned_alloc( conn_map_align(), conn_map_footprint( lg_slot_cnt ) );
160 0 : conn_map_t * conn_map = conn_map_join( conn_map_new( conn_map_mem, lg_slot_cnt ) );
161 0 : if( FD_UNLIKELY( !conn_map ) ) FD_LOG_ERR(( "conn_map alloc failed" ));
162 :
163 0 : FILE * pcap_file = fopen( params->pcap_path, "rb" );
164 0 : if( FD_UNLIKELY( !pcap_file ) ) {
165 0 : FD_LOG_ERR(( "fopen(%s) failed (%d-%s)", params->pcap_path, errno, fd_io_strerror( errno ) ));
166 0 : }
167 :
168 0 : *iter = (quic_pcap_iter_t) {
169 0 : .pcap_file = pcap_file,
170 0 : .conn_map = conn_map,
171 0 : .key_map = key_map,
172 0 : .key_max = params->key_max
173 0 : };
174 0 : return iter;
175 0 : }
176 :
177 : static void
178 : quic_pcap_iter_add_one_key( quic_pcap_iter_t * iter,
179 : char const * str,
180 0 : ulong str_sz ) {
181 :
182 : /* Silently ignore tiny lines, those are probably just whitespace */
183 0 : if( str_sz<6 ) return;
184 :
185 : /* Copy into mutable buffer */
186 0 : char line[ 512 ];
187 0 : if( FD_UNLIKELY( str_sz>=sizeof(line) ) ) {
188 0 : FD_LOG_WARNING(( "Ignoring oversz TLS key log line" ));
189 0 : FD_LOG_HEXDUMP_DEBUG(( "Oversz TLS key log line", str, str_sz ));
190 0 : return;
191 0 : }
192 0 : fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( line ), str, str_sz ) );
193 :
194 : /* Tokenize */
195 0 : char * tokens[3];
196 0 : ulong tok_cnt = fd_cstr_tokenize( tokens, 3, line, ' ' );
197 0 : if( FD_UNLIKELY( tok_cnt!=3 ) ) {
198 0 : FD_LOG_WARNING(( "Ignoring malformed TLS key log line" ));
199 0 : FD_LOG_HEXDUMP_DEBUG(( "Malformed TLS key log line", str, str_sz ));
200 0 : return;
201 0 : }
202 :
203 : /* Parse client random */
204 0 : if( FD_UNLIKELY( strlen( tokens[1] )!=64UL ) ) {
205 0 : FD_LOG_WARNING(( "Ignoring odd sized client random in TLS key log" ));
206 0 : return;
207 0 : }
208 0 : key32_t client_random;
209 0 : if( FD_UNLIKELY( fd_hex_decode( client_random.key, tokens[1], 32UL )!=32UL ) ) {
210 0 : FD_LOG_WARNING(( "Ignoring malformed client random in TLS key log" ));
211 0 : return;
212 0 : }
213 :
214 : /* Parse encryption key */
215 0 : if( FD_UNLIKELY( strlen( tokens[2] )!=64UL ) ) {
216 0 : FD_LOG_WARNING(( "Ignoring odd sized encryption key in TLS key log" ));
217 0 : return;
218 0 : }
219 0 : uchar encryption_key[32];
220 0 : if( FD_UNLIKELY( fd_hex_decode( encryption_key, tokens[2], 32UL )!=32UL ) ) {
221 0 : FD_LOG_WARNING(( "Ignoring malformed encryption key in TLS key log" ));
222 0 : return;
223 0 : }
224 :
225 : /* Upsert record */
226 0 : key_map_t * record = key_map_query( iter->key_map, client_random, NULL );
227 0 : if( !record ) {
228 0 : if( FD_UNLIKELY( key_map_key_cnt( iter->key_map ) >= iter->key_max ) ) {
229 0 : iter->key_ignore_cnt++;
230 0 : static int warned = 0;
231 0 : if( !warned ) {
232 0 : FD_LOG_WARNING(( "Reached TLS key limit (%lu), ignoring new connections", iter->key_max ));
233 0 : warned = 1;
234 0 : }
235 0 : return;
236 0 : }
237 0 : record = key_map_insert( iter->key_map, client_random );
238 0 : *record = (key_map_t) { .client_random = client_random };
239 0 : }
240 :
241 : /* Extract decryption key
242 : For now, ignore handshake keys */
243 0 : if( strncmp( tokens[0], "CLIENT_TRAFFIC_SECRET_", 22UL ) ||
244 0 : strncmp( tokens[0], "SERVER_TRAFFIC_SECRET_", 22UL ) ) {
245 :
246 0 : int is_client = ( tokens[0][0] == 'C' );
247 0 : ulong key_idx = fd_cstr_to_ulong( tokens[0] + 22UL );
248 0 : if( key_idx!=0 ) {
249 0 : iter->key_ignore_cnt++;
250 0 : FD_LOG_DEBUG(( "Ignoring key rotation" ));
251 0 : return;
252 0 : }
253 :
254 0 : uchar * dst = ( is_client ? record->client_app_secret : record->server_app_secret );
255 0 : memcpy( dst, encryption_key, 32 );
256 0 : iter->key_cnt++;
257 :
258 0 : } else {
259 0 : iter->key_ignore_cnt++;
260 0 : }
261 :
262 0 : }
263 :
264 : static void
265 : quic_pcap_iter_add_keys( quic_pcap_iter_t * iter,
266 : char const * str,
267 0 : ulong str_sz ) {
268 0 : while( str_sz ) {
269 0 : char const * crlf = memmem( str, str_sz, "\r\n", 2UL );
270 0 : char const * lf = memchr( str, '\n', str_sz );
271 0 : char const * eol = ( crlf ? crlf+2 : ( lf ? lf+1 : str+str_sz ) );
272 0 : quic_pcap_iter_add_one_key( iter, str, str_sz );
273 0 : str_sz -= (ulong)( eol - str );
274 0 : }
275 0 : }
276 :
277 : static void
278 : quic_pcap_iter_deliver_initial(
279 : quic_pcap_iter_t * iter,
280 : uint ip4_saddr,
281 : uchar * data,
282 : ulong data_sz,
283 : ulong * out_pkt_sz
284 0 : ) {
285 0 : (void)iter;
286 0 : (void)ip4_saddr;
287 0 : (void)out_pkt_sz;
288 :
289 0 : fd_quic_initial_t initial[1];
290 0 : ulong rc = fd_quic_decode_initial( initial, data, data_sz );
291 0 : if( FD_UNLIKELY( rc==FD_QUIC_PARSE_FAIL ) ) return;
292 0 : ulong pnoff = initial->pkt_num_pnoff;
293 0 : ulong tot_sz = pnoff + initial->len;
294 0 : if( FD_UNLIKELY( tot_sz>data_sz ) ) return;
295 0 : *out_pkt_sz = tot_sz;
296 0 : data_sz = tot_sz;
297 :
298 0 : fd_quic_crypto_secrets_t secrets[1];
299 0 : fd_quic_gen_initial_secrets( secrets, initial->dst_conn_id, initial->dst_conn_id_len, /* is_server */ 1 );
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 : }
|