github.com/MerlinKodo/quic-go@v0.39.2/internal/wire/version_negotiation_test.go (about) 1 package wire 2 3 import ( 4 "encoding/binary" 5 6 "golang.org/x/exp/rand" 7 8 "github.com/MerlinKodo/quic-go/internal/protocol" 9 10 . "github.com/onsi/ginkgo/v2" 11 . "github.com/onsi/gomega" 12 ) 13 14 var _ = Describe("Version Negotiation Packets", func() { 15 randConnID := func(l int) protocol.ArbitraryLenConnectionID { 16 b := make(protocol.ArbitraryLenConnectionID, l) 17 _, err := rand.Read(b) 18 Expect(err).ToNot(HaveOccurred()) 19 return b 20 } 21 22 It("parses a Version Negotiation packet", func() { 23 srcConnID := randConnID(rand.Intn(255) + 1) 24 destConnID := randConnID(rand.Intn(255) + 1) 25 versions := []protocol.VersionNumber{0x22334455, 0x33445566} 26 data := []byte{0x80, 0, 0, 0, 0} 27 data = append(data, uint8(len(destConnID))) 28 data = append(data, destConnID...) 29 data = append(data, uint8(len(srcConnID))) 30 data = append(data, srcConnID...) 31 for _, v := range versions { 32 data = append(data, []byte{0, 0, 0, 0}...) 33 binary.BigEndian.PutUint32(data[len(data)-4:], uint32(v)) 34 } 35 Expect(IsVersionNegotiationPacket(data)).To(BeTrue()) 36 dest, src, supportedVersions, err := ParseVersionNegotiationPacket(data) 37 Expect(err).ToNot(HaveOccurred()) 38 Expect(dest).To(Equal(destConnID)) 39 Expect(src).To(Equal(srcConnID)) 40 Expect(supportedVersions).To(Equal(versions)) 41 }) 42 43 It("errors if it contains versions of the wrong length", func() { 44 connID := protocol.ArbitraryLenConnectionID{1, 2, 3, 4, 5, 6, 7, 8} 45 versions := []protocol.VersionNumber{0x22334455, 0x33445566} 46 data := ComposeVersionNegotiation(connID, connID, versions) 47 _, _, _, err := ParseVersionNegotiationPacket(data[:len(data)-2]) 48 Expect(err).To(MatchError("Version Negotiation packet has a version list with an invalid length")) 49 }) 50 51 It("errors if the version list is empty", func() { 52 connID := protocol.ArbitraryLenConnectionID{1, 2, 3, 4, 5, 6, 7, 8} 53 versions := []protocol.VersionNumber{0x22334455} 54 data := ComposeVersionNegotiation(connID, connID, versions) 55 // remove 8 bytes (two versions), since ComposeVersionNegotiation also added a reserved version number 56 data = data[:len(data)-8] 57 _, _, _, err := ParseVersionNegotiationPacket(data) 58 Expect(err).To(MatchError("Version Negotiation packet has empty version list")) 59 }) 60 61 It("adds a reserved version", func() { 62 srcConnID := protocol.ArbitraryLenConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37} 63 destConnID := protocol.ArbitraryLenConnectionID{1, 2, 3, 4, 5, 6, 7, 8} 64 versions := []protocol.VersionNumber{1001, 1003} 65 data := ComposeVersionNegotiation(destConnID, srcConnID, versions) 66 Expect(IsLongHeaderPacket(data[0])).To(BeTrue()) 67 Expect(data[0] & 0x40).ToNot(BeZero()) 68 v, err := ParseVersion(data) 69 Expect(err).ToNot(HaveOccurred()) 70 Expect(v).To(BeZero()) 71 dest, src, supportedVersions, err := ParseVersionNegotiationPacket(data) 72 Expect(err).ToNot(HaveOccurred()) 73 Expect(dest).To(Equal(destConnID)) 74 Expect(src).To(Equal(srcConnID)) 75 // the supported versions should include one reserved version number 76 Expect(supportedVersions).To(HaveLen(len(versions) + 1)) 77 for _, v := range versions { 78 Expect(supportedVersions).To(ContainElement(v)) 79 } 80 var reservedVersion protocol.VersionNumber 81 versionLoop: 82 for _, ver := range supportedVersions { 83 for _, v := range versions { 84 if v == ver { 85 continue versionLoop 86 } 87 } 88 reservedVersion = ver 89 } 90 Expect(reservedVersion).ToNot(BeZero()) 91 Expect(reservedVersion&0x0f0f0f0f == 0x0a0a0a0a).To(BeTrue()) // check that it's a greased version number 92 }) 93 })