quic

package module
v0.30.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 21, 2022 License: MIT Imports: 37 Imported by: 0

README

A QUIC implementation in pure Go

PkgGoDev Code Coverage

quic-go is an implementation of the QUIC protocol, RFC 9000 protocol in Go. In addition to RFC 9000, it currently implements the IETF QUIC draft-29. Support for draft-29 will eventually be dropped, as it is phased out of the ecosystem.

Guides

We currently support Go 1.16.x, Go 1.17.x, and Go 1.18.x.

Running tests:

go test ./...
QUIC without HTTP/3

Take a look at this echo example.

Usage

As a server

See the example server. Starting a QUIC server is very similar to the standard lib http in go:

http.Handle("/", http.FileServer(http.Dir(wwwDir)))
http3.ListenAndServeQUIC("localhost:4242", "/path/to/cert/chain.pem", "/path/to/privkey.pem", nil)
As a client

See the example client. Use a http3.RoundTripper as a Transport in a http.Client.

http.Client{
  Transport: &http3.RoundTripper{},
}

Projects using quic-go

Project Description Stars
algernon Small self-contained pure-Go web server with Lua, Markdown, HTTP/2, QUIC, Redis and PostgreSQL support GitHub Repo stars
caddy Fast, multi-platform web server with automatic HTTPS GitHub Repo stars
go-ipfs IPFS implementation in go GitHub Repo stars
nextdns NextDNS CLI client (DoH Proxy) GitHub Repo stars
syncthing Open Source Continuous File Synchronization GitHub Repo stars
traefik The Cloud Native Application Proxy GitHub Repo stars
v2ray-core A platform for building proxies to bypass network restrictions GitHub Repo stars
cloudflared A tunneling daemon that proxies traffic from the Cloudflare network to your origins GitHub Repo stars
OONI Probe The Open Observatory of Network Interference (OONI) aims to empower decentralized efforts in documenting Internet censorship around the world. GitHub Repo stars

Contributing

We are always happy to welcome new contributors! We have a number of self-contained issues that are suitable for first-time contributors, they are tagged with help wanted. If you have any questions, please feel free to reach out by opening an issue or leaving a comment.

Documentation

Index

Constants

View Source
const (
	NoError                   = qerr.NoError
	InternalError             = qerr.InternalError
	ConnectionRefused         = qerr.ConnectionRefused
	FlowControlError          = qerr.FlowControlError
	StreamLimitError          = qerr.StreamLimitError
	StreamStateError          = qerr.StreamStateError
	FinalSizeError            = qerr.FinalSizeError
	FrameEncodingError        = qerr.FrameEncodingError
	TransportParameterError   = qerr.TransportParameterError
	ConnectionIDLimitError    = qerr.ConnectionIDLimitError
	ProtocolViolation         = qerr.ProtocolViolation
	InvalidToken              = qerr.InvalidToken
	ApplicationErrorErrorCode = qerr.ApplicationErrorErrorCode
	CryptoBufferExceeded      = qerr.CryptoBufferExceeded
	KeyUpdateError            = qerr.KeyUpdateError
	AEADLimitReached          = qerr.AEADLimitReached
	NoViablePathError         = qerr.NoViablePathError
)
View Source
const (
	// VersionDraft29 is IETF QUIC draft-29
	VersionDraft29 = protocol.VersionDraft29
	// Version1 is RFC 9000
	Version1 = protocol.Version1
)

Variables

View Source
var Err0RTTRejected = errors.New("0-RTT rejected")

Err0RTTRejected is the returned from: * Open{Uni}Stream{Sync} * Accept{Uni}Stream * Stream.Read and Stream.Write when the server rejects a 0-RTT connection attempt.

View Source
var SessionTracingKey = sessionTracingCtxKey{}

SessionTracingKey can be used to associate a ConnectionTracer with a Session. It is set on the Session.Context() context, as well as on the context passed to logging.Tracer.NewConnectionTracer.

Functions

This section is empty.

Types

type ApplicationError added in v0.26.0

type ApplicationError = qerr.ApplicationError

type ApplicationErrorCode added in v0.26.0

