Skip to content

goburrow/quic

Repository files navigation

Quiwi 🥝

Go Reference

QUIC transport protocol (https://quicwg.org/) implementation in Go. The goal is to provide low level APIs for applications or protocols using QUIC as a transport.

TLS 1.3 support is based on standard Go TLS package (https://github.com/golang/go/tree/master/src/crypto/tls), licensed under the 3-clause BSD license.

Features

  • Handshake with TLS 1.3
  • Version negotiation
  • Address validation
  • Loss detection
  • Congestion control
  • Streams
  • Flow control
  • ChaCha20 header protection
  • TLS session resumption
  • Anti-amplification
  • Unreliable datagram
  • qlog
  • Key update
  • Connection migration
  • Path MTU discovery
  • Zero RTT
  • HTTP/3

Development

Run tests:

go test ./...

Build command:

cd cmd/quiwi
go build

# To enable tracing
go build -tags quicdebug

# Check heap allocations
go build -gcflags '-m' 2>&1 | sort -V > debug.txt
go test -bench BenchmarkStream -run NONE -benchmem -memprofile mem.out -cpuprofile cpu.out
go tool pprof -http=:8080 mem.out

# Raspberry Pi Zero
GOOS=linux GOARCH=arm GOARM=6 CGO_ENABLED=0 go build

APIs

Package transport provides low-level APIs to control QUIC connections. Applications write input data to the connection and read output data for sending to peer.

config := transport.NewConfig()
server, err := transport.Accept(scid, odcid, config)
config := transport.NewConfig()
client, err := transport.Connect(scid, dcid, config)
for !conn.IsClosed() { // Loop until the connection is closed
	timeout := conn.Timeout()
	// (A negative timeout means that the timer should be disarmed)
	select {
		case data := <-dataChanel:  // Got data from peer
			n, err := conn.Write(data)
		case <-time.After(timeout): // Got receiving timeout
			n, err := conn.Write(nil)
	}
	// Get and process connection events
	events = conn.Events(events)
	for { // Loop until err != nil or n == 0
		n, err := conn.Read(buf)
		// Send buf[:n] to peer
	}
}

The root package quic instead provides high-level APIs where QUIC data are transferred over UDP. It also handles version negotiation, address validation and logging.

server := quic.NewServer(config)
server.SetHandler(handler)
err := server.ListenAndServe(address)
client := quic.NewClient(config)
client.SetHandler(handler)
err := client.ListenAndServe(address)
err = client.Connect(serverAddress)
// wait
client.Close()

Applications get connection events in the handler to control QUIC connections:

func (handler) Serve(conn *quic.Conn, events []transport.Event) {
	for _, e := range events {
		switch e.Type {
		case transport.EventConnOpen:
		case transport.EventConnClosed:
		}
	}
}

Server

See cmd/quiwi/server.go

Usage: quiwi server [arguments]
  -cache string
    	certificate cache directory when using ACME (default ".")
  -cert string
    	TLS certificate path
  -domains string
    	allowed host names for ACME (separated by a comma)
  -key string
    	TLS certificate key path
  -listen string
    	listen on the given IP:port (default ":4433")
  -qlog string
    	write logs to qlog file
  -retry
    	enable address validation using Retry packet
  -root string
    	root directory (default "www")
  -v int
    	log verbose: 0=off 1=error 2=info 3=debug 4=trace (default 2)

Examples:

# Listen on port 4433:
./quiwi server -cert ../../testdata/cert.pem -key ../../testdata/key.pem

# Automatically get certificate from Let's Encrypt:
# (This will also listen on TCP port 443 to handle "tls-alpn-01" challenge)
./quiwi server -domains example.com

Add SSLKEYLOGFILE=key.log to have TLS keys logged to file.

Client

See cmd/quiwi/client.go

Usage: quiwi client [arguments] <url>
  -cipher string
    	TLS 1.3 cipher suite, e.g. TLS_CHACHA20_POLY1305_SHA256
  -insecure
    	skip verifying server certificate
  -listen string
    	listen on the given IP:port (default "0.0.0.0:0")
  -qlog string
    	write logs to qlog file
  -root string
    	root download directory
  -v int
    	log verbose: 0=off 1=error 2=info 3=debug 4=trace (default 2)

Examples

./quiwi client https://quic.tech:4433/

./quiwi client -insecure https://localhost:4433/file.txt

Datagram

See cmd/quiwi/datagram.go

Usage: quiwi datagram [arguments] [url]
  -cert string
    	TLS certificate path (server only) (default "cert.pem")
  -data string
    	Datagram for sending (or from stdin if empty)
  -insecure
    	skip verifying server certificate (client only)
  -key string
    	TLS certificate key path (server only) (default "key.pem")
  -listen string
    	listen on the given IP:port (default "0.0.0.0:0")
  -v int
    	log verbose: 0=off 1=error 2=info 3=debug 4=trace (default 2)

Examples:

# Server
./quiwi datagram -listen 127.0.0.1:4433

# Client
./quiwi datagram -insecure -data hello https://127.0.0.1:4433

Testing

See interop/README.md

Fuzzing

See https://github.com/goburrow/quic-fuzz