// 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 Negotiaion") } if got := getPacketType(gotPkt); got != packetTypeVersionNegotiation { t.Fatalf("got packet type %v; want Version Negotiaion", 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{}) }