refactor header parsing in a version independent and dependent part

This commit is contained in:
Marten Seemann 2018-06-30 23:32:26 +07:00
parent 74ed3f7037
commit 4109c85c8a
20 changed files with 1587 additions and 1804 deletions

View file

@ -346,10 +346,15 @@ func (c *client) handleRead(remoteAddr net.Addr, packet []byte) {
rcvTime := time.Now()
r := bytes.NewReader(packet)
hdr, err := wire.ParseHeaderSentByServer(r)
iHdr, err := wire.ParseInvariantHeader(r)
// drop the packet if we can't parse the header
if err != nil {
c.logger.Errorf("error handling packet: %s", err)
c.logger.Errorf("error parsing invariant header: %s", err)
return
}
hdr, err := iHdr.Parse(r, protocol.PerspectiveServer, c.version)
if err != nil {
c.logger.Errorf("error parsing header: %s", err)
return
}
hdr.Raw = packet[:len(packet)-r.Len()]
@ -553,3 +558,10 @@ func (c *client) Close(err error) error {
}
return c.session.Close(err)
}
func (c *client) GetVersion() protocol.VersionNumber {
c.mutex.Lock()
v := c.version
c.mutex.Unlock()
return v
}

View file

@ -72,20 +72,25 @@ func (m *clientMultiplexer) listen(c net.PacketConn, sessions packetHandlerManag
rcvTime := time.Now()
r := bytes.NewReader(data)
hdr, err := wire.ParseHeaderSentByServer(r)
iHdr, err := wire.ParseInvariantHeader(r)
// drop the packet if we can't parse the header
if err != nil {
m.logger.Debugf("error parsing packet from %s: %s", addr, err)
m.logger.Debugf("error parsing invariant header from %s: %s", addr, err)
continue
}
client, ok := sessions.Get(iHdr.DestConnectionID)
if !ok {
m.logger.Debugf("received a packet with an unexpected connection ID %s", iHdr.DestConnectionID)
continue
}
hdr, err := iHdr.Parse(r, protocol.PerspectiveServer, client.GetVersion())
if err != nil {
m.logger.Debugf("error parsing header from %s: %s", addr, err)
continue
}
hdr.Raw = data[:len(data)-r.Len()]
packetData := data[len(data)-r.Len():]
client, ok := sessions.Get(hdr.DestConnectionID)
if !ok {
m.logger.Debugf("received a packet with an unexpected connection ID %s", hdr.DestConnectionID)
continue
}
client.handlePacket(&receivedPacket{
remoteAddr: addr,
header: hdr,

View file

@ -33,6 +33,7 @@ var _ = Describe("Client Multiplexer", func() {
packetHandler.EXPECT().handlePacket(gomock.Any()).Do(func(_ *receivedPacket) {
close(handledPacket)
})
packetHandler.EXPECT().GetVersion()
getClientMultiplexer().Add(conn, connID, packetHandler)
Eventually(handledPacket).Should(BeClosed())
// makes the listen go routine return
@ -54,10 +55,12 @@ var _ = Describe("Client Multiplexer", func() {
Expect(p.header.DestConnectionID).To(Equal(connID1))
close(handledPacket1)
})
packetHandler1.EXPECT().GetVersion()
packetHandler2.EXPECT().handlePacket(gomock.Any()).Do(func(p *receivedPacket) {
Expect(p.header.DestConnectionID).To(Equal(connID2))
close(handledPacket2)
})
packetHandler2.EXPECT().GetVersion()
getClientMultiplexer().Add(conn, connID1, packetHandler1)
getClientMultiplexer().Add(conn, connID2, packetHandler2)
Eventually(handledPacket1).Should(BeClosed())

View file

@ -42,7 +42,6 @@ var _ = Describe("Client", func() {
Expect(err).ToNot(HaveOccurred())
return b.Bytes()
}
_ = acceptClientVersionPacket
BeforeEach(func() {
connID = protocol.ConnectionID{0, 0, 0, 0, 0, 0, 0x13, 0x37}
@ -522,6 +521,11 @@ var _ = Describe("Client", func() {
})
})
It("tells its version", func() {
Expect(cl.version).ToNot(BeZero())
Expect(cl.GetVersion()).To(Equal(cl.version))
})
It("ignores packets with an invalid public header", func() {
cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any handlePacket calls
cl.handleRead(addr, []byte("invalid packet"))
@ -785,8 +789,22 @@ var _ = Describe("Client", func() {
})
Context("Public Reset handling", func() {
var (
pr []byte
hdr *wire.Header
hdrLen int
)
BeforeEach(func() {
cl.config = &Config{}
pr = wire.WritePublicReset(cl.destConnID, 1, 0)
r := bytes.NewReader(pr)
iHdr, err := wire.ParseInvariantHeader(r)
Expect(err).ToNot(HaveOccurred())
hdr, err = iHdr.Parse(r, protocol.PerspectiveServer, versionGQUICFrames)
Expect(err).ToNot(HaveOccurred())
hdrLen = r.Len()
})
It("closes the session when receiving a Public Reset", func() {
@ -801,28 +819,20 @@ var _ = Describe("Client", func() {
It("ignores Public Resets from the wrong remote address", func() {
cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls
spoofedAddr := &net.UDPAddr{IP: net.IPv4(1, 2, 3, 4), Port: 5678}
pr := wire.WritePublicReset(cl.destConnID, 1, 0)
r := bytes.NewReader(pr)
hdr, err := wire.ParseHeaderSentByServer(r)
Expect(err).ToNot(HaveOccurred())
err = cl.handlePacketImpl(&receivedPacket{
err := cl.handlePacketImpl(&receivedPacket{
remoteAddr: spoofedAddr,
header: hdr,
data: pr[len(pr)-r.Len():],
data: pr[len(pr)-hdrLen:],
})
Expect(err).To(MatchError("Received a spoofed Public Reset"))
})
It("ignores unparseable Public Resets", func() {
cl.session = NewMockQuicSession(mockCtrl) // don't EXPECT any calls
pr := wire.WritePublicReset(cl.destConnID, 1, 0)
r := bytes.NewReader(pr)
hdr, err := wire.ParseHeaderSentByServer(r)
Expect(err).ToNot(HaveOccurred())
err = cl.handlePacketImpl(&receivedPacket{
err := cl.handlePacketImpl(&receivedPacket{
remoteAddr: addr,
header: hdr,
data: pr[len(pr)-r.Len() : len(pr)-5], // cut off the last 5 bytes
data: pr[len(pr)-hdrLen : len(pr)-5], // cut off the last 5 bytes
})
Expect(err.Error()).To(ContainSubstring("Received a Public Reset. An error occurred parsing the packet"))
})

View file

@ -2,6 +2,8 @@ package wire
import (
"bytes"
"errors"
"fmt"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
@ -37,54 +39,7 @@ type Header struct {
PayloadLen protocol.ByteCount
}
// ParseHeaderSentByServer parses the header for a packet that was sent by the server.
func ParseHeaderSentByServer(b *bytes.Reader) (*Header, error) {
typeByte, err := b.ReadByte()
if err != nil {
return nil, err
}
_ = b.UnreadByte() // unread the type byte
var isPublicHeader bool
if typeByte&0x80 > 0 { // gQUIC always has 0x80 unset. IETF Long Header or Version Negotiation
isPublicHeader = false
} else {
// gQUIC never uses 6 byte packet numbers, so the third and fourth bit will never be 11
isPublicHeader = typeByte&0x30 != 0x30
}
return parsePacketHeader(b, protocol.PerspectiveServer, isPublicHeader)
}
// ParseHeaderSentByClient parses the header for a packet that was sent by the client.
func ParseHeaderSentByClient(b *bytes.Reader) (*Header, error) {
typeByte, err := b.ReadByte()
if err != nil {
return nil, err
}
_ = b.UnreadByte() // unread the type byte
// In an IETF QUIC packet header
// * either 0x80 is set (for the Long Header)
// * or 0x8 is unset (for the Short Header)
// In a gQUIC Public Header
// * 0x80 is always unset and
// * and 0x8 is always set (this is the Connection ID flag, which the client always sets)
isPublicHeader := typeByte&0x88 == 0x8
return parsePacketHeader(b, protocol.PerspectiveClient, isPublicHeader)
}
func parsePacketHeader(b *bytes.Reader, sentBy protocol.Perspective, isPublicHeader bool) (*Header, error) {
// This is a gQUIC Public Header.
if isPublicHeader {
hdr, err := parsePublicHeader(b, sentBy)
if err != nil {
return nil, err
}
hdr.IsPublicHeader = true // save that this is a Public Header, so we can log it correctly later
return hdr, nil
}
return parseHeader(b)
}
var errInvalidPacketNumberLen6 = errors.New("invalid packet number length: 6 bytes")
// Write writes the Header.
func (h *Header) Write(b *bytes.Buffer, pers protocol.Perspective, version protocol.VersionNumber) error {
@ -92,17 +47,142 @@ func (h *Header) Write(b *bytes.Buffer, pers protocol.Perspective, version proto
h.IsPublicHeader = true // save that this is a Public Header, so we can log it correctly later
return h.writePublicHeader(b, pers, version)
}
return h.writeHeader(b)
// write an IETF QUIC header
if h.IsLongHeader {
return h.writeLongHeader(b)
}
return h.writeShortHeader(b)
}
// TODO: add support for the key phase
func (h *Header) writeLongHeader(b *bytes.Buffer) error {
if h.SrcConnectionID.Len() != protocol.ConnectionIDLen {
return fmt.Errorf("Header: source connection ID must be %d bytes, is %d", protocol.ConnectionIDLen, h.SrcConnectionID.Len())
}
b.WriteByte(byte(0x80 | h.Type))
utils.BigEndian.WriteUint32(b, uint32(h.Version))
connIDLen, err := encodeConnIDLen(h.DestConnectionID, h.SrcConnectionID)
if err != nil {
return err
}
b.WriteByte(connIDLen)
b.Write(h.DestConnectionID.Bytes())
b.Write(h.SrcConnectionID.Bytes())
utils.WriteVarInt(b, uint64(h.PayloadLen))
return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
}
func (h *Header) writeShortHeader(b *bytes.Buffer) error {
typeByte := byte(0x30)
typeByte |= byte(h.KeyPhase << 6)
b.WriteByte(typeByte)
b.Write(h.DestConnectionID.Bytes())
return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
}
// writePublicHeader writes a Public Header.
func (h *Header) writePublicHeader(b *bytes.Buffer, pers protocol.Perspective, _ protocol.VersionNumber) error {
if h.ResetFlag || (h.VersionFlag && pers == protocol.PerspectiveServer) {
return errors.New("PublicHeader: Can only write regular packets")
}
if h.SrcConnectionID.Len() != 0 {
return errors.New("PublicHeader: SrcConnectionID must not be set")
}
if len(h.DestConnectionID) != 0 && len(h.DestConnectionID) != 8 {
return fmt.Errorf("PublicHeader: wrong length for Connection ID: %d (expected 8)", len(h.DestConnectionID))
}
publicFlagByte := uint8(0x00)
if h.VersionFlag {
publicFlagByte |= 0x01
}
if h.DestConnectionID.Len() > 0 {
publicFlagByte |= 0x08
}
if len(h.DiversificationNonce) > 0 {
if len(h.DiversificationNonce) != 32 {
return errors.New("invalid diversification nonce length")
}
publicFlagByte |= 0x04
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
publicFlagByte |= 0x00
case protocol.PacketNumberLen2:
publicFlagByte |= 0x10
case protocol.PacketNumberLen4:
publicFlagByte |= 0x20
}
b.WriteByte(publicFlagByte)
if h.DestConnectionID.Len() > 0 {
b.Write(h.DestConnectionID)
}
if h.VersionFlag && pers == protocol.PerspectiveClient {
utils.BigEndian.WriteUint32(b, uint32(h.Version))
}
if len(h.DiversificationNonce) > 0 {
b.Write(h.DiversificationNonce)
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(h.PacketNumber))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(h.PacketNumber))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber))
case protocol.PacketNumberLen6:
return errInvalidPacketNumberLen6
default:
return errors.New("PublicHeader: PacketNumberLen not set")
}
return nil
}
// GetLength determines the length of the Header.
func (h *Header) GetLength(pers protocol.Perspective, version protocol.VersionNumber) (protocol.ByteCount, error) {
func (h *Header) GetLength(version protocol.VersionNumber) (protocol.ByteCount, error) {
if !version.UsesTLS() {
return h.getPublicHeaderLength(pers)
return h.getPublicHeaderLength()
}
return h.getHeaderLength()
}
func (h *Header) getHeaderLength() (protocol.ByteCount, error) {
if h.IsLongHeader {
return 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol.ByteCount(h.DestConnectionID.Len()+h.SrcConnectionID.Len()) + utils.VarIntLen(uint64(h.PayloadLen)) + protocol.ByteCount(h.PacketNumberLen), nil
}
length := protocol.ByteCount(1 /* type byte */ + h.DestConnectionID.Len())
if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 {
return 0, fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen)
}
length += protocol.ByteCount(h.PacketNumberLen)
return length, nil
}
// getPublicHeaderLength gets the length of the publicHeader in bytes.
// It can only be called for regular packets.
func (h *Header) getPublicHeaderLength() (protocol.ByteCount, error) {
length := protocol.ByteCount(1) // 1 byte for public flags
if h.PacketNumberLen == protocol.PacketNumberLen6 {
return 0, errInvalidPacketNumberLen6
}
if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 {
return 0, errPacketNumberLenNotSet
}
length += protocol.ByteCount(h.PacketNumberLen)
length += protocol.ByteCount(h.DestConnectionID.Len()) // if set, always 8 bytes
// Version Number in packets sent by the client
if h.VersionFlag {
length += 4
}
length += protocol.ByteCount(len(h.DiversificationNonce))
return length, nil
}
// Log logs the Header
func (h *Header) Log(logger utils.Logger) {
if h.IsPublicHeader {
@ -111,3 +191,57 @@ func (h *Header) Log(logger utils.Logger) {
h.logHeader(logger)
}
}
func (h *Header) logHeader(logger utils.Logger) {
if h.IsLongHeader {
if h.Version == 0 {
logger.Debugf("\tVersionNegotiationPacket{DestConnectionID: %s, SrcConnectionID: %s, SupportedVersions: %s}", h.DestConnectionID, h.SrcConnectionID, h.SupportedVersions)
} else {
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, PayloadLen: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, h.PacketNumber, h.PacketNumberLen, h.PayloadLen, h.Version)
}
} else {
logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, h.KeyPhase)
}
}
func (h *Header) logPublicHeader(logger utils.Logger) {
ver := "(unset)"
if h.Version != 0 {
ver = h.Version.String()
}
logger.Debugf("\tPublic Header{ConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, Version: %s, DiversificationNonce: %#v}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, ver, h.DiversificationNonce)
}
func encodeConnIDLen(dest, src protocol.ConnectionID) (byte, error) {
dcil, err := encodeSingleConnIDLen(dest)
if err != nil {
return 0, err
}
scil, err := encodeSingleConnIDLen(src)
if err != nil {
return 0, err
}
return scil | dcil<<4, nil
}
func encodeSingleConnIDLen(id protocol.ConnectionID) (byte, error) {
len := id.Len()
if len == 0 {
return 0, nil
}
if len < 4 || len > 18 {
return 0, fmt.Errorf("invalid connection ID length: %d bytes", len)
}
return byte(len - 3), nil
}
func decodeConnIDLen(enc byte) (int /*dest conn id len*/, int /*src conn id len*/) {
return decodeSingleConnIDLen(enc >> 4), decodeSingleConnIDLen(enc & 0xf)
}
func decodeSingleConnIDLen(enc uint8) int {
if enc == 0 {
return 0
}
return int(enc) + 3
}

View file

@ -0,0 +1,196 @@
package wire
import (
"bytes"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// The InvariantHeader is the version independent part of the header
type InvariantHeader struct {
IsLongHeader bool
Version protocol.VersionNumber
SrcConnectionID protocol.ConnectionID
DestConnectionID protocol.ConnectionID
typeByte byte
}
// ParseInvariantHeader parses the version independent part of the header
func ParseInvariantHeader(b *bytes.Reader) (*InvariantHeader, error) {
typeByte, err := b.ReadByte()
if err != nil {
return nil, err
}
h := &InvariantHeader{typeByte: typeByte}
h.IsLongHeader = typeByte&0x80 > 0
// If this is not a Long Header, it could either be a Public Header or a Short Header.
if !h.IsLongHeader {
// In the Public Header 0x8 is the Connection ID Flag.
// In the IETF Short Header:
// * 0x8 it is the gQUIC Demultiplexing bit, and always 0.
// * 0x20 and 0x10 are always 1.
if typeByte&0x8 > 0 || typeByte&0x38 == 0x30 {
h.DestConnectionID, err = protocol.ReadConnectionID(b, 8)
if err != nil {
return nil, err
}
}
return h, nil
}
// Long Header
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h.Version = protocol.VersionNumber(v)
connIDLenByte, err := b.ReadByte()
if err != nil {
return nil, err
}
dcil, scil := decodeConnIDLen(connIDLenByte)
h.DestConnectionID, err = protocol.ReadConnectionID(b, dcil)
if err != nil {
return nil, err
}
h.SrcConnectionID, err = protocol.ReadConnectionID(b, scil)
if err != nil {
return nil, err
}
return h, nil
}
// Parse parses the version dependent part of the header
func (iv *InvariantHeader) Parse(b *bytes.Reader, sentBy protocol.Perspective, ver protocol.VersionNumber) (*Header, error) {
if iv.IsLongHeader {
if iv.Version == 0 { // Version Negotiation Packet
return iv.parseVersionNegotiationPacket(b)
}
return iv.parseLongHeader(b)
}
// The Public Header never uses 6 byte packet numbers.
// Therefore, the third and fourth bit will never be 11.
// For the Short Header, the third and fourth bit are always 11.
if iv.typeByte&0x30 != 0x30 {
if sentBy == protocol.PerspectiveServer && iv.typeByte&0x1 > 0 {
return iv.parseVersionNegotiationPacket(b)
}
return iv.parsePublicHeader(b, sentBy, ver)
}
return iv.parseShortHeader(b)
}
func (iv *InvariantHeader) toHeader() *Header {
return &Header{
IsLongHeader: iv.IsLongHeader,
DestConnectionID: iv.DestConnectionID,
SrcConnectionID: iv.SrcConnectionID,
Version: iv.Version,
}
}
func (iv *InvariantHeader) parseVersionNegotiationPacket(b *bytes.Reader) (*Header, error) {
h := iv.toHeader()
h.VersionFlag = true
if b.Len() == 0 {
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list")
}
h.IsVersionNegotiation = true
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 (iv *InvariantHeader) parseLongHeader(b *bytes.Reader) (*Header, error) {
h := iv.toHeader()
pl, err := utils.ReadVarInt(b)
if err != nil {
return nil, err
}
h.PayloadLen = protocol.ByteCount(pl)
pn, pnLen, err := utils.ReadVarIntPacketNumber(b)
if err != nil {
return nil, err
}
h.PacketNumber = pn
h.PacketNumberLen = pnLen
h.Type = protocol.PacketType(iv.typeByte & 0x7f)
if h.Type != protocol.PacketTypeInitial && h.Type != protocol.PacketTypeRetry && h.Type != protocol.PacketType0RTT && h.Type != protocol.PacketTypeHandshake {
return nil, qerr.Error(qerr.InvalidPacketHeader, fmt.Sprintf("Received packet with invalid packet type: %d", h.Type))
}
return h, nil
}
func (iv *InvariantHeader) parseShortHeader(b *bytes.Reader) (*Header, error) {
h := iv.toHeader()
h.KeyPhase = int(iv.typeByte&0x40) >> 6
pn, pnLen, err := utils.ReadVarIntPacketNumber(b)
if err != nil {
return nil, err
}
h.PacketNumber = pn
h.PacketNumberLen = pnLen
return h, nil
}
func (iv *InvariantHeader) parsePublicHeader(b *bytes.Reader, sentBy protocol.Perspective, ver protocol.VersionNumber) (*Header, error) {
h := iv.toHeader()
h.IsPublicHeader = true
h.ResetFlag = iv.typeByte&0x2 > 0
if h.ResetFlag {
return h, nil
}
h.VersionFlag = iv.typeByte&0x1 > 0
if h.VersionFlag && sentBy == protocol.PerspectiveClient {
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
h.Version = protocol.VersionNumber(v)
}
// Contrary to what the gQUIC wire spec says, the 0x4 bit only indicates the presence of the diversification nonce for packets sent by the server.
// It doesn't have any meaning when sent by the client.
if sentBy == protocol.PerspectiveServer && iv.typeByte&0x4 > 0 {
h.DiversificationNonce = make([]byte, 32)
if _, err := io.ReadFull(b, h.DiversificationNonce); err != nil {
if err == io.ErrUnexpectedEOF {
return nil, io.EOF
}
return nil, err
}
}
switch iv.typeByte & 0x30 {
case 0x00:
h.PacketNumberLen = protocol.PacketNumberLen1
case 0x10:
h.PacketNumberLen = protocol.PacketNumberLen2
case 0x20:
h.PacketNumberLen = protocol.PacketNumberLen4
}
pn, err := utils.BigEndian.ReadUintN(b, uint8(h.PacketNumberLen))
if err != nil {
return nil, err
}
h.PacketNumber = protocol.PacketNumber(pn)
return h, nil
}

View file

@ -0,0 +1,487 @@
package wire
import (
"bytes"
"encoding/binary"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Header Parsing", func() {
Context("IETF QUIC Header", func() {
appendPacketNumber := func(data []byte, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen) []byte {
buf := &bytes.Buffer{}
utils.WriteVarIntPacketNumber(buf, pn, pnLen)
return append(data, buf.Bytes()...)
}
Context("Version Negotiation Packets", func() {
It("parses", func() {
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
destConnID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}
versions := []protocol.VersionNumber{0x22334455, 0x33445566}
data, err := ComposeVersionNegotiation(destConnID, srcConnID, versions)
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.DestConnectionID).To(Equal(destConnID))
Expect(iHdr.SrcConnectionID).To(Equal(srcConnID))
Expect(iHdr.IsLongHeader).To(BeTrue())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsVersionNegotiation).To(BeTrue())
Expect(hdr.Version).To(BeZero())
Expect(hdr.DestConnectionID).To(Equal(destConnID))
Expect(hdr.SrcConnectionID).To(Equal(srcConnID))
for _, v := range versions {
Expect(hdr.SupportedVersions).To(ContainElement(v))
}
})
It("errors if it contains versions of the wrong length", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x22334455, 0x33445566}
data, err := ComposeVersionNegotiation(connID, connID, versions)
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(data[:len(data)-2])
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket))
})
It("errors if the version list is empty", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x22334455}
data, err := ComposeVersionNegotiation(connID, connID, versions)
Expect(err).ToNot(HaveOccurred())
// remove 8 bytes (two versions), since ComposeVersionNegotiation also added a reserved version number
b := bytes.NewReader(data[:len(data)-8])
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).To(MatchError("InvalidVersionNegotiationPacket: empty version list"))
})
})
Context("Long Headers", func() {
It("parses a long header", func() {
destConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}
srcConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x42, 0x42}
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x55, // connection ID lengths
}
data = append(data, destConnID...)
data = append(data, srcConnID...)
data = append(data, encodeVarInt(0x1337)...) // payload length
// packet number
data = appendPacketNumber(data, 0xbeef, protocol.PacketNumberLen4)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.IsLongHeader).To(BeTrue())
Expect(iHdr.DestConnectionID).To(Equal(destConnID))
Expect(iHdr.SrcConnectionID).To(Equal(srcConnID))
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.Type).To(Equal(protocol.PacketTypeInitial))
Expect(hdr.IsLongHeader).To(BeTrue())
Expect(hdr.DestConnectionID).To(Equal(destConnID))
Expect(hdr.SrcConnectionID).To(Equal(srcConnID))
Expect(hdr.PayloadLen).To(Equal(protocol.ByteCount(0x1337)))
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xbeef)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(hdr.Version).To(Equal(protocol.VersionNumber(0x1020304)))
Expect(hdr.IsVersionNegotiation).To(BeFalse())
Expect(b.Len()).To(BeZero())
})
It("parses a long header without a destination connection ID", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x01, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, // source connection ID
}
data = append(data, encodeVarInt(0x42)...) // payload length
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.SrcConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}))
Expect(iHdr.DestConnectionID).To(BeEmpty())
})
It("parses a long header without a source connection ID", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x70, // connection ID lengths
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // source connection ID
}
data = append(data, encodeVarInt(0x42)...) // payload length
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.SrcConnectionID).To(BeEmpty())
Expect(iHdr.DestConnectionID).To(Equal(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))
})
It("parses a long header with a 2 byte packet number", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x0, // connection ID lengths
}
data = append(data, encodeVarInt(0x42)...) // payload length
data = appendPacketNumber(data, 0x123, protocol.PacketNumberLen2)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x123)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
})
It("rejects packets sent with an unknown packet type", func() {
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
buf := &bytes.Buffer{}
err := (&Header{
IsLongHeader: true,
Type: 42,
SrcConnectionID: srcConnID,
Version: 0x10203040,
PacketNumber: 1,
PacketNumberLen: protocol.PacketNumberLen1,
}).Write(buf, protocol.PerspectiveClient, protocol.VersionTLS)
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(buf.Bytes())
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).To(MatchError("InvalidPacketHeader: Received packet with invalid packet type: 42"))
})
It("errors on EOF, when parsing the invariant header", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x55, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // destination connection ID
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // source connection ID
}
for i := 0; i < len(data); i++ {
_, err := ParseInvariantHeader(bytes.NewReader(data[:i]))
Expect(err).To(Equal(io.EOF))
}
})
It("errors on EOF, when parsing the header", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x0, // connection ID lengths
}
iHdrLen := len(data)
data = append(data, encodeVarInt(0x1337)...)
data = appendPacketNumber(data, 0xdeadbeef, protocol.PacketNumberLen4)
for i := iHdrLen; i < len(data); i++ {
b := bytes.NewReader(data[:i])
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).To(Equal(io.EOF))
}
})
})
Context("Short Headers", func() {
It("reads a short header with a connection ID", func() {
connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}
data := append([]byte{0x30}, connID...)
data = appendPacketNumber(data, 0x42, protocol.PacketNumberLen1)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.IsLongHeader).To(BeFalse())
Expect(iHdr.DestConnectionID).To(Equal(connID))
hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.KeyPhase).To(Equal(0))
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42)))
Expect(hdr.IsVersionNegotiation).To(BeFalse())
Expect(b.Len()).To(BeZero())
})
It("reads the Key Phase Bit", func() {
data := []byte{
0x30 ^ 0x40,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 11, protocol.PacketNumberLen1)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsLongHeader).To(BeFalse())
Expect(hdr.KeyPhase).To(Equal(1))
Expect(b.Len()).To(BeZero())
})
It("reads a header with a 2 byte packet number", func() {
data := []byte{
0x30 ^ 0x40 ^ 0x1,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 0x1337, protocol.PacketNumberLen2)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsLongHeader).To(BeFalse())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1337)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
Expect(b.Len()).To(BeZero())
})
It("reads a header with a 4 byte packet number", func() {
data := []byte{
0x30 ^ 0x40 ^ 0x2,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 0x99beef, protocol.PacketNumberLen4)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsLongHeader).To(BeFalse())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x99beef)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(b.Len()).To(BeZero())
})
It("errors on EOF, when parsing the invariant header", func() {
data := []byte{
0x30 ^ 0x2,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
for i := 0; i < len(data); i++ {
_, err := ParseInvariantHeader(bytes.NewReader(data[:i]))
Expect(err).To(Equal(io.EOF))
}
})
It("errors on EOF, when parsing the invariant header", func() {
data := []byte{
0x30 ^ 0x2,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
iHdrLen := len(data)
data = appendPacketNumber(data, 0xdeadbeef, protocol.PacketNumberLen4)
for i := iHdrLen; i < len(data); i++ {
b := bytes.NewReader(data[:i])
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).To(Equal(io.EOF))
}
})
})
})
Context("Public Header", func() {
It("accepts a sample client header", func() {
ver := make([]byte, 4)
binary.BigEndian.PutUint32(ver, uint32(protocol.SupportedVersions[0]))
b := bytes.NewReader(append(append([]byte{0x09, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}, ver...), 0x01))
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.IsLongHeader).To(BeFalse())
hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.IsVersionNegotiation).To(BeFalse())
Expect(hdr.ResetFlag).To(BeFalse())
connID := protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.Version).To(Equal(protocol.SupportedVersions[0]))
Expect(hdr.SupportedVersions).To(BeEmpty())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(1)))
Expect(b.Len()).To(BeZero())
})
It("accepts an omitted connection ID", func() {
b := bytes.NewReader([]byte{0x0, 0x1})
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.IsLongHeader).To(BeFalse())
Expect(iHdr.DestConnectionID).To(BeEmpty())
Expect(iHdr.SrcConnectionID).To(BeEmpty())
hdr, err := iHdr.Parse(b, protocol.PerspectiveClient, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(1)))
Expect(b.Len()).To(BeZero())
})
It("parses a PUBLIC_RESET packet", func() {
b := bytes.NewReader([]byte{0xa, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8})
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.IsLongHeader).To(BeFalse())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.ResetFlag).To(BeTrue())
Expect(hdr.VersionFlag).To(BeFalse())
Expect(hdr.IsVersionNegotiation).To(BeFalse())
connID := protocol.ConnectionID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.DestConnectionID).To(Equal(connID))
})
It("reads a diversification nonce sent by the server", func() {
divNonce := []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}
Expect(divNonce).To(HaveLen(32))
b := bytes.NewReader(append(append([]byte{0x0c, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c}, divNonce...), 0x37))
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(iHdr.IsLongHeader).To(BeFalse())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).ToNot(BeEmpty())
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.DiversificationNonce).To(Equal(divNonce))
Expect(b.Len()).To(BeZero())
})
It("errors on EOF", func() {
data := []byte{
0x10 ^ 0x8 ^ 0x4,
0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c,
}
iHdrLen := len(data)
data = append(data, bytes.Repeat([]byte{0}, 32)...) // add a diversification nonce
data = append(data, []byte{0x13, 37}...) // packet number
for i := iHdrLen; i < len(data); i++ {
b := bytes.NewReader(data[:i])
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).To(Equal(io.EOF))
}
})
Context("version negotiation packets", func() {
appendVersion := func(data []byte, v protocol.VersionNumber) []byte {
data = append(data, []byte{0, 0, 0, 0}...)
binary.BigEndian.PutUint32(data[len(data)-4:], uint32(v))
return data
}
It("parses", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x13, 0x37}
b := bytes.NewReader(ComposeGQUICVersionNegotiation(connID, versions))
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.Version).To(BeZero()) // unitialized
Expect(hdr.IsVersionNegotiation).To(BeTrue())
// in addition to the versions, the supported versions might contain a reserved version number
for _, version := range versions {
Expect(hdr.SupportedVersions).To(ContainElement(version))
}
Expect(b.Len()).To(BeZero())
})
It("errors if it doesn't contain any versions", func() {
b := bytes.NewReader([]byte{0x9, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c})
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).To(MatchError("InvalidVersionNegotiationPacket: empty version list"))
})
It("reads version negotiation packets containing unsupported versions", func() {
data := []byte{0x9, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c}
data = appendVersion(data, 1) // unsupported version
data = appendVersion(data, protocol.SupportedVersions[0])
data = appendVersion(data, 99) // unsupported version
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.IsVersionNegotiation).To(BeTrue())
Expect(hdr.SupportedVersions).To(Equal([]protocol.VersionNumber{1, protocol.SupportedVersions[0], 99}))
Expect(b.Len()).To(BeZero())
})
It("errors on invalid version tags", func() {
data := ComposeGQUICVersionNegotiation(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, protocol.SupportedVersions)
data = append(data, []byte{0x13, 0x37}...)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
_, err = iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket))
})
})
Context("Packet Number lengths", func() {
It("accepts 1-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde})
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xde)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1))
Expect(b.Len()).To(BeZero())
})
It("accepts 2-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde, 0xca})
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xdeca)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
Expect(b.Len()).To(BeZero())
})
It("accepts 4-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x28, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xad, 0xfb, 0xca, 0xde})
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xadfbcade)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(b.Len()).To(BeZero())
})
})
})
})

