mirror of
https://github.com/golang/net.git
synced 2026-03-31 02:17:08 +09:00
The x/net go.mod now depends on go1.23. Change-Id: I24960949d84753f84f75fbdc97b7dfb92191a4d2 Reviewed-on: https://go-review.googlesource.com/c/net/+/664295 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jonathan Amsterdam <jba@google.com> Auto-Submit: Damien Neil <dneil@google.com>
246 lines
6.5 KiB
Go
246 lines
6.5 KiB
Go
// 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.
|
|
|
|
package quic
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"encoding/hex"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestPacketHeader(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
packet []byte
|
|
isLongHeader bool
|
|
packetType packetType
|
|
dstConnID []byte
|
|
}{{
|
|
// Initial packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.1
|
|
// (truncated)
|
|
name: "rfc9001_a1",
|
|
packet: unhex(`
|
|
c000000001088394c8f03e5157080000 449e7b9aec34d1b1c98dd7689fb8ec11
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeInitial,
|
|
dstConnID: unhex(`8394c8f03e515708`),
|
|
}, {
|
|
// Initial packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.3
|
|
// (truncated)
|
|
name: "rfc9001_a3",
|
|
packet: unhex(`
|
|
cf000000010008f067a5502a4262b500 4075c0d95a482cd0991cd25b0aac406a
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeInitial,
|
|
dstConnID: []byte{},
|
|
}, {
|
|
// Retry packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.4
|
|
name: "rfc9001_a4",
|
|
packet: unhex(`
|
|
ff000000010008f067a5502a4262b574 6f6b656e04a265ba2eff4d829058fb3f
|
|
0f2496ba
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeRetry,
|
|
dstConnID: []byte{},
|
|
}, {
|
|
// Short header packet from https://www.rfc-editor.org/rfc/rfc9001#section-a.5
|
|
name: "rfc9001_a5",
|
|
packet: unhex(`
|
|
4cfe4189655e5cd55c41f69080575d7999c25a5bfb
|
|
`),
|
|
isLongHeader: false,
|
|
packetType: packetType1RTT,
|
|
dstConnID: unhex(`fe4189655e5cd55c`),
|
|
}, {
|
|
// Version Negotiation packet.
|
|
name: "version_negotiation",
|
|
packet: unhex(`
|
|
80 00000000 01ff0001020304
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeVersionNegotiation,
|
|
dstConnID: []byte{0xff},
|
|
}, {
|
|
// Too-short packet.
|
|
name: "truncated_after_connid_length",
|
|
packet: unhex(`
|
|
cf0000000105
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeInitial,
|
|
dstConnID: nil,
|
|
}, {
|
|
// Too-short packet.
|
|
name: "truncated_after_version",
|
|
packet: unhex(`
|
|
cf00000001
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeInitial,
|
|
dstConnID: nil,
|
|
}, {
|
|
// Much too short packet.
|
|
name: "truncated_in_version",
|
|
packet: unhex(`
|
|
cf000000
|
|
`),
|
|
isLongHeader: true,
|
|
packetType: packetTypeInvalid,
|
|
dstConnID: nil,
|
|
}} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
if got, want := isLongHeader(test.packet[0]), test.isLongHeader; got != want {
|
|
t.Errorf("packet %x:\nisLongHeader(packet) = %v, want %v", test.packet, got, want)
|
|
}
|
|
if got, want := getPacketType(test.packet), test.packetType; got != want {
|
|
t.Errorf("packet %x:\ngetPacketType(packet) = %v, want %v", test.packet, got, want)
|
|
}
|
|
gotConnID, gotOK := dstConnIDForDatagram(test.packet)
|
|
wantConnID, wantOK := test.dstConnID, test.dstConnID != nil
|
|
if !bytes.Equal(gotConnID, wantConnID) || gotOK != wantOK {
|
|
t.Errorf("packet %x:\ndstConnIDForDatagram(packet) = {%x}, %v; want {%x}, %v", test.packet, gotConnID, gotOK, wantConnID, wantOK)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestEncodeDecodeVersionNegotiation(t *testing.T) {
|
|
dstConnID := []byte("this is a very long destination connection id")
|
|
srcConnID := []byte("this is a very long source connection id")
|
|
versions := []uint32{1, 0xffffffff}
|
|
got := appendVersionNegotiation([]byte{}, dstConnID, srcConnID, versions...)
|
|
want := bytes.Join([][]byte{{
|
|
0b1100_0000, // header byte
|
|
0, 0, 0, 0, // Version
|
|
byte(len(dstConnID)),
|
|
}, dstConnID, {
|
|
byte(len(srcConnID)),
|
|
}, srcConnID, {
|
|
0x00, 0x00, 0x00, 0x01,
|
|
0xff, 0xff, 0xff, 0xff,
|
|
}}, nil)
|
|
if !bytes.Equal(got, want) {
|
|
t.Fatalf("appendVersionNegotiation(nil, %x, %x, %v):\ngot %x\nwant %x",
|
|
dstConnID, srcConnID, versions, got, want)
|
|
}
|
|
gotDst, gotSrc, gotVersionBytes := parseVersionNegotiation(got)
|
|
if got, want := gotDst, dstConnID; !bytes.Equal(got, want) {
|
|
t.Errorf("parseVersionNegotiation: got dstConnID = %x, want %x", got, want)
|
|
}
|
|
if got, want := gotSrc, srcConnID; !bytes.Equal(got, want) {
|
|
t.Errorf("parseVersionNegotiation: got srcConnID = %x, want %x", got, want)
|
|
}
|
|
var gotVersions []uint32
|
|
for len(gotVersionBytes) >= 4 {
|
|
gotVersions = append(gotVersions, binary.BigEndian.Uint32(gotVersionBytes))
|
|
gotVersionBytes = gotVersionBytes[4:]
|
|
}
|
|
if got, want := gotVersions, versions; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("parseVersionNegotiation: got versions = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseGenericLongHeaderPacket(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
packet []byte
|
|
version uint32
|
|
dstConnID []byte
|
|
srcConnID []byte
|
|
data []byte
|
|
}{{
|
|
name: "long header packet",
|
|
packet: unhex(`
|
|
80 01020304 04a1a2a3a4 05b1b2b3b4b5 c1
|
|
`),
|
|
version: 0x01020304,
|
|
dstConnID: unhex(`a1a2a3a4`),
|
|
srcConnID: unhex(`b1b2b3b4b5`),
|
|
data: unhex(`c1`),
|
|
}, {
|
|
name: "zero everything",
|
|
packet: unhex(`
|
|
80 00000000 00 00
|
|
`),
|
|
version: 0,
|
|
dstConnID: []byte{},
|
|
srcConnID: []byte{},
|
|
data: []byte{},
|
|
}} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
p, ok := parseGenericLongHeaderPacket(test.packet)
|
|
if !ok {
|
|
t.Fatalf("parseGenericLongHeaderPacket() = _, false; want true")
|
|
}
|
|
if got, want := p.version, test.version; got != want {
|
|
t.Errorf("version = %v, want %v", got, want)
|
|
}
|
|
if got, want := p.dstConnID, test.dstConnID; !bytes.Equal(got, want) {
|
|
t.Errorf("Destination Connection ID = {%x}, want {%x}", got, want)
|
|
}
|
|
if got, want := p.srcConnID, test.srcConnID; !bytes.Equal(got, want) {
|
|
t.Errorf("Source Connection ID = {%x}, want {%x}", got, want)
|
|
}
|
|
if got, want := p.data, test.data; !bytes.Equal(got, want) {
|
|
t.Errorf("Data = {%x}, want {%x}", got, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseGenericLongHeaderPacketErrors(t *testing.T) {
|
|
for _, test := range []struct {
|
|
name string
|
|
packet []byte
|
|
}{{
|
|
name: "short header packet",
|
|
packet: unhex(`
|
|
00 01020304 04a1a2a3a4 05b1b2b3b4b5 c1
|
|
`),
|
|
}, {
|
|
name: "packet too short",
|
|
packet: unhex(`
|
|
80 000000
|
|
`),
|
|
}, {
|
|
name: "destination id too long",
|
|
packet: unhex(`
|
|
80 00000000 02 00
|
|
`),
|
|
}, {
|
|
name: "source id too long",
|
|
packet: unhex(`
|
|
80 00000000 00 01
|
|
`),
|
|
}} {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
_, ok := parseGenericLongHeaderPacket(test.packet)
|
|
if ok {
|
|
t.Fatalf("parseGenericLongHeaderPacket() = _, true; want false")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func unhex(s string) []byte {
|
|
b, err := hex.DecodeString(strings.Map(func(c rune) rune {
|
|
switch c {
|
|
case ' ', '\t', '\n':
|
|
return -1
|
|
}
|
|
return c
|
|
}, s))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|