type ApplicationErrorCode = qerr.ApplicationErrorCode

type ClientToken added in v0.26.0

type ClientToken struct {
	// contains filtered or unexported fields
}

A ClientToken is a token received by the client. It can be used to skip address validation on future connection attempts.

type Config

type Config struct {
	// The QUIC versions that can be negotiated.
	// If not set, it uses all versions available.
	// Warning: This API should not be considered stable and will change soon.
	Versions []VersionNumber
	// The length of the connection ID in bytes.
	// It can be 0, or any value between 4 and 18.
	// If not set, the interpretation depends on where the Config is used:
	// If used for dialing an address, a 0 byte connection ID will be used.
	// If used for a server, or dialing on a packet conn, a 4 byte connection ID will be used.
	// When dialing on a packet conn, the ConnectionIDLength value must be the same for every Dial call.
	ConnectionIDLength int
	// HandshakeIdleTimeout is the idle timeout before completion of the handshake.
	// Specifically, if we don't receive any packet from the peer within this time, the connection attempt is aborted.
	// If this value is zero, the timeout is set to 5 seconds.
	HandshakeIdleTimeout time.Duration
	// MaxIdleTimeout is the maximum duration that may pass without any incoming network activity.
	// The actual value for the idle timeout is the minimum of this value and the peer's.
	// This value only applies after the handshake has completed.
	// If the timeout is exceeded, the connection is closed.
	// If this value is zero, the timeout is set to 30 seconds.
	MaxIdleTimeout time.Duration
	// AcceptToken determines if a Token is accepted.
	// It is called with token = nil if the client didn't send a token.
	// If not set, a default verification function is used:
	// * it verifies that the address matches, and
	//   * if the token is a retry token, that it was issued within the last 5 seconds
	//   * else, that it was issued within the last 24 hours.
	// This option is only valid for the server.
	AcceptToken func(clientAddr net.Addr, token *Token) bool
	// The TokenStore stores tokens received from the server.
	// Tokens are used to skip address validation on future connection attempts.
	// The key used to store tokens is the ServerName from the tls.Config, if set
	// otherwise the token is associated with the server's IP address.
	TokenStore TokenStore
	// InitialStreamReceiveWindow is the initial size of the stream-level flow control window for receiving data.
	// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
	// will increase the window up to MaxStreamReceiveWindow.
	// If this value is zero, it will default to 512 KB.
	InitialStreamReceiveWindow uint64
	// MaxStreamReceiveWindow is the maximum stream-level flow control window for receiving data.
	// If this value is zero, it will default to 6 MB.
	MaxStreamReceiveWindow uint64
	// InitialConnectionReceiveWindow is the initial size of the stream-level flow control window for receiving data.
	// If the application is consuming data quickly enough, the flow control auto-tuning algorithm
	// will increase the window up to MaxConnectionReceiveWindow.
	// If this value is zero, it will default to 512 KB.
	InitialConnectionReceiveWindow uint64
	// MaxConnectionReceiveWindow is the connection-level flow control window for receiving data.
	// If this value is zero, it will default to 15 MB.
	MaxConnectionReceiveWindow uint64
	// AllowConnectionWindowIncrease is called every time the connection flow controller attempts
	// to increase the connection flow control window.
	// If set, the caller can prevent an increase of the window. Typically, it would do so to
	// limit the memory usage.
	// To avoid deadlocks, it is not valid to call other functions on the session or on streams
	// in this callback.
	AllowConnectionWindowIncrease func(sess Session, delta uint64) bool
	// MaxIncomingStreams is the maximum number of concurrent bidirectional streams that a peer is allowed to open.
	// Values above 2^60 are invalid.
	// If not set, it will default to 100.
	// If set to a negative value, it doesn't allow any bidirectional streams.
	MaxIncomingStreams int64
	// MaxIncomingUniStreams is the maximum number of concurrent unidirectional streams that a peer is allowed to open.
	// Values above 2^60 are invalid.
	// If not set, it will default to 100.
	// If set to a negative value, it doesn't allow any unidirectional streams.
	MaxIncomingUniStreams int64
	// The StatelessResetKey is used to generate stateless reset tokens.
	// If no key is configured, sending of stateless resets is disabled.
	StatelessResetKey []byte
	// KeepAlive defines whether this peer will periodically send a packet to keep the connection alive.
	KeepAlive bool
	// DisablePathMTUDiscovery disables Path MTU Discovery (RFC 8899).
	// Packets will then be at most 1252 (IPv4) / 1232 (IPv6) bytes in size.
	// Note that if Path MTU discovery is causing issues on your system, please open a new issue
	DisablePathMTUDiscovery bool
	// DisableVersionNegotiationPackets disables the sending of Version Negotiation packets.
	// This can be useful if version information is exchanged out-of-band.
	// It has no effect for a client.
	DisableVersionNegotiationPackets bool
	// See https://datatracker.ietf.org/doc/draft-ietf-quic-datagram/.
	// Datagrams will only be available when both peers enable datagram support.
	EnableDatagrams bool
	// CongestionControlAlgo is a field to select the congestion control algorithm.
	CongestionControlAlgo congestion.CongestionAlgo
	Tracer                logging.Tracer
}

