LCOV - code coverage report
Current view: top level - waltz/quic - fd_quic_pcap_main.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 321 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 17 0.0 %

          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_, &params );
     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             : }

Generated by: LCOV version 1.14