Skip to content

Commit

Permalink
use the new crypto/tls QUIC Transport
Browse files Browse the repository at this point in the history
  • Loading branch information
marten-seemann committed Jun 24, 2023
1 parent 21388c8 commit b2f96dc
Show file tree
Hide file tree
Showing 54 changed files with 2,079 additions and 1,502 deletions.
12 changes: 1 addition & 11 deletions .circleci/config.yml
@@ -1,11 +1,5 @@
version: 2.1
executors:
test-go119:
docker:
- image: "cimg/go:1.19"
environment:
runrace: true
TIMESCALE_FACTOR: 3
test-go120:
docker:
- image: "cimg/go:1.20"
Expand All @@ -15,7 +9,7 @@ executors:

jobs:
"test": &test
executor: test-go119
executor: test-go120
steps:
- checkout
- run:
Expand All @@ -39,14 +33,10 @@ jobs:
- run:
name: "Run version negotiation tests with qlog"
command: go run github.com/onsi/ginkgo/v2/ginkgo -v -randomize-all -trace integrationtests/versionnegotiation -- -qlog
go119:
<<: *test
go120:
<<: *test
executor: test-go120

workflows:
workflow:
jobs:
- go119
- go120
2 changes: 1 addition & 1 deletion .github/workflows/cross-compile.yml
Expand Up @@ -4,7 +4,7 @@ jobs:
strategy:
fail-fast: false
matrix:
go: [ "1.19.x", "1.20.x" ]
go: [ "1.20.x", "1.21.0-rc.2" ]
runs-on: ${{ fromJSON(vars['CROSS_COMPILE_RUNNER_UBUNTU'] || '"ubuntu-latest"') }}
name: "Cross Compilation (Go ${{matrix.go}})"
steps:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/integration.yml
Expand Up @@ -5,7 +5,7 @@ jobs:
strategy:
fail-fast: false
matrix:
go: [ "1.19.x", "1.20.x" ]
go: [ "1.20.x", "1.21.0-rc.2" ]
runs-on: ${{ fromJSON(vars['INTEGRATION_RUNNER_UBUNTU'] || '"ubuntu-latest"') }}
env:
DEBUG: false # set this to true to export qlogs and save them as artifacts
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/unit.yml
Expand Up @@ -7,7 +7,7 @@ jobs:
fail-fast: false
matrix:
os: [ "ubuntu", "windows", "macos" ]
go: [ "1.19.x", "1.20.x" ]
go: [ "1.20.x", "1.21.0-rc.2" ]
runs-on: ${{ fromJSON(vars[format('UNIT_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }}
name: Unit tests (${{ matrix.os}}, Go ${{ matrix.go }})
steps:
Expand Down
2 changes: 2 additions & 0 deletions .golangci.yml
@@ -1,4 +1,6 @@
run:
skip-files:
- internal/handshake/cipher_suite.go
linters-settings:
depguard:
type: blacklist
Expand Down
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -220,7 +220,8 @@ quic-go always aims to support the latest two Go releases.

### Dependency on forked crypto/tls

Since the standard library didn't provide any QUIC APIs before the Go 1.21 release, we had to fork crypto/tls to add the required APIs ourselves: [qtls for Go 1.20](https://github.com/quic-go/qtls-go1-20) and [qtls for Go 1.19](https://github.com/quic-go/qtls-go1-19). This had led to a lot of pain in the Go ecosystem, and we're happy that we can rely on Go 1.21 going forward.
Since the standard library didn't provide any QUIC APIs before the Go 1.21 release, we had to fork crypto/tls to add the required APIs ourselves: [qtls for Go 1.20](https://github.com/quic-go/qtls-go1-20).
This had led to a lot of pain in the Go ecosystem, and we're happy that we can rely on Go 1.21 going forward.

## Contributing

Expand Down
1 change: 1 addition & 0 deletions codecov.yml
Expand Up @@ -8,6 +8,7 @@ coverage:
- http3/gzip_reader.go
- interop/
- internal/ackhandler/packet_linkedlist.go
- internal/handshake/cipher_suite.go
- internal/utils/byteinterval_linkedlist.go
- internal/utils/newconnectionid_linkedlist.go
- internal/utils/packetinterval_linkedlist.go
Expand Down
66 changes: 34 additions & 32 deletions connection.go
Expand Up @@ -52,7 +52,7 @@ type streamManager interface {
}

type cryptoStreamHandler interface {
RunHandshake()
StartHandshake() error
ChangeConnectionID(protocol.ConnectionID)
SetLargest1RTTAcked(protocol.PacketNumber) error
SetHandshakeConfirmed()
Expand Down Expand Up @@ -98,15 +98,15 @@ type connRunner interface {

type handshakeRunner struct {
onReceivedParams func(*wire.TransportParameters)
onError func(error)
onReceivedReadKeys func()
dropKeys func(protocol.EncryptionLevel)
onHandshakeComplete func()
}

func (r *handshakeRunner) OnReceivedParams(tp *wire.TransportParameters) { r.onReceivedParams(tp) }
func (r *handshakeRunner) OnError(e error) { r.onError(e) }
func (r *handshakeRunner) DropKeys(el protocol.EncryptionLevel) { r.dropKeys(el) }
func (r *handshakeRunner) OnHandshakeComplete() { r.onHandshakeComplete() }
func (r *handshakeRunner) OnReceivedReadKeys() { r.onReceivedReadKeys() }

type closeError struct {
err error
Expand Down Expand Up @@ -329,14 +329,13 @@ var newConnection = func(
cs := handshake.NewCryptoSetupServer(
initialStream,
handshakeStream,
s.oneRTTStream,
clientDestConnID,
conn.LocalAddr(),
conn.RemoteAddr(),
params,
&handshakeRunner{
onReceivedParams: s.handleTransportParameters,
onError: s.closeLocal,
dropKeys: s.dropEncryptionLevel,
onReceivedParams: s.handleTransportParameters,
dropKeys: s.dropEncryptionLevel,
onReceivedReadKeys: s.receivedReadKeys,
onHandshakeComplete: func() {
runner.Retire(clientDestConnID)
close(s.handshakeCompleteChan)
Expand Down Expand Up @@ -418,6 +417,7 @@ var newClientConnection = func(
s.mtuDiscoverer = newMTUDiscoverer(s.rttStats, getMaxPacketSize(s.conn.RemoteAddr()), s.sentPacketHandler.SetMaxDatagramSize)
initialStream := newCryptoStream()
handshakeStream := newCryptoStream()
oneRTTStream := newCryptoStream()
params := &wire.TransportParameters{
InitialMaxStreamDataBidiRemote: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
InitialMaxStreamDataBidiLocal: protocol.ByteCount(s.config.InitialStreamReceiveWindow),
Expand Down Expand Up @@ -448,14 +448,13 @@ var newClientConnection = func(
cs, clientHelloWritten := handshake.NewCryptoSetupClient(
initialStream,
handshakeStream,
oneRTTStream,
destConnID,
conn.LocalAddr(),
conn.RemoteAddr(),
params,
&handshakeRunner{
onReceivedParams: s.handleTransportParameters,
onError: s.closeLocal,
dropKeys: s.dropEncryptionLevel,
onReceivedReadKeys: s.receivedReadKeys,
onHandshakeComplete: func() { close(s.handshakeCompleteChan) },
},
tlsConf,
Expand All @@ -467,7 +466,7 @@ var newClientConnection = func(
)
s.clientHelloWritten = clientHelloWritten
s.cryptoStreamHandler = cs
s.cryptoStreamManager = newCryptoStreamManager(cs, initialStream, handshakeStream, newCryptoStream())
s.cryptoStreamManager = newCryptoStreamManager(cs, initialStream, handshakeStream, oneRTTStream)
s.unpacker = newPacketUnpacker(cs, s.srcConnIDLen)
s.packer = newPacketPacker(srcConnID, s.connIDManager.Get, initialStream, handshakeStream, s.sentPacketHandler, s.retransmissionQueue, cs, s.framer, s.receivedPacketHandler, s.datagramQueue, s.perspective)
if len(tlsConf.ServerName) > 0 {
Expand Down Expand Up @@ -530,11 +529,9 @@ func (s *connection) run() error {

s.timer = *newTimer()

handshaking := make(chan struct{})
go func() {
defer close(handshaking)
s.cryptoStreamHandler.RunHandshake()
}()
if err := s.cryptoStreamHandler.StartHandshake(); err != nil {
return err
}
go func() {
if err := s.sendQueue.Run(); err != nil {
s.destroyImpl(err)
Expand Down Expand Up @@ -686,7 +683,6 @@ runLoop:
}

s.cryptoStreamHandler.Close()
<-handshaking
s.sendQueue.Close() // close the send queue before sending the CONNECTION_CLOSE
s.handleCloseError(&closeErr)
if e := (&errCloseForRecreating{}); !errors.As(closeErr.err, &e) && s.tracer != nil {
Expand Down Expand Up @@ -717,7 +713,9 @@ func (s *connection) supportsDatagrams() bool {
func (s *connection) ConnectionState() ConnectionState {
s.connStateMutex.Lock()
defer s.connStateMutex.Unlock()
s.connState.TLS = s.cryptoStreamHandler.ConnectionState()
cs := s.cryptoStreamHandler.ConnectionState()
s.connState.TLS = cs.ConnectionState
s.connState.Used0RTT = cs.Used0RTT
return s.connState
}

Expand Down Expand Up @@ -786,7 +784,7 @@ func (s *connection) handleHandshakeComplete() {
if err != nil {
s.closeLocal(err)
}
if ticket != nil {
if ticket != nil { // may be nil if session tickets are disabled via tls.Config.SessionTicketsDisabled
s.oneRTTStream.Write(ticket)
for s.oneRTTStream.HasData() {
s.queueControlFrame(s.oneRTTStream.PopCryptoFrame(protocol.MaxPostHandshakeCryptoFrameSize))
Expand Down Expand Up @@ -1378,16 +1376,13 @@ func (s *connection) handleConnectionCloseFrame(frame *wire.ConnectionCloseFrame
}

func (s *connection) handleCryptoFrame(frame *wire.CryptoFrame, encLevel protocol.EncryptionLevel) error {
encLevelChanged, err := s.cryptoStreamManager.HandleCryptoFrame(frame, encLevel)
if err != nil {
return err
}
if encLevelChanged {
// Queue all packets for decryption that have been undecryptable so far.
s.undecryptablePacketsToProcess = s.undecryptablePackets
s.undecryptablePackets = nil
}
return nil
return s.cryptoStreamManager.HandleCryptoFrame(frame, encLevel)
}

func (s *connection) receivedReadKeys() {
// Queue all packets for decryption that have been undecryptable so far.
s.undecryptablePacketsToProcess = s.undecryptablePackets
s.undecryptablePackets = nil
}

func (s *connection) handleStreamFrame(frame *wire.StreamFrame) error {
Expand Down Expand Up @@ -1629,11 +1624,15 @@ func (s *connection) handleCloseError(closeErr *closeError) {
}

func (s *connection) dropEncryptionLevel(encLevel protocol.EncryptionLevel) {
s.sentPacketHandler.DropPackets(encLevel)
s.receivedPacketHandler.DropPackets(encLevel)
if s.tracer != nil {
s.tracer.DroppedEncryptionLevel(encLevel)
}
s.sentPacketHandler.DropPackets(encLevel)
s.receivedPacketHandler.DropPackets(encLevel)
if err := s.cryptoStreamManager.Drop(encLevel); err != nil {
s.closeLocal(err)
return
}
if encLevel == protocol.Encryption0RTT {
s.streamsMap.ResetFor0RTT()
if err := s.connFlowController.Reset(); err != nil {
Expand Down Expand Up @@ -1817,6 +1816,9 @@ func (s *connection) sendPackets(now time.Time) error {
s.framer.QueueControlFrame(&wire.DataBlockedFrame{MaximumData: offset})
}
s.windowUpdateQueue.QueueAll()
if cf := s.cryptoStreamManager.GetPostHandshakeData(protocol.MaxPostHandshakeCryptoFrameSize); cf != nil {
s.queueControlFrame(cf)
}

if !s.handshakeConfirmed {
packet, err := s.packer.PackCoalescedPacket(false, s.mtuDiscoverer.CurrentSize(), s.version)
Expand Down

0 comments on commit b2f96dc

Please sign in to comment.