LCOV - code coverage report
Current view: top level - waltz/quic/tests - fuzz_quic_wire.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 129 271 47.6 %
Date: 2024-11-13 11:58:15 Functions: 5 14 35.7 %

          Line data    Source code
       1             : /* fuzz_quic_wire is a simple and stateless fuzz target for fd_quic.
       2             : 
       3             :    The attack surface consists of fd_quic's packet handlers.
       4             :    The input vectors are the raw contents of UDP datagrams (in encrypted
       5             :    form)  A custom mutator is used to temporarily remove the decryption
       6             :    before calling the generic libFuzzer mutator.  If we tried mutating
       7             :    the encrypted inputs directly, everything would just be an encryption
       8             :    failure.
       9             : 
      10             :    The goal of fuzz_quic_wire is to cover the early upstream stages of
      11             :    the QUIC packet processing pipeline.  This includes packet header
      12             :    parsing, connection creation, retry handling, etc. */
      13             : 
      14             : #include "../../../util/sanitize/fd_fuzz.h"
      15             : #include "fd_quic_test_helpers.h"
      16             : #include "../crypto/fd_quic_crypto_suites.h"
      17             : #include "../templ/fd_quic_parse_util.h"
      18             : #include "../../tls/test_tls_helper.h"
      19             : #include "../../../util/net/fd_eth.h"
      20             : #include "../../../util/net/fd_ip4.h"
      21             : #include "../../../util/net/fd_udp.h"
      22             : #include "../fd_quic_proto.h"
      23             : #include "../fd_quic_proto.c"
      24             : #include "../fd_quic_private.h"
      25             : 
      26             : #include <assert.h>
      27             : 
      28             : static void
      29             : my_stream_new_cb( fd_quic_stream_t * stream,
      30           0 :                   void *             quic_ctx ) {
      31           0 :   (void)stream; (void)quic_ctx;
      32           0 : }
      33             : 
      34             : static void
      35             : my_stream_notify_cb( fd_quic_stream_t * stream,
      36             :                      void *             stream_ctx,
      37           0 :                      int                notify_type ) {
      38           0 :   (void)stream; (void)stream_ctx; (void)notify_type;
      39           0 : }
      40             : 
      41             : static void
      42             : my_stream_receive_cb( fd_quic_stream_t * stream,
      43             :                       void *             ctx,
      44             :                       uchar const *      data,
      45             :                       ulong              data_sz,
      46             :                       ulong              offset,
      47           0 :                       int                fin ) {
      48           0 :   (void)ctx; (void)stream; (void)data; (void)data_sz; (void)offset; (void)fin;
      49           0 : }
      50             : 
      51             : static FD_TL ulong g_clock;
      52             : 
      53             : static ulong
      54        4284 : test_clock( void * context FD_FN_UNUSED ) {
      55        4284 :   return g_clock;
      56        4284 : }
      57             : 
      58             : int
      59             : LLVMFuzzerInitialize( int *    pargc,
      60          18 :                       char *** pargv ) {
      61          18 :   putenv( "FD_LOG_BACKTRACE=0" );
      62          18 :   fd_boot( pargc, pargv );
      63          18 :   atexit( fd_halt );
      64          18 :   fd_log_level_logfile_set(0);
      65          18 :   fd_log_level_stderr_set(0);
      66          18 :   return 0;
      67          18 : }
      68             : 
      69             : static int
      70             : _aio_send( void *                    ctx,
      71             :            fd_aio_pkt_info_t const * batch,
      72             :            ulong                     batch_cnt,
      73             :            ulong *                   opt_batch_idx,
      74        1071 :            int                       flush ) {
      75        1071 :   (void)flush;
      76        1071 :   (void)batch;
      77        1071 :   (void)batch_cnt;
      78        1071 :   (void)opt_batch_idx;
      79        1071 :   (void)ctx;
      80        1071 :   return 0;
      81        1071 : }
      82             : 
      83             : static void
      84             : send_udp_packet( fd_quic_t *   quic,
      85             :                  uchar const * data,
      86        2088 :                  ulong         size ) {
      87             : 
      88        2088 :   uchar buf[16384];
      89             : 
      90        2088 :   ulong headers_sz = sizeof(fd_eth_hdr_t) + sizeof(fd_ip4_hdr_t) + sizeof(fd_udp_hdr_t);
      91             : 
      92        2088 :   uchar * cur = buf;
      93        2088 :   uchar * end = buf + sizeof(buf);
      94             : 
      95        2088 :   fd_eth_hdr_t eth = { .net_type = FD_ETH_HDR_TYPE_IP };
      96        2088 :   fd_ip4_hdr_t ip4 = {
      97        2088 :     .verihl      = FD_IP4_VERIHL(4,5),
      98        2088 :     .protocol    = FD_IP4_HDR_PROTOCOL_UDP,
      99        2088 :     .net_tot_len = (ushort)( sizeof(fd_ip4_hdr_t)+sizeof(fd_udp_hdr_t)+size ),
     100        2088 :   };
     101        2088 :   fd_udp_hdr_t udp = {
     102        2088 :     .net_sport = 8000,
     103        2088 :     .net_dport = 8001,
     104        2088 :     .net_len   = (ushort)( sizeof(fd_udp_hdr_t)+size ),
     105        2088 :     .check     = 0
     106        2088 :   };
     107             : 
     108             :   /* Guaranteed to not overflow */
     109        2088 :   fd_quic_encode_eth( cur, (ulong)( end-cur ), &eth ); cur += sizeof(fd_eth_hdr_t);
     110        2088 :   fd_quic_encode_ip4( cur, (ulong)( end-cur ), &ip4 ); cur += sizeof(fd_ip4_hdr_t);
     111        2088 :   fd_quic_encode_udp( cur, (ulong)( end-cur ), &udp ); cur += sizeof(fd_udp_hdr_t);
     112             : 
     113        2088 :   if( cur + size > end ) return;
     114        2088 :   fd_memcpy( cur, data, size );
     115             : 
     116             :   /* Main fuzz entrypoint */
     117             : 
     118        2088 :   fd_quic_process_packet( quic, buf, headers_sz + size );
     119        2088 : }
     120             : 
     121             : int
     122             : LLVMFuzzerTestOneInput( uchar const * data,
     123        2088 :                         ulong         size ) {
     124             : 
     125        2088 :   fd_rng_t _rng[1]; fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, 0U, 0UL ) );
     126             : 
     127             :   /* Memory region to hold the QUIC instance */
     128        2088 :   static uchar quic_mem[ 1<<23 ] __attribute__((aligned(FD_QUIC_ALIGN)));
     129             : 
     130             :   /* Create ultra low limits for QUIC instance for maximum performance */
     131        2088 :   fd_quic_limits_t const quic_limits = {
     132        2088 :     .conn_cnt         = 2,
     133        2088 :     .handshake_cnt    = 2,
     134        2088 :     .conn_id_cnt      = 4,
     135        2088 :     .rx_stream_cnt    = 1,
     136        2088 :     .inflight_pkt_cnt = 8UL,
     137        2088 :     .stream_pool_cnt  = 8UL
     138        2088 :   };
     139             : 
     140             :   /* Enable features depending on the last few bits.  The last bits are
     141             :      pseudorandom (either ignored or belong to the MAC tag) */
     142        2088 :   uint last_byte = 0U;
     143        2088 :   if( size > 0 ) last_byte = data[ size-1 ];
     144        2088 :   int enable_retry = !!(last_byte & 1);
     145        2088 :   int role         =   (last_byte & 2) ? FD_QUIC_ROLE_SERVER : FD_QUIC_ROLE_CLIENT;
     146        2088 :   int established  = !!(last_byte & 4);
     147             : 
     148        2088 :   assert( fd_quic_footprint( &quic_limits ) <= sizeof(quic_mem) );
     149        2088 :   void *      shquic = fd_quic_new( quic_mem, &quic_limits );
     150        2088 :   fd_quic_t * quic   = fd_quic_join( shquic );
     151             : 
     152        2088 :   fd_quic_config_anonymous( quic, role );
     153             : 
     154        2088 :   fd_tls_test_sign_ctx_t test_signer = fd_tls_test_sign_ctx( rng );
     155        2088 :   fd_quic_config_test_signer( quic, &test_signer );
     156             : 
     157        2088 :   quic->cb.stream_new = my_stream_new_cb;
     158        2088 :   quic->cb.stream_notify = my_stream_notify_cb;
     159        2088 :   quic->cb.stream_receive = my_stream_receive_cb;
     160        2088 :   quic->cb.now = test_clock;
     161        2088 :   quic->config.retry = enable_retry;
     162             : 
     163        2088 :   fd_aio_t aio_[1];
     164        2088 :   fd_aio_t * aio = fd_aio_join( fd_aio_new( aio_, NULL, _aio_send ) );
     165        2088 :   assert( aio );
     166             : 
     167        2088 :   fd_quic_set_aio_net_tx( quic, aio );
     168        2088 :   assert( fd_quic_init( quic ) );
     169        2088 :   assert( quic->config.idle_timeout > 0 );
     170             : 
     171        2088 :   fd_quic_state_t * state = fd_quic_get_state( quic );
     172             : 
     173             :   /* Create dummy connection */
     174        2088 :   ulong             our_conn_id  = 0UL;
     175        2088 :   fd_quic_conn_id_t peer_conn_id = { .sz=8 };
     176        2088 :   uint              dst_ip_addr  = 0U;
     177        2088 :   ushort            dst_udp_port = (ushort)0;
     178             : 
     179        2088 :   fd_quic_conn_t * conn =
     180        2088 :     fd_quic_conn_create( quic,
     181        2088 :                          our_conn_id, &peer_conn_id,
     182        2088 :                          dst_ip_addr,  (ushort)dst_udp_port,
     183        2088 :                          1  /* we are the server */ );
     184        2088 :   assert( conn );
     185        2088 :   assert( conn->svc_type == FD_QUIC_SVC_WAIT );
     186             : 
     187        2088 :   conn->tx_max_data                            =       512UL;
     188        2088 :   conn->tx_initial_max_stream_data_uni         =        64UL;
     189        2088 :   conn->rx_max_data                            =       512UL;
     190        2088 :   conn->rx_sup_stream_id                       =        32UL;
     191        2088 :   conn->tx_max_datagram_sz                     = FD_QUIC_MTU;
     192        2088 :   conn->tx_sup_stream_id                       =        32UL;
     193             : 
     194        2088 :   if( established ) {
     195         861 :     conn->state = FD_QUIC_CONN_STATE_ACTIVE;
     196         861 :     conn->keys_avail = 0xff;
     197         861 :   }
     198             : 
     199        2088 :   g_clock = 1000UL;
     200             : 
     201             :   /* Calls fuzz entrypoint */
     202        2088 :   send_udp_packet( quic, data, size );
     203             : 
     204             :   /* svc_quota is the max number of service calls that we expect to
     205             :      schedule in response to a single packet. */
     206        2088 :   long svc_quota = fd_long_max( (long)size, 1000L );
     207             : 
     208        3090 :   while( state->svc_queue[ FD_QUIC_SVC_INSTANT ].tail!=UINT_MAX ) {
     209        1002 :     fd_quic_service( quic );
     210        1002 :     assert( --svc_quota > 0 );
     211        1002 :   }
     212        2088 :   assert( conn->svc_type != FD_QUIC_SVC_INSTANT );
     213             : 
     214             :   /* Generate ACKs */
     215        2109 :   while( state->svc_queue[ FD_QUIC_SVC_ACK_TX ].head != UINT_MAX ) {
     216          21 :     fd_quic_conn_t * conn = fd_quic_conn_at_idx( state, state->svc_queue[ FD_QUIC_SVC_ACK_TX ].head );
     217          21 :     g_clock = conn->svc_time;
     218          21 :     fd_quic_service( quic );
     219          21 :     assert( --svc_quota > 0 );
     220          21 :   }
     221        2088 :   assert( conn->svc_type != FD_QUIC_SVC_INSTANT &&
     222        2088 :           conn->svc_type != FD_QUIC_SVC_ACK_TX );
     223             : 
     224             :   /* Simulate conn timeout */
     225        5349 :   while( state->svc_queue[ FD_QUIC_SVC_WAIT ].head != UINT_MAX ) {
     226        3261 :     ulong idle_timeout_ts = conn->last_activity + quic->config.idle_timeout + 1UL;
     227        3261 :     fd_quic_conn_t * conn = fd_quic_conn_at_idx( state, state->svc_queue[ FD_QUIC_SVC_WAIT ].head );
     228             : 
     229             :     /* Idle timeouts should not be scheduled significantly late */
     230        3261 :     assert( conn->svc_time < idle_timeout_ts + (ulong)2e9 );
     231             : 
     232        3261 :     g_clock = conn->svc_time;
     233        3261 :     fd_quic_service( quic );
     234        3261 :     assert( --svc_quota > 0 );
     235        3261 :   }
     236        2088 :   assert( conn->svc_type == UINT_MAX );
     237        2088 :   assert( conn->state == FD_QUIC_CONN_STATE_DEAD || conn->state == FD_QUIC_CONN_STATE_INVALID );
     238             : 
     239        2088 :   fd_quic_delete( fd_quic_leave( fd_quic_fini( quic ) ) );
     240        2088 :   fd_aio_delete( fd_aio_leave( aio ) );
     241        2088 :   fd_rng_delete( fd_rng_leave( rng ) );
     242        2088 :   return 0;
     243        2088 : }
     244             : 
     245             : #if !FD_QUIC_DISABLE_CRYPTO
     246             : 
     247             : static fd_quic_crypto_keys_t const keys[1] = {{
     248             :   .pkt_key    = {0},
     249             :   .iv         = {0},
     250             :   .hp_key     = {0},
     251             : }};
     252             : 
     253             : /* guess_packet_size attempts to discover the end of a QUIC packet.
     254             :    Returns the total length (including GCM tag) on success, sets *pn_off
     255             :    to the packet number offset and *pn to the packet number.  Returns
     256             :    0UL on failure. */
     257             : 
     258             : static ulong
     259             : guess_packet_size( uchar const * data,
     260             :                    ulong         size,
     261           0 :                    ulong *       pn_off ) {
     262             : 
     263           0 :   uchar const * cur_ptr = data;
     264           0 :   ulong         cur_sz  = size;
     265             : 
     266           0 :   ulong pkt_num_pnoff = 0UL;
     267           0 :   ulong total_len     = size;
     268             : 
     269           0 :   if( FD_UNLIKELY( size < 1 ) ) return FD_QUIC_PARSE_FAIL;
     270           0 :   uchar hdr_form = fd_quic_h0_hdr_form( *cur_ptr );
     271             : 
     272           0 :   ulong rc;
     273           0 :   if( hdr_form == 1 ) {  /* long header */
     274             : 
     275           0 :     uchar long_packet_type = fd_quic_h0_long_packet_type( *cur_ptr );
     276           0 :     cur_ptr += 1; cur_sz -= 1UL;
     277           0 :     fd_quic_long_hdr_t long_hdr[1];
     278           0 :     rc = fd_quic_decode_long_hdr( long_hdr, cur_ptr, cur_sz );
     279           0 :     if( rc == FD_QUIC_PARSE_FAIL ) return 0UL;
     280           0 :     cur_ptr += rc; cur_sz -= rc;
     281             : 
     282           0 :     switch( long_packet_type ) {
     283           0 :     case FD_QUIC_PKT_TYPE_INITIAL: {
     284           0 :       fd_quic_initial_t initial[1];
     285           0 :       rc = fd_quic_decode_initial( initial, cur_ptr, cur_sz );
     286           0 :       if( rc == FD_QUIC_PARSE_FAIL ) return 0UL;
     287           0 :       cur_ptr += rc; cur_sz -= rc;
     288             : 
     289           0 :       pkt_num_pnoff = initial->pkt_num_pnoff;
     290           0 :       total_len     = pkt_num_pnoff + initial->len;
     291           0 :       break;
     292           0 :     }
     293           0 :     case FD_QUIC_PKT_TYPE_HANDSHAKE: {
     294           0 :       fd_quic_handshake_t handshake[1];
     295           0 :       rc = fd_quic_decode_handshake( handshake, cur_ptr, cur_sz );
     296           0 :       if( rc == FD_QUIC_PARSE_FAIL ) return 0UL;
     297           0 :       cur_ptr += rc; cur_sz -= rc;
     298             : 
     299           0 :       pkt_num_pnoff = handshake->pkt_num_pnoff;
     300           0 :       total_len     = pkt_num_pnoff + handshake->len;
     301           0 :       break;
     302           0 :     }
     303           0 :     case FD_QUIC_PKT_TYPE_RETRY:
     304             :       /* Do we need to decrypt Retry packets?  I'm not sure */
     305             :       /* TODO correctly derive size of packet in case there is another
     306             :               packet following the retry packet */
     307           0 :       return 0UL;
     308           0 :     case FD_QUIC_PKT_TYPE_ZERO_RTT:
     309             :       /* No support for 0-RTT yet */
     310           0 :       return 0UL;
     311           0 :     default:
     312           0 :       __builtin_unreachable();
     313           0 :     }
     314             : 
     315           0 :   } else {  /* short header */
     316             : 
     317           0 :     fd_quic_one_rtt_t one_rtt[1];
     318           0 :     one_rtt->dst_conn_id_len = 8;
     319           0 :     rc = fd_quic_decode_one_rtt( one_rtt, cur_ptr, cur_sz );
     320           0 :     if( rc == FD_QUIC_PARSE_FAIL ) return 0UL;
     321           0 :     cur_ptr += rc; cur_sz -= rc;
     322             : 
     323           0 :     pkt_num_pnoff = one_rtt->pkt_num_pnoff;
     324             : 
     325           0 :   }
     326             : 
     327           0 :   *pn_off = pkt_num_pnoff;
     328           0 :   return total_len;
     329           0 : }
     330             : 
     331             : /* decrypt_packet attempts to decrypt the first QUIC packet in the given
     332             :    buffer.  data points to the first byte of the QUIC packet.  size is
     333             :    the number of bytes until the end of the UDP datagram.  Returns the
     334             :    number of bytes that belonged to the first packet (<= size) on
     335             :    success.  Returns 0 on failure and leaves the packet (partially)
     336             :    encrypted. */
     337             : 
     338             : static ulong
     339             : decrypt_packet( uchar * const data,
     340           0 :                 ulong   const size ) {
     341             : 
     342           0 :   ulong pkt_num_pnoff = 0UL;
     343           0 :   ulong total_len = guess_packet_size( data, size, &pkt_num_pnoff );
     344           0 :   if( !total_len ) return 0UL;
     345             : 
     346             :   /* Decrypt the packet */
     347             : 
     348           0 :   int decrypt_res = fd_quic_crypto_decrypt_hdr( data, size, pkt_num_pnoff, keys );
     349           0 :   if( decrypt_res != FD_QUIC_SUCCESS ) return 0UL;
     350             : 
     351           0 :   uint  pkt_number_sz = fd_quic_h0_pkt_num_len( data[0] ) + 1u;
     352           0 :   ulong pkt_number    = fd_quic_pktnum_decode( data+pkt_num_pnoff, pkt_number_sz );
     353             : 
     354           0 :   decrypt_res =
     355           0 :     fd_quic_crypto_decrypt( data,           size,
     356           0 :                             pkt_num_pnoff,  pkt_number,
     357           0 :                             keys );
     358           0 :   if( decrypt_res != FD_QUIC_SUCCESS ) return 0UL;
     359             : 
     360           0 :   return fd_ulong_min( total_len + FD_QUIC_CRYPTO_TAG_SZ, size );
     361           0 : }
     362             : 
     363             : /* decrypt_payload attempts to remove packet protection of a UDP
     364             :    datagram payload in-place.  Note that a UDP datagram can contain
     365             :    multiple QUIC packets. */
     366             : 
     367             : static int
     368             : decrypt_payload( uchar * data,
     369           0 :                  ulong   size ) {
     370             : 
     371           0 :   if( size < 16 ) return 0;
     372             : 
     373             :   /* Heuristic: If the last 16 bytes of the packet (the AES-GCM tag) are
     374             :      zero consider it an unencrypted packet */
     375             : 
     376           0 :   uint mask=0U;
     377           0 :   for( ulong j=0UL; j<16UL; j++ ) mask |= data[size-16+j];
     378           0 :   if( !mask ) return 1;
     379             : 
     380           0 :   uchar * cur_ptr = data;
     381           0 :   ulong   cur_sz  = size;
     382             : 
     383           0 :   do {
     384             : 
     385           0 :     ulong sz = decrypt_packet( cur_ptr, cur_sz );
     386           0 :     if( !sz ) return 0;
     387           0 :     assert( sz <= cur_sz );  /* prevent out of bounds */
     388             : 
     389           0 :     cur_ptr += sz;  cur_sz -= sz;
     390             : 
     391           0 :   } while( cur_sz );
     392             : 
     393           0 :   return 1;
     394           0 : }
     395             : 
     396             : static ulong
     397             : encrypt_packet( uchar * const data,
     398           0 :                 ulong   const size ) {
     399             : 
     400           0 :   uchar out[ FD_QUIC_MTU ];
     401             : 
     402           0 :   ulong pkt_num_pnoff = 0UL;
     403           0 :   ulong total_len = guess_packet_size( data, size, &pkt_num_pnoff );
     404           0 :   if( ( total_len < FD_QUIC_CRYPTO_TAG_SZ ) |
     405           0 :       ( total_len > size                  ) |
     406           0 :       ( total_len > sizeof(out)           ) )
     407           0 :     return size;
     408             : 
     409           0 :   uchar first = data[0];
     410           0 :   ulong pkt_number_sz = ( first & 0x03u ) + 1;
     411             : 
     412           0 :   ulong         out_sz = total_len;
     413           0 :   uchar const * hdr    = data;
     414           0 :   ulong         hdr_sz = pkt_num_pnoff + pkt_number_sz;
     415             : 
     416           0 :   ulong pkt_number = 0UL;
     417           0 :   for( ulong j = 0UL; j < pkt_number_sz; ++j ) {
     418           0 :     pkt_number = ( pkt_number << 8UL ) + (ulong)( hdr[pkt_num_pnoff + j] );
     419           0 :   }
     420             : 
     421           0 :   if( ( out_sz          < hdr_sz ) |
     422           0 :       ( out_sz - hdr_sz < FD_QUIC_CRYPTO_TAG_SZ ) )
     423           0 :     return size;
     424             : 
     425           0 :   uchar const * pay    = hdr + hdr_sz;
     426           0 :   ulong         pay_sz = out_sz - hdr_sz - FD_QUIC_CRYPTO_TAG_SZ;
     427             : 
     428           0 :   int encrypt_res =
     429           0 :     fd_quic_crypto_encrypt( out, &out_sz,
     430           0 :                             hdr, hdr_sz,
     431           0 :                             pay, pay_sz,
     432           0 :                             keys, keys,
     433           0 :                             pkt_number );
     434           0 :   if( encrypt_res != FD_QUIC_SUCCESS )
     435           0 :     return size;
     436           0 :   assert( out_sz == total_len );
     437             : 
     438           0 :   fd_memcpy( data, out, out_sz );
     439           0 :   return out_sz;
     440           0 : }
     441             : 
     442             : static void
     443             : encrypt_payload( uchar * data,
     444           0 :                  ulong   size ) {
     445             : 
     446           0 :   uchar * cur_ptr = data;
     447           0 :   ulong   cur_sz  = size;
     448             : 
     449           0 :   while( cur_sz ) {
     450           0 :     ulong sz = encrypt_packet( cur_ptr, cur_sz );
     451           0 :     assert( sz );            /* prevent infinite loop */
     452           0 :     assert( sz <= cur_sz );  /* prevent out of bounds */
     453             : 
     454           0 :     cur_ptr += sz;  cur_sz -= sz;
     455           0 :   }
     456           0 : }
     457             : 
     458             : /* LLVMFuzzerCustomMutator has the following behavior:
     459             : 
     460             :    - If the input is not encrypted, mutates the raw input, and produces
     461             :      an encrypted output
     462             :    - If the input is encrypted, mutates the decrypted input, and
     463             :      produces another encrypted output
     464             :    - If the input appears to be encrypted but fails to decrypt, mutates
     465             :      the raw encrypted input, and produces another output that will fail
     466             :      to decrypt. */
     467             : 
     468             : ulong
     469             : LLVMFuzzerCustomMutator( uchar * data,
     470             :                          ulong   data_sz,
     471             :                          ulong   max_sz,
     472           0 :                          uint    seed ) {
     473           0 :   int ok = decrypt_payload( data, data_sz );
     474           0 :   data_sz = LLVMFuzzerMutate( data, data_sz, max_sz );
     475           0 :   if( ok ) encrypt_payload( data, data_sz );
     476           0 :   (void)seed;
     477           0 :   return data_sz;
     478           0 : }
     479             : 
     480             : /* Find a strategy for custom crossover of decrypted packets */
     481             : 
     482             : #endif /* !FD_QUIC_DISABLE_CRYPTO */

Generated by: LCOV version 1.14