diff --git a/internal/wire/header.go b/internal/wire/header.go index a01f40ca..d08df0f7 100644 --- a/internal/wire/header.go +++ b/internal/wire/header.go @@ -40,6 +40,15 @@ func IsLongHeaderPacket(firstByte byte) bool { return firstByte&0x80 > 0 } +// ParseVersion parses the QUIC version. +// It should only be called for Long Header packets (Short Header packets don't contain a version number). +func ParseVersion(data []byte) (protocol.VersionNumber, error) { + if len(data) < 5 { + return 0, io.EOF + } + return protocol.VersionNumber(binary.BigEndian.Uint32(data[1:5])), nil +} + // IsVersionNegotiationPacket says if this is a version negotiation packet func IsVersionNegotiationPacket(b []byte) bool { if len(b) < 5 { diff --git a/internal/wire/header_test.go b/internal/wire/header_test.go index de7d2673..12a3a211 100644 --- a/internal/wire/header_test.go +++ b/internal/wire/header_test.go @@ -111,6 +111,24 @@ var _ = Describe("Header Parsing", func() { Expect(Is0RTTPacket(append(zeroRTTHeader, []byte("foobar")...))).To(BeTrue()) }) }) + Context("parsing the version", func() { + It("parses the version", func() { + b := []byte{0x80, 0xde, 0xad, 0xbe, 0xef} + v, err := ParseVersion(b) + Expect(err).ToNot(HaveOccurred()) + Expect(v).To(Equal(protocol.VersionNumber(0xdeadbeef))) + }) + + It("errors with EOF", func() { + b := []byte{0x80, 0xde, 0xad, 0xbe, 0xef} + _, err := ParseVersion(b) + Expect(err).ToNot(HaveOccurred()) + for i := range b { + _, err := ParseVersion(b[:i]) + Expect(err).To(MatchError(io.EOF)) + } + }) + }) Context("Identifying Version Negotiation Packets", func() { It("identifies version negotiation packets", func() {