View file

@ -2,7 +2,6 @@ package wire
import (
"bytes"
"io"
"log"
"os"
@ -18,235 +17,503 @@ var _ = Describe("Header", func() {
versionIETFHeader = protocol.VersionTLS // a QUIC version that uses the IETF Header format
)
Context("parsing", func() {
It("parses an IETF draft Short Header, when the QUIC version supports TLS", func() {
buf := &bytes.Buffer{}
// use a Short Header, which isn't distinguishable from the gQUIC Public Header when looking at the type byte
err := (&Header{
IsLongHeader: false,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
KeyPhase: 1,
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen2,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
hdr, err := ParseHeaderSentByClient(bytes.NewReader(buf.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.KeyPhase).To(BeEquivalentTo(1))
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42)))
Expect(hdr.IsPublicHeader).To(BeFalse())
Context("Writing", func() {
var buf *bytes.Buffer
BeforeEach(func() {
buf = &bytes.Buffer{}
})
It("parses an IETF draft header, when the version is not known, but it has Long Header format", func() {
Context("IETF Header", func() {
appendPacketNumber := func(data []byte, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen) []byte {
buf := &bytes.Buffer{}
utils.WriteVarIntPacketNumber(buf, pn, pnLen)
return append(data, buf.Bytes()...)
}
Context("Long Header", func() {
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
It("writes", func() {
err := (&Header{
IsLongHeader: true,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
Type: protocol.PacketType0RTT,
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen2,
Version: 0x1234,
}).writeHeader(buf)
Type: 0x5,
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe},
SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x0, 0x0, 0x13, 0x37},
PayloadLen: 0xcafe,
PacketNumber: 0xdecaf,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
hdr, err := ParseHeaderSentByClient(bytes.NewReader(buf.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.Type).To(Equal(protocol.PacketType0RTT))
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x42)))
Expect(hdr.IsPublicHeader).To(BeFalse())
Expect(hdr.Version).To(Equal(protocol.VersionNumber(0x1234)))
expected := []byte{
0x80 ^ 0x5,
0x1, 0x2, 0x3, 0x4, // version number
0x35, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // dest connection ID
0xde, 0xca, 0xfb, 0xad, 0x0, 0x0, 0x13, 0x37, // source connection ID
}
expected = append(expected, encodeVarInt(0xcafe)...) // payload length
expected = appendPacketNumber(expected, 0xdecaf, protocol.PacketNumberLen4)
Expect(buf.Bytes()).To(Equal(expected))
})
It("doesn't mistake packets with a Short Header for Version Negotiation Packets", func() {
// make sure this packet could be mistaken for a Version Negotiation Packet, if we only look at the 0x1 bit
buf := &bytes.Buffer{}
It("refuses to write a header with a too short connection ID", func() {
err := (&Header{
IsLongHeader: false,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3}, // connection IDs must be at least 4 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).To(MatchError("invalid connection ID length: 3 bytes"))
})
It("refuses to write a header with a too long connection ID", func() {
err := (&Header{
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, // connection IDs must be at most 18 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).To(MatchError("invalid connection ID length: 19 bytes"))
})
It("refuses to write a Long Header with the wrong connection ID length", func() {
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6}
Expect(srcConnID).ToNot(Equal(protocol.ConnectionIDLen))
err := (&Header{
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5}, // connection IDs must be at most 18 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).To(MatchError("Header: source connection ID must be 8 bytes, is 6"))
})
It("writes a header with an 18 byte connection ID", func() {
err := (&Header{
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, // connection IDs must be at most 18 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(ContainSubstring(string([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18})))
})
})
Context("short header", func() {
It("writes a header with connection ID", func() {
err := (&Header{
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 0x42,
}).writeHeader(buf)
}).Write(buf, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
hdr, err := ParseHeaderSentByServer(bytes.NewReader(buf.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsPublicHeader).To(BeFalse())
Expect(buf.Bytes()).To(Equal([]byte{
0x30,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
0x42, // packet number
}))
})
It("parses a gQUIC Public Header, when the version is not known", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
buf := &bytes.Buffer{}
It("writes a header without connection ID", func() {
err := (&Header{
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 0x42,
}).Write(buf, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x30,
0x42, // packet number
}))
})
It("writes a header with a 2 byte packet number", func() {
err := (&Header{
PacketNumberLen: protocol.PacketNumberLen2,
PacketNumber: 0x765,
}).Write(buf, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
expected := []byte{0x30}
expected = appendPacketNumber(expected, 0x765, protocol.PacketNumberLen2)
Expect(buf.Bytes()).To(Equal(expected))
})
It("writes a header with a 4 byte packet number", func() {
err := (&Header{
VersionFlag: true,
Version: versionPublicHeader,
DestConnectionID: connID,
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen4,
}).writePublicHeader(buf, protocol.PerspectiveClient, versionPublicHeader)
PacketNumber: 0x123456,
}).Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
hdr, err := ParseHeaderSentByClient(bytes.NewReader(buf.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1337)))
Expect(hdr.Version).To(Equal(versionPublicHeader))
Expect(hdr.IsPublicHeader).To(BeTrue())
expected := []byte{0x30}
expected = appendPacketNumber(expected, 0x123456, protocol.PacketNumberLen4)
Expect(buf.Bytes()).To(Equal(expected))
})
It("parses a gQUIC Public Header", func() {
connID := protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1}
buf := &bytes.Buffer{}
It("errors when given an invalid packet number length", func() {
err := (&Header{
PacketNumberLen: 3,
PacketNumber: 0xdecafbad,
}).Write(buf, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).To(MatchError("invalid packet number length: 3"))
})
It("writes the Key Phase Bit", func() {
err := (&Header{
KeyPhase: 1,
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 0x42,
}).Write(buf, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x30 | 0x40,
0x42, // packet number
}))
})
})
})
Context("Public Header", func() {
connID := protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}
It("writes a sample header as a server", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0x1337,
PacketNumber: 2,
PacketNumberLen: protocol.PacketNumberLen4,
DiversificationNonce: bytes.Repeat([]byte{'f'}, 32),
}).writePublicHeader(buf, protocol.PerspectiveServer, versionPublicHeader)
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
hdr, err := ParseHeaderSentByServer(bytes.NewReader(buf.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0x1337)))
Expect(hdr.DiversificationNonce).To(HaveLen(32))
Expect(hdr.IsPublicHeader).To(BeTrue())
Expect(buf.Bytes()).To(Equal([]byte{
0x28,
0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
0, 0, 0, 2,
}))
})
It("errors when parsing the gQUIC header fails", func() {
buf := &bytes.Buffer{}
err := (&Header{
VersionFlag: true,
Version: versionPublicHeader,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
It("writes a sample header as a client", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen2,
}).writePublicHeader(buf, protocol.PerspectiveClient, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
_, err = ParseHeaderSentByClient(bytes.NewReader(buf.Bytes()[0:12]))
Expect(err).To(MatchError(io.EOF))
})
It("errors when given no data", func() {
_, err := ParseHeaderSentByServer(bytes.NewReader([]byte{}))
Expect(err).To(MatchError(io.EOF))
_, err = ParseHeaderSentByClient(bytes.NewReader([]byte{}))
Expect(err).To(MatchError(io.EOF))
})
It("parses a gQUIC Version Negotiation Packet", func() {
connID := protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0xde, 0xca, 0xfb, 0xad}
versions := []protocol.VersionNumber{0x13, 0x37}
data := ComposeGQUICVersionNegotiation(connID, versions)
hdr, err := ParseHeaderSentByServer(bytes.NewReader(data))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsPublicHeader).To(BeTrue())
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
// in addition to the versions, the supported versions might contain a reserved version number
for _, version := range versions {
Expect(hdr.SupportedVersions).To(ContainElement(version))
}
err := hdr.Write(buf, protocol.PerspectiveClient, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
0x13, 0x37,
}))
})
It("parses an IETF draft style Version Negotiation Packet", func() {
destConnID := protocol.ConnectionID{1, 3, 3, 7, 1, 3, 3, 7}
srcConnID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x13, 0x37}
data, err := ComposeVersionNegotiation(destConnID, srcConnID, versions)
Expect(err).ToNot(HaveOccurred())
hdr, err := ParseHeaderSentByServer(bytes.NewReader(data))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsPublicHeader).To(BeFalse())
Expect(hdr.IsVersionNegotiation).To(BeTrue())
Expect(hdr.DestConnectionID).To(Equal(destConnID))
Expect(hdr.SrcConnectionID).To(Equal(srcConnID))
Expect(hdr.Version).To(BeZero())
// in addition to the versions, the supported versions might contain a reserved version number
for _, version := range versions {
Expect(hdr.SupportedVersions).To(ContainElement(version))
}
})
})
Context("writing", func() {
It("writes a gQUIC Public Header", func() {
buf := &bytes.Buffer{}
hdr := &Header{
It("refuses to write a Public Header with a source connection ID", func() {
hdr := Header{
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1},
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen4,
}
err := hdr.Write(buf, protocol.PerspectiveClient, versionPublicHeader)
Expect(err).To(MatchError("PublicHeader: SrcConnectionID must not be set"))
})
It("refuses to write a Public Header if the connection ID has the wrong length", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 2,
PacketNumberLen: protocol.PacketNumberLen2,
}
err := hdr.Write(buf, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).To(MatchError("PublicHeader: wrong length for Connection ID: 7 (expected 8)"))
})
It("refuses to write a Public Header if the PacketNumberLen is not set", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 2,
}
err := hdr.Write(buf, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).To(MatchError("PublicHeader: PacketNumberLen not set"))
})
It("omits the connection ID", func() {
hdr := Header{
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 1,
}
err := hdr.Write(buf, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{0x0, 0x1}))
})
It("writes diversification nonces", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen1,
DiversificationNonce: bytes.Repeat([]byte{1}, 32),
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0xc,
0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0x42,
}))
})
It("writes packets with Version Flag, as a client", func() {
hdr := Header{
VersionFlag: true,
Version: 0x11223344,
DestConnectionID: connID,
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen1,
}
err := hdr.Write(buf, protocol.PerspectiveClient, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
// must be the first assertion
Expect(buf.Len()).To(Equal(1 + 8 + 4 + 1)) // 1 FlagByte + 8 ConnectionID + 4 version number + 1 PacketNumber
firstByte, _ := buf.ReadByte()
Expect(firstByte & 0x01).To(Equal(uint8(1)))
Expect(firstByte & 0x30).To(Equal(uint8(0x0)))
Expect(buf.Bytes()[8:12]).To(Equal([]byte{0x11, 0x22, 0x33, 0x44}))
Expect(buf.Bytes()[12:13]).To(Equal([]byte{0x42}))
})
Context("packet number length", func() {
It("doesn't write a header if the packet number length is not set", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xDECAFBAD,
}
err := hdr.Write(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).To(MatchError("PublicHeader: PacketNumberLen not set"))
})
It("writes a header with a 1-byte packet number", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen1,
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x8,
0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
0xad,
}))
})
It("writes a header with a 2-byte packet number", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen2,
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
_, err = parsePublicHeader(bytes.NewReader(buf.Bytes()), protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsPublicHeader).To(BeTrue())
Expect(buf.Bytes()).To(Equal([]byte{
0x18,
0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
0xfb, 0xad,
}))
})
It("writes a IETF draft header", func() {
buf := &bytes.Buffer{}
hdr := &Header{
Type: protocol.PacketTypeHandshake,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen2,
KeyPhase: 1,
It("writes a header with a 4-byte packet number", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0x13decafbad,
PacketNumberLen: protocol.PacketNumberLen4,
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
_, err = ParseHeaderSentByServer(bytes.NewReader(buf.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsPublicHeader).To(BeFalse())
Expect(buf.Bytes()).To(Equal([]byte{
0x28,
0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
0xde, 0xca, 0xfb, 0xad,
}))
})
It("refuses to write a header with a 6-byte packet number", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xbe1337decafbad,
PacketNumberLen: protocol.PacketNumberLen6,
}
err := hdr.writePublicHeader(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).To(MatchError(errInvalidPacketNumberLen6))
})
})
})
})
Context("getting the length", func() {
It("get the length of a gQUIC Public Header", func() {
buf := &bytes.Buffer{}
hdr := &Header{
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen2,
DiversificationNonce: bytes.Repeat([]byte{'f'}, 32),
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
publicHeaderLen, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
ietfHeaderLen, err := hdr.getHeaderLength()
Expect(err).ToNot(HaveOccurred())
Expect(publicHeaderLen).ToNot(Equal(ietfHeaderLen)) // make sure we can distinguish between the two header types
len, err := hdr.GetLength(protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(len).To(Equal(publicHeaderLen))
var buf *bytes.Buffer
BeforeEach(func() {
buf = &bytes.Buffer{}
})
It("get the length of a a IETF draft header", func() {
buf := &bytes.Buffer{}
hdr := &Header{
Context("IETF QUIC", func() {
It("has the right length for the Long Header, for a short payload length", func() {
h := &Header{
IsLongHeader: true,
PayloadLen: 1,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen2,
KeyPhase: 1,
PacketNumberLen: protocol.PacketNumberLen1,
}
err := hdr.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 8 /* src conn id */ + 1 /* short payload len */ + 1 /* packet number */
Expect(h.GetLength(versionIETFHeader)).To(BeEquivalentTo(expectedLen))
err := h.Write(buf, protocol.PerspectiveClient, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
publicHeaderLen, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(buf.Len()).To(Equal(expectedLen))
})
It("has the right length for the Long Header, for a long payload length", func() {
h := &Header{
IsLongHeader: true,
PayloadLen: 1500,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
PacketNumberLen: protocol.PacketNumberLen2,
}
expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 8 /* src conn id */ + 2 /* long payload len */ + 2 /* packet number */
Expect(h.GetLength(versionIETFHeader)).To(BeEquivalentTo(expectedLen))
err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
ietfHeaderLen, err := hdr.getHeaderLength()
Expect(buf.Len()).To(Equal(expectedLen))
})
It("has the right length for a Short Header containing a connection ID", func() {
h := &Header{
PacketNumberLen: protocol.PacketNumberLen1,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
}
Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 8 + 1)))
err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(publicHeaderLen).ToNot(Equal(ietfHeaderLen)) // make sure we can distinguish between the two header types
len, err := hdr.GetLength(protocol.PerspectiveServer, versionIETFHeader)
Expect(buf.Len()).To(Equal(10))
})
It("has the right length for a short header without a connection ID", func() {
h := &Header{PacketNumberLen: protocol.PacketNumberLen1}
Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 1)))
err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(len).To(Equal(ietfHeaderLen))
Expect(buf.Len()).To(Equal(2))
})
It("has the right length for a short header with a 2 byte packet number", func() {
h := &Header{PacketNumberLen: protocol.PacketNumberLen2}
Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 2)))
err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(3))
})
It("has the right length for a short header with a 5 byte packet number", func() {
h := &Header{PacketNumberLen: protocol.PacketNumberLen4}
Expect(h.GetLength(versionIETFHeader)).To(Equal(protocol.ByteCount(1 + 4)))
err := h.Write(buf, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(5))
})
It("errors when given an invalid packet number length", func() {
h := &Header{PacketNumberLen: 5}
_, err := h.GetLength(versionIETFHeader)
Expect(err).To(MatchError("invalid packet number length: 5"))
})
})
})
Context("logging", func() {
Context("Public Header", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
It("errors when PacketNumberLen is not set", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
}
_, err := hdr.GetLength(versionPublicHeader)
Expect(err).To(MatchError(errPacketNumberLenNotSet))
})
It("gets the length of a packet with longest packet number length and connectionID", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
}
length, err := hdr.GetLength(versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 8 + 4))) // 1 byte public flag, 8 bytes connectionID, and packet number
})
It("gets the lengths of a packet sent by the client with the VersionFlag set", func() {
hdr := Header{
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
VersionFlag: true,
Version: versionPublicHeader,
}
length, err := hdr.GetLength(versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 4 + 4))) // 1 byte public flag, 4 version number, and packet number
})
It("gets the length of a packet with longest packet number length and omitted connectionID", func() {
hdr := Header{
PacketNumber: 0xDECAFBAD,
PacketNumberLen: protocol.PacketNumberLen4,
}
length, err := hdr.GetLength(versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 4))) // 1 byte public flag, and packet number
})
It("gets the length of a packet 2 byte packet number length ", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xDECAFBAD,
PacketNumberLen: protocol.PacketNumberLen2,
}
length, err := hdr.GetLength(versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 8 + 2))) // 1 byte public flag, 8 byte connectionID, and packet number
})
It("works with diversification nonce", func() {
hdr := Header{
DiversificationNonce: []byte("foo"),
PacketNumberLen: protocol.PacketNumberLen1,
}
length, err := hdr.GetLength(versionPublicHeader)
Expect(err).NotTo(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 3 + 1))) // 1 byte public flag, 3 byte DiversificationNonce, 1 byte PacketNumber
})
})
Context("Logging", func() {
var (
buf *bytes.Buffer
logger utils.Logger
@ -263,23 +530,88 @@ var _ = Describe("Header", func() {
log.SetOutput(os.Stdout)
})
It("logs an IETF draft header", func() {
(&Header{
IsLongHeader: true,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
Version: 0x1337,
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("Long Header"))
Context("IETF QUIC Header", func() {
It("logs version negotiation packets", func() {
destConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}
srcConnID := protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37}
data, err := ComposeVersionNegotiation(destConnID, srcConnID, []protocol.VersionNumber{0x12345678, 0x87654321})
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
hdr.Log(logger)
Expect(buf.String()).To(ContainSubstring("VersionNegotiationPacket{DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337"))
Expect(buf.String()).To(ContainSubstring("0x12345678"))
Expect(buf.String()).To(ContainSubstring("0x87654321"))
})
It("logs a Public Header", func() {
It("logs Long Headers", func() {
(&Header{
IsLongHeader: true,
Type: protocol.PacketTypeHandshake,
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen2,
PayloadLen: 54321,
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37},
Version: 0xfeed,
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("Long Header{Type: Handshake, DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337, PacketNumber: 0x1337, PacketNumberLen: 2, PayloadLen: 54321, Version: 0xfeed}"))
})
It("logs Short Headers containing a connection ID", func() {
(&Header{
KeyPhase: 1,
PacketNumber: 0x1337,
PacketNumberLen: 4,
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("Short Header{DestConnectionID: 0xdeadbeefcafe1337, PacketNumber: 0x1337, PacketNumberLen: 4, KeyPhase: 1}"))
})
})
Context("Public Header", func() {
It("logs a Public Header containing a connection ID", func() {
(&Header{
IsPublicHeader: true,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
DestConnectionID: protocol.ConnectionID{0x13, 0x37, 0, 0, 0xde, 0xca, 0xfb, 0xad},
PacketNumber: 0x1337,
PacketNumberLen: 6,
Version: protocol.Version39,
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("Public Header"))
Expect(buf.String()).To(ContainSubstring("Public Header{ConnectionID: 0x13370000decafbad, PacketNumber: 0x1337, PacketNumberLen: 6, Version: gQUIC 39"))
})
It("logs a Public Header with omitted connection ID", func() {
(&Header{
IsPublicHeader: true,
PacketNumber: 0x1337,
PacketNumberLen: 6,
Version: protocol.Version39,
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("Public Header{ConnectionID: (empty)"))
})
It("logs a Public Header without a version", func() {
(&Header{
IsPublicHeader: true,
PacketNumber: 0x1337,
PacketNumberLen: 6,
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("Version: (unset)"))
})
It("logs diversification nonces", func() {
(&Header{
IsPublicHeader: true,
DestConnectionID: []byte{0x13, 0x13, 0, 0, 0xde, 0xca, 0xfb, 0xad},
DiversificationNonce: []byte{0xba, 0xdf, 0x00, 0x0d},
}).Log(logger)
Expect(buf.String()).To(ContainSubstring("DiversificationNonce: []byte{0xba, 0xdf, 0x0, 0xd}"))
})
})
})
})

View file

@ -1,205 +0,0 @@
package wire
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
// parseHeader parses the header.
func parseHeader(b *bytes.Reader) (*Header, error) {
typeByte, err := b.ReadByte()
if err != nil {
return nil, err
}
if typeByte&0x80 > 0 {
return parseLongHeader(b, typeByte)
}
return parseShortHeader(b, typeByte)
}
// parse long header and version negotiation packets
func parseLongHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
v, err := utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
connIDLenByte, err := b.ReadByte()
if err != nil {
return nil, err
}
dcil, scil := decodeConnIDLen(connIDLenByte)
destConnID, err := protocol.ReadConnectionID(b, dcil)
if err != nil {
return nil, err
}
srcConnID, err := protocol.ReadConnectionID(b, scil)
if err != nil {
return nil, err
}
h := &Header{
IsLongHeader: true,
Version: protocol.VersionNumber(v),
DestConnectionID: destConnID,
SrcConnectionID: srcConnID,
}
if v == 0 { // version negotiation packet
if b.Len() == 0 {
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list")
}
h.IsVersionNegotiation = true
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
}
pl, err := utils.ReadVarInt(b)
if err != nil {
return nil, err
}
h.PayloadLen = protocol.ByteCount(pl)
pn, pnLen, err := utils.ReadVarIntPacketNumber(b)
if err != nil {
return nil, err
}
h.PacketNumber = pn
h.PacketNumberLen = pnLen
h.Type = protocol.PacketType(typeByte & 0x7f)
if h.Type != protocol.PacketTypeInitial && h.Type != protocol.PacketTypeRetry && h.Type != protocol.PacketType0RTT && h.Type != protocol.PacketTypeHandshake {
return nil, qerr.Error(qerr.InvalidPacketHeader, fmt.Sprintf("Received packet with invalid packet type: %d", h.Type))
}
return h, nil
}
func parseShortHeader(b *bytes.Reader, typeByte byte) (*Header, error) {
connID := make(protocol.ConnectionID, 8)
if _, err := io.ReadFull(b, connID); err != nil {
if err == io.ErrUnexpectedEOF {
err = io.EOF
}
return nil, err
}
// bits 2 and 3 must be set, bit 4 must be unset
if typeByte&0x38 != 0x30 {
return nil, errors.New("invalid bits 3, 4 and 5")
}
pn, pnLen, err := utils.ReadVarIntPacketNumber(b)
if err != nil {
return nil, err
}
return &Header{
KeyPhase: int(typeByte&0x40) >> 6,
DestConnectionID: connID,
PacketNumber: pn,
PacketNumberLen: pnLen,
}, nil
}
// writeHeader writes the Header.
func (h *Header) writeHeader(b *bytes.Buffer) error {
if h.IsLongHeader {
return h.writeLongHeader(b)
}
return h.writeShortHeader(b)
}
// TODO: add support for the key phase
func (h *Header) writeLongHeader(b *bytes.Buffer) error {
if h.SrcConnectionID.Len() != protocol.ConnectionIDLen {
return fmt.Errorf("Header: source connection ID must be %d bytes, is %d", protocol.ConnectionIDLen, h.SrcConnectionID.Len())
}
b.WriteByte(byte(0x80 | h.Type))
utils.BigEndian.WriteUint32(b, uint32(h.Version))
connIDLen, err := encodeConnIDLen(h.DestConnectionID, h.SrcConnectionID)
if err != nil {
return err
}
b.WriteByte(connIDLen)
b.Write(h.DestConnectionID.Bytes())
b.Write(h.SrcConnectionID.Bytes())
utils.WriteVarInt(b, uint64(h.PayloadLen))
return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
}
func (h *Header) writeShortHeader(b *bytes.Buffer) error {
typeByte := byte(0x30)
typeByte |= byte(h.KeyPhase << 6)
b.WriteByte(typeByte)
b.Write(h.DestConnectionID.Bytes())
return utils.WriteVarIntPacketNumber(b, h.PacketNumber, h.PacketNumberLen)
}
func (h *Header) getHeaderLength() (protocol.ByteCount, error) {
if h.IsLongHeader {
return 1 /* type byte */ + 4 /* version */ + 1 /* conn id len byte */ + protocol.ByteCount(h.DestConnectionID.Len()+h.SrcConnectionID.Len()) + utils.VarIntLen(uint64(h.PayloadLen)) + protocol.ByteCount(h.PacketNumberLen), nil
}
length := protocol.ByteCount(1 /* type byte */ + h.DestConnectionID.Len())
if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 {
return 0, fmt.Errorf("invalid packet number length: %d", h.PacketNumberLen)
}
length += protocol.ByteCount(h.PacketNumberLen)
return length, nil
}
func (h *Header) logHeader(logger utils.Logger) {
if h.IsLongHeader {
if h.Version == 0 {
logger.Debugf("\tVersionNegotiationPacket{DestConnectionID: %s, SrcConnectionID: %s, SupportedVersions: %s}", h.DestConnectionID, h.SrcConnectionID, h.SupportedVersions)
} else {
logger.Debugf("\tLong Header{Type: %s, DestConnectionID: %s, SrcConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, PayloadLen: %d, Version: %s}", h.Type, h.DestConnectionID, h.SrcConnectionID, h.PacketNumber, h.PacketNumberLen, h.PayloadLen, h.Version)
}
} else {
logger.Debugf("\tShort Header{DestConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, KeyPhase: %d}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, h.KeyPhase)
}
}
func encodeConnIDLen(dest, src protocol.ConnectionID) (byte, error) {
dcil, err := encodeSingleConnIDLen(dest)
if err != nil {
return 0, err
}
scil, err := encodeSingleConnIDLen(src)
if err != nil {
return 0, err
}
return scil | dcil<<4, nil
}
func encodeSingleConnIDLen(id protocol.ConnectionID) (byte, error) {
len := id.Len()
if len == 0 {
return 0, nil
}
if len < 4 || len > 18 {
return 0, fmt.Errorf("invalid connection ID length: %d bytes", len)
}
return byte(len - 3), nil
}
func decodeConnIDLen(enc byte) (int /*dest conn id len*/, int /*src conn id len*/) {
return decodeSingleConnIDLen(enc >> 4), decodeSingleConnIDLen(enc & 0xf)
}
func decodeSingleConnIDLen(enc uint8) int {
if enc == 0 {
return 0
}
return int(enc) + 3
}

View file

@ -1,539 +0,0 @@
package wire
import (
"bytes"
"io"
"log"
"os"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("IETF QUIC Header", func() {
srcConnID := protocol.ConnectionID(bytes.Repeat([]byte{'f'}, protocol.ConnectionIDLen))
appendPacketNumber := func(data []byte, pn protocol.PacketNumber, pnLen protocol.PacketNumberLen) []byte {
buf := &bytes.Buffer{}
utils.WriteVarIntPacketNumber(buf, pn, pnLen)
return append(data, buf.Bytes()...)
}
Context("parsing", func() {
Context("Version Negotiation Packets", func() {
It("parses", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x22334455, 0x33445566}
data, err := ComposeVersionNegotiation(connID, connID, versions)
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.IsVersionNegotiation).To(BeTrue())
Expect(h.Version).To(BeZero())
Expect(h.DestConnectionID).To(Equal(connID))
Expect(h.SrcConnectionID).To(Equal(connID))
for _, v := range versions {
Expect(h.SupportedVersions).To(ContainElement(v))
}
})
It("errors if it contains versions of the wrong length", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x22334455, 0x33445566}
data, err := ComposeVersionNegotiation(connID, connID, versions)
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(data[:len(data)-2])
_, err = parseHeader(b)
Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket))
})
It("errors if the version list is empty", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x22334455}
data, err := ComposeVersionNegotiation(connID, connID, versions)
Expect(err).ToNot(HaveOccurred())
// remove 8 bytes (two versions), since ComposeVersionNegotiation also added a reserved version number
_, err = parseHeader(bytes.NewReader(data[:len(data)-8]))
Expect(err).To(MatchError("InvalidVersionNegotiationPacket: empty version list"))
})
})
Context("long headers", func() {
It("parses a long header", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x55, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // destination connection ID
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // source connection ID
}
data = append(data, encodeVarInt(0x1337)...) // payload length
// packet number
data = appendPacketNumber(data, 0xbeef, protocol.PacketNumberLen4)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.Type).To(Equal(protocol.PacketTypeInitial))
Expect(h.IsLongHeader).To(BeTrue())
Expect(h.DestConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}))
Expect(h.SrcConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}))
Expect(h.PayloadLen).To(Equal(protocol.ByteCount(0x1337)))
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0xbeef)))
Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(h.Version).To(Equal(protocol.VersionNumber(0x1020304)))
Expect(h.IsVersionNegotiation).To(BeFalse())
Expect(b.Len()).To(BeZero())
})
It("parses a long header without a destination connection ID", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x01, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, // source connection ID
}
data = append(data, encodeVarInt(0x42)...) // payload length
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.SrcConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef}))
Expect(h.DestConnectionID).To(BeEmpty())
})
It("parses a long header with a 2 byte connection ID", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x0, // connection ID lengths
}
data = append(data, encodeVarInt(0x42)...) // payload length
data = appendPacketNumber(data, 0x123, protocol.PacketNumberLen2)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x123)))
Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
})
It("parses a long header without a source connection ID", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x70, // connection ID lengths
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, // source connection ID
}
data = append(data, encodeVarInt(0x42)...) // payload length
data = append(data, []byte{0xde, 0xca, 0xfb, 0xad}...)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.SrcConnectionID).To(BeEmpty())
Expect(h.DestConnectionID).To(Equal(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}))
})
It("rejects packets sent with an unknown packet type", func() {
buf := &bytes.Buffer{}
err := (&Header{
IsLongHeader: true,
Type: 42,
SrcConnectionID: srcConnID,
Version: 0x10203040,
PacketNumber: 1,
PacketNumberLen: protocol.PacketNumberLen1,
}).Write(buf, protocol.PerspectiveClient, protocol.VersionTLS)
Expect(err).ToNot(HaveOccurred())
b := bytes.NewReader(buf.Bytes())
_, err = parseHeader(b)
Expect(err).To(MatchError("InvalidPacketHeader: Received packet with invalid packet type: 42"))
})
It("errors on EOF", func() {
data := []byte{
0x80 ^ uint8(protocol.PacketTypeInitial),
0x1, 0x2, 0x3, 0x4, // version number
0x55, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // destination connection ID
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // source connection ID
}
data = appendPacketNumber(data, 0x1337, protocol.PacketNumberLen4)
for i := 0; i < len(data); i++ {
_, err := parseHeader(bytes.NewReader(data[:i]))
Expect(err).To(Equal(io.EOF))
}
})
})
Context("short headers", func() {
It("reads a short header with a connection ID", func() {
data := []byte{
0x30, // 1 byte packet number
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 0x42, protocol.PacketNumberLen1)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.IsLongHeader).To(BeFalse())
Expect(h.KeyPhase).To(Equal(0))
Expect(h.DestConnectionID).To(Equal(protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}))
Expect(h.SrcConnectionID).To(BeEmpty())
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x42)))
Expect(h.IsVersionNegotiation).To(BeFalse())
Expect(b.Len()).To(BeZero())
})
It("reads the Key Phase Bit", func() {
data := []byte{
0x30 ^ 0x40,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 11, protocol.PacketNumberLen1)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.IsLongHeader).To(BeFalse())
Expect(h.KeyPhase).To(Equal(1))
Expect(b.Len()).To(BeZero())
})
It("reads a header with a 2 byte packet number", func() {
data := []byte{
0x30 ^ 0x40 ^ 0x1,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 0x1337, protocol.PacketNumberLen2)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.IsLongHeader).To(BeFalse())
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x1337)))
Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
Expect(b.Len()).To(BeZero())
})
It("reads a header with a 4 byte packet number", func() {
data := []byte{
0x30 ^ 0x40 ^ 0x2,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 0x99beef, protocol.PacketNumberLen4)
b := bytes.NewReader(data)
h, err := parseHeader(b)
Expect(err).ToNot(HaveOccurred())
Expect(h.IsLongHeader).To(BeFalse())
Expect(h.PacketNumber).To(Equal(protocol.PacketNumber(0x99beef)))
Expect(h.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(b.Len()).To(BeZero())
})
It("rejects headers that have bit 3,4 and 5 set incorrectly", func() {
data := []byte{
0x38 ^ 0x2,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 1234, protocol.PacketNumberLen2)
b := bytes.NewReader(data)
_, err := parseHeader(b)
Expect(err).To(MatchError("invalid bits 3, 4 and 5"))
})
It("errors on EOF", func() {
data := []byte{
0x30 ^ 0x2,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
}
data = appendPacketNumber(data, 1234, protocol.PacketNumberLen2)
for i := 0; i < len(data); i++ {
_, err := parseHeader(bytes.NewReader(data[:i]))
Expect(err).To(Equal(io.EOF))
}
})
})
})
Context("writing", func() {
var buf *bytes.Buffer
BeforeEach(func() {
buf = &bytes.Buffer{}
})
Context("long header", func() {
It("writes", func() {
err := (&Header{
IsLongHeader: true,
Type: 0x5,
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe},
SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x0, 0x0, 0x13, 0x37},
PayloadLen: 0xcafe,
PacketNumber: 0xdecaf,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
expected := []byte{
0x80 ^ 0x5,
0x1, 0x2, 0x3, 0x4, // version number
0x35, // connection ID lengths
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, // dest connection ID
0xde, 0xca, 0xfb, 0xad, 0x0, 0x0, 0x13, 0x37, // source connection ID
}
expected = append(expected, encodeVarInt(0xcafe)...) // payload length
expected = appendPacketNumber(expected, 0xdecaf, protocol.PacketNumberLen4)
Expect(buf.Bytes()).To(Equal(expected))
})
It("refuses to write a header with a too short connection ID", func() {
err := (&Header{
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3}, // connection IDs must be at least 4 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).writeHeader(buf)
Expect(err).To(MatchError("invalid connection ID length: 3 bytes"))
})
It("refuses to write a header with a too long connection ID", func() {
err := (&Header{
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19}, // connection IDs must be at most 18 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).writeHeader(buf)
Expect(err).To(MatchError("invalid connection ID length: 19 bytes"))
})
It("writes a header with an 18 byte connection ID", func() {
err := (&Header{
IsLongHeader: true,
Type: 0x5,
SrcConnectionID: srcConnID,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18}, // connection IDs must be at most 18 bytes long
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
Version: 0x1020304,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(ContainSubstring(string([]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18})))
})
})
Context("short header", func() {
It("writes a header with connection ID", func() {
err := (&Header{
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 0x42,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x30,
0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37, // connection ID
0x42, // packet number
}))
})
It("writes a header without connection ID", func() {
err := (&Header{
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 0x42,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x30,
0x42, // packet number
}))
})
It("writes a header with a 2 byte packet number", func() {
err := (&Header{
PacketNumberLen: protocol.PacketNumberLen2,
PacketNumber: 0x765,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
expected := []byte{0x30}
expected = appendPacketNumber(expected, 0x765, protocol.PacketNumberLen2)
Expect(buf.Bytes()).To(Equal(expected))
})
It("writes a header with a 4 byte packet number", func() {
err := (&Header{
PacketNumberLen: protocol.PacketNumberLen4,
PacketNumber: 0x123456,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
expected := []byte{0x30}
expected = appendPacketNumber(expected, 0x123456, protocol.PacketNumberLen4)
Expect(buf.Bytes()).To(Equal(expected))
})
It("errors when given an invalid packet number length", func() {
err := (&Header{
PacketNumberLen: 3,
PacketNumber: 0xdecafbad,
}).writeHeader(buf)
Expect(err).To(MatchError("invalid packet number length: 3"))
})
It("writes the Key Phase Bit", func() {
err := (&Header{
KeyPhase: 1,
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 0x42,
}).writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Bytes()).To(Equal([]byte{
0x30 | 0x40,
0x42, // packet number
}))
})
})
})
Context("length", func() {
var buf *bytes.Buffer
BeforeEach(func() {
buf = &bytes.Buffer{}
})
It("has the right length for the long header, for a short payload length", func() {
h := &Header{
IsLongHeader: true,
PayloadLen: 1,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
PacketNumberLen: protocol.PacketNumberLen1,
}
expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 8 /* src conn id */ + 1 /* short payload len */ + 1 /* packet number */
Expect(h.getHeaderLength()).To(BeEquivalentTo(expectedLen))
err := h.writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(expectedLen))
})
It("has the right length for the long header, for a long payload length", func() {
h := &Header{
IsLongHeader: true,
PayloadLen: 1500,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
PacketNumberLen: protocol.PacketNumberLen2,
}
expectedLen := 1 /* type byte */ + 4 /* version */ + 1 /* conn ID len */ + 8 /* dest conn id */ + 8 /* src conn id */ + 2 /* long payload len */ + 2 /* packet number */
Expect(h.getHeaderLength()).To(BeEquivalentTo(expectedLen))
err := h.writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(expectedLen))
})
It("has the right length for a hort header containing a connection ID", func() {
h := &Header{
PacketNumberLen: protocol.PacketNumberLen1,
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
}
Expect(h.getHeaderLength()).To(Equal(protocol.ByteCount(1 + 8 + 1)))
err := h.writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(10))
})
It("has the right length for a short header without a connection ID", func() {
h := &Header{PacketNumberLen: protocol.PacketNumberLen1}
Expect(h.getHeaderLength()).To(Equal(protocol.ByteCount(1 + 1)))
err := h.writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(2))
})
It("has the right length for a short header with a 2 byte packet number", func() {
h := &Header{PacketNumberLen: protocol.PacketNumberLen2}
Expect(h.getHeaderLength()).To(Equal(protocol.ByteCount(1 + 2)))
err := h.writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(3))
})
It("has the right length for a short header with a 5 byte packet number", func() {
h := &Header{PacketNumberLen: protocol.PacketNumberLen4}
Expect(h.getHeaderLength()).To(Equal(protocol.ByteCount(1 + 4)))
err := h.writeHeader(buf)
Expect(err).ToNot(HaveOccurred())
Expect(buf.Len()).To(Equal(5))
})
It("errors when given an invalid packet number length", func() {
h := &Header{PacketNumberLen: 5}
_, err := h.getHeaderLength()
Expect(err).To(MatchError("invalid packet number length: 5"))
})
})
Context("logging", func() {
var (
buf *bytes.Buffer
logger utils.Logger
)
BeforeEach(func() {
buf = &bytes.Buffer{}
logger = utils.DefaultLogger
logger.SetLogLevel(utils.LogLevelDebug)
log.SetOutput(buf)
})
AfterEach(func() {
log.SetOutput(os.Stdout)
})
It("logs version negotiation packets", func() {
destConnID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}
srcConnID := protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37}
data, err := ComposeVersionNegotiation(destConnID, srcConnID, []protocol.VersionNumber{0x12345678, 0x87654321})
Expect(err).ToNot(HaveOccurred())
hdr, err := parseLongHeader(bytes.NewReader(data[1:]), data[0])
Expect(err).ToNot(HaveOccurred())
hdr.logHeader(logger)
Expect(buf.String()).To(ContainSubstring("VersionNegotiationPacket{DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337"))
Expect(buf.String()).To(ContainSubstring("0x12345678"))
Expect(buf.String()).To(ContainSubstring("0x87654321"))
})
It("logs Long Headers", func() {
(&Header{
IsLongHeader: true,
Type: protocol.PacketTypeHandshake,
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen2,
PayloadLen: 54321,
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
SrcConnectionID: protocol.ConnectionID{0xde, 0xca, 0xfb, 0xad, 0x013, 0x37, 0x13, 0x37},
Version: 0xfeed,
}).logHeader(logger)
Expect(buf.String()).To(ContainSubstring("Long Header{Type: Handshake, DestConnectionID: 0xdeadbeefcafe1337, SrcConnectionID: 0xdecafbad13371337, PacketNumber: 0x1337, PacketNumberLen: 2, PayloadLen: 54321, Version: 0xfeed}"))
})
It("logs Short Headers containing a connection ID", func() {
(&Header{
KeyPhase: 1,
PacketNumber: 0x1337,
PacketNumberLen: 4,
DestConnectionID: protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37},
}).logHeader(logger)
Expect(buf.String()).To(ContainSubstring("Short Header{DestConnectionID: 0xdeadbeefcafe1337, PacketNumber: 0x1337, PacketNumberLen: 4, KeyPhase: 1}"))
})
})
})

