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