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

Generated by: LCOV version 1.14