View file

@ -1,223 +0,0 @@
package wire
import (
"bytes"
"errors"
"fmt"
"io"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
)
var (
errInvalidConnectionID = qerr.Error(qerr.InvalidPacketHeader, "connection ID cannot be 0")
errInvalidPacketNumberLen6 = errors.New("invalid packet number length: 6 bytes")
)
// writePublicHeader writes a Public Header.
func (h *Header) writePublicHeader(b *bytes.Buffer, pers protocol.Perspective, _ protocol.VersionNumber) error {
if h.ResetFlag || (h.VersionFlag && pers == protocol.PerspectiveServer) {
return errors.New("PublicHeader: Can only write regular packets")
}
if h.SrcConnectionID.Len() != 0 {
return errors.New("PublicHeader: SrcConnectionID must not be set")
}
if len(h.DestConnectionID) != 0 && len(h.DestConnectionID) != 8 {
return fmt.Errorf("PublicHeader: wrong length for Connection ID: %d (expected 8)", len(h.DestConnectionID))
}
publicFlagByte := uint8(0x00)
if h.VersionFlag {
publicFlagByte |= 0x01
}
if h.ResetFlag {
publicFlagByte |= 0x02
}
if h.DestConnectionID.Len() > 0 {
publicFlagByte |= 0x08
}
if len(h.DiversificationNonce) > 0 {
if len(h.DiversificationNonce) != 32 {
return errors.New("invalid diversification nonce length")
}
publicFlagByte |= 0x04
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
publicFlagByte |= 0x00
case protocol.PacketNumberLen2:
publicFlagByte |= 0x10
case protocol.PacketNumberLen4:
publicFlagByte |= 0x20
}
b.WriteByte(publicFlagByte)
if h.DestConnectionID.Len() > 0 {
b.Write(h.DestConnectionID)
}
if h.VersionFlag && pers == protocol.PerspectiveClient {
utils.BigEndian.WriteUint32(b, uint32(h.Version))
}
if len(h.DiversificationNonce) > 0 {
b.Write(h.DiversificationNonce)
}
switch h.PacketNumberLen {
case protocol.PacketNumberLen1:
b.WriteByte(uint8(h.PacketNumber))
case protocol.PacketNumberLen2:
utils.BigEndian.WriteUint16(b, uint16(h.PacketNumber))
case protocol.PacketNumberLen4:
utils.BigEndian.WriteUint32(b, uint32(h.PacketNumber))
case protocol.PacketNumberLen6:
return errInvalidPacketNumberLen6
default:
return errors.New("PublicHeader: PacketNumberLen not set")
}
return nil
}
// parsePublicHeader parses a QUIC packet's Public Header.
// The packetSentBy is the perspective of the peer that sent this PublicHeader, i.e. if we're the server, packetSentBy should be PerspectiveClient.
func parsePublicHeader(b *bytes.Reader, packetSentBy protocol.Perspective) (*Header, error) {
header := &Header{}
// First byte
publicFlagByte, err := b.ReadByte()
if err != nil {
return nil, err
}
header.ResetFlag = publicFlagByte&0x02 > 0
header.VersionFlag = publicFlagByte&0x01 > 0
// TODO: activate this check once Chrome sends the correct value
// see https://github.com/lucas-clemente/quic-go/issues/232
// if publicFlagByte&0x04 > 0 {
// return nil, errors.New("diversification nonces should only be sent by servers")
// }
hasConnectionID := publicFlagByte&0x08 > 0
if !hasConnectionID && packetSentBy == protocol.PerspectiveClient {
return nil, qerr.Error(qerr.InvalidPacketHeader, "receiving packets with omitted ConnectionID is not supported")
}
if header.hasPacketNumber(packetSentBy) {
switch publicFlagByte & 0x30 {
case 0x30:
return nil, errInvalidPacketNumberLen6
case 0x20:
header.PacketNumberLen = protocol.PacketNumberLen4
case 0x10:
header.PacketNumberLen = protocol.PacketNumberLen2
case 0x00:
header.PacketNumberLen = protocol.PacketNumberLen1
}
}
// Connection ID
if hasConnectionID {
connID, err := protocol.ReadConnectionID(b, 8)
if err != nil {
return nil, err
}
if connID[0] == 0 && connID[1] == 0 && connID[2] == 0 && connID[3] == 0 && connID[4] == 0 && connID[5] == 0 && connID[6] == 0 && connID[7] == 0 {
return nil, errInvalidConnectionID
}
header.DestConnectionID = connID
}
// Contrary to what the gQUIC wire spec says, the 0x4 bit only indicates the presence of the diversification nonce for packets sent by the server.
// It doesn't have any meaning when sent by the client.
if packetSentBy == protocol.PerspectiveServer && publicFlagByte&0x04 > 0 {
if !header.VersionFlag && !header.ResetFlag {
header.DiversificationNonce = make([]byte, 32)
if _, err := io.ReadFull(b, header.DiversificationNonce); err != nil {
return nil, err
}
}
}
// Version (optional)
if !header.ResetFlag && header.VersionFlag {
if packetSentBy == protocol.PerspectiveServer { // parse the version negotiation packet
if b.Len() == 0 {
return nil, qerr.Error(qerr.InvalidVersionNegotiationPacket, "empty version list")
}
if b.Len()%4 != 0 {
return nil, qerr.InvalidVersionNegotiationPacket
}
header.IsVersionNegotiation = true
header.SupportedVersions = make([]protocol.VersionNumber, 0)
for {
var versionTag uint32
versionTag, err = utils.BigEndian.ReadUint32(b)
if err != nil {
break
}
v := protocol.VersionNumber(versionTag)
header.SupportedVersions = append(header.SupportedVersions, v)
}
// a version negotiation packet doesn't have a packet number
return header, nil
}
// packet was sent by the client. Read the version number
var versionTag uint32
versionTag, err = utils.BigEndian.ReadUint32(b)
if err != nil {
return nil, err
}
header.Version = protocol.VersionNumber(versionTag)
}
// Packet number
if header.hasPacketNumber(packetSentBy) {
packetNumber, err := utils.BigEndian.ReadUintN(b, uint8(header.PacketNumberLen))
if err != nil {
return nil, err
}
header.PacketNumber = protocol.PacketNumber(packetNumber)
}
return header, nil
}
// getPublicHeaderLength gets the length of the publicHeader in bytes.
// It can only be called for regular packets.
func (h *Header) getPublicHeaderLength(pers protocol.Perspective) (protocol.ByteCount, error) {
length := protocol.ByteCount(1) // 1 byte for public flags
if h.PacketNumberLen == protocol.PacketNumberLen6 {
return 0, errInvalidPacketNumberLen6
}
if h.PacketNumberLen != protocol.PacketNumberLen1 && h.PacketNumberLen != protocol.PacketNumberLen2 && h.PacketNumberLen != protocol.PacketNumberLen4 {
return 0, errPacketNumberLenNotSet
}
length += protocol.ByteCount(h.PacketNumberLen)
length += protocol.ByteCount(h.DestConnectionID.Len()) // if set, always 8 bytes
// Version Number in packets sent by the client
if h.VersionFlag {
length += 4
}
length += protocol.ByteCount(len(h.DiversificationNonce))
return length, nil
}
// hasPacketNumber determines if this Public Header will contain a packet number
// this depends on the ResetFlag, the VersionFlag and who sent the packet
func (h *Header) hasPacketNumber(packetSentBy protocol.Perspective) bool {
if h.ResetFlag {
return false
}
if h.VersionFlag && packetSentBy == protocol.PerspectiveServer {
return false
}
return true
}
func (h *Header) logPublicHeader(logger utils.Logger) {
ver := "(unset)"
if h.Version != 0 {
ver = h.Version.String()
}
logger.Debugf("\tPublic Header{ConnectionID: %s, PacketNumber: %#x, PacketNumberLen: %d, Version: %s, DiversificationNonce: %#v}", h.DestConnectionID, h.PacketNumber, h.PacketNumberLen, ver, h.DiversificationNonce)
}

