github.com/ooni/psiphon/tunnel-core@v0.0.0-20230105123940-fe12a24c96ee/oovendor/quic-go/interface.go (about) 1 package quic 2 3 import ( 4 "context" 5 "errors" 6 "io" 7 "net" 8 "time" 9 10 "github.com/ooni/psiphon/tunnel-core/psiphon/common/prng" 11 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/handshake" 12 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/internal/protocol" 13 "github.com/ooni/psiphon/tunnel-core/oovendor/quic-go/logging" 14 ) 15 16 // The StreamID is the ID of a QUIC stream. 17 type StreamID = protocol.StreamID 18 19 // A VersionNumber is a QUIC version number. 20 type VersionNumber = protocol.VersionNumber 21 22 const ( 23 // VersionDraft29 is IETF QUIC draft-29 24 VersionDraft29 = protocol.VersionDraft29 25 // Version1 is RFC 9000 26 Version1 = protocol.Version1 27 ) 28 29 // A Token can be used to verify the ownership of the client address. 30 type Token struct { 31 // IsRetryToken encodes how the client received the token. There are two ways: 32 // * In a Retry packet sent when trying to establish a new connection. 33 // * In a NEW_TOKEN frame on a previous connection. 34 IsRetryToken bool 35 RemoteAddr string 36 SentTime time.Time 37 } 38 39 // A ClientToken is a token received by the client. 40 // It can be used to skip address validation on future connection attempts. 41 type ClientToken struct { 42 data []byte 43 } 44 45 type TokenStore interface { 46 // Pop searches for a ClientToken associated with the given key. 47 // Since tokens are not supposed to be reused, it must remove the token from the cache. 48 // It returns nil when no token is found. 49 Pop(key string) (token *ClientToken) 50 51 // Put adds a token to the cache with the given key. It might get called 52 // multiple times in a connection. 53 Put(key string, token *ClientToken) 54 } 55 56 // Err0RTTRejected is the returned from: 57 // * Open{Uni}Stream{Sync} 58 // * Accept{Uni}Stream 59 // * Stream.Read and Stream.Write 60 // when the server rejects a 0-RTT connection attempt. 61 var Err0RTTRejected = errors.New("0-RTT rejected") 62 63 // SessionTracingKey can be used to associate a ConnectionTracer with a Session. 64 // It is set on the Session.Context() context, 65 // as well as on the context passed to logging.Tracer.NewConnectionTracer. 66 var SessionTracingKey = sessionTracingCtxKey{} 67 68 type sessionTracingCtxKey struct{} 69 70 // Stream is the interface implemented by QUIC streams 71 // In addition to the errors listed on the Session, 72 // calls to stream functions can return a StreamError if the stream is canceled. 73 type Stream interface { 74 ReceiveStream 75 SendStream 76 // SetDeadline sets the read and write deadlines associated 77 // with the connection. It is equivalent to calling both 78 // SetReadDeadline and SetWriteDeadline. 79 SetDeadline(t time.Time) error 80 } 81 82 // A ReceiveStream is a unidirectional Receive Stream. 83 type ReceiveStream interface { 84 // StreamID returns the stream ID. 85 StreamID() StreamID 86 // Read reads data from the stream. 87 // Read can be made to time out and return a net.Error with Timeout() == true 88 // after a fixed time limit; see SetDeadline and SetReadDeadline. 89 // If the stream was canceled by the peer, the error implements the StreamError 90 // interface, and Canceled() == true. 91 // If the session was closed due to a timeout, the error satisfies 92 // the net.Error interface, and Timeout() will be true. 93 io.Reader 94 // CancelRead aborts receiving on this stream. 95 // It will ask the peer to stop transmitting stream data. 96 // Read will unblock immediately, and future Read calls will fail. 97 // When called multiple times or after reading the io.EOF it is a no-op. 98 CancelRead(StreamErrorCode) 99 // SetReadDeadline sets the deadline for future Read calls and 100 // any currently-blocked Read call. 101 // A zero value for t means Read will not time out. 102 103 SetReadDeadline(t time.Time) error 104 } 105 106 // A SendStream is a unidirectional Send Stream. 107 type SendStream interface { 108 // StreamID returns the stream ID. 109 StreamID() StreamID 110 // Write writes data to the stream. 111 // Write can be made to time out and return a net.Error with Timeout() == true 112 // after a fixed time limit; see SetDeadline and SetWriteDeadline. 113 // If the stream was canceled by the peer, the error implements the StreamError 114 // interface, and Canceled() == true. 115 // If the session was closed due to a timeout, the error satisfies 116 // the net.Error interface, and Timeout() will be true. 117 io.Writer 118 // Close closes the write-direction of the stream. 119 // Future calls to Write are not permitted after calling Close. 120 // It must not be called concurrently with Write. 121 // It must not be called after calling CancelWrite. 122 io.Closer 123 // CancelWrite aborts sending on this stream. 124 // Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably. 125 // Write will unblock immediately, and future calls to Write will fail. 126 // When called multiple times or after closing the stream it is a no-op. 127 CancelWrite(StreamErrorCode) 128 // The Context is canceled as soon as the write-side of the stream is closed. 129 // This happens when Close() or CancelWrite() is called, or when the peer 130 // cancels the read-side of their stream. 131 // Warning: This API should not be considered stable and might change soon. 132 Context() context.Context 133 // SetWriteDeadline sets the deadline for future Write calls 134 // and any currently-blocked Write call. 135 // Even if write times out, it may return n > 0, indicating that 136 // some data was successfully written. 137 // A zero value for t means Write will not time out. 138 SetWriteDeadline(t time.Time) error 139 } 140 141 // A Session is a QUIC connection between two peers. 142 // Calls to the session (and to streams) can return the following types of errors: 143 // * ApplicationError: for errors triggered by the application running on top of QUIC 144 // * TransportError: for errors triggered by the QUIC transport (in many cases a misbehaving peer) 145 // * IdleTimeoutError: when the peer goes away unexpectedly (this is a net.Error timeout error) 146 // * HandshakeTimeoutError: when the cryptographic handshake takes too long (this is a net.Error timeout error) 147 // * StatelessResetError: when we receive a stateless reset (this is a net.Error temporary error) 148 // * VersionNegotiationError: returned by the client, when there's no version overlap between the peers 149 type Session interface { 150 // AcceptStream returns the next stream opened by the peer, blocking until one is available. 151 // If the session was closed due to a timeout, the error satisfies 152 // the net.Error interface, and Timeout() will be true. 153 AcceptStream(context.Context) (Stream, error) 154 // AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available. 155 // If the session was closed due to a timeout, the error satisfies 156 // the net.Error interface, and Timeout() will be true. 157 AcceptUniStream(context.Context) (ReceiveStream, error) 158 // OpenStream opens a new bidirectional QUIC stream. 159 // There is no signaling to the peer about new streams: 160 // The peer can only accept the stream after data has been sent on the stream. 161 // If the error is non-nil, it satisfies the net.Error interface. 162 // When reaching the peer's stream limit, err.Temporary() will be true. 163 // If the session was closed due to a timeout, Timeout() will be true. 164 OpenStream() (Stream, error) 165 // OpenStreamSync opens a new bidirectional QUIC stream. 166 // It blocks until a new stream can be opened. 167 // If the error is non-nil, it satisfies the net.Error interface. 168 // If the session was closed due to a timeout, Timeout() will be true. 169 OpenStreamSync(context.Context) (Stream, error) 170 // OpenUniStream opens a new outgoing unidirectional QUIC stream. 171 // If the error is non-nil, it satisfies the net.Error interface. 172 // When reaching the peer's stream limit, Temporary() will be true. 173 // If the session was closed due to a timeout, Timeout() will be true. 174 OpenUniStream() (SendStream, error) 175 // OpenUniStreamSync opens a new outgoing unidirectional QUIC stream. 176 // It blocks until a new stream can be opened. 177 // If the error is non-nil, it satisfies the net.Error interface. 178 // If the session was closed due to a timeout, Timeout() will be true. 179 OpenUniStreamSync(context.Context) (SendStream, error) 180 // LocalAddr returns the local address. 181 LocalAddr() net.Addr 182 // RemoteAddr returns the address of the peer. 183 RemoteAddr() net.Addr 184 // CloseWithError closes the connection with an error. 185 // The error string will be sent to the peer. 186 CloseWithError(ApplicationErrorCode, string) error 187 // The context is cancelled when the session is closed. 188 // Warning: This API should not be considered stable and might change soon. 189 Context() context.Context 190 // ConnectionState returns basic details about the QUIC connection. 191 // It blocks until the handshake completes. 192 // Warning: This API should not be considered stable and might change soon. 193 ConnectionState() ConnectionState 194 195 // SendMessage sends a message as a datagram. 196 // See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/. 197 SendMessage([]byte) error 198 // ReceiveMessage gets a message received in a datagram. 199 // See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/. 200 ReceiveMessage() ([]byte, error) 201 } 202 203 // An EarlySession is a session that is handshaking. 204 // Data sent during the handshake is encrypted using the forward secure keys. 205 // When using client certificates, the client's identity is only verified 206 // after completion of the handshake. 207 type EarlySession interface { 208 Session 209 210 // HandshakeComplete blocks until the handshake completes (or fails). 211 // Data sent before completion of the handshake is encrypted with 1-RTT keys. 212 // Note that the client's identity hasn't been verified yet. 213 HandshakeComplete() context.Context 214 215 NextSession() Session 216 } 217 218 // Config contains all configuration data needed for a QUIC server or client. 219 type Config struct { 220 // The QUIC versions that can be negotiated. 221 // If not set, it uses all versions available. 222 // Warning: This API should not be considered stable and will change soon. 223 Versions []VersionNumber 224 // The length of the connection ID in bytes. 225 // It can be 0, or any value between 4 and 18. 226 // If not set, the interpretation depends on where the Config is used: 227 // If used for dialing an address, a 0 byte connection ID will be used. 228 // If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used. 229 // When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call. 230 ConnectionIDLength int 231 // HandshakeIdleTimeout is the idle timeout before completion of the handshake. 232 // Specifically, if we don't receive any packet from the peer within this time, the connection attempt is aborted. 233 // If this value is zero, the timeout is set to 5 seconds. 234 HandshakeIdleTimeout time.Duration 235 // MaxIdleTimeout is the maximum duration that may pass without any incoming network activity. 236 // The actual value for the idle timeout is the minimum of this value and the peer's. 237 // This value only applies after the handshake has completed. 238 // If the timeout is exceeded, the connection is closed. 239 // If this value is zero, the timeout is set to 30 seconds. 240 MaxIdleTimeout time.Duration 241 // AcceptToken determines if a Token is accepted. 242 // It is called with token = nil if the client didn't send a token. 243 // If not set, a default verification function is used: 244 // * it verifies that the address matches, and 245 // * if the token is a retry token, that it was issued within the last 5 seconds 246 // * else, that it was issued within the last 24 hours. 247 // This option is only valid for the server. 248 AcceptToken func(clientAddr net.Addr, token *Token) bool 249 // The TokenStore stores tokens received from the server. 250 // Tokens are used to skip address validation on future connection attempts. 251 // The key used to store tokens is the ServerName from the tls.Config, if set 252 // otherwise the token is associated with the server's IP address. 253 TokenStore TokenStore 254 // InitialStreamReceiveWindow is the initial size of the stream-level flow control window for receiving data. 255 // If the application is consuming data quickly enough, the flow control auto-tuning algorithm 256 // will increase the window up to MaxStreamReceiveWindow. 257 // If this value is zero, it will default to 512 KB. 258 InitialStreamReceiveWindow uint64 259 // MaxStreamReceiveWindow is the maximum stream-level flow control window for receiving data. 260 // If this value is zero, it will default to 6 MB. 261 MaxStreamReceiveWindow uint64 262 // InitialConnectionReceiveWindow is the initial size of the stream-level flow control window for receiving data. 263 // If the application is consuming data quickly enough, the flow control auto-tuning algorithm 264 // will increase the window up to MaxConnectionReceiveWindow. 265 // If this value is zero, it will default to 512 KB. 266 InitialConnectionReceiveWindow uint64 267 // MaxConnectionReceiveWindow is the connection-level flow control window for receiving data. 268 // If this value is zero, it will default to 15 MB. 269 MaxConnectionReceiveWindow uint64 270 // AllowConnectionWindowIncrease is called every time the connection flow controller attempts 271 // to increase the connection flow control window. 272 // If set, the caller can prevent an increase of the window. Typically, it would do so to 273 // limit the memory usage. 274 // To avoid deadlocks, it is not valid to call other functions on the session or on streams 275 // in this callback. 276 AllowConnectionWindowIncrease func(sess Session, delta uint64) bool 277 // MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open. 278 // Values above 2^60 are invalid. 279 // If not set, it will default to 100. 280 // If set to a negative value, it doesn't allow any bidirectional streams. 281 MaxIncomingStreams int64 282 // MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open. 283 // Values above 2^60 are invalid. 284 // If not set, it will default to 100. 285 // If set to a negative value, it doesn't allow any unidirectional streams. 286 MaxIncomingUniStreams int64 287 // The StatelessResetKey is used to generate stateless reset tokens. 288 // If no key is configured, sending of stateless resets is disabled. 289 StatelessResetKey []byte 290 // KeepAlive defines whether this peer will periodically send a packet to keep the connection alive. 291 KeepAlive bool 292 // DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899). 293 // Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size. 294 // Note that if Path MTU discovery is causing issues on your system, please open a new issue 295 DisablePathMTUDiscovery bool 296 // DisableVersionNegotiationPackets disables the sending of Version Negotiation packets. 297 // This can be useful if version information is exchanged out-of-band. 298 // It has no effect for a client. 299 DisableVersionNegotiationPackets bool 300 // See https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/. 301 // Datagrams will only be available when both peers enable datagram support. 302 EnableDatagrams bool 303 Tracer logging.Tracer 304 305 // [Psiphon] 306 // ClientHelloSeed is used for TLS Client Hello randomization and replay. 307 ClientHelloSeed *prng.Seed 308 309 // [Psiphon] 310 // GetClientHelloRandom is used by the QUIC client to supply a specific 311 // value in the TLS Client Hello random field. This is used to send an 312 // anti-probing message, indistinguishable from random, that proves 313 // knowlegde of a shared secret key. 314 GetClientHelloRandom func() ([]byte, error) 315 316 // [Psiphon] 317 // VerifyClientHelloRandom is used by the QUIC server to verify that the 318 // TLS Client Hello random field, supplied in the Initial packet for a 319 // new connection, was created using the shared secret key and is not 320 // replayed. 321 VerifyClientHelloRandom func(net.Addr, []byte) bool 322 323 // [Psiphon] 324 // ClientMaxPacketSizeAdjustment indicates that the max packet size should 325 // be reduced by the specified amount. This is used to reserve space for 326 // packet obfuscation overhead while remaining at or under the 1280 327 // initial target packet size as well as protocol.MaxPacketBufferSize, 328 // the maximum packet size under MTU discovery. 329 ClientMaxPacketSizeAdjustment int 330 331 // [Psiphon] 332 // ServerMaxPacketSizeAdjustment indicates that, for the flow associated 333 // with the given client address, the max packet size should be reduced 334 // by the specified amount. This is used to reserve space for packet 335 // obfuscation overhead while remaining at or under the 1280 target 336 // packet size. Must be set only for QUIC server configs. 337 ServerMaxPacketSizeAdjustment func(net.Addr) int 338 } 339 340 // ConnectionState records basic details about a QUIC connection 341 type ConnectionState struct { 342 TLS handshake.ConnectionState 343 SupportsDatagrams bool 344 } 345 346 // A Listener for incoming QUIC connections 347 type Listener interface { 348 // Close the server. All active sessions will be closed. 349 Close() error 350 // Addr returns the local network addr that the server is listening on. 351 Addr() net.Addr 352 // Accept returns new sessions. It should be called in a loop. 353 Accept(context.Context) (Session, error) 354 } 355 356 // An EarlyListener listens for incoming QUIC connections, 357 // and returns them before the handshake completes. 358 type EarlyListener interface { 359 // Close the server. All active sessions will be closed. 360 Close() error 361 // Addr returns the local network addr that the server is listening on. 362 Addr() net.Addr 363 // Accept returns new early sessions. It should be called in a loop. 364 Accept(context.Context) (EarlySession, error) 365 }