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  }