LCOV - code coverage report
Current view: top level - app/shared_dev/commands/quic_trace - fd_quic_trace_rx_tile.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 270 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /* fd_quic_trace_rx_tile.c does passive decryption of incoming QUIC
       2             :    packets.
       3             : 
       4             :    It mocks the setup procedure and run loop of a real fd_quic_tile. */
       5             : 
       6             : #include "fd_quic_trace.h"
       7             : 
       8             : #include "../../../../waltz/quic/fd_quic_private.h"
       9             : #include "../../../../waltz/quic/templ/fd_quic_parse_util.h"
      10             : #include "../../../../waltz/quic/fd_quic_proto.c"
      11             : #include "../../../../util/net/fd_eth.h"
      12             : #include "../../../../util/net/fd_ip4.h"
      13             : #include "../../../../util/net/fd_udp.h"
      14             : 
      15             : static int
      16             : before_frag( void * _ctx FD_FN_UNUSED,
      17             :              ulong  in_idx,
      18             :              ulong  seq,
      19           0 :              ulong  sig ) {
      20             :   /* Skip non-QUIC packets */
      21           0 :   ulong proto = fd_disco_netmux_sig_proto( sig );
      22           0 :   if( proto!=DST_PROTO_TPU_QUIC ) return 1;
      23             : 
      24             :   /* Delay receive until fd_quic_tile is caught up */
      25           0 :   ulong * tgt_fseq = fd_quic_trace_target_fseq[ in_idx ];
      26           0 :   for(;;) {
      27           0 :     ulong tgt_seq = fd_fseq_query( tgt_fseq );
      28           0 :     if( FD_LIKELY( fd_seq_ge( tgt_seq, seq ) ) ) break;
      29           0 :     FD_SPIN_PAUSE();
      30           0 :   }
      31             : 
      32           0 :   return 0;
      33           0 : }
      34             : 
      35             : static void
      36             : during_frag( void * _ctx   FD_PARAM_UNUSED,
      37             :              ulong  in_idx FD_PARAM_UNUSED,
      38             :              ulong  seq    FD_PARAM_UNUSED,
      39             :              ulong  sig    FD_PARAM_UNUSED,
      40             :              ulong  chunk,
      41             :              ulong  sz,
      42           0 :              ulong  ctl ) {
      43           0 :   fd_quic_ctx_t * ctx = &fd_quic_trace_ctx;
      44           0 :   fd_memcpy( ctx->buffer, fd_net_rx_translate_frag( &ctx->net_in_bounds, chunk, ctl, sz ), sz );
      45           0 : }
      46             : 
      47             : static int
      48             : bounds_check_conn( fd_quic_t *      quic,
      49           0 :                    fd_quic_conn_t * conn ) {
      50           0 :   long conn_off = (long)((ulong)conn-(ulong)quic);
      51           0 :   return conn_off >= (long)quic->layout.conns_off && conn_off < (long)quic->layout.conn_map_off;
      52           0 : }
      53             : 
      54             : static void
      55             : fd_quic_trace_initial( fd_quic_trace_ctx_t * trace_ctx,
      56             :                        uchar *               data,
      57             :                        ulong                 data_sz,
      58             :                        uint                  ip4_saddr,
      59           0 :                        ushort                udp_sport ) {
      60           0 :   fd_quic_ctx_t *      ctx      = &fd_quic_trace_ctx;
      61           0 :   fd_quic_t *          quic     = ctx->quic;
      62           0 :   fd_quic_state_t *    state    = fd_quic_get_state( quic );
      63           0 :   fd_quic_conn_map_t * conn_map = translate_ptr( state->conn_map );
      64             : 
      65           0 :   if( FD_UNLIKELY( data_sz < FD_QUIC_SHORTEST_PKT ) ) return;
      66             : 
      67           0 :   fd_quic_initial_t initial[1] = {0};
      68           0 :   ulong rc = fd_quic_decode_initial( initial, data, data_sz );
      69           0 :   if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
      70           0 :     FD_LOG_DEBUG(( "fd_quic_decode_initial failed" ));
      71           0 :     return;
      72           0 :   }
      73           0 :   ulong len = (ulong)( initial->pkt_num_pnoff + initial->len );
      74           0 :   if( FD_UNLIKELY( len > data_sz ) ) {
      75           0 :     FD_LOG_DEBUG(( "Bogus initial packet length" ));
      76           0 :     return;
      77           0 :   }
      78           0 :   if( FD_UNLIKELY( initial->dst_conn_id_len > 20 ) ) {
      79           0 :     FD_LOG_DEBUG(( "Bogus destination connection id length: %u", (uint)initial->dst_conn_id_len ));
      80           0 :   }
      81             : 
      82           0 :   fd_quic_crypto_keys_t _keys[1];
      83           0 :   fd_quic_crypto_keys_t const * keys = NULL;
      84           0 :   if( initial->dst_conn_id_len == FD_QUIC_CONN_ID_SZ ) {
      85           0 :     ulong dst_conn_id = fd_ulong_load_8( initial->dst_conn_id );
      86           0 :     if( dst_conn_id==0 ) return;
      87           0 :     fd_quic_conn_map_t * conn_entry = fd_quic_conn_map_query( conn_map, dst_conn_id, NULL );
      88           0 :     if( conn_entry ) {
      89           0 :       fd_quic_conn_t * conn = translate_ptr( conn_entry->conn );
      90           0 :       if( FD_LIKELY( bounds_check_conn( quic, conn ) ) ) {
      91           0 :         keys = &conn->keys[fd_quic_enc_level_initial_id][0];
      92           0 :       }
      93           0 :     }
      94           0 :   }
      95           0 :   if( !keys ) {
      96             :     /* Set secrets->initial_secret */
      97           0 :     fd_quic_crypto_secrets_t secrets[1];
      98           0 :     fd_quic_gen_initial_secrets(
      99           0 :         secrets,
     100           0 :         initial->dst_conn_id, initial->dst_conn_id_len,
     101           0 :         /* is_client */ 0 );
     102             : 
     103             :     /* Derive secrets->secret[0][0] */
     104           0 :     fd_tls_hkdf_expand_label(
     105           0 :         secrets->secret[0][0], FD_QUIC_SECRET_SZ,
     106           0 :         secrets->initial_secret,
     107           0 :         FD_QUIC_CRYPTO_LABEL_CLIENT_IN,
     108           0 :         FD_QUIC_CRYPTO_LABEL_CLIENT_IN_LEN,
     109           0 :         NULL, 0UL );
     110             : 
     111             :     /* Derive decryption key */
     112           0 :     fd_quic_gen_keys( _keys, secrets->secret[0][0] );
     113           0 :     keys = _keys;
     114           0 :   }
     115             : 
     116           0 :   ulong pktnum_off = initial->pkt_num_pnoff;
     117           0 :   int hdr_err = fd_quic_crypto_decrypt_hdr( data, data_sz, pktnum_off, keys );
     118           0 :   if( hdr_err!=FD_QUIC_SUCCESS ) return;
     119             : 
     120           0 :   ulong pktnum_sz   = fd_quic_h0_pkt_num_len( data[0] )+1u;
     121           0 :   ulong pktnum_comp = fd_quic_pktnum_decode( data+pktnum_off, pktnum_sz );
     122           0 :   ulong pktnum      = pktnum_comp;  /* don't bother decompressing since initial pktnum is usually low */
     123             : 
     124           0 :   int crypt_err = fd_quic_crypto_decrypt( data, data_sz, pktnum_off, pktnum, keys );
     125           0 :   if( crypt_err!=FD_QUIC_SUCCESS ) return;
     126             : 
     127           0 :   ulong hdr_sz  = pktnum_off + pktnum_sz;
     128           0 :   ulong wrap_sz = hdr_sz + FD_QUIC_CRYPTO_TAG_SZ;
     129           0 :   if( FD_UNLIKELY( data_sz<wrap_sz ) ) return;
     130             : 
     131           0 :   uchar conn_id_truncated[24] = {0};
     132           0 :   fd_memcpy( conn_id_truncated, initial->dst_conn_id, initial->dst_conn_id_len );
     133           0 :   fd_quic_trace_frame_ctx_t frame_ctx = {
     134           0 :     .conn_id  = fd_ulong_load_8( conn_id_truncated ),
     135           0 :     .pkt_num  = pktnum,
     136           0 :     .src_ip   = ip4_saddr,
     137           0 :     .src_port = udp_sport,
     138           0 :     .pkt_type = FD_QUIC_PKT_TYPE_INITIAL
     139           0 :   };
     140             : 
     141           0 :   if( trace_ctx->dump ) {
     142           0 :     fd_quic_pretty_print_quic_pkt( &state->quic_pretty_print,
     143           0 :                                    state->now,
     144           0 :                                    data,
     145           0 :                                    data_sz,
     146           0 :                                    "ingress",
     147           0 :                                    ip4_saddr,
     148           0 :                                    udp_sport );
     149           0 :   } else {
     150           0 :     fd_quic_trace_frames( &frame_ctx, data+hdr_sz, data_sz-wrap_sz );
     151           0 :   }
     152           0 : }
     153             : 
     154             : static void
     155             : fd_quic_trace_handshake( fd_quic_trace_ctx_t * trace_ctx,
     156             :                          uchar *               data,
     157             :                          ulong                 data_sz,
     158             :                          uint                  ip4_saddr,
     159           0 :                          ushort                udp_sport ) {
     160           0 :   fd_quic_ctx_t *      ctx      = &fd_quic_trace_ctx;
     161           0 :   fd_quic_t *          quic     = ctx->quic;
     162           0 :   fd_quic_state_t *    state    = fd_quic_get_state( quic );
     163           0 :   fd_quic_conn_map_t * conn_map = translate_ptr( state->conn_map );
     164             : 
     165           0 :   if( FD_UNLIKELY( data_sz < FD_QUIC_SHORTEST_PKT ) ) return;
     166             : 
     167           0 :   fd_quic_handshake_t handshake[1] = {0};
     168           0 :   ulong rc = fd_quic_decode_handshake( handshake, data, data_sz );
     169           0 :   if( FD_UNLIKELY( rc == FD_QUIC_PARSE_FAIL ) ) {
     170           0 :     FD_LOG_DEBUG(( "fd_quic_decode_handshake failed" ));
     171           0 :     return;
     172           0 :   }
     173           0 :   ulong len = (ulong)( handshake->pkt_num_pnoff + handshake->len );
     174           0 :   if( FD_UNLIKELY( len > data_sz ) ) {
     175           0 :     FD_LOG_DEBUG(( "Bogus handshake packet length" ));
     176           0 :     return;
     177           0 :   }
     178             : 
     179             :   /* keeping this logic similar to the equivalent in fd_quic_trace_initial */
     180             :   /* for future merging */
     181           0 :   fd_quic_crypto_keys_t const * keys = NULL;
     182           0 :   if( handshake->dst_conn_id_len == FD_QUIC_CONN_ID_SZ ) {
     183           0 :     ulong dst_conn_id = fd_ulong_load_8( handshake->dst_conn_id );
     184           0 :     if( dst_conn_id==0 ) return;
     185           0 :     fd_quic_conn_map_t * conn_entry = fd_quic_conn_map_query( conn_map, dst_conn_id, NULL );
     186           0 :     if( conn_entry ) {
     187           0 :       fd_quic_conn_t * conn = translate_ptr( conn_entry->conn );
     188           0 :       if( FD_LIKELY( bounds_check_conn( quic, conn ) ) ) {
     189           0 :         keys = &conn->keys[fd_quic_enc_level_handshake_id][0];
     190           0 :       }
     191           0 :     }
     192           0 :   }
     193           0 :   if( !keys ) {
     194           0 :     return;
     195           0 :   }
     196             : 
     197           0 :   ulong pktnum_off = handshake->pkt_num_pnoff;
     198           0 :   int hdr_err = fd_quic_crypto_decrypt_hdr( data, data_sz, pktnum_off, keys );
     199           0 :   if( hdr_err!=FD_QUIC_SUCCESS ) return;
     200             : 
     201           0 :   ulong pktnum_sz   = fd_quic_h0_pkt_num_len( data[0] )+1u;
     202           0 :   ulong pktnum_comp = fd_quic_pktnum_decode( data+pktnum_off, pktnum_sz );
     203           0 :   ulong pktnum      = pktnum_comp; /* TODO decompress */
     204             : 
     205           0 :   int crypt_err = fd_quic_crypto_decrypt( data, data_sz, pktnum_off, pktnum, keys );
     206           0 :   if( crypt_err!=FD_QUIC_SUCCESS ) return;
     207             : 
     208           0 :   ulong hdr_sz  = pktnum_off + pktnum_sz;
     209           0 :   ulong wrap_sz = hdr_sz + FD_QUIC_CRYPTO_TAG_SZ;
     210           0 :   if( FD_UNLIKELY( data_sz<wrap_sz ) ) return;
     211             : 
     212           0 :   uchar conn_id_truncated[8] = {0};
     213           0 :   fd_memcpy( conn_id_truncated, handshake->dst_conn_id, 8 );
     214           0 :   fd_quic_trace_frame_ctx_t frame_ctx = {
     215           0 :     .conn_id  = fd_ulong_load_8( conn_id_truncated ),
     216           0 :     .pkt_num  = pktnum,
     217           0 :     .src_ip   = ip4_saddr,
     218           0 :     .src_port = udp_sport,
     219           0 :     .pkt_type = FD_QUIC_PKT_TYPE_INITIAL
     220           0 :   };
     221             : 
     222           0 :   if( trace_ctx->dump ) {
     223           0 :     fd_quic_pretty_print_quic_pkt( &state->quic_pretty_print,
     224           0 :                                    state->now,
     225           0 :                                    data,
     226           0 :                                    data_sz,
     227           0 :                                    "ingress",
     228           0 :                                    ip4_saddr,
     229           0 :                                    udp_sport );
     230           0 :   } else {
     231           0 :     fd_quic_trace_frames( &frame_ctx, data+hdr_sz, data_sz-wrap_sz );
     232           0 :   }
     233           0 : }
     234             : 
     235             : static void
     236             : fd_quic_trace_1rtt( fd_quic_trace_ctx_t * trace_ctx,
     237             :                     uchar *               data,
     238             :                     ulong                 data_sz,
     239             :                     uint                  ip4_saddr,
     240           0 :                     ushort                udp_sport ) {
     241           0 :   fd_quic_ctx_t *      ctx      = &fd_quic_trace_ctx;
     242           0 :   fd_quic_t *          quic     = ctx->quic;
     243           0 :   fd_quic_state_t *    state    = fd_quic_get_state( quic );
     244           0 :   fd_quic_conn_map_t * conn_map = translate_ptr( state->conn_map );
     245             : 
     246           0 :   if( FD_UNLIKELY( data_sz < FD_QUIC_SHORTEST_PKT ) ) return;
     247             : 
     248             :   /* Look up conn */
     249           0 :   ulong dst_conn_id = fd_ulong_load_8( data+1 );
     250           0 :   fd_quic_conn_map_t * conn_entry = fd_quic_conn_map_query( conn_map, dst_conn_id, NULL );
     251           0 :   if( !conn_entry || !dst_conn_id ) return;
     252           0 :   fd_quic_conn_t * conn = translate_ptr( conn_entry->conn );
     253           0 :   if( FD_UNLIKELY( !bounds_check_conn( quic, conn ) ) ) return;
     254             : 
     255           0 :   fd_quic_crypto_keys_t * keys = &conn->keys[ fd_quic_enc_level_appdata_id ][ 0 ];
     256             : 
     257           0 :   ulong pktnum_off = 9UL;
     258           0 :   int hdr_err = fd_quic_crypto_decrypt_hdr( data, data_sz, pktnum_off, keys );
     259           0 :   if( hdr_err!=FD_QUIC_SUCCESS ) return;
     260             : 
     261           0 :   ulong pktnum_sz   = fd_quic_h0_pkt_num_len( data[0] )+1u;
     262           0 :   ulong pktnum_comp = fd_quic_pktnum_decode( data+9UL, pktnum_sz );
     263           0 :   ulong pktnum      = fd_quic_reconstruct_pkt_num( pktnum_comp, pktnum_sz, conn->exp_pkt_number[2] );
     264           0 :   int crypt_err = fd_quic_crypto_decrypt( data, data_sz, pktnum_off, pktnum, keys );
     265           0 :   if( crypt_err!=FD_QUIC_SUCCESS ) return;
     266             : 
     267           0 :   ulong hdr_sz  = pktnum_off + pktnum_sz;
     268           0 :   ulong wrap_sz = hdr_sz + FD_QUIC_CRYPTO_TAG_SZ;
     269           0 :   if( FD_UNLIKELY( data_sz<wrap_sz ) ) return;
     270             : 
     271           0 :   fd_quic_trace_frame_ctx_t frame_ctx = {
     272           0 :     .conn_id  = dst_conn_id,
     273           0 :     .pkt_num  = pktnum,
     274           0 :     .src_ip   = ip4_saddr,
     275           0 :     .src_port = udp_sport,
     276           0 :     .pkt_type = FD_QUIC_PKT_TYPE_ONE_RTT
     277           0 :   };
     278             : 
     279           0 :   if( trace_ctx->dump ) {
     280           0 :     fd_quic_pretty_print_quic_pkt( &state->quic_pretty_print,
     281           0 :                                    state->now,
     282           0 :                                    data,
     283           0 :                                    data_sz,
     284           0 :                                    "ingress",
     285           0 :                                    ip4_saddr,
     286           0 :                                    udp_sport );
     287           0 :   } else {
     288           0 :     fd_quic_trace_frames( &frame_ctx, data+hdr_sz, data_sz-wrap_sz );
     289           0 :   }
     290             : 
     291           0 :   (void)ip4_saddr; (void)conn;
     292           0 : }
     293             : 
     294             : static void
     295             : fd_quic_trace_pkt( void *          ctx,
     296             :                    uchar *         data,
     297             :                    ulong           data_sz,
     298             :                    uint            ip4_saddr,
     299           0 :                    ushort          udp_sport ) {
     300             :   /* FIXME: for now, only handle 1-RTT */
     301           0 :   int is_long = fd_quic_h0_hdr_form( data[0] );
     302           0 :   if( is_long ) {
     303           0 :     switch( fd_quic_h0_long_packet_type( data[0] ) ) {
     304           0 :     case FD_QUIC_PKT_TYPE_INITIAL:
     305           0 :       fd_quic_trace_initial( ctx, data, data_sz, ip4_saddr, udp_sport );
     306           0 :       break;
     307           0 :     case FD_QUIC_PKT_TYPE_HANDSHAKE:
     308           0 :       fd_quic_trace_handshake( ctx, data, data_sz, ip4_saddr, udp_sport );
     309           0 :       break;
     310           0 :     }
     311             : 
     312             :     /* FD_QUIC_PKT_TYPE_RETRY    as the server, we shouldn't be receiving RETRY packets */
     313             :     /* FD_QUIC_PKT_TYPE_ZERO_RTT we don't support 0-RTT packets */
     314           0 :   } else {
     315           0 :     fd_quic_trace_1rtt( ctx, data, data_sz, ip4_saddr, udp_sport );
     316           0 :   }
     317           0 : }
     318             : 
     319             : static void
     320             : after_frag( void * _ctx,
     321             :             ulong  in_idx,
     322             :             ulong  seq,
     323             :             ulong  sig,
     324             :             ulong  sz,
     325             :             ulong  tsorig,
     326             :             ulong  tspub,
     327           0 :             fd_stem_context_t * stem ) {
     328           0 :   (void)in_idx; (void)seq; (void)sig; (void)tsorig; (void)tspub; (void)stem;
     329             : 
     330           0 :   fd_quic_ctx_t * ctx = &fd_quic_trace_ctx;
     331             : 
     332           0 :   if( sz < FD_QUIC_SHORTEST_PKT ) return;
     333           0 :   if( sz > sizeof(ctx->buffer)  ) return;
     334             : 
     335           0 :   uchar * cur  = ctx->buffer;
     336           0 :   uchar * end  = cur+sz;
     337             : 
     338           0 :   fd_eth_hdr_t const * eth_hdr = fd_type_pun_const( cur );
     339           0 :   cur += sizeof(fd_eth_hdr_t);
     340           0 :   if( FD_UNLIKELY( cur>end ) ) return;
     341           0 :   if( FD_UNLIKELY( fd_ushort_bswap( eth_hdr->net_type )!=FD_ETH_HDR_TYPE_IP ) ) return;
     342             : 
     343           0 :   fd_ip4_hdr_t const * ip4_hdr = fd_type_pun_const( cur );
     344           0 :   if( FD_UNLIKELY( cur+sizeof(fd_ip4_hdr_t) > end ) ) return;
     345           0 :   cur += FD_IP4_GET_LEN( *ip4_hdr );
     346           0 :   if( FD_UNLIKELY( cur>end ) ) return;
     347           0 :   if( FD_UNLIKELY( ip4_hdr->protocol!=FD_IP4_HDR_PROTOCOL_UDP ) ) return;
     348             : 
     349           0 :   fd_udp_hdr_t const * udp_hdr = fd_type_pun_const( cur );
     350           0 :   if( FD_UNLIKELY( cur+sizeof(fd_udp_hdr_t) > end ) ) return;
     351           0 :   cur += sizeof(fd_udp_hdr_t);
     352           0 :   if( FD_UNLIKELY( cur>end ) ) return;
     353           0 :   (void)udp_hdr;
     354             : 
     355           0 :   uint   ip4_saddr = fd_uint_load_4( ip4_hdr->saddr_c );
     356           0 :   ushort udp_sport = fd_ushort_bswap( udp_hdr->net_sport );
     357           0 :   fd_quic_trace_pkt( _ctx, cur, (ulong)( end-cur ), ip4_saddr, udp_sport );
     358           0 : }
     359             : 
     360             : 
     361             : #define STEM_BURST (1UL)
     362             : 
     363             : #define STEM_CALLBACK_CONTEXT_TYPE  fd_quic_trace_ctx_t
     364             : #define STEM_CALLBACK_CONTEXT_ALIGN 1
     365           0 : #define STEM_CALLBACK_BEFORE_FRAG   before_frag
     366           0 : #define STEM_CALLBACK_DURING_FRAG   during_frag
     367           0 : #define STEM_CALLBACK_AFTER_FRAG    after_frag
     368             : 
     369             : #include "../../../../disco/stem/fd_stem.c"
     370             : 
     371             : void
     372           0 : fd_quic_trace_rx_tile( fd_frag_meta_t const * in_mcache, int dump ) {
     373           0 :   fd_frag_meta_t const * in_mcache_tbl[1] = { in_mcache };
     374             : 
     375           0 :   uchar   fseq_mem[ FD_FSEQ_FOOTPRINT ] __attribute__((aligned(FD_FSEQ_ALIGN)));
     376           0 :   ulong * fseq = fd_fseq_join( fd_fseq_new( fseq_mem, 0UL ) );
     377           0 :   ulong * fseq_tbl[1] = { fseq };
     378             : 
     379           0 :   fd_rng_t rng[1];
     380           0 :   FD_TEST( fd_rng_join( fd_rng_new( rng, (uint)fd_tickcount(), 0UL ) ) );
     381             : 
     382           0 :   uchar scratch[ sizeof(fd_stem_tile_in_t)+128 ] __attribute__((aligned(FD_STEM_SCRATCH_ALIGN)));
     383             : 
     384           0 :   fd_quic_trace_ctx_t ctx[1] = {{ .dump = dump }};
     385             : 
     386           0 :   stem_run1( /* in_cnt     */ 1UL,
     387           0 :              /* in_mcache  */ in_mcache_tbl,
     388           0 :              /* in_fseq    */ fseq_tbl,
     389           0 :              /* out_cnt    */ 0UL,
     390             :              /* out_mcache */ NULL,
     391           0 :              /* cons_cnt   */ 0UL,
     392             :              /* cons_out   */ NULL,
     393             :              /* cons_fseq  */ NULL,
     394           0 :              /* stem_burst */ 1UL,
     395           0 :              /* stem_lazy  */ 0L,
     396           0 :              /* rng        */ rng,
     397           0 :              /* scratch    */ scratch,
     398           0 :              /* ctx        */ ctx );
     399             : 
     400           0 :   fd_fseq_delete( fd_fseq_leave( fseq ) );
     401           0 : }

Generated by: LCOV version 1.14