mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-05 05:07:36 +03:00
refactor header parsing in a version independent and dependent part
This commit is contained in:
parent
74ed3f7037
commit
4109c85c8a
20 changed files with 1587 additions and 1804 deletions
16
client.go
16
client.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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"))
|
||||
})
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
196
internal/wire/header_parser.go
Normal file
196
internal/wire/header_parser.go
Normal 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
|
||||
}
|
487
internal/wire/header_parser_test.go
Normal file
487
internal/wire/header_parser_test.go
Normal 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())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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}"))
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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}"))
|
||||
})
|
||||
})
|
||||
})
|
|
@ -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)
|
||||
}
|
|
@ -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}"))
|
||||
})
|
||||
|
||||
})
|
||||
})
|
|
@ -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))
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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() {
|
||||
|
|
49
server.go
49
server.go
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
})
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue