pad datagrams containing ack-eliciting Initial packets from the server

This commit is contained in:
Marten Seemann 2020-10-25 14:43:57 +07:00
parent 27f569e2c9
commit 459fa5d19b
2 changed files with 112 additions and 92 deletions

View file

@ -303,12 +303,21 @@ func (p *packetPacker) MaybePackAckPacket(handshakeConfirmed bool) (*packedPacke
if err != nil { if err != nil {
return nil, err return nil, err
} }
return p.writeSinglePacket(hdr, payload, encLevel, sealer) packet, err := p.writeSinglePacket(hdr, payload, encLevel, sealer)
if err != nil {
return nil, err
}
p.maybePadPacket(packet.packetContents, packet.buffer)
return packet, nil
} }
func (p *packetPacker) maybePadPacket(firstPacket *packetContents, buffer *packetBuffer) { func (p *packetPacker) maybePadPacket(firstPacket *packetContents, buffer *packetBuffer) {
// Only Initial packets need to be padded. // Only Initial packets need to be padded.
if firstPacket.header.Type != protocol.PacketTypeInitial || p.perspective == protocol.PerspectiveServer { if firstPacket.header.Type != protocol.PacketTypeInitial {
return
}
// For the server, only ack-eliciting Initial packets need to be padded.
if p.perspective == protocol.PerspectiveServer && !ackhandler.HasAckElicitingFrames(firstPacket.frames) {
return return
} }
if dataLen := protocol.ByteCount(len(buffer.Data)); dataLen < p.maxPacketSize { if dataLen := protocol.ByteCount(len(buffer.Data)); dataLen < p.maxPacketSize {

View file

@ -2,6 +2,7 @@ package quic
import ( import (
"bytes" "bytes"
"fmt"
"math/rand" "math/rand"
"net" "net"
"time" "time"
@ -216,18 +217,33 @@ var _ = Describe("Packet packer", func() {
Expect(p).To(BeNil()) Expect(p).To(BeNil())
}) })
It("packs Handshake ACK-only packets", func() { It("packs Initial ACK-only packets, and pads them (for the client)", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2) packer.perspective = protocol.PerspectiveClient
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42)) pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil) pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}} ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true) ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true).Return(ack)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, true).Return(ack)
p, err := packer.MaybePackAckPacket(false) p, err := packer.MaybePackAckPacket(false)
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil()) Expect(p).ToNot(BeNil())
Expect(p.EncryptionLevel()).To(Equal(protocol.EncryptionHandshake)) Expect(p.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.ack).To(Equal(ack)) Expect(p.ack).To(Equal(ack))
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
})
It("packs Initial ACK-only packets, and doesn't pads them (for the server)", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ack := &wire.AckFrame{AckRanges: []wire.AckRange{{Smallest: 1, Largest: 10}}}
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, true).Return(ack)
p, err := packer.MaybePackAckPacket(false)
Expect(err).NotTo(HaveOccurred())
Expect(p).ToNot(BeNil())
Expect(p.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.ack).To(Equal(ack))
checkLength(p.buffer.Data)
}) })
It("packs 1-RTT ACK-only packets", func() { It("packs 1-RTT ACK-only packets", func() {
@ -784,20 +800,21 @@ var _ = Describe("Packet packer", func() {
Context("packing crypto packets", func() { Context("packing crypto packets", func() {
It("sets the length", func() { It("sets the length", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2) pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42)) pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x42))
f := &wire.CryptoFrame{ f := &wire.CryptoFrame{
Offset: 0x1337, Offset: 0x1337,
Data: []byte("foobar"), Data: []byte("foobar"),
} }
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false) ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
initialStream.EXPECT().HasData().Return(true).AnyTimes() handshakeStream.EXPECT().HasData().Return(true).AnyTimes()
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f) handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f)
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil) sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable) sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable) sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
p, err := packer.PackCoalescedPacket(protocol.MaxByteCount) p, err := packer.PackCoalescedPacket(protocol.MaxByteCount)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(p).ToNot(BeNil())
checkLength(p.buffer.Data) checkLength(p.buffer.Data)
}) })
@ -846,6 +863,7 @@ var _ = Describe("Packet packer", func() {
}) })
p, err := packer.PackCoalescedPacket(protocol.MaxByteCount) p, err := packer.PackCoalescedPacket(protocol.MaxByteCount)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(p.buffer.Len()).To(BeEquivalentTo(packer.maxPacketSize))
Expect(p.packets).To(HaveLen(2)) Expect(p.packets).To(HaveLen(2))
Expect(p.packets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial)) Expect(p.packets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.packets[0].frames).To(HaveLen(1)) Expect(p.packets[0].frames).To(HaveLen(1))
@ -859,7 +877,7 @@ var _ = Describe("Packet packer", func() {
hdr, _, rest, err = wire.ParsePacket(rest, 0) hdr, _, rest, err = wire.ParsePacket(rest, 0)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(hdr.Type).To(Equal(protocol.PacketTypeHandshake)) Expect(hdr.Type).To(Equal(protocol.PacketTypeHandshake))
Expect(rest).To(BeEmpty()) Expect(rest).To(Equal(make([]byte, len(rest)))) // padding
}) })
It("packs a coalesced packet with Initial / 0-RTT, and pads it", func() { It("packs a coalesced packet with Initial / 0-RTT, and pads it", func() {
@ -937,13 +955,14 @@ var _ = Describe("Packet packer", func() {
}) })
It("doesn't add a coalesced packet if the remaining size is smaller than MaxCoalescedPacketSize", func() { It("doesn't add a coalesced packet if the remaining size is smaller than MaxCoalescedPacketSize", func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2) pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24)) pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil) sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
// don't EXPECT any calls to GetHandshakeSealer and Get1RTTSealer // don't EXPECT any calls to GetHandshakeSealer and Get1RTTSealer
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false) ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
initialStream.EXPECT().HasData().Return(true).Times(2) handshakeStream.EXPECT().HasData().Return(true).Times(2)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame { handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(size protocol.ByteCount) *wire.CryptoFrame {
s := size - protocol.MinCoalescedPacketSize s := size - protocol.MinCoalescedPacketSize
f := &wire.CryptoFrame{Offset: 0x1337} f := &wire.CryptoFrame{Offset: 0x1337}
f.Data = bytes.Repeat([]byte{'f'}, int(s-f.Length(packer.version)-1)) f.Data = bytes.Repeat([]byte{'f'}, int(s-f.Length(packer.version)-1))
@ -953,7 +972,7 @@ var _ = Describe("Packet packer", func() {
p, err := packer.PackCoalescedPacket(protocol.MaxByteCount) p, err := packer.PackCoalescedPacket(protocol.MaxByteCount)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(p.packets).To(HaveLen(1)) Expect(p.packets).To(HaveLen(1))
Expect(p.packets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial)) Expect(p.packets[0].EncryptionLevel()).To(Equal(protocol.EncryptionHandshake))
Expect(len(p.buffer.Data)).To(BeEquivalentTo(maxPacketSize - protocol.MinCoalescedPacketSize)) Expect(len(p.buffer.Data)).To(BeEquivalentTo(maxPacketSize - protocol.MinCoalescedPacketSize))
checkLength(p.buffer.Data) checkLength(p.buffer.Data)
}) })
@ -966,13 +985,14 @@ var _ = Describe("Packet packer", func() {
It("packs a small packet", func() { It("packs a small packet", func() {
const size = protocol.MinCoalescedPacketSize + 10 const size = protocol.MinCoalescedPacketSize + 10
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2) pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x24)) pnManager.EXPECT().PopPacketNumber(protocol.EncryptionHandshake).Return(protocol.PacketNumber(0x24))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil) sealingManager.EXPECT().GetInitialSealer().Return(nil, handshake.ErrKeysDropped)
// don't EXPECT any calls to GetHandshakeSealer and Get1RTTSealer sealingManager.EXPECT().GetHandshakeSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false) // don't EXPECT any calls to Get1RTTSealer
initialStream.EXPECT().HasData().Return(true).Times(2) ackFramer.EXPECT().GetAckFrame(protocol.EncryptionHandshake, false)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(s protocol.ByteCount) *wire.CryptoFrame { handshakeStream.EXPECT().HasData().Return(true).Times(2)
handshakeStream.EXPECT().PopCryptoFrame(gomock.Any()).DoAndReturn(func(s protocol.ByteCount) *wire.CryptoFrame {
f := &wire.CryptoFrame{Offset: 0x1337} f := &wire.CryptoFrame{Offset: 0x1337}
f.Data = bytes.Repeat([]byte{'f'}, int(s-f.Length(packer.version)-1)) f.Data = bytes.Repeat([]byte{'f'}, int(s-f.Length(packer.version)-1))
Expect(f.Length(packer.version)).To(Equal(s)) Expect(f.Length(packer.version)).To(Equal(s))
@ -1070,7 +1090,6 @@ var _ = Describe("Packet packer", func() {
Expect(p.packets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial)) Expect(p.packets[0].EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(p.packets[0].frames).To(Equal([]ackhandler.Frame{{Frame: f}})) Expect(p.packets[0].frames).To(Equal([]ackhandler.Frame{{Frame: f}}))
Expect(p.packets[0].header.IsLongHeader).To(BeTrue()) Expect(p.packets[0].header.IsLongHeader).To(BeTrue())
checkLength(p.buffer.Data)
}) })
It("sends an Initial packet containing only an ACK", func() { It("sends an Initial packet containing only an ACK", func() {
@ -1116,30 +1135,34 @@ var _ = Describe("Packet packer", func() {
Expect(p.packets[0].ack).To(Equal(ack)) Expect(p.packets[0].ack).To(Equal(ack))
}) })
It("pads Initial packets to the required minimum packet size", func() { for _, pers := range []protocol.Perspective{protocol.PerspectiveServer, protocol.PerspectiveClient} {
token := []byte("initial token") perspective := pers
packer.SetToken(token)
f := &wire.CryptoFrame{Data: []byte("foobar")} It(fmt.Sprintf("pads Initial packets to the required minimum packet size, for the %s", perspective), func() {
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2) token := []byte("initial token")
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42)) packer.SetToken(token)
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil) f := &wire.CryptoFrame{Data: []byte("foobar")}
sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable) pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
sealingManager.EXPECT().Get0RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable) pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable) sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false) sealingManager.EXPECT().GetHandshakeSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
initialStream.EXPECT().HasData().Return(true).Times(2) sealingManager.EXPECT().Get0RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
initialStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f) sealingManager.EXPECT().Get1RTTSealer().Return(nil, handshake.ErrKeysNotYetAvailable)
packer.perspective = protocol.PerspectiveClient ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
p, err := packer.PackCoalescedPacket(protocol.MaxByteCount) initialStream.EXPECT().HasData().Return(true).Times(2)
Expect(err).ToNot(HaveOccurred()) initialStream.EXPECT().PopCryptoFrame(gomock.Any()).Return(f)
Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize)) packer.perspective = protocol.PerspectiveClient
Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize)) p, err := packer.PackCoalescedPacket(protocol.MaxByteCount)
Expect(p.packets).To(HaveLen(1)) Expect(err).ToNot(HaveOccurred())
Expect(p.packets[0].header.Token).To(Equal(token)) Expect(p.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(p.packets[0].frames).To(HaveLen(1)) Expect(p.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
cf := p.packets[0].frames[0].Frame.(*wire.CryptoFrame) Expect(p.packets).To(HaveLen(1))
Expect(cf.Data).To(Equal([]byte("foobar"))) Expect(p.packets[0].header.Token).To(Equal(token))
}) Expect(p.packets[0].frames).To(HaveLen(1))
cf := p.packets[0].frames[0].Frame.(*wire.CryptoFrame)
Expect(cf.Data).To(Equal([]byte("foobar")))
})
}
It("adds an ACK frame", func() { It("adds an ACK frame", func() {
f := &wire.CryptoFrame{Data: []byte("foobar")} f := &wire.CryptoFrame{Data: []byte("foobar")}
@ -1165,44 +1188,32 @@ var _ = Describe("Packet packer", func() {
}) })
Context("packing probe packets", func() { Context("packing probe packets", func() {
It("packs an Initial probe packet", func() { for _, pers := range []protocol.Perspective{protocol.PerspectiveServer, protocol.PerspectiveClient} {
f := &wire.CryptoFrame{Data: []byte("Initial")} perspective := pers
retransmissionQueue.AddInitial(f)
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
initialStream.EXPECT().HasData()
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
packet, err := packer.MaybePackProbePacket(protocol.EncryptionInitial) It(fmt.Sprintf("packs an Initial probe packet and pads it, for the %s", perspective), func() {
Expect(err).ToNot(HaveOccurred()) packer.perspective = perspective
Expect(packet).ToNot(BeNil()) f := &wire.CryptoFrame{Data: []byte("Initial")}
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionInitial)) retransmissionQueue.AddInitial(f)
Expect(packet.frames).To(HaveLen(1)) sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil)
Expect(packet.frames[0].Frame).To(Equal(f)) ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false)
Expect(packet.buffer.Len()).To(BeNumerically("<", protocol.MinInitialPacketSize)) initialStream.EXPECT().HasData()
checkLength(packet.buffer.Data) pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2)
}) pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42))
It("packs an Initial probe packet and pads it, for the client", func() { packet, err := packer.MaybePackProbePacket(protocol.EncryptionInitial)
packer.perspective = protocol.PerspectiveClient Expect(err).ToNot(HaveOccurred())
f := &wire.CryptoFrame{Data: []byte("Initial")} Expect(packet).ToNot(BeNil())
retransmissionQueue.AddInitial(f) Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
sealingManager.EXPECT().GetInitialSealer().Return(getSealer(), nil) Expect(packet.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
ackFramer.EXPECT().GetAckFrame(protocol.EncryptionInitial, false) Expect(packet.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
initialStream.EXPECT().HasData() Expect(packet.frames).To(HaveLen(1))
pnManager.EXPECT().PeekPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42), protocol.PacketNumberLen2) Expect(packet.frames[0].Frame).To(Equal(f))
pnManager.EXPECT().PopPacketNumber(protocol.EncryptionInitial).Return(protocol.PacketNumber(0x42)) _, _, rest, err := wire.ParsePacket(packet.buffer.Data, 0)
Expect(err).ToNot(HaveOccurred())
packet, err := packer.MaybePackProbePacket(protocol.EncryptionInitial) Expect(rest).To(Equal(make([]byte, len(rest))))
Expect(err).ToNot(HaveOccurred()) })
Expect(packet).ToNot(BeNil()) }
Expect(packet.EncryptionLevel()).To(Equal(protocol.EncryptionInitial))
Expect(packet.buffer.Len()).To(BeNumerically(">=", protocol.MinInitialPacketSize))
Expect(packet.buffer.Len()).To(BeEquivalentTo(maxPacketSize))
Expect(packet.frames).To(HaveLen(1))
Expect(packet.frames[0].Frame).To(Equal(f))
})
It("packs a Handshake probe packet", func() { It("packs a Handshake probe packet", func() {
f := &wire.CryptoFrame{Data: []byte("Handshake")} f := &wire.CryptoFrame{Data: []byte("Handshake")}