Config contains all configuration data needed for a QUIC server or client.

func (*Config) Clone added in v0.26.0

func (c *Config) Clone() *Config

Clone clones a Config

type ConnectionState added in v0.7.0

type ConnectionState struct {
	TLS               handshake.ConnectionState
	SupportsDatagrams bool
}

ConnectionState records basic details about a QUIC connection

type EarlyListener added in v0.26.0

type EarlyListener interface {
	// Close the server. All active sessions will be closed.
	Close() error
	// Addr returns the local network addr that the server is listening on.
	Addr() net.Addr
	// Accept returns new early sessions. It should be called in a loop.
	Accept(context.Context) (EarlySession, error)
}

An EarlyListener listens for incoming QUIC connections, and returns them before the handshake completes.

func ListenAddrEarly added in v0.26.0

func ListenAddrEarly(addr string, tlsConf *tls.Config, config *Config) (EarlyListener, error)

ListenAddrEarly works like ListenAddr, but it returns sessions before the handshake completes.

func ListenEarly added in v0.26.0

func ListenEarly(conn net.PacketConn, tlsConf *tls.Config, config *Config) (EarlyListener, error)

ListenEarly works like Listen, but it returns sessions before the handshake completes.

type EarlySession added in v0.26.0

type EarlySession interface {
	Session

	// HandshakeComplete blocks until the handshake completes (or fails).
	// Data sent before completion of the handshake is encrypted with 1-RTT keys.
	// Note that the client's identity hasn't been verified yet.
	HandshakeComplete() context.Context

	NextSession() Session
}

An EarlySession is a session that is handshaking. Data sent during the handshake is encrypted using the forward secure keys. When using client certificates, the client's identity is only verified after completion of the handshake.

func DialAddrEarly added in v0.26.0

func DialAddrEarly(
	addr string,
	tlsConf *tls.Config,
	config *Config,
) (EarlySession, error)

DialAddrEarly establishes a new 0-RTT QUIC connection to a server. It uses a new UDP connection and closes this connection when the QUIC session is closed. The hostname for SNI is taken from the given address. The tls.Config.CipherSuites allows setting of TLS 1.3 cipher suites.

func DialAddrEarlyContext added in v0.26.0

func DialAddrEarlyContext(
	ctx context.Context,
	addr string,
	tlsConf *tls.Config,
	config *Config,
) (EarlySession, error)

DialAddrEarlyContext establishes a new 0-RTT QUIC connection to a server using provided context. See DialAddrEarly for details

func DialEarly added in v0.26.0

func DialEarly(
	pconn net.PacketConn,
	remoteAddr net.Addr,
	host string,
	tlsConf *tls.Config,
	config *Config,
) (EarlySession, error)

DialEarly establishes a new 0-RTT QUIC connection to a server using a net.PacketConn. The same PacketConn can be used for multiple calls to Dial and Listen, QUIC connection IDs are used for demultiplexing the different connections. The host parameter is used for SNI. The tls.Config must define an application protocol (using NextProtos).

