implement parsing of IETF Version Negotiation Packets

This commit is contained in:
Marten Seemann
2017-10-14 12:31:26 -07:00
parent fad279cb75
commit 7cb8e87580
2 changed files with 73 additions and 21 deletions

View File

@@ -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) {

View File

@@ -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))
}
})