| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914 |
- package quic
- import (
- "bytes"
- "errors"
- "fmt"
- "net"
- "time"
- "github.com/Psiphon-Labs/quic-go/internal/ackhandler"
- "github.com/Psiphon-Labs/quic-go/internal/handshake"
- "github.com/Psiphon-Labs/quic-go/internal/protocol"
- "github.com/Psiphon-Labs/quic-go/internal/qerr"
- "github.com/Psiphon-Labs/quic-go/internal/utils"
- "github.com/Psiphon-Labs/quic-go/internal/wire"
- )
- type packer interface {
- PackCoalescedPacket() (*coalescedPacket, error)
- PackPacket() (*packedPacket, error)
- MaybePackProbePacket(protocol.EncryptionLevel) (*packedPacket, error)
- MaybePackAckPacket(handshakeConfirmed bool) (*packedPacket, error)
- PackConnectionClose(*qerr.TransportError) (*coalescedPacket, error)
- PackApplicationClose(*qerr.ApplicationError) (*coalescedPacket, error)
- SetMaxPacketSize(protocol.ByteCount)
- PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount) (*packedPacket, error)
- HandleTransportParameters(*wire.TransportParameters)
- SetToken([]byte)
- }
- type sealer interface {
- handshake.LongHeaderSealer
- }
- type payload struct {
- frames []ackhandler.Frame
- ack *wire.AckFrame
- length protocol.ByteCount
- }
- type packedPacket struct {
- buffer *packetBuffer
- *packetContents
- }
- type packetContents struct {
- header *wire.ExtendedHeader
- ack *wire.AckFrame
- frames []ackhandler.Frame
- length protocol.ByteCount
- isMTUProbePacket bool
- }
- type coalescedPacket struct {
- buffer *packetBuffer
- packets []*packetContents
- }
- func (p *packetContents) EncryptionLevel() protocol.EncryptionLevel {
- if !p.header.IsLongHeader {
- return protocol.Encryption1RTT
- }
- //nolint:exhaustive // Will never be called for Retry packets (and they don't have encrypted data).
- switch p.header.Type {
- case protocol.PacketTypeInitial:
- return protocol.EncryptionInitial
- case protocol.PacketTypeHandshake:
- return protocol.EncryptionHandshake
- case protocol.PacketType0RTT:
- return protocol.Encryption0RTT
- default:
- panic("can't determine encryption level")
- }
- }
- func (p *packetContents) IsAckEliciting() bool {
- return ackhandler.HasAckElicitingFrames(p.frames)
- }
- func (p *packetContents) ToAckHandlerPacket(now time.Time, q *retransmissionQueue) *ackhandler.Packet {
- largestAcked := protocol.InvalidPacketNumber
- if p.ack != nil {
- largestAcked = p.ack.LargestAcked()
- }
- encLevel := p.EncryptionLevel()
- for i := range p.frames {
- if p.frames[i].OnLost != nil {
- continue
- }
- switch encLevel {
- case protocol.EncryptionInitial:
- p.frames[i].OnLost = q.AddInitial
- case protocol.EncryptionHandshake:
- p.frames[i].OnLost = q.AddHandshake
- case protocol.Encryption0RTT, protocol.Encryption1RTT:
- p.frames[i].OnLost = q.AddAppData
- }
- }
- return &ackhandler.Packet{
- PacketNumber: p.header.PacketNumber,
- LargestAcked: largestAcked,
- Frames: p.frames,
- Length: p.length,
- EncryptionLevel: encLevel,
- SendTime: now,
- IsPathMTUProbePacket: p.isMTUProbePacket,
- }
- }
- func getMaxPacketSize(addr net.Addr, maxPacketSizeAdustment int) protocol.ByteCount {
- maxSize := protocol.ByteCount(protocol.MinInitialPacketSize)
- // If this is not a UDP address, we don't know anything about the MTU.
- // Use the minimum size of an Initial packet as the max packet size.
- if udpAddr, ok := addr.(*net.UDPAddr); ok {
- if utils.IsIPv4(udpAddr.IP) {
- maxSize = protocol.InitialPacketSizeIPv4
- } else {
- maxSize = protocol.InitialPacketSizeIPv6
- }
- // [Psiphon]
- //
- // Adjust the max packet size to allow for obfuscation overhead. This
- // is a best-effort operation. In practice, maxPacketSizeAdustment
- // will be tens of bytes and maxSize is over 1200 bytes; the
- // condition here is a sanity check guard to prevent negative sizes
- // and possible panics. We don't expect to need to make the largest
- // adustment that would be possible when the condition is false.
- //
- // TODO: internal/congestion.cubicSender continues to use
- // initialMaxDatagramSize = protocol.InitialPacketSizeIPv4
- if maxSize > protocol.ByteCount(maxPacketSizeAdustment) {
- maxSize -= protocol.ByteCount(maxPacketSizeAdustment)
- }
- }
- return maxSize
- }
- type packetNumberManager interface {
- PeekPacketNumber(protocol.EncryptionLevel) (protocol.PacketNumber, protocol.PacketNumberLen)
- PopPacketNumber(protocol.EncryptionLevel) protocol.PacketNumber
- }
- type sealingManager interface {
- GetInitialSealer() (handshake.LongHeaderSealer, error)
- GetHandshakeSealer() (handshake.LongHeaderSealer, error)
- Get0RTTSealer() (handshake.LongHeaderSealer, error)
- Get1RTTSealer() (handshake.ShortHeaderSealer, error)
- }
- type frameSource interface {
- HasData() bool
- AppendStreamFrames([]ackhandler.Frame, protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount)
- AppendControlFrames([]ackhandler.Frame, protocol.ByteCount) ([]ackhandler.Frame, protocol.ByteCount)
- }
- type ackFrameSource interface {
- GetAckFrame(encLevel protocol.EncryptionLevel, onlyIfQueued bool) *wire.AckFrame
- }
- type packetPacker struct {
- srcConnID protocol.ConnectionID
- getDestConnID func() protocol.ConnectionID
- perspective protocol.Perspective
- version protocol.VersionNumber
- cryptoSetup sealingManager
- initialStream cryptoStream
- handshakeStream cryptoStream
- token []byte
- pnManager packetNumberManager
- framer frameSource
- acks ackFrameSource
- datagramQueue *datagramQueue
- retransmissionQueue *retransmissionQueue
- maxPacketSize protocol.ByteCount
- numNonAckElicitingAcks int
- }
- var _ packer = &packetPacker{}
- func newPacketPacker(
- srcConnID protocol.ConnectionID,
- getDestConnID func() protocol.ConnectionID,
- initialStream cryptoStream,
- handshakeStream cryptoStream,
- packetNumberManager packetNumberManager,
- retransmissionQueue *retransmissionQueue,
- remoteAddr net.Addr, // only used for determining the max packet size
- // [Psiphon]
- maxPacketSizeAdustment int,
- cryptoSetup sealingManager,
- framer frameSource,
- acks ackFrameSource,
- datagramQueue *datagramQueue,
- perspective protocol.Perspective,
- version protocol.VersionNumber,
- ) *packetPacker {
- return &packetPacker{
- cryptoSetup: cryptoSetup,
- getDestConnID: getDestConnID,
- srcConnID: srcConnID,
- initialStream: initialStream,
- handshakeStream: handshakeStream,
- retransmissionQueue: retransmissionQueue,
- datagramQueue: datagramQueue,
- perspective: perspective,
- version: version,
- framer: framer,
- acks: acks,
- pnManager: packetNumberManager,
- maxPacketSize: getMaxPacketSize(remoteAddr, maxPacketSizeAdustment),
- }
- }
- // PackConnectionClose packs a packet that closes the connection with a transport error.
- func (p *packetPacker) PackConnectionClose(e *qerr.TransportError) (*coalescedPacket, error) {
- var reason string
- // don't send details of crypto errors
- if !e.ErrorCode.IsCryptoError() {
- reason = e.ErrorMessage
- }
- return p.packConnectionClose(false, uint64(e.ErrorCode), e.FrameType, reason)
- }
- // PackApplicationClose packs a packet that closes the connection with an application error.
- func (p *packetPacker) PackApplicationClose(e *qerr.ApplicationError) (*coalescedPacket, error) {
- return p.packConnectionClose(true, uint64(e.ErrorCode), 0, e.ErrorMessage)
- }
- func (p *packetPacker) packConnectionClose(
- isApplicationError bool,
- errorCode uint64,
- frameType uint64,
- reason string,
- ) (*coalescedPacket, error) {
- var sealers [4]sealer
- var hdrs [4]*wire.ExtendedHeader
- var payloads [4]*payload
- var size protocol.ByteCount
- var numPackets uint8
- encLevels := [4]protocol.EncryptionLevel{protocol.EncryptionInitial, protocol.EncryptionHandshake, protocol.Encryption0RTT, protocol.Encryption1RTT}
- for i, encLevel := range encLevels {
- if p.perspective == protocol.PerspectiveServer && encLevel == protocol.Encryption0RTT {
- continue
- }
- ccf := &wire.ConnectionCloseFrame{
- IsApplicationError: isApplicationError,
- ErrorCode: errorCode,
- FrameType: frameType,
- ReasonPhrase: reason,
- }
- // don't send application errors in Initial or Handshake packets
- if isApplicationError && (encLevel == protocol.EncryptionInitial || encLevel == protocol.EncryptionHandshake) {
- ccf.IsApplicationError = false
- ccf.ErrorCode = uint64(qerr.ApplicationErrorErrorCode)
- ccf.ReasonPhrase = ""
- }
- payload := &payload{
- frames: []ackhandler.Frame{{Frame: ccf}},
- length: ccf.Length(p.version),
- }
- var sealer sealer
- var err error
- var keyPhase protocol.KeyPhaseBit // only set for 1-RTT
- switch encLevel {
- case protocol.EncryptionInitial:
- sealer, err = p.cryptoSetup.GetInitialSealer()
- case protocol.EncryptionHandshake:
- sealer, err = p.cryptoSetup.GetHandshakeSealer()
- case protocol.Encryption0RTT:
- sealer, err = p.cryptoSetup.Get0RTTSealer()
- case protocol.Encryption1RTT:
- var s handshake.ShortHeaderSealer
- s, err = p.cryptoSetup.Get1RTTSealer()
- if err == nil {
- keyPhase = s.KeyPhase()
- }
- sealer = s
- }
- if err == handshake.ErrKeysNotYetAvailable || err == handshake.ErrKeysDropped {
- continue
- }
- if err != nil {
- return nil, err
- }
- sealers[i] = sealer
- var hdr *wire.ExtendedHeader
- if encLevel == protocol.Encryption1RTT {
- hdr = p.getShortHeader(keyPhase)
- } else {
- hdr = p.getLongHeader(encLevel)
- }
- hdrs[i] = hdr
- payloads[i] = payload
- size += p.packetLength(hdr, payload) + protocol.ByteCount(sealer.Overhead())
- numPackets++
- }
- contents := make([]*packetContents, 0, numPackets)
- buffer := getPacketBuffer()
- for i, encLevel := range encLevels {
- if sealers[i] == nil {
- continue
- }
- var paddingLen protocol.ByteCount
- if encLevel == protocol.EncryptionInitial {
- paddingLen = p.initialPaddingLen(payloads[i].frames, size)
- }
- c, err := p.appendPacket(buffer, hdrs[i], payloads[i], paddingLen, encLevel, sealers[i], false)
- if err != nil {
- return nil, err
- }
- contents = append(contents, c)
- }
- return &coalescedPacket{buffer: buffer, packets: contents}, nil
- }
- // packetLength calculates the length of the serialized packet.
- // It takes into account that packets that have a tiny payload need to be padded,
- // such that len(payload) + packet number len >= 4 + AEAD overhead
- func (p *packetPacker) packetLength(hdr *wire.ExtendedHeader, payload *payload) protocol.ByteCount {
- var paddingLen protocol.ByteCount
- pnLen := protocol.ByteCount(hdr.PacketNumberLen)
- if payload.length < 4-pnLen {
- paddingLen = 4 - pnLen - payload.length
- }
- return hdr.GetLength(p.version) + payload.length + paddingLen
- }
- func (p *packetPacker) MaybePackAckPacket(handshakeConfirmed bool) (*packedPacket, error) {
- var encLevel protocol.EncryptionLevel
- var ack *wire.AckFrame
- if !handshakeConfirmed {
- ack = p.acks.GetAckFrame(protocol.EncryptionInitial, true)
- if ack != nil {
- encLevel = protocol.EncryptionInitial
- } else {
- ack = p.acks.GetAckFrame(protocol.EncryptionHandshake, true)
- if ack != nil {
- encLevel = protocol.EncryptionHandshake
- }
- }
- }
- if ack == nil {
- ack = p.acks.GetAckFrame(protocol.Encryption1RTT, true)
- if ack == nil {
- return nil, nil
- }
- encLevel = protocol.Encryption1RTT
- }
- payload := &payload{
- ack: ack,
- length: ack.Length(p.version),
- }
- sealer, hdr, err := p.getSealerAndHeader(encLevel)
- if err != nil {
- return nil, err
- }
- return p.writeSinglePacket(hdr, payload, encLevel, sealer)
- }
- // size is the expected size of the packet, if no padding was applied.
- func (p *packetPacker) initialPaddingLen(frames []ackhandler.Frame, size protocol.ByteCount) protocol.ByteCount {
- // For the server, only ack-eliciting Initial packets need to be padded.
- if p.perspective == protocol.PerspectiveServer && !ackhandler.HasAckElicitingFrames(frames) {
- return 0
- }
- if size >= p.maxPacketSize {
- return 0
- }
- return p.maxPacketSize - size
- }
- // PackCoalescedPacket packs a new packet.
- // It packs an Initial / Handshake if there is data to send in these packet number spaces.
- // It should only be called before the handshake is confirmed.
- func (p *packetPacker) PackCoalescedPacket() (*coalescedPacket, error) {
- maxPacketSize := p.maxPacketSize
- if p.perspective == protocol.PerspectiveClient {
- maxPacketSize = protocol.MinInitialPacketSize
- }
- var initialHdr, handshakeHdr, appDataHdr *wire.ExtendedHeader
- var initialPayload, handshakePayload, appDataPayload *payload
- var numPackets int
- // Try packing an Initial packet.
- initialSealer, err := p.cryptoSetup.GetInitialSealer()
- if err != nil && err != handshake.ErrKeysDropped {
- return nil, err
- }
- var size protocol.ByteCount
- if initialSealer != nil {
- initialHdr, initialPayload = p.maybeGetCryptoPacket(maxPacketSize-protocol.ByteCount(initialSealer.Overhead()), size, protocol.EncryptionInitial)
- if initialPayload != nil {
- size += p.packetLength(initialHdr, initialPayload) + protocol.ByteCount(initialSealer.Overhead())
- numPackets++
- }
- }
- // Add a Handshake packet.
- var handshakeSealer sealer
- if size < maxPacketSize-protocol.MinCoalescedPacketSize {
- var err error
- handshakeSealer, err = p.cryptoSetup.GetHandshakeSealer()
- if err != nil && err != handshake.ErrKeysDropped && err != handshake.ErrKeysNotYetAvailable {
- return nil, err
- }
- if handshakeSealer != nil {
- handshakeHdr, handshakePayload = p.maybeGetCryptoPacket(maxPacketSize-size-protocol.ByteCount(handshakeSealer.Overhead()), size, protocol.EncryptionHandshake)
- if handshakePayload != nil {
- s := p.packetLength(handshakeHdr, handshakePayload) + protocol.ByteCount(handshakeSealer.Overhead())
- size += s
- numPackets++
- }
- }
- }
- // Add a 0-RTT / 1-RTT packet.
- var appDataSealer sealer
- appDataEncLevel := protocol.Encryption1RTT
- if size < maxPacketSize-protocol.MinCoalescedPacketSize {
- var err error
- appDataSealer, appDataHdr, appDataPayload = p.maybeGetAppDataPacket(maxPacketSize-size, size)
- if err != nil {
- return nil, err
- }
- if appDataHdr != nil {
- if appDataHdr.IsLongHeader {
- appDataEncLevel = protocol.Encryption0RTT
- }
- if appDataPayload != nil {
- size += p.packetLength(appDataHdr, appDataPayload) + protocol.ByteCount(appDataSealer.Overhead())
- numPackets++
- }
- }
- }
- if numPackets == 0 {
- return nil, nil
- }
- buffer := getPacketBuffer()
- packet := &coalescedPacket{
- buffer: buffer,
- packets: make([]*packetContents, 0, numPackets),
- }
- if initialPayload != nil {
- padding := p.initialPaddingLen(initialPayload.frames, size)
- cont, err := p.appendPacket(buffer, initialHdr, initialPayload, padding, protocol.EncryptionInitial, initialSealer, false)
- if err != nil {
- return nil, err
- }
- packet.packets = append(packet.packets, cont)
- }
- if handshakePayload != nil {
- cont, err := p.appendPacket(buffer, handshakeHdr, handshakePayload, 0, protocol.EncryptionHandshake, handshakeSealer, false)
- if err != nil {
- return nil, err
- }
- packet.packets = append(packet.packets, cont)
- }
- if appDataPayload != nil {
- cont, err := p.appendPacket(buffer, appDataHdr, appDataPayload, 0, appDataEncLevel, appDataSealer, false)
- if err != nil {
- return nil, err
- }
- packet.packets = append(packet.packets, cont)
- }
- return packet, nil
- }
- // PackPacket packs a packet in the application data packet number space.
- // It should be called after the handshake is confirmed.
- func (p *packetPacker) PackPacket() (*packedPacket, error) {
- sealer, hdr, payload := p.maybeGetAppDataPacket(p.maxPacketSize, 0)
- if payload == nil {
- return nil, nil
- }
- buffer := getPacketBuffer()
- encLevel := protocol.Encryption1RTT
- if hdr.IsLongHeader {
- encLevel = protocol.Encryption0RTT
- }
- cont, err := p.appendPacket(buffer, hdr, payload, 0, encLevel, sealer, false)
- if err != nil {
- return nil, err
- }
- return &packedPacket{
- buffer: buffer,
- packetContents: cont,
- }, nil
- }
- func (p *packetPacker) maybeGetCryptoPacket(maxPacketSize, currentSize protocol.ByteCount, encLevel protocol.EncryptionLevel) (*wire.ExtendedHeader, *payload) {
- var s cryptoStream
- var hasRetransmission bool
- //nolint:exhaustive // Initial and Handshake are the only two encryption levels here.
- switch encLevel {
- case protocol.EncryptionInitial:
- s = p.initialStream
- hasRetransmission = p.retransmissionQueue.HasInitialData()
- case protocol.EncryptionHandshake:
- s = p.handshakeStream
- hasRetransmission = p.retransmissionQueue.HasHandshakeData()
- }
- hasData := s.HasData()
- var ack *wire.AckFrame
- if encLevel == protocol.EncryptionInitial || currentSize == 0 {
- ack = p.acks.GetAckFrame(encLevel, !hasRetransmission && !hasData)
- }
- if !hasData && !hasRetransmission && ack == nil {
- // nothing to send
- return nil, nil
- }
- var payload payload
- if ack != nil {
- payload.ack = ack
- payload.length = ack.Length(p.version)
- maxPacketSize -= payload.length
- }
- hdr := p.getLongHeader(encLevel)
- maxPacketSize -= hdr.GetLength(p.version)
- if hasRetransmission {
- for {
- var f wire.Frame
- //nolint:exhaustive // 0-RTT packets can't contain any retransmission.s
- switch encLevel {
- case protocol.EncryptionInitial:
- f = p.retransmissionQueue.GetInitialFrame(maxPacketSize)
- case protocol.EncryptionHandshake:
- f = p.retransmissionQueue.GetHandshakeFrame(maxPacketSize)
- }
- if f == nil {
- break
- }
- payload.frames = append(payload.frames, ackhandler.Frame{Frame: f})
- frameLen := f.Length(p.version)
- payload.length += frameLen
- maxPacketSize -= frameLen
- }
- } else if s.HasData() {
- cf := s.PopCryptoFrame(maxPacketSize)
- payload.frames = []ackhandler.Frame{{Frame: cf}}
- payload.length += cf.Length(p.version)
- }
- return hdr, &payload
- }
- func (p *packetPacker) maybeGetAppDataPacket(maxPacketSize, currentSize protocol.ByteCount) (sealer, *wire.ExtendedHeader, *payload) {
- var sealer sealer
- var encLevel protocol.EncryptionLevel
- var hdr *wire.ExtendedHeader
- oneRTTSealer, err := p.cryptoSetup.Get1RTTSealer()
- if err == nil {
- encLevel = protocol.Encryption1RTT
- sealer = oneRTTSealer
- hdr = p.getShortHeader(oneRTTSealer.KeyPhase())
- } else {
- // 1-RTT sealer not yet available
- if p.perspective != protocol.PerspectiveClient {
- return nil, nil, nil
- }
- sealer, err = p.cryptoSetup.Get0RTTSealer()
- if sealer == nil || err != nil {
- return nil, nil, nil
- }
- encLevel = protocol.Encryption0RTT
- hdr = p.getLongHeader(protocol.Encryption0RTT)
- }
- maxPayloadSize := maxPacketSize - hdr.GetLength(p.version) - protocol.ByteCount(sealer.Overhead())
- payload := p.maybeGetAppDataPacketWithEncLevel(maxPayloadSize, encLevel == protocol.Encryption1RTT && currentSize == 0)
- return sealer, hdr, payload
- }
- func (p *packetPacker) maybeGetAppDataPacketWithEncLevel(maxPayloadSize protocol.ByteCount, ackAllowed bool) *payload {
- payload := p.composeNextPacket(maxPayloadSize, ackAllowed)
- // check if we have anything to send
- if len(payload.frames) == 0 {
- if payload.ack == nil {
- return nil
- }
- // the packet only contains an ACK
- if p.numNonAckElicitingAcks >= protocol.MaxNonAckElicitingAcks {
- ping := &wire.PingFrame{}
- // don't retransmit the PING frame when it is lost
- payload.frames = append(payload.frames, ackhandler.Frame{Frame: ping, OnLost: func(wire.Frame) {}})
- payload.length += ping.Length(p.version)
- p.numNonAckElicitingAcks = 0
- } else {
- p.numNonAckElicitingAcks++
- }
- } else {
- p.numNonAckElicitingAcks = 0
- }
- return payload
- }
- func (p *packetPacker) composeNextPacket(maxFrameSize protocol.ByteCount, ackAllowed bool) *payload {
- payload := &payload{frames: make([]ackhandler.Frame, 0, 1)}
- var hasDatagram bool
- if p.datagramQueue != nil {
- if datagram := p.datagramQueue.Get(); datagram != nil {
- payload.frames = append(payload.frames, ackhandler.Frame{
- Frame: datagram,
- // set it to a no-op. Then we won't set the default callback, which would retransmit the frame.
- OnLost: func(wire.Frame) {},
- })
- payload.length += datagram.Length(p.version)
- hasDatagram = true
- }
- }
- var ack *wire.AckFrame
- hasData := p.framer.HasData()
- hasRetransmission := p.retransmissionQueue.HasAppData()
- // TODO: make sure ACKs are sent when a lot of DATAGRAMs are queued
- if !hasDatagram && ackAllowed {
- ack = p.acks.GetAckFrame(protocol.Encryption1RTT, !hasRetransmission && !hasData)
- if ack != nil {
- payload.ack = ack
- payload.length += ack.Length(p.version)
- }
- }
- if ack == nil && !hasData && !hasRetransmission {
- return payload
- }
- if hasRetransmission {
- for {
- remainingLen := maxFrameSize - payload.length
- if remainingLen < protocol.MinStreamFrameSize {
- break
- }
- f := p.retransmissionQueue.GetAppDataFrame(remainingLen)
- if f == nil {
- break
- }
- payload.frames = append(payload.frames, ackhandler.Frame{Frame: f})
- payload.length += f.Length(p.version)
- }
- }
- if hasData {
- var lengthAdded protocol.ByteCount
- payload.frames, lengthAdded = p.framer.AppendControlFrames(payload.frames, maxFrameSize-payload.length)
- payload.length += lengthAdded
- payload.frames, lengthAdded = p.framer.AppendStreamFrames(payload.frames, maxFrameSize-payload.length)
- payload.length += lengthAdded
- }
- return payload
- }
- func (p *packetPacker) MaybePackProbePacket(encLevel protocol.EncryptionLevel) (*packedPacket, error) {
- var hdr *wire.ExtendedHeader
- var payload *payload
- var sealer sealer
- //nolint:exhaustive // Probe packets are never sent for 0-RTT.
- switch encLevel {
- case protocol.EncryptionInitial:
- var err error
- sealer, err = p.cryptoSetup.GetInitialSealer()
- if err != nil {
- return nil, err
- }
- hdr, payload = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), 0, protocol.EncryptionInitial)
- case protocol.EncryptionHandshake:
- var err error
- sealer, err = p.cryptoSetup.GetHandshakeSealer()
- if err != nil {
- return nil, err
- }
- hdr, payload = p.maybeGetCryptoPacket(p.maxPacketSize-protocol.ByteCount(sealer.Overhead()), 0, protocol.EncryptionHandshake)
- case protocol.Encryption1RTT:
- oneRTTSealer, err := p.cryptoSetup.Get1RTTSealer()
- if err != nil {
- return nil, err
- }
- sealer = oneRTTSealer
- hdr = p.getShortHeader(oneRTTSealer.KeyPhase())
- payload = p.maybeGetAppDataPacketWithEncLevel(p.maxPacketSize-protocol.ByteCount(sealer.Overhead())-hdr.GetLength(p.version), true)
- default:
- panic("unknown encryption level")
- }
- if payload == nil {
- return nil, nil
- }
- size := p.packetLength(hdr, payload) + protocol.ByteCount(sealer.Overhead())
- var padding protocol.ByteCount
- if encLevel == protocol.EncryptionInitial {
- padding = p.initialPaddingLen(payload.frames, size)
- }
- buffer := getPacketBuffer()
- cont, err := p.appendPacket(buffer, hdr, payload, padding, encLevel, sealer, false)
- if err != nil {
- return nil, err
- }
- return &packedPacket{
- buffer: buffer,
- packetContents: cont,
- }, nil
- }
- func (p *packetPacker) PackMTUProbePacket(ping ackhandler.Frame, size protocol.ByteCount) (*packedPacket, error) {
- payload := &payload{
- frames: []ackhandler.Frame{ping},
- length: ping.Length(p.version),
- }
- buffer := getPacketBuffer()
- sealer, err := p.cryptoSetup.Get1RTTSealer()
- if err != nil {
- return nil, err
- }
- hdr := p.getShortHeader(sealer.KeyPhase())
- padding := size - p.packetLength(hdr, payload) - protocol.ByteCount(sealer.Overhead())
- contents, err := p.appendPacket(buffer, hdr, payload, padding, protocol.Encryption1RTT, sealer, true)
- if err != nil {
- return nil, err
- }
- contents.isMTUProbePacket = true
- return &packedPacket{
- buffer: buffer,
- packetContents: contents,
- }, nil
- }
- func (p *packetPacker) getSealerAndHeader(encLevel protocol.EncryptionLevel) (sealer, *wire.ExtendedHeader, error) {
- switch encLevel {
- case protocol.EncryptionInitial:
- sealer, err := p.cryptoSetup.GetInitialSealer()
- if err != nil {
- return nil, nil, err
- }
- hdr := p.getLongHeader(protocol.EncryptionInitial)
- return sealer, hdr, nil
- case protocol.Encryption0RTT:
- sealer, err := p.cryptoSetup.Get0RTTSealer()
- if err != nil {
- return nil, nil, err
- }
- hdr := p.getLongHeader(protocol.Encryption0RTT)
- return sealer, hdr, nil
- case protocol.EncryptionHandshake:
- sealer, err := p.cryptoSetup.GetHandshakeSealer()
- if err != nil {
- return nil, nil, err
- }
- hdr := p.getLongHeader(protocol.EncryptionHandshake)
- return sealer, hdr, nil
- case protocol.Encryption1RTT:
- sealer, err := p.cryptoSetup.Get1RTTSealer()
- if err != nil {
- return nil, nil, err
- }
- hdr := p.getShortHeader(sealer.KeyPhase())
- return sealer, hdr, nil
- default:
- return nil, nil, fmt.Errorf("unexpected encryption level: %s", encLevel)
- }
- }
- func (p *packetPacker) getShortHeader(kp protocol.KeyPhaseBit) *wire.ExtendedHeader {
- pn, pnLen := p.pnManager.PeekPacketNumber(protocol.Encryption1RTT)
- hdr := &wire.ExtendedHeader{}
- hdr.PacketNumber = pn
- hdr.PacketNumberLen = pnLen
- hdr.DestConnectionID = p.getDestConnID()
- hdr.KeyPhase = kp
- return hdr
- }
- func (p *packetPacker) getLongHeader(encLevel protocol.EncryptionLevel) *wire.ExtendedHeader {
- pn, pnLen := p.pnManager.PeekPacketNumber(encLevel)
- hdr := &wire.ExtendedHeader{
- PacketNumber: pn,
- PacketNumberLen: pnLen,
- }
- hdr.IsLongHeader = true
- hdr.Version = p.version
- hdr.SrcConnectionID = p.srcConnID
- hdr.DestConnectionID = p.getDestConnID()
- //nolint:exhaustive // 1-RTT packets are not long header packets.
- switch encLevel {
- case protocol.EncryptionInitial:
- hdr.Type = protocol.PacketTypeInitial
- hdr.Token = p.token
- case protocol.EncryptionHandshake:
- hdr.Type = protocol.PacketTypeHandshake
- case protocol.Encryption0RTT:
- hdr.Type = protocol.PacketType0RTT
- }
- return hdr
- }
- // writeSinglePacket packs a single packet.
- func (p *packetPacker) writeSinglePacket(
- hdr *wire.ExtendedHeader,
- payload *payload,
- encLevel protocol.EncryptionLevel,
- sealer sealer,
- ) (*packedPacket, error) {
- buffer := getPacketBuffer()
- var paddingLen protocol.ByteCount
- if encLevel == protocol.EncryptionInitial {
- paddingLen = p.initialPaddingLen(payload.frames, hdr.GetLength(p.version)+payload.length+protocol.ByteCount(sealer.Overhead()))
- }
- contents, err := p.appendPacket(buffer, hdr, payload, paddingLen, encLevel, sealer, false)
- if err != nil {
- return nil, err
- }
- return &packedPacket{
- buffer: buffer,
- packetContents: contents,
- }, nil
- }
- func (p *packetPacker) appendPacket(buffer *packetBuffer, header *wire.ExtendedHeader, payload *payload, padding protocol.ByteCount, encLevel protocol.EncryptionLevel, sealer sealer, isMTUProbePacket bool) (*packetContents, error) {
- var paddingLen protocol.ByteCount
- pnLen := protocol.ByteCount(header.PacketNumberLen)
- if payload.length < 4-pnLen {
- paddingLen = 4 - pnLen - payload.length
- }
- paddingLen += padding
- if header.IsLongHeader {
- header.Length = pnLen + protocol.ByteCount(sealer.Overhead()) + payload.length + paddingLen
- }
- hdrOffset := buffer.Len()
- buf := bytes.NewBuffer(buffer.Data)
- if err := header.Write(buf, p.version); err != nil {
- return nil, err
- }
- payloadOffset := buf.Len()
- if payload.ack != nil {
- if err := payload.ack.Write(buf, p.version); err != nil {
- return nil, err
- }
- }
- if paddingLen > 0 {
- buf.Write(make([]byte, paddingLen))
- }
- for _, frame := range payload.frames {
- if err := frame.Write(buf, p.version); err != nil {
- return nil, err
- }
- }
- if payloadSize := protocol.ByteCount(buf.Len()-payloadOffset) - paddingLen; payloadSize != payload.length {
- return nil, fmt.Errorf("PacketPacker BUG: payload size inconsistent (expected %d, got %d bytes)", payload.length, payloadSize)
- }
- if !isMTUProbePacket {
- if size := protocol.ByteCount(buf.Len() + sealer.Overhead()); size > p.maxPacketSize {
- return nil, fmt.Errorf("PacketPacker BUG: packet too large (%d bytes, allowed %d bytes)", size, p.maxPacketSize)
- }
- }
- raw := buffer.Data
- // encrypt the packet
- raw = raw[:buf.Len()]
- _ = sealer.Seal(raw[payloadOffset:payloadOffset], raw[payloadOffset:], header.PacketNumber, raw[hdrOffset:payloadOffset])
- raw = raw[0 : buf.Len()+sealer.Overhead()]
- // apply header protection
- pnOffset := payloadOffset - int(header.PacketNumberLen)
- sealer.EncryptHeader(raw[pnOffset+4:pnOffset+4+16], &raw[hdrOffset], raw[pnOffset:payloadOffset])
- buffer.Data = raw
- num := p.pnManager.PopPacketNumber(encLevel)
- if num != header.PacketNumber {
- return nil, errors.New("packetPacker BUG: Peeked and Popped packet numbers do not match")
- }
- return &packetContents{
- header: header,
- ack: payload.ack,
- frames: payload.frames,
- length: buffer.Len() - hdrOffset,
- }, nil
- }
- func (p *packetPacker) SetToken(token []byte) {
- p.token = token
- }
- // When a higher MTU is discovered, use it.
- func (p *packetPacker) SetMaxPacketSize(s protocol.ByteCount) {
- p.maxPacketSize = s
- }
- // If the peer sets a max_packet_size that's smaller than the size we're currently using,
- // we need to reduce the size of packets we send.
- func (p *packetPacker) HandleTransportParameters(params *wire.TransportParameters) {
- if params.MaxUDPPayloadSize != 0 {
- p.maxPacketSize = utils.MinByteCount(p.maxPacketSize, params.MaxUDPPayloadSize)
- }
- }
|