func DialEarlyContext added in v0.26.0

func DialEarlyContext(
	ctx context.Context,
	pconn net.PacketConn,
	remoteAddr net.Addr,
	host string,
	tlsConf *tls.Config,
	config *Config,
) (EarlySession, error)

DialEarlyContext establishes a new 0-RTT QUIC connection to a server using a net.PacketConn using the provided context. See DialEarly for details.

type HandshakeTimeoutError added in v0.26.0

type HandshakeTimeoutError = qerr.HandshakeTimeoutError

type IdleTimeoutError added in v0.26.0

type IdleTimeoutError = qerr.IdleTimeoutError

type Listener

type Listener interface {
	// Close the server. All active sessions will be closed.
	Close() error
	// Addr returns the local network addr that the server is listening on.
	Addr() net.Addr
	// Accept returns new sessions. It should be called in a loop.
	Accept(context.Context) (Session, error)
}

A Listener for incoming QUIC connections

func Listen

func Listen(conn net.PacketConn, tlsConf *tls.Config, config *Config) (Listener, error)

Listen listens for QUIC connections on a given net.PacketConn. If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does), ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write packets. A single net.PacketConn only be used for a single call to Listen. The PacketConn can be used for simultaneous calls to Dial. QUIC connection IDs are used for demultiplexing the different connections. The tls.Config must not be nil and must contain a certificate configuration. The tls.Config.CipherSuites allows setting of TLS 1.3 cipher suites. Furthermore, it must define an application control (using NextProtos). The quic.Config may be nil, in that case the default values will be used.

func ListenAddr

func ListenAddr(addr string, tlsConf *tls.Config, config *Config) (Listener, error)

ListenAddr creates a QUIC server listening on a given address. The tls.Config must not be nil and must contain a certificate configuration. The quic.Config may be nil, in that case the default values will be used.

type OOBCapablePacketConn added in v0.26.0

type OOBCapablePacketConn interface {
	net.PacketConn
	SyscallConn() (syscall.RawConn, error)
	ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
	WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
}

If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will read the ECN bits from the IP header. In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets.

type ReceiveStream added in v0.7.0

type ReceiveStream interface {
	// StreamID returns the stream ID.
	StreamID() StreamID
	// Read reads data from the stream.
	// Read can be made to time out and return a net.Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetReadDeadline.
	// If the stream was canceled by the peer, the error implements the StreamError
	// interface, and Canceled() == true.
	// If the session was closed due to a timeout, the error satisfies
	// the net.Error interface, and Timeout() will be true.
	io.Reader
	// CancelRead aborts receiving on this stream.
	// It will ask the peer to stop transmitting stream data.
	// Read will unblock immediately, and future Read calls will fail.
	// When called multiple times or after reading the io.EOF it is a no-op.
	CancelRead(StreamErrorCode)

	SetReadDeadline(t time.Time) error
}

A ReceiveStream is a unidirectional Receive Stream.

type SendStream added in v0.7.0

type SendStream interface {
	// StreamID returns the stream ID.
	StreamID() StreamID
	// Write writes data to the stream.
	// Write can be made to time out and return a net.Error with Timeout() == true
	// after a fixed time limit; see SetDeadline and SetWriteDeadline.
	// If the stream was canceled by the peer, the error implements the StreamError
	// interface, and Canceled() == true.
	// If the session was closed due to a timeout, the error satisfies
	// the net.Error interface, and Timeout() will be true.
	io.Writer
	// Close closes the write-direction of the stream.
	// Future calls to Write are not permitted after calling Close.
	// It must not be called concurrently with Write.
	// It must not be called after calling CancelWrite.
	io.Closer
	// CancelWrite aborts sending on this stream.
	// Data already written, but not yet delivered to the peer is not guaranteed to be delivered reliably.
	// Write will unblock immediately, and future calls to Write will fail.
	// When called multiple times or after closing the stream it is a no-op.
	CancelWrite(StreamErrorCode)
	// The Context is canceled as soon as the write-side of the stream is closed.
	// This happens when Close() or CancelWrite() is called, or when the peer
	// cancels the read-side of their stream.
	// Warning: This API should not be considered stable and might change soon.
	Context() context.Context
	// SetWriteDeadline sets the deadline for future Write calls
	// and any currently-blocked Write call.
	// Even if write times out, it may return n > 0, indicating that
	// some data was successfully written.
	// A zero value for t means Write will not time out.
	SetWriteDeadline(t time.Time) error
}