View file

@ -1,475 +0,0 @@
package wire
import (
"bytes"
"encoding/binary"
"log"
"os"
"github.com/lucas-clemente/quic-go/internal/protocol"
"github.com/lucas-clemente/quic-go/internal/utils"
"github.com/lucas-clemente/quic-go/qerr"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Public Header", func() {
connID := protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}
Context("when parsing", func() {
It("accepts a sample client header", func() {
ver := make([]byte, 4)
binary.BigEndian.PutUint32(ver, uint32(protocol.SupportedVersions[0]))
b := bytes.NewReader(append(append([]byte{0x09, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}, ver...), 0x01))
hdr, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.IsVersionNegotiation).To(BeFalse())
Expect(hdr.ResetFlag).To(BeFalse())
connID := protocol.ConnectionID{0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6}
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.Version).To(Equal(protocol.SupportedVersions[0]))
Expect(hdr.SupportedVersions).To(BeEmpty())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(1)))
Expect(b.Len()).To(BeZero())
})
It("does not accept an omittedd connection ID as a server", func() {
b := bytes.NewReader([]byte{0x00, 0x01})
_, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).To(MatchError("InvalidPacketHeader: receiving packets with omitted ConnectionID is not supported"))
})
It("accepts an omitted connection ID as a client", func() {
b := bytes.NewReader([]byte{0x00, 0x01})
hdr, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).To(BeEmpty())
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(b.Len()).To(BeZero())
})
It("rejects 0 as a connection ID", func() {
b := bytes.NewReader([]byte{0x09, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x51, 0x30, 0x33, 0x30, 0x01})
_, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).To(MatchError(errInvalidConnectionID))
})
It("parses a PUBLIC_RESET packet", func() {
b := bytes.NewReader([]byte{0xa, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8})
hdr, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.ResetFlag).To(BeTrue())
Expect(hdr.VersionFlag).To(BeFalse())
Expect(hdr.IsVersionNegotiation).To(BeFalse())
connID := protocol.ConnectionID{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.DestConnectionID).To(Equal(connID))
})
It("reads a diversification nonce sent by the server", func() {
divNonce := []byte{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f}
Expect(divNonce).To(HaveLen(32))
b := bytes.NewReader(append(append([]byte{0x0c, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c}, divNonce...), 0x37))
hdr, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).ToNot(BeEmpty())
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.DiversificationNonce).To(Equal(divNonce))
Expect(b.Len()).To(BeZero())
})
Context("version negotiation packets", func() {
appendVersion := func(data []byte, v protocol.VersionNumber) []byte {
data = append(data, []byte{0, 0, 0, 0}...)
binary.BigEndian.PutUint32(data[len(data)-4:], uint32(v))
return data
}
It("parses", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
versions := []protocol.VersionNumber{0x13, 0x37}
b := bytes.NewReader(ComposeGQUICVersionNegotiation(connID, versions))
hdr, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).To(Equal(connID))
Expect(hdr.SrcConnectionID).To(BeEmpty())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.Version).To(BeZero()) // unitialized
Expect(hdr.IsVersionNegotiation).To(BeTrue())
// in addition to the versions, the supported versions might contain a reserved version number
for _, version := range versions {
Expect(hdr.SupportedVersions).To(ContainElement(version))
}
Expect(b.Len()).To(BeZero())
})
It("errors if it doesn't contain any versions", func() {
b := bytes.NewReader([]byte{0x9, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c})
_, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).To(MatchError("InvalidVersionNegotiationPacket: empty version list"))
})
It("reads version negotiation packets containing unsupported versions", func() {
data := []byte{0x9, 0xf6, 0x19, 0x86, 0x66, 0x9b, 0x9f, 0xfa, 0x4c}
data = appendVersion(data, 1) // unsupported version
data = appendVersion(data, protocol.SupportedVersions[0])
data = appendVersion(data, 99) // unsupported version
b := bytes.NewReader(data)
hdr, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.IsVersionNegotiation).To(BeTrue())
Expect(hdr.SupportedVersions).To(Equal([]protocol.VersionNumber{1, protocol.SupportedVersions[0], 99}))
Expect(b.Len()).To(BeZero())
})
It("errors on invalid version tags", func() {
data := ComposeGQUICVersionNegotiation(protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}, protocol.SupportedVersions)
data = append(data, []byte{0x13, 0x37}...)
b := bytes.NewReader(data)
_, err := parsePublicHeader(b, protocol.PerspectiveServer)
Expect(err).To(MatchError(qerr.InvalidVersionNegotiationPacket))
})
})
Context("Packet Number lengths", func() {
It("accepts 1-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde})
hdr, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xde)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen1))
Expect(b.Len()).To(BeZero())
})
It("accepts 2-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde, 0xca})
hdr, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xdeca)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen2))
Expect(b.Len()).To(BeZero())
})
It("accepts 4-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x28, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xad, 0xfb, 0xca, 0xde})
hdr, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PacketNumber).To(Equal(protocol.PacketNumber(0xadfbcade)))
Expect(hdr.PacketNumberLen).To(Equal(protocol.PacketNumberLen4))
Expect(b.Len()).To(BeZero())
})
It("rejects 6-byte packet numbers", func() {
b := bytes.NewReader([]byte{0x38, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x23, 0x42, 0xad, 0xfb, 0xca, 0xde})
_, err := parsePublicHeader(b, protocol.PerspectiveClient)
Expect(err).To(MatchError(errInvalidPacketNumberLen6))
})
})
})
Context("when writing", func() {
It("writes a sample header as a server", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 2,
PacketNumberLen: protocol.PacketNumberLen4,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{0x28, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0, 0, 0, 2}))
})
It("writes a sample header as a client", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen2,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveClient, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x13, 0x37}))
})
It("refuses to write a Public Header with a source connection ID", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: protocol.ConnectionID{8, 7, 6, 5, 4, 3, 2, 1},
PacketNumber: 0x1337,
PacketNumberLen: protocol.PacketNumberLen4,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveClient, versionBigEndian)
Expect(err).To(MatchError("PublicHeader: SrcConnectionID must not be set"))
})
It("refuses to write a Public Header if the connection ID has the wrong length", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 2,
PacketNumberLen: protocol.PacketNumberLen2,
}
b := &bytes.Buffer{}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).To(MatchError("PublicHeader: wrong length for Connection ID: 7 (expected 8)"))
})
It("refuses to write a Public Header if the PacketNumberLen is not set", func() {
connID := protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 2,
}
b := &bytes.Buffer{}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).To(MatchError("PublicHeader: PacketNumberLen not set"))
})
It("omits the connection ID", func() {
b := &bytes.Buffer{}
hdr := Header{
PacketNumberLen: protocol.PacketNumberLen1,
PacketNumber: 1,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{0x0, 0x1}))
})
It("writes diversification nonces", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 1,
PacketNumberLen: protocol.PacketNumberLen1,
DiversificationNonce: bytes.Repeat([]byte{1}, 32),
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, versionBigEndian)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{
0x0c, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0x01,
}))
})
It("doesn't write Version Negotiation Packets", func() {
b := &bytes.Buffer{}
hdr := Header{
VersionFlag: true,
DestConnectionID: connID,
PacketNumber: 2,
PacketNumberLen: protocol.PacketNumberLen6,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).To(MatchError("PublicHeader: Can only write regular packets"))
})
It("writes packets with Version Flag, as a client", func() {
b := &bytes.Buffer{}
hdr := Header{
VersionFlag: true,
Version: protocol.Version39,
DestConnectionID: connID,
PacketNumber: 0x42,
PacketNumberLen: protocol.PacketNumberLen1,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveClient, protocol.VersionWhatever)
Expect(err).ToNot(HaveOccurred())
// must be the first assertion
Expect(b.Len()).To(Equal(1 + 8 + 4 + 1)) // 1 FlagByte + 8 ConnectionID + 4 version number + 1 PacketNumber
firstByte, _ := b.ReadByte()
Expect(firstByte & 0x01).To(Equal(uint8(1)))
Expect(firstByte & 0x30).To(Equal(uint8(0x0)))
Expect(string(b.Bytes()[8:12])).To(Equal("Q039"))
Expect(b.Bytes()[12:13]).To(Equal([]byte{0x42}))
})
Context("getting the length", func() {
It("errors when PacketNumberLen is not set", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
}
_, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(err).To(MatchError(errPacketNumberLenNotSet))
})
It("gets the length of a packet with longest packet number length and connectionID", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
}
length, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 8 + 4))) // 1 byte public flag, 8 bytes connectionID, and packet number
})
It("gets the lengths of a packet sent by the client with the VersionFlag set", func() {
hdr := Header{
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen4,
VersionFlag: true,
Version: versionBigEndian,
}
length, err := hdr.getPublicHeaderLength(protocol.PerspectiveClient)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 4 + 4))) // 1 byte public flag, 4 version number, and packet number
})
It("gets the length of a packet with longest packet number length and omitted connectionID", func() {
hdr := Header{
PacketNumber: 0xDECAFBAD,
PacketNumberLen: protocol.PacketNumberLen4,
}
length, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 4))) // 1 byte public flag, and packet number
})
It("gets the length of a packet 2 byte packet number length ", func() {
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xDECAFBAD,
PacketNumberLen: protocol.PacketNumberLen2,
}
length, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(err).ToNot(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 8 + 2))) // 1 byte public flag, 8 byte connectionID, and packet number
})
It("works with diversification nonce", func() {
hdr := Header{
DiversificationNonce: []byte("foo"),
PacketNumberLen: protocol.PacketNumberLen1,
}
length, err := hdr.getPublicHeaderLength(protocol.PerspectiveServer)
Expect(err).NotTo(HaveOccurred())
Expect(length).To(Equal(protocol.ByteCount(1 + 3 + 1))) // 1 byte public flag, 3 byte DiversificationNonce, 1 byte PacketNumber
})
})
Context("packet number length", func() {
It("doesn't write a header if the packet number length is not set", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xDECAFBAD,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, protocol.VersionWhatever)
Expect(err).To(MatchError("PublicHeader: PacketNumberLen not set"))
})
Context("in big endian", func() {
version := versionBigEndian
It("writes a header with a 1-byte packet number", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen1,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, version)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xad}))
})
It("writes a header with a 2-byte packet number", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xdecafbad,
PacketNumberLen: protocol.PacketNumberLen2,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, version)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{0x18, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xfb, 0xad}))
})
It("writes a header with a 4-byte packet number", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0x13decafbad,
PacketNumberLen: protocol.PacketNumberLen4,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, version)
Expect(err).ToNot(HaveOccurred())
Expect(b.Bytes()).To(Equal([]byte{0x28, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0xde, 0xca, 0xfb, 0xad}))
})
It("refuses to write a header with a 6-byte packet number", func() {
b := &bytes.Buffer{}
hdr := Header{
DestConnectionID: connID,
PacketNumber: 0xbe1337decafbad,
PacketNumberLen: protocol.PacketNumberLen6,
}
err := hdr.writePublicHeader(b, protocol.PerspectiveServer, version)
Expect(err).To(MatchError(errInvalidPacketNumberLen6))
})
})
})
})
Context("logging", func() {
var (
buf *bytes.Buffer
logger utils.Logger
)
BeforeEach(func() {
buf = &bytes.Buffer{}
logger = utils.DefaultLogger
logger.SetLogLevel(utils.LogLevelDebug)
log.SetOutput(buf)
})
AfterEach(func() {
log.SetOutput(os.Stdout)
})
It("logs a Public Header containing a connection ID", func() {
(&Header{
DestConnectionID: protocol.ConnectionID{0x13, 0x37, 0, 0, 0xde, 0xca, 0xfb, 0xad},
PacketNumber: 0x1337,
PacketNumberLen: 6,
Version: protocol.Version39,
}).logPublicHeader(logger)
Expect(buf.String()).To(ContainSubstring("Public Header{ConnectionID: 0x13370000decafbad, PacketNumber: 0x1337, PacketNumberLen: 6, Version: gQUIC 39"))
})
It("logs a Public Header with omitted connection ID", func() {
(&Header{
PacketNumber: 0x1337,
PacketNumberLen: 6,
Version: protocol.Version39,
}).logPublicHeader(logger)
Expect(buf.String()).To(ContainSubstring("Public Header{ConnectionID: (empty)"))
})
It("logs a Public Header without a version", func() {
(&Header{
PacketNumber: 0x1337,
PacketNumberLen: 6,
}).logPublicHeader(logger)
Expect(buf.String()).To(ContainSubstring("Version: (unset)"))
})
It("logs diversification nonces", func() {
(&Header{
DestConnectionID: []byte{0x13, 0x13, 0, 0, 0xde, 0xca, 0xfb, 0xad},
DiversificationNonce: []byte{0xba, 0xdf, 0x00, 0x0d},
}).logPublicHeader(logger)
Expect(buf.String()).To(ContainSubstring("DiversificationNonce: []byte{0xba, 0xdf, 0x0, 0xd}"))
})
})
})

