Line data Source code
1 : #ifndef HEADER_fd_src_waltz_quic_tests_fd_quic_sandbox_h 2 : #define HEADER_fd_src_waltz_quic_tests_fd_quic_sandbox_h 3 : 4 : #include "../fd_quic.h" 5 : #include "../log/fd_quic_log_user.h" 6 : #include "../../../tango/mcache/fd_mcache.h" 7 : #include "../../../tango/dcache/fd_dcache.h" 8 : #include "../../../util/net/fd_ip4.h" 9 : 10 : /* fd_quic_sandbox_t is used to setup and analyze a conversation with 11 : fd_quic. It manages an instrumented fd_quic_t instance and records 12 : its outgoing packets. The packet capture is a ring buffer 13 : (mcache/dcache pair) that captures the last N packets. 14 : 15 : fd_quic_sandbox_t is single-threaded only. fd_quic_sandbox_t cannot 16 : be shared across different address spaces. The usual mcache lockless 17 : concurrency patterns for accessing the captured packet ring are thus 18 : unnecessary. It is not safe to declare a fd_quic_sandbox_t variable, 19 : use the object lifecycle API instead. */ 20 : 21 : struct fd_quic_sandbox { 22 : /* Static members (values only changed by new/delete) */ 23 : 24 : ulong magic; /* ==FD_QUIC_SANDBOX_MAGIC */ 25 : fd_quic_t * quic; /* the QUIC instance to be tested */ 26 : fd_frag_meta_t * pkt_mcache; /* captured packet descriptor */ 27 : void * pkt_dcache; /* captured packet data */ 28 : ulong pkt_mtu; /* captured packet max payload sz */ 29 : fd_quic_log_rx_t log_rx[1]; 30 : 31 : /* State */ 32 : 33 : ulong pkt_seq_r; /* seq no of next packet not yet read */ 34 : ulong pkt_seq_w; /* seq no of next packet to publish */ 35 : ulong pkt_chunk; /* publisher chunk index */ 36 : ulong wallclock; /* time as seen by fd_quic (ns) */ 37 : }; 38 : 39 : typedef struct fd_quic_sandbox fd_quic_sandbox_t; 40 : 41 : /* FD_QUIC_SANDBOX_MAGIC is a unique random number identifying an 42 : fd_quic_sandbox_t object. */ 43 : 44 3 : #define FD_QUIC_SANDBOX_MAGIC (0xf072dd5e98bb6e91UL) /* random */ 45 : 46 : /* FD_QUIC_SANDBOX_SELF_IP4 is the default IP address of the sandbox 47 : fd_quic_t. */ 48 : 49 3 : #define FD_QUIC_SANDBOX_SELF_IP4 FD_IP4_ADDR( 30, 0, 0, 1 ) 50 : 51 : /* FD_QUIC_SANDBOX_PEER_IP4 is the default IP address of the mock peer 52 : that the sandbox fd_quic_t is talking with. */ 53 : 54 300000 : #define FD_QUIC_SANDBOX_PEER_IP4 FD_IP4_ADDR( 30, 0, 0, 2 ) 55 : 56 : /* FD_QUIC_SANDBOX_SELF_PORT is the default UDP port of the sandbox 57 : fd_quic_t. */ 58 : 59 79319457 : #define FD_QUIC_SANDBOX_SELF_PORT ((ushort)9000) 60 : 61 : /* FD_QUIC_SANDBOX_PEER_PORT is the default UDP port of the mock peer 62 : that the sandbox fd_quic_t is talking with. */ 63 : 64 158938896 : #define FD_QUIC_SANDBOX_PEER_PORT ((ushort)9001) 65 : 66 : /* FD_QUIC_SANDBOX_IDLE_TIMEOUT is the default fd_quic idle timeout. */ 67 : 68 300003 : #define FD_QUIC_SANDBOX_IDLE_TIMEOUT (1000000000UL) /* 1s */ 69 : 70 : /* Object lifecycle ***************************************************/ 71 : 72 : FD_PROTOTYPES_BEGIN 73 : 74 : /* fd_quic_sandbox_{align,footprint} describe requirements for the 75 : memory region backing an fd_quic_sandbox_t. 76 : 77 : quic_limits are the parameters for the fd_quic_t owned by 78 : fd_quic_sandbox_t. pkt_cnt are the number of packets that are 79 : buffered (must be a power of 2). mtu is the max size of each packet 80 : (only the UDP datagram, not including Ethernet or IPv4 headers). 81 : 82 : fd_quic_footprint returns 0UL if any of the parameters are invalid 83 : and can thus be used for fast validation. */ 84 : 85 : ulong 86 : fd_quic_sandbox_align( void ); 87 : 88 : ulong 89 : fd_quic_sandbox_footprint( fd_quic_limits_t const * quic_limits, 90 : ulong pkt_cnt, 91 : ulong mtu ); 92 : 93 : /* fd_quic_sandbox_new formats the memory region 'mem' for use as an 94 : fd_quic_sandbox_t. The arguments must match those given to 95 : fd_quic_sandbox_footprint when creating the memory region (assumes 96 : that parameters are valid, i.e. footprint returned non-zero). 97 : Returns mem on success. On failure, returns NULL and logs reason for 98 : failure. */ 99 : 100 : fd_quic_sandbox_t * 101 : fd_quic_sandbox_new( void * mem, 102 : fd_quic_limits_t const * quic_limits, 103 : ulong pkt_cnt, 104 : ulong mtu ); 105 : 106 : /* fd_quic_sandbox_init resets the fd_quic_sandbox_t to a common state. 107 : 108 : sandbox points to a local join to the fd_quic_sandbox_t. 109 : role is one of FD_QUIC_ROLE_{CLIENT,SERVER}. 110 : 111 : On return, 112 : - the fake wallclock is 0UL 113 : - the embedded fd_quic_t instance is in 'initialized state' (via 114 : fd_quic_init), having no connections and empty object pools 115 : - the packet capture ring is empty 116 : - the idle_timeout is 1s 117 : - the local identity key is Ed25519 secret of b'\x41' * 32 */ 118 : 119 : fd_quic_sandbox_t * 120 : fd_quic_sandbox_init( fd_quic_sandbox_t * sandbox, 121 : int role ); 122 : 123 : /* fd_quic_sandbox_delete destroys an fd_quic_sandbox_t object and 124 : releases the memory region back to the caller. */ 125 : 126 : void * 127 : fd_quic_sandbox_delete( fd_quic_sandbox_t * mem ); 128 : 129 : FD_PROTOTYPES_END 130 : 131 : /* Encryption *********************************************************/ 132 : 133 : FD_PROTOTYPES_BEGIN 134 : 135 : /* fd_quic_sandbox_{self,peer}_ed25519_keypair is the default Ed25519 136 : key pair of the sandbox fd_quic_t and the mock peer respectively. 137 : 138 : The first 32 bytes is the scalar/private key, the last 32 bytes is 139 : the encoded public key. */ 140 : 141 : extern uchar const fd_quic_sandbox_self_ed25519_keypair[64]; 142 : extern uchar const fd_quic_sandbox_peer_ed25519_keypair[64]; 143 : 144 : /* fd_quic_sandbox_aes128_{key,iv} are the default AES-128-GCM secret 145 : key and IV of the sandbox fd_quic_t and mock peer. They are the 146 : same for anywhere symmetric crypto is used, except for the QUIC 147 : initial layer where the protocol hardcoded keys are useds. */ 148 : 149 : extern uchar const fd_quic_sandbox_aes128_key[16]; 150 : extern uchar const fd_quic_sandbox_aes128_iv [12]; 151 : 152 : FD_PROTOTYPES_END 153 : 154 : /* Packet Capture *****************************************************/ 155 : 156 : FD_PROTOTYPES_BEGIN 157 : 158 : /* fd_quic_sandbox_next_packet reads the next buffered packet that 159 : fd_quic_t might have sent earlier. Returns a pointer to the frag 160 : descriptor and advances the read index if a packet was available. 161 : Returns NULL if there is no new packet. If packet loss occurs due 162 : to fd_quic having overrun the reader, logs a warning. Use 163 : fd_quic_sandbox_packet_data to get a pointer to the data. */ 164 : 165 : fd_frag_meta_t const * 166 : fd_quic_sandbox_next_packet( fd_quic_sandbox_t * sandbox ); 167 : 168 : /* fd_quic_sandbox_packet_data returns a pointer to the first byte of 169 : packet data, given a fd_frag_meta_t in the sandbox pkt cap mcache. */ 170 : 171 : FD_FN_CONST static inline uchar * 172 : fd_quic_sandbox_packet_data( fd_quic_sandbox_t * sandbox, 173 0 : fd_frag_meta_t const * frag ) { 174 0 : void * base = (void *)sandbox; /* aligned by FD_CHUNK_ALIGN */ 175 0 : return fd_chunk_to_laddr( base, frag->chunk ); 176 0 : } 177 : 178 : FD_PROTOTYPES_END 179 : 180 : /* Mock API ***********************************************************/ 181 : 182 : /* fd_quic_sandbox_new_conn_established injects a new established 183 : connection into the fd_quic_t state. Uses the fd_rng_t to randomly 184 : populate identifiers such as the conn ID. Returns the newly created 185 : fd_quic_conn_t on success (owned by fd_quic_t). Returns NULL if no 186 : free conn slots are available or the conn ID map is full. 187 : 188 : Note that the returned pointer may become invalid at some point 189 : because the fd_quic_t might free it (e.g. connection failed due to 190 : protocol error). 191 : 192 : The new connection is configured as such: 193 : - The QUIC version is v1 194 : - Zero quota for streams 195 : - Zero quota for stream data 196 : - Zero quota for data 197 : - The self endpoint is FD_QUIC_SANDBOX_SELF_IP4:FD_QUIC_SANDBOX_SELF_PORT 198 : - The peer endpoint is FD_QUIC_SANDBOX_PEER_IP4:FD_QUIC_SANDBOX_PEER_PORT */ 199 : 200 : fd_quic_conn_t * 201 : fd_quic_sandbox_new_conn_established( fd_quic_sandbox_t * sandbox, 202 : fd_rng_t * rng ); 203 : 204 : /* fd_quic_sandbox_send_frame sends the given QUIC frame to the sandbox 205 : fd_quic instance via the given connection. This entrypoint side 206 : steps decryption and jumps directly to frame handling. Some frame 207 : handlers require packet metadata. 208 : The memory region at [frame,frame+frame_sz) contains the wire 209 : encoding of the frame. */ 210 : 211 : void 212 : fd_quic_sandbox_send_frame( fd_quic_sandbox_t * sandbox, 213 : fd_quic_conn_t * conn, 214 : fd_quic_pkt_t * pkt_meta, 215 : uchar const * frame, 216 : ulong frame_sz ); 217 : 218 : /* fd_quic_sandbox_send_lone_frame wraps fd_quic_sandbox_send_frame but 219 : with realistic packet meta. It simulates a frame sent in a single 220 : QUIC packet and advances the packet number accordingly. */ 221 : 222 : void 223 : fd_quic_sandbox_send_lone_frame( fd_quic_sandbox_t * sandbox, 224 : fd_quic_conn_t * conn, 225 : uchar const * frame, 226 : ulong frame_sz ); 227 : 228 : /* fd_quic_sandbox_send_ping_pkt sends a 1-RTT packet containing only a 229 : PING frame. */ 230 : 231 : void 232 : fd_quic_sandbox_send_ping_pkt( fd_quic_sandbox_t * sandbox, 233 : fd_quic_conn_t * conn, 234 : ulong pktnum ); 235 : 236 : FD_PROTOTYPES_END 237 : 238 : #endif /* HEADER_fd_src_waltz_quic_tests_fd_quic_sandbox_h */