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

Generated by: LCOV version 1.14