A SendStream is a unidirectional Send Stream.

type Session

type Session interface {
	// AcceptStream returns the next stream opened by the peer, blocking until one is available.
	// If the session was closed due to a timeout, the error satisfies
	// the net.Error interface, and Timeout() will be true.
	AcceptStream(context.Context) (Stream, error)
	// AcceptUniStream returns the next unidirectional stream opened by the peer, blocking until one is available.
	// If the session was closed due to a timeout, the error satisfies
	// the net.Error interface, and Timeout() will be true.
	AcceptUniStream(context.Context) (ReceiveStream, error)
	// OpenStream opens a new bidirectional QUIC stream.
	// There is no signaling to the peer about new streams:
	// The peer can only accept the stream after data has been sent on the stream.
	// If the error is non-nil, it satisfies the net.Error interface.
	// When reaching the peer's stream limit, err.Temporary() will be true.
	// If the session was closed due to a timeout, Timeout() will be true.
	OpenStream() (Stream, error)
	// OpenStreamSync opens a new bidirectional QUIC stream.
	// It blocks until a new stream can be opened.
	// If the error is non-nil, it satisfies the net.Error interface.
	// If the session was closed due to a timeout, Timeout() will be true.
	OpenStreamSync(context.Context) (Stream, error)
	// OpenUniStream opens a new outgoing unidirectional QUIC stream.
	// If the error is non-nil, it satisfies the net.Error interface.
	// When reaching the peer's stream limit, Temporary() will be true.
	// If the session was closed due to a timeout, Timeout() will be true.
	OpenUniStream() (SendStream, error)
	// OpenUniStreamSync opens a new outgoing unidirectional QUIC stream.
	// It blocks until a new stream can be opened.
	// If the error is non-nil, it satisfies the net.Error interface.
	// If the session was closed due to a timeout, Timeout() will be true.
	OpenUniStreamSync(context.Context) (SendStream, error)
	// LocalAddr returns the local address.
	LocalAddr() net.Addr
	// RemoteAddr returns the address of the peer.
	RemoteAddr() net.Addr
	// CloseWithError closes the connection with an error.
	// The error string will be sent to the peer.
	CloseWithError(ApplicationErrorCode, string) error
	// The context is cancelled when the session is closed.
	// Warning: This API should not be considered stable and might change soon.
	Context() context.Context
	// ConnectionState returns basic details about the QUIC connection.
	// It blocks until the handshake completes.
	// Warning: This API should not be considered stable and might change soon.
	ConnectionState() ConnectionState

	// SendMessage sends a message as a datagram.
	// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
	SendMessage([]byte) error
	// ReceiveMessage gets a message received in a datagram.
	// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
	ReceiveMessage() ([]byte, error)
}

A Session is a QUIC connection between two peers. Calls to the session (and to streams) can return the following types of errors: * ApplicationError: for errors triggered by the application running on top of QUIC * TransportError: for errors triggered by the QUIC transport (in many cases a misbehaving peer) * IdleTimeoutError: when the peer goes away unexpectedly (this is a net.Error timeout error) * HandshakeTimeoutError: when the cryptographic handshake takes too long (this is a net.Error timeout error) * StatelessResetError: when we receive a stateless reset (this is a net.Error temporary error) * VersionNegotiationError: returned by the client, when there's no version overlap between the peers

func Dial

func Dial(
	pconn net.PacketConn,
	remoteAddr net.Addr,
	host string,
	tlsConf *tls.Config,
	config *Config,
) (Session, error)

Dial establishes a new QUIC connection to a server using a net.PacketConn. If the PacketConn satisfies the OOBCapablePacketConn interface (as a net.UDPConn does), ECN and packet info support will be enabled. In this case, ReadMsgUDP and WriteMsgUDP will be used instead of ReadFrom and WriteTo to read/write packets. The same PacketConn can be used for multiple calls to Dial and Listen, QUIC connection IDs are used for demultiplexing the different connections. The host parameter is used for SNI. The tls.Config must define an application protocol (using NextProtos).

