minq

package module
v0.0.0-...-a5bd852 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2019 License: MIT Imports: 22 Imported by: 3

README

WARNING

This implementation is not under active development, and has diverged from the QUIC specification.

The QUIC WG maintains a list of active implementations.

A mink forming a Q


minq -- A minimal QUIC stack

Minq is a minimal implementation of QUIC, as documented at https://quicwg.github.io/. Minq partly implements draft-05 (it advertises -04 but it's actually more like the editor's copy) with TLS 1.3 draft-20 or draft-21.

Currently it will do:

  • A 1-RTT handshake (with self-generated and unverified certificates)
  • Some ACK processing
  • Primitive retransmission (manual, no timers)
  • 1-RTT application data
  • Exchange of stream close (though this doesn't really have much impact)

Important missing pieces for the first implementation draft include:

  • Handling ACK ranges
  • Real timeout and retransmission support

Other defects include:

  • Doesn't properly clean up state, so things will just grow without bound
  • TLS configuration and verification
  • A huge other pile of unknown and known defects.

WARNING

Minq is absolutely not suitable for any kind of production use and should only be used for testing. In particular, it explicitly doesn't validate certificates.

Quick Start (untested but should be rightish)

cd ${GOPATH}/src
go get github.com/ekr/minq
cd github.com/bifurcation/mint
git remote add ekr https://github.com/ekr/mint
git fetch ekr
git checkout ekr/quic_record_layer
cd ../../ekr/minq
go test

This should produce something like this:

Result =  010002616263
Result2 =  010002616263
Result =  0102616263
Result2 =  0102616263
{1 2 [97 98 99]}
{1 1 [8 16]}
{3 2 [8 16 24 32]}
Checking client state
Checking server state
Encoded frame  ab00deadbeef0000000000000001
Encoded frame  bb0100deadbeef00000000000000010e00000001
Result =  820123456789abcdefdeadbeefff000001
Result2 =  820123456789abcdefdeadbeefff000001
PASS
ok  	github.com/ekr/minq	1.285s

It's the "ok" at the end that's important.

There are two test programs that live in minq/bin/client and minq/bin/server. The server is an echo server that upcases the returned data. The client is just a passthrough.

In ${GOPATH}/src/github.com/ekr, doing

go run minq/bin/server/main.go
go run minq/bin/client/main.go

In separate windows should have the desired result.

Logging

To enable logging, set the MINQ_LOG environment variable, as in MINQ_LOG=connection go test. Valid values are:

// Pre-defined log types
const (
	logTypeAead       = "aead"
	logTypeCodec      = "codec"
	logTypeConnBuffer = "connbuffer"
	logTypeConnection = "connection"
	logTypeAck        = "ack"
	logTypeFrame      = "frame"
	logTypeHandshake  = "handshake"
	logTypeTls        = "tls"
	logTypeTrace      = "trace"
	logTypeServer     = "server"
	logTypeUdp        = "udp"
)

Multiple log levels can be separated by commas.

Mint

Minq depends on Mint (https://www.github.com/bifurcation/mint) for TLS. Right now we are on the following branch:

https://github.com/ekr/mint/tree/quic_record_layer

This branch is more experimental than usual.

Documentation

Overview

Package minq is a minimal implementation of QUIC, as documented at https://quicwg.github.io/. Minq partly implements draft-04.

Package minq is a minimal implementation of QUIC, as documented at https://quicwg.github.io/. Minq partly implements draft-04.

Internal structure indicating packets we have received

Index

Constants

View Source
const (
	RoleClient = Role(1)
	RoleServer = Role(2)
)

These are roles.

View Source
const (
	StateInit                   = State(1)
	StateWaitClientInitial      = State(2)
	StateWaitServerInitial      = State(3)
	StateWaitServerFirstFlight  = State(4)
	StateWaitClientSecondFlight = State(5)
	StateEstablished            = State(6)
	StateClosing                = State(7)
	StateClosed                 = State(8)
	StateError                  = State(9)
)

These are connection states.

View Source
const (
	SendStreamStateOpen        = SendStreamState(0)
	SendStreamStateSend        = SendStreamState(1)
	SendStreamStateCloseQueued = SendStreamState(2) // Not in the spec
	SendStreamStateDataSent    = SendStreamState(3)
	SendStreamStateResetSent   = SendStreamState(4)
	SendStreamStateDataRecvd   = SendStreamState(5) // Not tracked
	SendStreamStateResetRecvd  = SendStreamState(6) // Not tracked
)

SendStreamState values. Not all of these are tracked

View Source
const (
	RecvStreamStateRecv       = RecvStreamState(0)
	RecvStreamStateSizeKnown  = RecvStreamState(1)
	RecvStreamStateDataRecvd  = RecvStreamState(2) // Not tracked
	RecvStreamStateResetRecvd = RecvStreamState(3)
	RecvStreamStateDataRead   = RecvStreamState(4)
	RecvStreamStateResetRead  = RecvStreamState(5)
)

RecvStreamState values. Not all of these are tracked.

Variables

View Source
var ErrorConnIsClosed = fatalError("Connection is closed")
View Source
var ErrorConnIsClosing = nonFatalError("Connection is closing")
View Source
var ErrorConnectionTimedOut = fatalError("Connection timed out")
View Source
var ErrorDestroyConnection = fatalError("Terminate connection")
View Source
var ErrorFlowControlError = fatalError("Flow control error")
View Source
var ErrorFrameFormatError = fatalError("Frame format error")
View Source
var ErrorInvalidEncoding = fatalError("Invalid encoding")
View Source
var ErrorInvalidPacket = nonFatalError("Invalid packet")
View Source
var ErrorMissingValue = fatalError("Expected value is missing")
View Source
var ErrorProtocolViolation = fatalError("Protocol violation")
View Source
var ErrorReceivedVersionNegotiation = fatalError("Received a version negotiation packet advertising a different version than ours")
View Source
var ErrorStreamIsClosed = fatalError("Stream is closed")
View Source
var ErrorStreamReset = fatalError("Stream was reset")
View Source
var ErrorWouldBlock = nonFatalError("Would have blocked (QUIC)")

Return codes.

Functions

func SetLogOutput

func SetLogOutput(f func(string, ...interface{}))

Types

type CongestionController

type CongestionController interface {
	// contains filtered or unexported methods
}

type CongestionControllerDummy

type CongestionControllerDummy struct {
}

type CongestionControllerIetf

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

type Connection

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

func NewConnection

func NewConnection(trans Transport, role Role, tls *TlsConfig, handler ConnectionHandler) *Connection

Create a new QUIC connection. Should only be used with role=RoleClient, though we use it with RoleServer internally.

func (*Connection) CheckTimer

func (c *Connection) CheckTimer() (int, error)

Check the connection's timer and process any events whose time has expired in the meantime. This includes sending retransmits, etc.

func (*Connection) ClientId

func (c *Connection) ClientId() ConnectionId

ClientId returns the current identity, as dictated by the client.

func (*Connection) Close

func (c *Connection) Close() error

Close a connection.

func (*Connection) CreateSendStream

func (c *Connection) CreateSendStream() SendStream

CreateSendStream creates a stream that can send only.

func (*Connection) CreateStream

func (c *Connection) CreateStream() Stream

CreateStream creates a stream that can send and receive.

func (*Connection) Error

func (c *Connection) Error(appError uint16, reason string) error

func (*Connection) GetRecvStream

func (c *Connection) GetRecvStream(id uint64) RecvStream

GetRecvStream retrieves a stream with the given id. Returns nil if no such stream exists.

func (*Connection) GetSendStream

func (c *Connection) GetSendStream(id uint64) SendStream

GetSendStream retrieves a stream with the given id. Returns nil if no such stream exists.

func (*Connection) GetState

func (c *Connection) GetState() State

Get the current state of a connection.

func (*Connection) GetStream

func (c *Connection) GetStream(id uint64) Stream

GetStream retrieves a stream with the given id. Returns nil if no such stream exists.

func (*Connection) Input

func (c *Connection) Input(p []byte) error

Input provides a packet to the connection.

TODO(ekr@rtfm.com): when is error returned?

func (*Connection) Role

func (c *Connection) Role() Role

func (*Connection) ServerId

func (c *Connection) ServerId() ConnectionId

ServerId returns the current identity, as dictated by the server.

func (*Connection) SetHandler

func (c *Connection) SetHandler(h ConnectionHandler)

Set the handler class for a given connection.

func (*Connection) String

func (c *Connection) String() string

func (*Connection) Writable

func (c *Connection) Writable() bool

type ConnectionHandler

type ConnectionHandler interface {
	// The connection has changed state to state |s|
	StateChanged(s State)

	// NewRecvStream indicates that a new unidirectional stream has been
	// created by the remote peer. |s| contains the stream.
	NewRecvStream(s RecvStream)

	// NewStream indicates that a new bidirectional stream has been
	// created by the remote peer. |s| contains the stream.
	NewStream(s Stream)

	// StreamReadable indicates that |s| is now readable.
	StreamReadable(s RecvStream)
}

Interface for the handler object which the Connection will call to notify of events on the connection.

type ConnectionId

type ConnectionId []byte

ConnectionId identifies the connection that a packet belongs to.

func (ConnectionId) EncodeLength

func (c ConnectionId) EncodeLength() byte

EncodeLength produces the length encoding used in the long packet header.

func (ConnectionId) String

func (c ConnectionId) String() string

String stringifies a connection ID in the natural way.

type ErrorCode

type ErrorCode uint16

Protocol errors

type RecordLayerFactoryImpl

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

func (*RecordLayerFactoryImpl) NewLayer

type RecordLayerImpl

type RecordLayerImpl struct {
	sync.Mutex
	// contains filtered or unexported fields
}

func (*RecordLayerImpl) DiscardReadKey

func (r *RecordLayerImpl) DiscardReadKey(epoch mint.Epoch)

func (*RecordLayerImpl) Epoch

func (r *RecordLayerImpl) Epoch() mint.Epoch

func (*RecordLayerImpl) PeekRecordType

func (r *RecordLayerImpl) PeekRecordType(block bool) (mint.RecordType, error)

func (*RecordLayerImpl) ReadRecord

func (r *RecordLayerImpl) ReadRecord() (*mint.TLSPlaintext, error)

func (*RecordLayerImpl) Rekey

func (r *RecordLayerImpl) Rekey(epoch mint.Epoch, factory mint.AeadFactory, keys *mint.KeySet) error

func (*RecordLayerImpl) ResetClear

func (r *RecordLayerImpl) ResetClear(seq uint64)

func (*RecordLayerImpl) SetLabel

func (r *RecordLayerImpl) SetLabel(s string)

func (*RecordLayerImpl) SetVersion

func (r *RecordLayerImpl) SetVersion(v uint16)

func (*RecordLayerImpl) WriteRecord

func (r *RecordLayerImpl) WriteRecord(pt *mint.TLSPlaintext) error

type RecvStream

type RecvStream interface {
	// contains filtered or unexported methods
}

RecvStream can receive.

type RecvStreamState

type RecvStreamState uint8

RecvStreamState is the state of a RecvStream

func (RecvStreamState) String

func (s RecvStreamState) String() string

String produces a nice string from a RecvStreamState.

type Role

type Role uint8

Role determines whether an endpoint is client or server.

func (Role) String

func (r Role) String() string

type SendStream

type SendStream interface {
	// contains filtered or unexported methods
}

SendStream can send.

type SendStreamState

type SendStreamState uint8

SendStreamState is the state of a SendStream

func (SendStreamState) String

func (s SendStreamState) String() string

String produces a nice string from a SendStreamState.

type Server

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

Server represents a QUIC server. A server can be fed an arbitrary number of packets and will create Connections as needed, passing each packet to the right connection.

func NewServer

func NewServer(factory TransportFactory, tls *TlsConfig, handler ServerHandler) *Server

Create a new QUIC server with the provide TLS config.

func (*Server) CheckTimer

func (s *Server) CheckTimer() error

Check the server timers.

func (*Server) ConnectionCount

func (s *Server) ConnectionCount() int

How many connections do we have?

func (*Server) Input

func (s *Server) Input(addr *net.UDPAddr, data []byte) (*Connection, error)

Input passes an incoming packet to the Server.

func (*Server) SetHandler

func (s *Server) SetHandler(h ServerHandler)

SetHandler sets a handler function.

type ServerHandler

type ServerHandler interface {
	// A new connection has been created and can be found in |c|.
	NewConnection(c *Connection)
}

Interface for the handler object which the Server will call to notify of events.

type State

type State uint8

State is the state of a QUIC connection.

func (State) String

func (state State) String() string

type Stream

type Stream interface {
	// contains filtered or unexported methods
}

Stream is both a send and receive stream.

type TlsConfig

type TlsConfig struct {
	ServerName       string
	CertificateChain []*x509.Certificate
	Key              crypto.Signer

	ForceHrr bool
	// contains filtered or unexported fields
}

func NewTlsConfig

func NewTlsConfig(serverName string) TlsConfig

type Transport

type Transport interface {
	Send(p []byte) error
}

Interface for an object to send packets. Each Transport is bound to some particular remote address (or in testing we just use a mock which sends the packet into a queue).

type TransportFactory

type TransportFactory interface {
	// Make a transport object bound to |remote|.
	MakeTransport(remote *net.UDPAddr) (Transport, error)
}

TransportFactory makes transports bound to a specific remote address.

type TransportParameterId

type TransportParameterId uint16

type TransportParameterList

type TransportParameterList []transportParameter

type UdpTransport

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

func NewUdpTransport

func NewUdpTransport(u *net.UDPConn, r *net.UDPAddr) *UdpTransport

func (*UdpTransport) Send

func (t *UdpTransport) Send(p []byte) error

type UdpTransportFactory

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

func NewUdpTransportFactory

func NewUdpTransportFactory(sock *net.UDPConn) *UdpTransportFactory

func (*UdpTransportFactory) MakeTransport

func (f *UdpTransportFactory) MakeTransport(remote *net.UDPAddr) (Transport, error)

type VersionNumber

type VersionNumber uint32

The protocol version number.

Directories

Path Synopsis
bin

Jump to

Keyboard shortcuts

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