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