func DialAddr

func DialAddr(
	addr string,
	tlsConf *tls.Config,
	config *Config,
) (Session, error)

DialAddr establishes a new QUIC connection to a server. It uses a new UDP connection and closes this connection when the QUIC session is closed. The hostname for SNI is taken from the given address. The tls.Config.CipherSuites allows setting of TLS 1.3 cipher suites.

func DialAddrContext added in v0.8.0

func DialAddrContext(
	ctx context.Context,
	addr string,
	tlsConf *tls.Config,
	config *Config,
) (Session, error)

DialAddrContext establishes a new QUIC connection to a server using the provided context. See DialAddr for details.

func DialContext added in v0.8.0

func DialContext(
	ctx context.Context,
	pconn net.PacketConn,
	remoteAddr net.Addr,
	host string,
	tlsConf *tls.Config,
	config *Config,
) (Session, error)

DialContext establishes a new QUIC connection to a server using a net.PacketConn using the provided context. See Dial for details.

type StatelessResetError added in v0.26.0

type StatelessResetError = qerr.StatelessResetError

type Stream

type Stream interface {
	ReceiveStream
	SendStream
	// SetDeadline sets the read and write deadlines associated
	// with the connection. It is equivalent to calling both
	// SetReadDeadline and SetWriteDeadline.
	SetDeadline(t time.Time) error
}

Stream is the interface implemented by QUIC streams In addition to the errors listed on the Session, calls to stream functions can return a StreamError if the stream is canceled.

type StreamError added in v0.7.0

type StreamError struct {
	StreamID  StreamID
	ErrorCode StreamErrorCode
}

A StreamError is used for Stream.CancelRead and Stream.CancelWrite. It is also returned from Stream.Read and Stream.Write if the peer canceled reading or writing.

func (*StreamError) Error added in v0.26.0

func (e *StreamError) Error() string

func (*StreamError) Is added in v0.26.0

func (e *StreamError) Is(target error) bool

type StreamErrorCode added in v0.26.0

type StreamErrorCode = qerr.StreamErrorCode

type StreamID added in v0.6.0

type StreamID = protocol.StreamID

The StreamID is the ID of a QUIC stream.

type Token added in v0.26.0

type Token struct {
	// IsRetryToken encodes how the client received the token. There are two ways:
	// * In a Retry packet sent when trying to establish a new connection.
	// * In a NEW_TOKEN frame on a previous connection.
	IsRetryToken bool
	RemoteAddr   string
	SentTime     time.Time
}

A Token can be used to verify the ownership of the client address.

type TokenStore added in v0.26.0

type TokenStore interface {
	// Pop searches for a ClientToken associated with the given key.
	// Since tokens are not supposed to be reused, it must remove the token from the cache.
	// It returns nil when no token is found.
	Pop(key string) (token *ClientToken)

	// Put adds a token to the cache with the given key. It might get called
	// multiple times in a connection.
	Put(key string, token *ClientToken)
}

func NewLRUTokenStore added in v0.26.0

func NewLRUTokenStore(maxOrigins, tokensPerOrigin int) TokenStore

NewLRUTokenStore creates a new LRU cache for tokens received by the client. maxOrigins specifies how many origins this cache is saving tokens for. tokensPerOrigin specifies the maximum number of tokens per origin.

type TransportError added in v0.26.0

type TransportError = qerr.TransportError

type TransportErrorCode added in v0.26.0

type TransportErrorCode = qerr.TransportErrorCode

type VersionNegotiationError added in v0.26.0

type VersionNegotiationError = qerr.VersionNegotiationError

type VersionNumber added in v0.6.0

type VersionNumber = protocol.VersionNumber

A VersionNumber is a QUIC version number.

Directories

Path Synopsis
fuzzing
integrationtests
internal
interop
Package logging defines a logging interface for quic-go.
Package logging defines a logging interface for quic-go.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL