blob: 0bd8bac14b3218e15b8ce3979bb80ae99abb75e8 [file] [log] [blame]
// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21
package quic
import (
"bytes"
"context"
"crypto/tls"
"testing"
)
func TestVersionNegotiationServerReceivesUnknownVersion(t *testing.T) {
config := &Config{
TLSConfig: newTestTLSConfig(serverSide),
}
te := newTestEndpoint(t, config)
// Packet of unknown contents for some unrecognized QUIC version.
dstConnID := []byte{1, 2, 3, 4}
srcConnID := []byte{5, 6, 7, 8}
pkt := []byte{
0b1000_0000,
0x00, 0x00, 0x00, 0x0f,
}
pkt = append(pkt, byte(len(dstConnID)))
pkt = append(pkt, dstConnID...)
pkt = append(pkt, byte(len(srcConnID)))
pkt = append(pkt, srcConnID...)
for len(pkt) < paddedInitialDatagramSize {
pkt = append(pkt, 0)
}
te.write(&datagram{
b: pkt,
})
gotPkt := te.read()
if gotPkt == nil {
t.Fatalf("got no response; want Version Negotiation")
}
if got := getPacketType(gotPkt); got != packetTypeVersionNegotiation {
t.Fatalf("got packet type %v; want Version Negotiation", got)
}
gotDst, gotSrc, versions := parseVersionNegotiation(gotPkt)
if got, want := gotDst, srcConnID; !bytes.Equal(got, want) {
t.Errorf("got Destination Connection ID %x, want %x", got, want)
}
if got, want := gotSrc, dstConnID; !bytes.Equal(got, want) {
t.Errorf("got Source Connection ID %x, want %x", got, want)
}
if got, want := versions, []byte{0, 0, 0, 1}; !bytes.Equal(got, want) {
t.Errorf("got Supported Version %x, want %x", got, want)
}
}
func TestVersionNegotiationClientAborts(t *testing.T) {
tc := newTestConn(t, clientSide)
p := tc.readPacket() // client Initial packet
tc.endpoint.write(&datagram{
b: appendVersionNegotiation(nil, p.srcConnID, p.dstConnID, 10),
})
tc.wantIdle("connection does not send a CONNECTION_CLOSE")
if err := tc.conn.waitReady(canceledContext()); err != errVersionNegotiation {
t.Errorf("conn.waitReady() = %v, want errVersionNegotiation", err)
}
}
func TestVersionNegotiationClientIgnoresAfterProcessingPacket(t *testing.T) {
tc := newTestConn(t, clientSide)
tc.ignoreFrame(frameTypeAck)
p := tc.readPacket() // client Initial packet
tc.writeFrames(packetTypeInitial,
debugFrameCrypto{
data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial],
})
tc.endpoint.write(&datagram{
b: appendVersionNegotiation(nil, p.srcConnID, p.dstConnID, 10),
})
if err := tc.conn.waitReady(canceledContext()); err != context.Canceled {
t.Errorf("conn.waitReady() = %v, want context.Canceled", err)
}
tc.writeFrames(packetTypeHandshake,
debugFrameCrypto{
data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake],
})
tc.wantFrameType("conn ignores Version Negotiation and continues with handshake",
packetTypeHandshake, debugFrameCrypto{})
}
func TestVersionNegotiationClientIgnoresMismatchingSourceConnID(t *testing.T) {
tc := newTestConn(t, clientSide)
tc.ignoreFrame(frameTypeAck)
p := tc.readPacket() // client Initial packet
tc.endpoint.write(&datagram{
b: appendVersionNegotiation(nil, p.srcConnID, []byte("mismatch"), 10),
})
tc.writeFrames(packetTypeInitial,
debugFrameCrypto{
data: tc.cryptoDataIn[tls.QUICEncryptionLevelInitial],
})
tc.writeFrames(packetTypeHandshake,
debugFrameCrypto{
data: tc.cryptoDataIn[tls.QUICEncryptionLevelHandshake],
})
tc.wantFrameType("conn ignores Version Negotiation and continues with handshake",
packetTypeHandshake, debugFrameCrypto{})
}