forked from quic-go/quic-go
implement parsing of IETF Version Negotiation Packets
This commit is contained in:
@@ -6,34 +6,36 @@ import (
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
)
|
||||
|
||||
// The Header is the header of a QUIC Packet.
|
||||
// TODO: add support for the key phase
|
||||
type Header struct {
|
||||
Type uint8
|
||||
IsLongHeader bool
|
||||
KeyPhase int
|
||||
OmitConnectionID bool
|
||||
ConnectionID protocol.ConnectionID
|
||||
PacketNumber protocol.PacketNumber
|
||||
PacketNumberLen protocol.PacketNumberLen
|
||||
Version protocol.VersionNumber
|
||||
Type uint8
|
||||
IsLongHeader bool
|
||||
KeyPhase int
|
||||
OmitConnectionID bool
|
||||
ConnectionID protocol.ConnectionID
|
||||
PacketNumber protocol.PacketNumber
|
||||
PacketNumberLen protocol.PacketNumberLen
|
||||
Version protocol.VersionNumber
|
||||
SupportedVersions []protocol.VersionNumber // version number sent in a Version Negotiation Packet by the server
|
||||
}
|
||||
|
||||
// ParseHeader parses a header
|
||||
func ParseHeader(b *bytes.Reader) (*Header, error) {
|
||||
func ParseHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Header, error) {
|
||||
typeByte, err := b.ReadByte()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if typeByte&0x80 > 0 {
|
||||
return parseLongHeader(b, typeByte)
|
||||
return parseLongHeader(b, packetSentBy, typeByte)
|
||||
}
|
||||
return parseShortHeader(b, typeByte)
|
||||
}
|
||||
|
||||
func parseLongHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
|
||||
func parseLongHeader(b *bytes.Reader, packetSentBy protocol.Perspective, typeByte byte) (*Header, error) {
|
||||
connID, err := utils.BigEndian.ReadUint64(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -46,14 +48,28 @@ func parseLongHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Header{
|
||||
h := &Header{
|
||||
Type: typeByte & 0x7f,
|
||||
IsLongHeader: true,
|
||||
ConnectionID: protocol.ConnectionID(connID),
|
||||
PacketNumber: protocol.PacketNumber(pn),
|
||||
PacketNumberLen: protocol.PacketNumberLen4,
|
||||
Version: protocol.VersionNumber(v),
|
||||
}, nil
|
||||
}
|
||||
if h.Type == 0x1 { // Version Negotiation Packet
|
||||
if packetSentBy == protocol.PerspectiveClient {
|
||||
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "sent by the client")
|
||||
}
|
||||
h.SupportedVersions = make([]protocol.VersionNumber, b.Len()/4)
|
||||
for i := 0; b.Len() > 0; i++ {
|
||||
v, err := utils.BigEndian.ReadUint32(b)
|
||||
if err != nil {
|
||||
return nil, qerr.InvalidVersionNegotiationPacket
|
||||
}
|
||||
h.SupportedVersions[i] = protocol.VersionNumber(v)
|
||||
}
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func parseShortHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"io"
|
||||
|
||||
"github.com/lucas-clemente/quic-go/internal/protocol"
|
||||
"github.com/lucas-clemente/quic-go/qerr"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
@@ -25,7 +27,7 @@ var _ = Describe("Header", func() {
|
||||
|
||||
It("parses a long header", func() {
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.Type).To(BeEquivalentTo(3))
|
||||
Expect(h.IsLongHeader).To(BeTrue())
|
||||
@@ -39,10 +41,44 @@ var _ = Describe("Header", func() {
|
||||
|
||||
It("errors on EOF", func() {
|
||||
for i := 0; i < len(data); i++ {
|
||||
_, err := ParseHeader(bytes.NewReader(data[:i]))
|
||||
_, err := ParseHeader(bytes.NewReader(data[:i]), protocol.PerspectiveClient)
|
||||
Expect(err).To(Equal(io.EOF))
|
||||
}
|
||||
})
|
||||
|
||||
Context("Version Negotiation Packets", func() {
|
||||
BeforeEach(func() {
|
||||
data[0] = 0x80 ^ 0x1 // set the type byte to Version Negotiation Packet
|
||||
})
|
||||
|
||||
It("parses", func() {
|
||||
data = append(data, []byte{
|
||||
0x22, 0x33, 0x44, 0x55,
|
||||
0x33, 0x44, 0x55, 0x66}...,
|
||||
)
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveServer)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.SupportedVersions).To(Equal([]protocol.VersionNumber{
|
||||
0x22334455,
|
||||
0x33445566,
|
||||
}))
|
||||
})
|
||||
|
||||
It("errors if it contains versions of the wrong length", func() {
|
||||
data = append(data, []byte{0x22, 0x33}...) // too short. Should be 4 bytes.
|
||||
b := bytes.NewReader(data)
|
||||
_, err := ParseHeader(b, protocol.PerspectiveServer)
|
||||
Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket))
|
||||
})
|
||||
|
||||
It("errors if it was sent by the client", func() {
|
||||
data = append(data, []byte{0x22, 0x33, 0x44, 0x55}...)
|
||||
b := bytes.NewReader(data)
|
||||
_, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).To(MatchError("InvalidVersionNegotiationPacket: sent by the client"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("short headers", func() {
|
||||
@@ -53,7 +89,7 @@ var _ = Describe("Header", func() {
|
||||
0x42, // packet number
|
||||
}
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.IsLongHeader).To(BeFalse())
|
||||
Expect(h.KeyPhase).To(Equal(0))
|
||||
@@ -69,7 +105,7 @@ var _ = Describe("Header", func() {
|
||||
0x11,
|
||||
}
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.IsLongHeader).To(BeFalse())
|
||||
Expect(h.KeyPhase).To(Equal(1))
|
||||
@@ -82,7 +118,7 @@ var _ = Describe("Header", func() {
|
||||
0x21, // packet number
|
||||
}
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.IsLongHeader).To(BeFalse())
|
||||
Expect(h.OmitConnectionID).To(BeTrue())
|
||||
@@ -97,7 +133,7 @@ var _ = Describe("Header", func() {
|
||||
0x13, 0x37, // packet number
|
||||
}
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.IsLongHeader).To(BeFalse())
|
||||
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x1337)))
|
||||
@@ -111,7 +147,7 @@ var _ = Describe("Header", func() {
|
||||
0xde, 0xad, 0xbe, 0xef, // packet number
|
||||
}
|
||||
b := bytes.NewReader(data)
|
||||
h, err := ParseHeader(b)
|
||||
h, err := ParseHeader(b, protocol.PerspectiveClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(h.IsLongHeader).To(BeFalse())
|
||||
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0xdeadbeef)))
|
||||
@@ -126,7 +162,7 @@ var _ = Describe("Header", func() {
|
||||
0xde, 0xca, 0xfb, 0xad, // packet number
|
||||
}
|
||||
for i := 0; i < len(data); i++ {
|
||||
_, err := ParseHeader(bytes.NewReader(data[:i]))
|
||||
_, err := ParseHeader(bytes.NewReader(data[:i]), protocol.PerspectiveClient)
|
||||
Expect(err).To(Equal(io.EOF))
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user