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