View file

@ -13,7 +13,10 @@ var _ = Describe("Version Negotiation Packets", func() {
connID := protocol.ConnectionID{0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe, 0x13, 0x37}
versions := []protocol.VersionNumber{1001, 1003}
data := ComposeGQUICVersionNegotiation(connID, versions)
hdr, err := parsePublicHeader(bytes.NewReader(data), protocol.PerspectiveServer)
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionPublicHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.VersionFlag).To(BeTrue())
Expect(hdr.DestConnectionID).To(Equal(connID))
@ -28,7 +31,10 @@ var _ = Describe("Version Negotiation Packets", func() {
data, err := ComposeVersionNegotiation(destConnID, srcConnID, versions)
Expect(err).ToNot(HaveOccurred())
Expect(data[0] & 0x80).ToNot(BeZero())
hdr, err := parseHeader(bytes.NewReader(data))
b := bytes.NewReader(data)
iHdr, err := ParseInvariantHeader(b)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(b, protocol.PerspectiveServer, versionIETFHeader)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsVersionNegotiation).To(BeTrue())
Expect(hdr.DestConnectionID).To(Equal(destConnID))

View file

@ -21,6 +21,10 @@ const (
versionBigEndian = protocol.Version39
// a QUIC version that uses the IETF frame types
versionIETFFrames = protocol.VersionTLS
// a QUIC version that uses the gQUIC Public Header
versionPublicHeader = protocol.Version43
// a QUIC version that the IETF QUIC Header
versionIETFHeader = protocol.VersionTLS
)
func encodeVarInt(i uint64) []byte {

View file

@ -172,7 +172,7 @@ func (p *packetPacker) PackRetransmission(packet *ackhandler.Packet) ([]*packedP
var payloadLength protocol.ByteCount
header := p.getHeader(encLevel)
headerLength, err := header.GetLength(p.perspective, p.version)
headerLength, err := header.GetLength(p.version)
if err != nil {
return nil, err
}
@ -298,7 +298,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
encLevel, sealer := p.cryptoSetup.GetSealer()
header := p.getHeader(encLevel)
headerLength, err := header.GetLength(p.perspective, p.version)
headerLength, err := header.GetLength(p.version)
if err != nil {
return nil, err
}
@ -352,7 +352,7 @@ func (p *packetPacker) PackPacket() (*packedPacket, error) {
func (p *packetPacker) packCryptoPacket() (*packedPacket, error) {
encLevel, sealer := p.cryptoSetup.GetSealerForCryptoStream()
header := p.getHeader(encLevel)
headerLength, err := header.GetLength(p.perspective, p.version)
headerLength, err := header.GetLength(p.version)
if err != nil {
return nil, err
}
@ -498,7 +498,7 @@ func (p *packetPacker) writeAndSealPacket(
// the payload length is only needed for Long Headers
if header.IsLongHeader {
if header.Type == protocol.PacketTypeInitial {
headerLen, _ := header.GetLength(p.perspective, p.version)
headerLen, _ := header.GetLength(p.version)
header.PayloadLen = protocol.ByteCount(protocol.MinInitialPacketSize) - headerLen
} else {
payloadLen := protocol.ByteCount(sealer.Overhead())

View file

@ -63,6 +63,15 @@ var _ = Describe("Packet packer", func() {
divNonce []byte
)
checkPayloadLen := func(data []byte) {
r := bytes.NewReader(data)
iHdr, err := wire.ParseInvariantHeader(r)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
ExpectWithOffset(0, hdr.PayloadLen).To(BeEquivalentTo(r.Len()))
}
BeforeEach(func() {
version := versionGQUICFrames
mockSender := NewMockStreamSender(mockCtrl)
@ -268,11 +277,7 @@ var _ = Describe("Packet packer", func() {
mockStreamFramer.EXPECT().PopCryptoStreamFrame(gomock.Any()).Return(f)
p, err := packer.PackPacket()
Expect(err).ToNot(HaveOccurred())
// parse the packet
r := bytes.NewReader(p.raw)
hdr, err := wire.ParseHeaderSentByServer(r)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PayloadLen).To(BeEquivalentTo(r.Len()))
checkPayloadLen(p.raw)
})
It("packs a CONNECTION_CLOSE", func() {
@ -617,11 +622,7 @@ var _ = Describe("Packet packer", func() {
expectedPacketLen := packer.maxPacketSize - protocol.NonForwardSecurePacketSizeReduction
Expect(p.raw).To(HaveLen(int(expectedPacketLen)))
Expect(p.header.IsLongHeader).To(BeTrue())
// parse the packet
r := bytes.NewReader(p.raw)
hdr, err := wire.ParseHeaderSentByServer(r)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PayloadLen).To(BeEquivalentTo(r.Len()))
checkPayloadLen(p.raw)
})
It("sends unencrypted stream data on the crypto stream", func() {
@ -798,11 +799,7 @@ var _ = Describe("Packet packer", func() {
packer.cryptoSetup.(*mockCryptoSetup).encLevelSealCrypto = protocol.EncryptionUnencrypted
packet, err := packer.PackPacket()
Expect(err).ToNot(HaveOccurred())
// parse the header and check the values
r := bytes.NewReader(packet.raw)
hdr, err := wire.ParseHeaderSentByClient(r)
Expect(err).ToNot(HaveOccurred())
Expect(hdr.PayloadLen).To(BeEquivalentTo(r.Len()))
checkPayloadLen(packet.raw)
})
It("packs a retransmission for an Initial packet", func() {

View file

@ -20,6 +20,7 @@ import (
type packetHandler interface {
handlePacket(*receivedPacket)
Close(error) error
GetVersion() protocol.VersionNumber
}
type packetHandlerManager interface {
@ -303,7 +304,20 @@ func (s *server) handlePacket(remoteAddr net.Addr, packet []byte) error {
rcvTime := time.Now()
r := bytes.NewReader(packet)
hdr, err := wire.ParseHeaderSentByClient(r)
iHdr, err := wire.ParseInvariantHeader(r)
if err != nil {
return qerr.Error(qerr.InvalidPacketHeader, err.Error())
}
session, sessionKnown := s.sessionHandler.Get(iHdr.DestConnectionID)
if sessionKnown && session == nil {
// Late packet for closed session
return nil
}
version := protocol.VersionUnknown
if sessionKnown {
version = session.GetVersion()
}
hdr, err := iHdr.Parse(r, protocol.PerspectiveClient, version)
if err != nil {
return qerr.Error(qerr.InvalidPacketHeader, err.Error())
}
@ -311,12 +325,18 @@ func (s *server) handlePacket(remoteAddr net.Addr, packet []byte) error {
packetData := packet[len(packet)-r.Len():]
if hdr.IsPublicHeader {
return s.handleGQUICPacket(hdr, packetData, remoteAddr, rcvTime)
return s.handleGQUICPacket(session, hdr, packetData, remoteAddr, rcvTime)
}
return s.handleIETFQUICPacket(hdr, packetData, remoteAddr, rcvTime)
return s.handleIETFQUICPacket(session, hdr, packetData, remoteAddr, rcvTime)
}
func (s *server) handleIETFQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error {
func (s *server) handleIETFQUICPacket(
session packetHandler,
hdr *wire.Header,
packetData []byte,
remoteAddr net.Addr,
rcvTime time.Time,
) error {
if hdr.IsLongHeader {
if !s.supportsTLS {
return errors.New("Received an IETF QUIC Long Header")
@ -339,12 +359,7 @@ func (s *server) handleIETFQUICPacket(hdr *wire.Header, packetData []byte, remot
}
}
session, sessionKnown := s.sessionHandler.Get(hdr.DestConnectionID)
if sessionKnown && session == nil {
// Late packet for closed session
return nil
}
if !sessionKnown {
if session == nil {
s.logger.Debugf("Received %s packet for unknown connection %s.", hdr.Type, hdr.DestConnectionID)
return nil
}
@ -358,18 +373,20 @@ func (s *server) handleIETFQUICPacket(hdr *wire.Header, packetData []byte, remot
return nil
}
func (s *server) handleGQUICPacket(hdr *wire.Header, packetData []byte, remoteAddr net.Addr, rcvTime time.Time) error {
func (s *server) handleGQUICPacket(
session packetHandler,
hdr *wire.Header,
packetData []byte,
remoteAddr net.Addr,
rcvTime time.Time,
) error {
// ignore all Public Reset packets
if hdr.ResetFlag {
s.logger.Infof("Received unexpected Public Reset for connection %s.", hdr.DestConnectionID)
return nil
}
session, sessionKnown := s.sessionHandler.Get(hdr.DestConnectionID)
if sessionKnown && session == nil {
// Late packet for closed session
return nil
}
sessionKnown := session != nil
// If we don't have a session for this connection, and this packet cannot open a new connection, send a Public Reset
// This should only happen after a server restart, when we still receive packets for connections that we lost the state for.

View file

@ -221,6 +221,7 @@ var _ = Describe("Server", func() {
It("assigns packets to existing sessions", func() {
sess := NewMockQuicSession(mockCtrl)
sess.EXPECT().handlePacket(gomock.Any())
sess.EXPECT().GetVersion()
sessionHandler.EXPECT().Get(connID).Return(sess, true)
err := serv.handlePacket(nil, []byte{0x08, 0x4c, 0xfa, 0x9f, 0x9b, 0x66, 0x86, 0x19, 0xf6, 0x01})
@ -284,6 +285,7 @@ var _ = Describe("Server", func() {
It("ignores delayed packets with mismatching versions", func() {
sess := NewMockQuicSession(mockCtrl)
sess.EXPECT().GetVersion()
// don't EXPECT any handlePacket() calls to this session
sessionHandler.EXPECT().Get(connID).Return(sess, true)
@ -304,14 +306,18 @@ var _ = Describe("Server", func() {
})
It("errors on packets that are smaller than the Payload Length in the packet header", func() {
sess := NewMockQuicSession(mockCtrl)
sess.EXPECT().GetVersion().Return(protocol.VersionTLS)
sessionHandler.EXPECT().Get(connID).Return(sess, true)
serv.supportsTLS = true
b := &bytes.Buffer{}
hdr := &wire.Header{
IsLongHeader: true,
Type: protocol.PacketTypeHandshake,
PayloadLen: 1000,
SrcConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
DestConnectionID: protocol.ConnectionID{1, 2, 3, 4, 5, 6, 7, 8},
SrcConnectionID: connID,
DestConnectionID: connID,
PacketNumberLen: protocol.PacketNumberLen1,
Version: versionIETFFrames,
}
@ -325,6 +331,8 @@ var _ = Describe("Server", func() {
sess.EXPECT().handlePacket(gomock.Any()).Do(func(packet *receivedPacket) {
Expect(packet.data).To(HaveLen(123))
})
sess.EXPECT().GetVersion().Return(protocol.VersionTLS)
sessionHandler.EXPECT().Get(connID).Return(sess, true)
serv.supportsTLS = true
b := &bytes.Buffer{}
@ -338,12 +346,15 @@ var _ = Describe("Server", func() {
Version: versionIETFFrames,
}
Expect(hdr.Write(b, protocol.PerspectiveClient, versionIETFFrames)).To(Succeed())
sessionHandler.EXPECT().Get(connID).Return(sess, true)
err := serv.handlePacket(nil, append(b.Bytes(), make([]byte, 456)...))
Expect(err).ToNot(HaveOccurred())
})
It("drops packets with invalid packet types", func() {
sess := NewMockQuicSession(mockCtrl)
sess.EXPECT().GetVersion().Return(protocol.VersionTLS)
sessionHandler.EXPECT().Get(connID).Return(sess, true)
serv.supportsTLS = true
b := &bytes.Buffer{}
hdr := &wire.Header{
@ -361,6 +372,10 @@ var _ = Describe("Server", func() {
})
It("ignores Public Resets", func() {
sess := NewMockQuicSession(mockCtrl)
sess.EXPECT().GetVersion().Return(protocol.VersionTLS)
sessionHandler.EXPECT().Get(connID).Return(sess, true)
err := serv.handlePacket(nil, wire.WritePublicReset(connID, 1, 1337))
Expect(err).ToNot(HaveOccurred())
})
@ -485,10 +500,13 @@ var _ = Describe("Server", func() {
Eventually(func() int { return conn.dataWritten.Len() }).ShouldNot(BeZero())
Expect(conn.dataWrittenTo).To(Equal(udpAddr))
r := bytes.NewReader(conn.dataWritten.Bytes())
packet, err := wire.ParseHeaderSentByServer(r)
iHdr, err := wire.ParseInvariantHeader(r)
Expect(err).ToNot(HaveOccurred())
Expect(packet.VersionFlag).To(BeTrue())
Expect(packet.DestConnectionID).To(Equal(connID))
Expect(iHdr.IsLongHeader).To(BeFalse())
replyHdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(replyHdr.IsVersionNegotiation).To(BeTrue())
Expect(replyHdr.DestConnectionID).To(Equal(connID))
Expect(r.Len()).To(BeZero())
Consistently(done).ShouldNot(BeClosed())
// make the go routine return
@ -528,11 +546,13 @@ var _ = Describe("Server", func() {
Eventually(func() int { return conn.dataWritten.Len() }).ShouldNot(BeZero())
Expect(conn.dataWrittenTo).To(Equal(udpAddr))
r := bytes.NewReader(conn.dataWritten.Bytes())
packet, err := wire.ParseHeaderSentByServer(r)
iHdr, err := wire.ParseInvariantHeader(r)
Expect(err).ToNot(HaveOccurred())
Expect(packet.IsVersionNegotiation).To(BeTrue())
Expect(packet.DestConnectionID).To(Equal(connID))
Expect(packet.SrcConnectionID).To(Equal(connID))
replyHdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
Expect(replyHdr.IsVersionNegotiation).To(BeTrue())
Expect(replyHdr.DestConnectionID).To(Equal(connID))
Expect(replyHdr.SrcConnectionID).To(Equal(connID))
Expect(r.Len()).To(BeZero())
Consistently(done).ShouldNot(BeClosed())
// make the go routine return

View file

@ -73,13 +73,18 @@ var _ = Describe("Stateless TLS handling", func() {
unpackPacket := func(data []byte) (*wire.Header, []byte) {
r := bytes.NewReader(conn.dataWritten.Bytes())
hdr, err := wire.ParseHeaderSentByServer(r)
iHdr, err := wire.ParseInvariantHeader(r)
Expect(err).ToNot(HaveOccurred())
hdr, err := iHdr.Parse(r, protocol.PerspectiveServer, versionIETFFrames)
Expect(err).ToNot(HaveOccurred())
hdr.Raw = data[:len(data)-r.Len()]
var payload []byte
if r.Len() > 0 {
aead, err := crypto.NewNullAEAD(protocol.PerspectiveClient, hdr.SrcConnectionID, protocol.VersionTLS)
Expect(err).ToNot(HaveOccurred())
payload, err := aead.Open(nil, data[len(data)-r.Len():], hdr.PacketNumber, hdr.Raw)
payload, err = aead.Open(nil, data[len(data)-r.Len():], hdr.PacketNumber, hdr.Raw)
Expect(err).ToNot(HaveOccurred())
}
return hdr, payload
}
@ -92,9 +97,8 @@ var _ = Describe("Stateless TLS handling", func() {
}
server.HandleInitial(nil, hdr, bytes.Repeat([]byte{0}, protocol.MinInitialPacketSize))
Expect(conn.dataWritten.Len()).ToNot(BeZero())
hdr, err := wire.ParseHeaderSentByServer(bytes.NewReader(conn.dataWritten.Bytes()))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.IsVersionNegotiation).To(BeTrue())
replyHdr, _ := unpackPacket(conn.dataWritten.Bytes())
Expect(replyHdr.IsVersionNegotiation).To(BeTrue())
Expect(sessionChan).ToNot(Receive())
})
@ -130,13 +134,11 @@ var _ = Describe("Stateless TLS handling", func() {
hdr, data := getPacket(&wire.StreamFrame{Data: []byte("Client Hello")})
server.HandleInitial(nil, hdr, data)
Expect(conn.dataWritten.Len()).ToNot(BeZero())
r := bytes.NewReader(conn.dataWritten.Bytes())
replyHdr, err := wire.ParseHeaderSentByServer(r)
Expect(err).ToNot(HaveOccurred())
replyHdr, payload := unpackPacket(conn.dataWritten.Bytes())
Expect(replyHdr.Type).To(Equal(protocol.PacketTypeRetry))
Expect(replyHdr.SrcConnectionID).To(Equal(hdr.DestConnectionID))
Expect(replyHdr.DestConnectionID).To(Equal(hdr.SrcConnectionID))
Expect(replyHdr.PayloadLen).To(BeEquivalentTo(r.Len()))
Expect(replyHdr.PayloadLen).To(BeEquivalentTo(len(payload) + 16 /* AEAD overhead */))
Expect(sessionChan).ToNot(Receive())
})

View file

@ -1823,7 +1823,7 @@ var _ = Describe("Client Session", func() {
sess.queueControlFrame(&wire.PingFrame{})
var packet []byte
Eventually(mconn.written).Should(Receive(&packet))
hdr, err := wire.ParseHeaderSentByClient(bytes.NewReader(packet))
hdr, err := wire.ParseInvariantHeader(bytes.NewReader(packet))
Expect(err).ToNot(HaveOccurred())
Expect(hdr.DestConnectionID).To(Equal(protocol.ConnectionID{1, 3, 3, 7, 1, 3, 3, 7}))
// make sure the go routine returns