mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-04 20:57:36 +03:00
CONGESTION_FEEDBACK was reserved for future use in gQUIC, but has never actually been implemented. It won't make it to IETF QUIC, so we don't need to check for it. Note that we'd still reject a CONGESTION_FEEDBACK frame, since we're rejecting any unknown frame type.
262 lines
8.1 KiB
Go
262 lines
8.1 KiB
Go
package quic
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/lucas-clemente/quic-go/internal/crypto"
|
|
"github.com/lucas-clemente/quic-go/internal/protocol"
|
|
"github.com/lucas-clemente/quic-go/internal/wire"
|
|
"github.com/lucas-clemente/quic-go/qerr"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
type mockAEAD struct {
|
|
encLevelOpen protocol.EncryptionLevel
|
|
}
|
|
|
|
func (m *mockAEAD) Open(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel, error) {
|
|
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveClient, 0x1337, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
res, err := nullAEAD.Open(dst, src, packetNumber, associatedData)
|
|
return res, m.encLevelOpen, err
|
|
}
|
|
func (m *mockAEAD) Seal(dst, src []byte, packetNumber protocol.PacketNumber, associatedData []byte) ([]byte, protocol.EncryptionLevel) {
|
|
nullAEAD, err := crypto.NewNullAEAD(protocol.PerspectiveServer, 0x1337, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
return nullAEAD.Seal(dst, src, packetNumber, associatedData), protocol.EncryptionUnspecified
|
|
}
|
|
|
|
var _ quicAEAD = &mockAEAD{}
|
|
|
|
var _ = Describe("Packet unpacker", func() {
|
|
var (
|
|
unpacker *packetUnpacker
|
|
hdr *wire.Header
|
|
hdrBin []byte
|
|
data []byte
|
|
buf *bytes.Buffer
|
|
)
|
|
|
|
BeforeEach(func() {
|
|
hdr = &wire.Header{
|
|
PacketNumber: 10,
|
|
PacketNumberLen: 1,
|
|
}
|
|
hdrBin = []byte{0x04, 0x4c, 0x01}
|
|
unpacker = &packetUnpacker{aead: &mockAEAD{}}
|
|
data = nil
|
|
buf = &bytes.Buffer{}
|
|
})
|
|
|
|
setData := func(p []byte) {
|
|
data, _ = unpacker.aead.(*mockAEAD).Seal(nil, p, 0, hdrBin)
|
|
}
|
|
|
|
It("does not read read a private flag for QUIC Version >= 34", func() {
|
|
f := &wire.ConnectionCloseFrame{ReasonPhrase: "foo"}
|
|
err := f.Write(buf, 0)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("saves the encryption level", func() {
|
|
f := &wire.ConnectionCloseFrame{ReasonPhrase: "foo"}
|
|
err := f.Write(buf, 0)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
unpacker.aead.(*mockAEAD).encLevelOpen = protocol.EncryptionSecure
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.encryptionLevel).To(Equal(protocol.EncryptionSecure))
|
|
})
|
|
|
|
It("unpacks ACK frames", func() {
|
|
unpacker.version = protocol.VersionWhatever
|
|
f := &wire.AckFrame{
|
|
LargestAcked: 0x13,
|
|
LowestAcked: 1,
|
|
}
|
|
err := f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(HaveLen(1))
|
|
readFrame := packet.frames[0].(*wire.AckFrame)
|
|
Expect(readFrame).ToNot(BeNil())
|
|
Expect(readFrame.LargestAcked).To(Equal(protocol.PacketNumber(0x13)))
|
|
})
|
|
|
|
It("handles PADDING frames", func() {
|
|
setData([]byte{0, 0, 0}) // 3 bytes PADDING
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(BeEmpty())
|
|
})
|
|
|
|
It("handles PADDING between two other frames", func() {
|
|
f := &wire.PingFrame{}
|
|
err := f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
_, err = buf.Write(bytes.Repeat([]byte{0}, 10)) // 10 bytes PADDING
|
|
Expect(err).ToNot(HaveOccurred())
|
|
err = f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(HaveLen(2))
|
|
})
|
|
|
|
It("unpacks RST_STREAM frames", func() {
|
|
f := &wire.RstStreamFrame{
|
|
StreamID: 0xdeadbeef,
|
|
ByteOffset: 0xdecafbad11223344,
|
|
ErrorCode: 0x13371234,
|
|
}
|
|
err := f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("unpacks CONNECTION_CLOSE frames", func() {
|
|
f := &wire.ConnectionCloseFrame{ReasonPhrase: "foo"}
|
|
err := f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("unpacks GOAWAY frames", func() {
|
|
f := &wire.GoawayFrame{
|
|
ErrorCode: 1,
|
|
LastGoodStream: 2,
|
|
ReasonPhrase: "foo",
|
|
}
|
|
err := f.Write(buf, 0)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("unpacks WINDOW_UPDATE frames", func() {
|
|
f := &wire.WindowUpdateFrame{
|
|
StreamID: 0xDEADBEEF,
|
|
ByteOffset: 0xCAFE000000001337,
|
|
}
|
|
buf := &bytes.Buffer{}
|
|
err := f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("unpakcs BLOCKED frames", func() {
|
|
f := &wire.BlockedFrame{StreamID: 0xDEADBEEF}
|
|
buf := &bytes.Buffer{}
|
|
err := f.Write(buf, protocol.VersionWhatever)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("unpacks STOP_WAITING frames", func() {
|
|
setData([]byte{0x06, 0x03})
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{
|
|
&wire.StopWaitingFrame{LeastUnacked: 7},
|
|
}))
|
|
})
|
|
|
|
It("unpacks PING frames", func() {
|
|
setData([]byte{0x07})
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{
|
|
&wire.PingFrame{},
|
|
}))
|
|
})
|
|
|
|
It("errors on invalid type", func() {
|
|
setData([]byte{0x08})
|
|
_, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).To(MatchError("InvalidFrameData: unknown type byte 0x8"))
|
|
})
|
|
|
|
It("errors on invalid frames", func() {
|
|
for b, e := range map[byte]qerr.ErrorCode{
|
|
0x80: qerr.InvalidStreamData,
|
|
0x40: qerr.InvalidAckData,
|
|
0x01: qerr.InvalidRstStreamData,
|
|
0x02: qerr.InvalidConnectionCloseData,
|
|
0x03: qerr.InvalidGoawayData,
|
|
0x04: qerr.InvalidWindowUpdateData,
|
|
0x05: qerr.InvalidBlockedData,
|
|
0x06: qerr.InvalidStopWaitingData,
|
|
} {
|
|
setData([]byte{b})
|
|
_, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err.(*qerr.QuicError).ErrorCode).To(Equal(e))
|
|
}
|
|
})
|
|
|
|
Context("unpacking STREAM frames", func() {
|
|
It("unpacks unencrypted STREAM frames on the crypto stream", func() {
|
|
unpacker.aead.(*mockAEAD).encLevelOpen = protocol.EncryptionUnencrypted
|
|
f := &wire.StreamFrame{
|
|
StreamID: unpacker.version.CryptoStreamID(),
|
|
Data: []byte("foobar"),
|
|
}
|
|
err := f.Write(buf, 0)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("unpacks encrypted STREAM frames on the crypto stream", func() {
|
|
unpacker.aead.(*mockAEAD).encLevelOpen = protocol.EncryptionSecure
|
|
f := &wire.StreamFrame{
|
|
StreamID: unpacker.version.CryptoStreamID(),
|
|
Data: []byte("foobar"),
|
|
}
|
|
err := f.Write(buf, 0)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
packet, err := unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(packet.frames).To(Equal([]wire.Frame{f}))
|
|
})
|
|
|
|
It("does not unpack unencrypted STREAM frames on higher streams", func() {
|
|
unpacker.aead.(*mockAEAD).encLevelOpen = protocol.EncryptionUnencrypted
|
|
f := &wire.StreamFrame{
|
|
StreamID: 3,
|
|
Data: []byte("foobar"),
|
|
}
|
|
err := f.Write(buf, 0)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
setData(buf.Bytes())
|
|
_, err = unpacker.Unpack(hdrBin, hdr, data)
|
|
Expect(err).To(MatchError(qerr.Error(qerr.UnencryptedStreamData, "received unencrypted stream data on stream 3")))
|
|
})
|
|
})
|
|
})
|