mirror of
https://github.com/cloudflare/cloudflared.git
synced 2025-07-28 23:19:58 +00:00
TUN-4597: Add a QUIC server skeleton
- Added a QUIC server to accept streams - Unit test for this server also tests ALPN - Temporary echo capability for HTTP ConnectionType
This commit is contained in:
69
vendor/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go
generated
vendored
Normal file
69
vendor/github.com/lucas-clemente/quic-go/internal/protocol/connection_id.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
// A ConnectionID in QUIC
|
||||
type ConnectionID []byte
|
||||
|
||||
const maxConnectionIDLen = 20
|
||||
|
||||
// GenerateConnectionID generates a connection ID using cryptographic random
|
||||
func GenerateConnectionID(len int) (ConnectionID, error) {
|
||||
b := make([]byte, len)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ConnectionID(b), nil
|
||||
}
|
||||
|
||||
// GenerateConnectionIDForInitial generates a connection ID for the Initial packet.
|
||||
// It uses a length randomly chosen between 8 and 20 bytes.
|
||||
func GenerateConnectionIDForInitial() (ConnectionID, error) {
|
||||
r := make([]byte, 1)
|
||||
if _, err := rand.Read(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
len := MinConnectionIDLenInitial + int(r[0])%(maxConnectionIDLen-MinConnectionIDLenInitial+1)
|
||||
return GenerateConnectionID(len)
|
||||
}
|
||||
|
||||
// ReadConnectionID reads a connection ID of length len from the given io.Reader.
|
||||
// It returns io.EOF if there are not enough bytes to read.
|
||||
func ReadConnectionID(r io.Reader, len int) (ConnectionID, error) {
|
||||
if len == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
c := make(ConnectionID, len)
|
||||
_, err := io.ReadFull(r, c)
|
||||
if err == io.ErrUnexpectedEOF {
|
||||
return nil, io.EOF
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Equal says if two connection IDs are equal
|
||||
func (c ConnectionID) Equal(other ConnectionID) bool {
|
||||
return bytes.Equal(c, other)
|
||||
}
|
||||
|
||||
// Len returns the length of the connection ID in bytes
|
||||
func (c ConnectionID) Len() int {
|
||||
return len(c)
|
||||
}
|
||||
|
||||
// Bytes returns the byte representation
|
||||
func (c ConnectionID) Bytes() []byte {
|
||||
return []byte(c)
|
||||
}
|
||||
|
||||
func (c ConnectionID) String() string {
|
||||
if c.Len() == 0 {
|
||||
return "(empty)"
|
||||
}
|
||||
return fmt.Sprintf("%x", c.Bytes())
|
||||
}
|
30
vendor/github.com/lucas-clemente/quic-go/internal/protocol/encryption_level.go
generated
vendored
Normal file
30
vendor/github.com/lucas-clemente/quic-go/internal/protocol/encryption_level.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package protocol
|
||||
|
||||
// EncryptionLevel is the encryption level
|
||||
// Default value is Unencrypted
|
||||
type EncryptionLevel uint8
|
||||
|
||||
const (
|
||||
// EncryptionInitial is the Initial encryption level
|
||||
EncryptionInitial EncryptionLevel = 1 + iota
|
||||
// EncryptionHandshake is the Handshake encryption level
|
||||
EncryptionHandshake
|
||||
// Encryption0RTT is the 0-RTT encryption level
|
||||
Encryption0RTT
|
||||
// Encryption1RTT is the 1-RTT encryption level
|
||||
Encryption1RTT
|
||||
)
|
||||
|
||||
func (e EncryptionLevel) String() string {
|
||||
switch e {
|
||||
case EncryptionInitial:
|
||||
return "Initial"
|
||||
case EncryptionHandshake:
|
||||
return "Handshake"
|
||||
case Encryption0RTT:
|
||||
return "0-RTT"
|
||||
case Encryption1RTT:
|
||||
return "1-RTT"
|
||||
}
|
||||
return "unknown"
|
||||
}
|
36
vendor/github.com/lucas-clemente/quic-go/internal/protocol/key_phase.go
generated
vendored
Normal file
36
vendor/github.com/lucas-clemente/quic-go/internal/protocol/key_phase.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package protocol
|
||||
|
||||
// KeyPhase is the key phase
|
||||
type KeyPhase uint64
|
||||
|
||||
// Bit determines the key phase bit
|
||||
func (p KeyPhase) Bit() KeyPhaseBit {
|
||||
if p%2 == 0 {
|
||||
return KeyPhaseZero
|
||||
}
|
||||
return KeyPhaseOne
|
||||
}
|
||||
|
||||
// KeyPhaseBit is the key phase bit
|
||||
type KeyPhaseBit uint8
|
||||
|
||||
const (
|
||||
// KeyPhaseUndefined is an undefined key phase
|
||||
KeyPhaseUndefined KeyPhaseBit = iota
|
||||
// KeyPhaseZero is key phase 0
|
||||
KeyPhaseZero
|
||||
// KeyPhaseOne is key phase 1
|
||||
KeyPhaseOne
|
||||
)
|
||||
|
||||
func (p KeyPhaseBit) String() string {
|
||||
//nolint:exhaustive
|
||||
switch p {
|
||||
case KeyPhaseZero:
|
||||
return "0"
|
||||
case KeyPhaseOne:
|
||||
return "1"
|
||||
default:
|
||||
return "undefined"
|
||||
}
|
||||
}
|
79
vendor/github.com/lucas-clemente/quic-go/internal/protocol/packet_number.go
generated
vendored
Normal file
79
vendor/github.com/lucas-clemente/quic-go/internal/protocol/packet_number.go
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
package protocol
|
||||
|
||||
// A PacketNumber in QUIC
|
||||
type PacketNumber int64
|
||||
|
||||
// InvalidPacketNumber is a packet number that is never sent.
|
||||
// In QUIC, 0 is a valid packet number.
|
||||
const InvalidPacketNumber PacketNumber = -1
|
||||
|
||||
// PacketNumberLen is the length of the packet number in bytes
|
||||
type PacketNumberLen uint8
|
||||
|
||||
const (
|
||||
// PacketNumberLen1 is a packet number length of 1 byte
|
||||
PacketNumberLen1 PacketNumberLen = 1
|
||||
// PacketNumberLen2 is a packet number length of 2 bytes
|
||||
PacketNumberLen2 PacketNumberLen = 2
|
||||
// PacketNumberLen3 is a packet number length of 3 bytes
|
||||
PacketNumberLen3 PacketNumberLen = 3
|
||||
// PacketNumberLen4 is a packet number length of 4 bytes
|
||||
PacketNumberLen4 PacketNumberLen = 4
|
||||
)
|
||||
|
||||
// DecodePacketNumber calculates the packet number based on the received packet number, its length and the last seen packet number
|
||||
func DecodePacketNumber(
|
||||
packetNumberLength PacketNumberLen,
|
||||
lastPacketNumber PacketNumber,
|
||||
wirePacketNumber PacketNumber,
|
||||
) PacketNumber {
|
||||
var epochDelta PacketNumber
|
||||
switch packetNumberLength {
|
||||
case PacketNumberLen1:
|
||||
epochDelta = PacketNumber(1) << 8
|
||||
case PacketNumberLen2:
|
||||
epochDelta = PacketNumber(1) << 16
|
||||
case PacketNumberLen3:
|
||||
epochDelta = PacketNumber(1) << 24
|
||||
case PacketNumberLen4:
|
||||
epochDelta = PacketNumber(1) << 32
|
||||
}
|
||||
epoch := lastPacketNumber & ^(epochDelta - 1)
|
||||
var prevEpochBegin PacketNumber
|
||||
if epoch > epochDelta {
|
||||
prevEpochBegin = epoch - epochDelta
|
||||
}
|
||||
nextEpochBegin := epoch + epochDelta
|
||||
return closestTo(
|
||||
lastPacketNumber+1,
|
||||
epoch+wirePacketNumber,
|
||||
closestTo(lastPacketNumber+1, prevEpochBegin+wirePacketNumber, nextEpochBegin+wirePacketNumber),
|
||||
)
|
||||
}
|
||||
|
||||
func closestTo(target, a, b PacketNumber) PacketNumber {
|
||||
if delta(target, a) < delta(target, b) {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func delta(a, b PacketNumber) PacketNumber {
|
||||
if a < b {
|
||||
return b - a
|
||||
}
|
||||
return a - b
|
||||
}
|
||||
|
||||
// GetPacketNumberLengthForHeader gets the length of the packet number for the public header
|
||||
// it never chooses a PacketNumberLen of 1 byte, since this is too short under certain circumstances
|
||||
func GetPacketNumberLengthForHeader(packetNumber, leastUnacked PacketNumber) PacketNumberLen {
|
||||
diff := uint64(packetNumber - leastUnacked)
|
||||
if diff < (1 << (16 - 1)) {
|
||||
return PacketNumberLen2
|
||||
}
|
||||
if diff < (1 << (24 - 1)) {
|
||||
return PacketNumberLen3
|
||||
}
|
||||
return PacketNumberLen4
|
||||
}
|
195
vendor/github.com/lucas-clemente/quic-go/internal/protocol/params.go
generated
vendored
Normal file
195
vendor/github.com/lucas-clemente/quic-go/internal/protocol/params.go
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
package protocol
|
||||
|
||||
import "time"
|
||||
|
||||
// DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use.
|
||||
const DesiredReceiveBufferSize = (1 << 20) * 2 // 2 MB
|
||||
|
||||
// InitialPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
|
||||
const InitialPacketSizeIPv4 = 1252
|
||||
|
||||
// InitialPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
|
||||
const InitialPacketSizeIPv6 = 1232
|
||||
|
||||
// MaxCongestionWindowPackets is the maximum congestion window in packet.
|
||||
const MaxCongestionWindowPackets = 10000
|
||||
|
||||
// MaxUndecryptablePackets limits the number of undecryptable packets that are queued in the session.
|
||||
const MaxUndecryptablePackets = 32
|
||||
|
||||
// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window
|
||||
// This is the value that Chromium is using
|
||||
const ConnectionFlowControlMultiplier = 1.5
|
||||
|
||||
// DefaultInitialMaxStreamData is the default initial stream-level flow control window for receiving data
|
||||
const DefaultInitialMaxStreamData = (1 << 10) * 512 // 512 kb
|
||||
|
||||
// DefaultInitialMaxData is the connection-level flow control window for receiving data
|
||||
const DefaultInitialMaxData = ConnectionFlowControlMultiplier * DefaultInitialMaxStreamData
|
||||
|
||||
// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data
|
||||
const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB
|
||||
|
||||
// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data
|
||||
const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 15 MB
|
||||
|
||||
// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client
|
||||
const WindowUpdateThreshold = 0.25
|
||||
|
||||
// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open
|
||||
const DefaultMaxIncomingStreams = 100
|
||||
|
||||
// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open
|
||||
const DefaultMaxIncomingUniStreams = 100
|
||||
|
||||
// MaxServerUnprocessedPackets is the max number of packets stored in the server that are not yet processed.
|
||||
const MaxServerUnprocessedPackets = 1024
|
||||
|
||||
// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
|
||||
const MaxSessionUnprocessedPackets = 256
|
||||
|
||||
// SkipPacketInitialPeriod is the initial period length used for packet number skipping to prevent an Optimistic ACK attack.
|
||||
// Every time a packet number is skipped, the period is doubled, up to SkipPacketMaxPeriod.
|
||||
const SkipPacketInitialPeriod PacketNumber = 256
|
||||
|
||||
// SkipPacketMaxPeriod is the maximum period length used for packet number skipping.
|
||||
const SkipPacketMaxPeriod PacketNumber = 128 * 1024
|
||||
|
||||
// MaxAcceptQueueSize is the maximum number of sessions that the server queues for accepting.
|
||||
// If the queue is full, new connection attempts will be rejected.
|
||||
const MaxAcceptQueueSize = 32
|
||||
|
||||
// TokenValidity is the duration that a (non-retry) token is considered valid
|
||||
const TokenValidity = 24 * time.Hour
|
||||
|
||||
// RetryTokenValidity is the duration that a retry token is considered valid
|
||||
const RetryTokenValidity = 10 * time.Second
|
||||
|
||||
// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
|
||||
// When reached, it imposes a soft limit on sending new packets:
|
||||
// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
|
||||
const MaxOutstandingSentPackets = 2 * MaxCongestionWindowPackets
|
||||
|
||||
// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission.
|
||||
// When reached, no more packets will be sent.
|
||||
// This value *must* be larger than MaxOutstandingSentPackets.
|
||||
const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4
|
||||
|
||||
// MaxNonAckElicitingAcks is the maximum number of packets containing an ACK,
|
||||
// but no ack-eliciting frames, that we send in a row
|
||||
const MaxNonAckElicitingAcks = 19
|
||||
|
||||
// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames
|
||||
// prevents DoS attacks against the streamFrameSorter
|
||||
const MaxStreamFrameSorterGaps = 1000
|
||||
|
||||
// MinStreamFrameBufferSize is the minimum data length of a received STREAM frame
|
||||
// that we use the buffer for. This protects against a DoS where an attacker would send us
|
||||
// very small STREAM frames to consume a lot of memory.
|
||||
const MinStreamFrameBufferSize = 128
|
||||
|
||||
// MinCoalescedPacketSize is the minimum size of a coalesced packet that we pack.
|
||||
// If a packet has less than this number of bytes, we won't coalesce any more packets onto it.
|
||||
const MinCoalescedPacketSize = 128
|
||||
|
||||
// MaxCryptoStreamOffset is the maximum offset allowed on any of the crypto streams.
|
||||
// This limits the size of the ClientHello and Certificates that can be received.
|
||||
const MaxCryptoStreamOffset = 16 * (1 << 10)
|
||||
|
||||
// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout
|
||||
const MinRemoteIdleTimeout = 5 * time.Second
|
||||
|
||||
// DefaultIdleTimeout is the default idle timeout
|
||||
const DefaultIdleTimeout = 30 * time.Second
|
||||
|
||||
// DefaultHandshakeIdleTimeout is the default idle timeout used before handshake completion.
|
||||
const DefaultHandshakeIdleTimeout = 5 * time.Second
|
||||
|
||||
// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds.
|
||||
const DefaultHandshakeTimeout = 10 * time.Second
|
||||
|
||||
// MaxKeepAliveInterval is the maximum time until we send a packet to keep a connection alive.
|
||||
// It should be shorter than the time that NATs clear their mapping.
|
||||
const MaxKeepAliveInterval = 20 * time.Second
|
||||
|
||||
// RetiredConnectionIDDeleteTimeout is the time we keep closed sessions around in order to retransmit the CONNECTION_CLOSE.
|
||||
// after this time all information about the old connection will be deleted
|
||||
const RetiredConnectionIDDeleteTimeout = 5 * time.Second
|
||||
|
||||
// MinStreamFrameSize is the minimum size that has to be left in a packet, so that we add another STREAM frame.
|
||||
// This avoids splitting up STREAM frames into small pieces, which has 2 advantages:
|
||||
// 1. it reduces the framing overhead
|
||||
// 2. it reduces the head-of-line blocking, when a packet is lost
|
||||
const MinStreamFrameSize ByteCount = 128
|
||||
|
||||
// MaxPostHandshakeCryptoFrameSize is the maximum size of CRYPTO frames
|
||||
// we send after the handshake completes.
|
||||
const MaxPostHandshakeCryptoFrameSize = 1000
|
||||
|
||||
// MaxAckFrameSize is the maximum size for an ACK frame that we write
|
||||
// Due to the varint encoding, ACK frames can grow (almost) indefinitely large.
|
||||
// The MaxAckFrameSize should be large enough to encode many ACK range,
|
||||
// but must ensure that a maximum size ACK frame fits into one packet.
|
||||
const MaxAckFrameSize ByteCount = 1000
|
||||
|
||||
// MaxDatagramFrameSize is the maximum size of a DATAGRAM frame as defined in
|
||||
// https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
|
||||
// The size is chosen such that a DATAGRAM frame fits into a QUIC packet.
|
||||
const MaxDatagramFrameSize ByteCount = 1220
|
||||
|
||||
// DatagramRcvQueueLen is the length of the receive queue for DATAGRAM frames.
|
||||
// See https://datatracker.ietf.org/doc/draft-pauly-quic-datagram/.
|
||||
const DatagramRcvQueueLen = 128
|
||||
|
||||
// MaxNumAckRanges is the maximum number of ACK ranges that we send in an ACK frame.
|
||||
// It also serves as a limit for the packet history.
|
||||
// If at any point we keep track of more ranges, old ranges are discarded.
|
||||
const MaxNumAckRanges = 32
|
||||
|
||||
// MinPacingDelay is the minimum duration that is used for packet pacing
|
||||
// If the packet packing frequency is higher, multiple packets might be sent at once.
|
||||
// Example: For a packet pacing delay of 200μs, we would send 5 packets at once, wait for 1ms, and so forth.
|
||||
const MinPacingDelay = time.Millisecond
|
||||
|
||||
// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections
|
||||
// if no other value is configured.
|
||||
const DefaultConnectionIDLength = 4
|
||||
|
||||
// MaxActiveConnectionIDs is the number of connection IDs that we're storing.
|
||||
const MaxActiveConnectionIDs = 4
|
||||
|
||||
// MaxIssuedConnectionIDs is the maximum number of connection IDs that we're issuing at the same time.
|
||||
const MaxIssuedConnectionIDs = 6
|
||||
|
||||
// PacketsPerConnectionID is the number of packets we send using one connection ID.
|
||||
// If the peer provices us with enough new connection IDs, we switch to a new connection ID.
|
||||
const PacketsPerConnectionID = 10000
|
||||
|
||||
// AckDelayExponent is the ack delay exponent used when sending ACKs.
|
||||
const AckDelayExponent = 3
|
||||
|
||||
// Estimated timer granularity.
|
||||
// The loss detection timer will not be set to a value smaller than granularity.
|
||||
const TimerGranularity = time.Millisecond
|
||||
|
||||
// MaxAckDelay is the maximum time by which we delay sending ACKs.
|
||||
const MaxAckDelay = 25 * time.Millisecond
|
||||
|
||||
// MaxAckDelayInclGranularity is the max_ack_delay including the timer granularity.
|
||||
// This is the value that should be advertised to the peer.
|
||||
const MaxAckDelayInclGranularity = MaxAckDelay + TimerGranularity
|
||||
|
||||
// KeyUpdateInterval is the maximum number of packets we send or receive before initiating a key update.
|
||||
const KeyUpdateInterval = 100 * 1000
|
||||
|
||||
// Max0RTTQueueingDuration is the maximum time that we store 0-RTT packets in order to wait for the corresponding Initial to be received.
|
||||
const Max0RTTQueueingDuration = 100 * time.Millisecond
|
||||
|
||||
// Max0RTTQueues is the maximum number of connections that we buffer 0-RTT packets for.
|
||||
const Max0RTTQueues = 32
|
||||
|
||||
// Max0RTTQueueLen is the maximum number of 0-RTT packets that we buffer for each connection.
|
||||
// When a new session is created, all buffered packets are passed to the session immediately.
|
||||
// To avoid blocking, this value has to be smaller than MaxSessionUnprocessedPackets.
|
||||
// To avoid packets being dropped as undecryptable by the session, this value has to be smaller than MaxUndecryptablePackets.
|
||||
const Max0RTTQueueLen = 31
|
26
vendor/github.com/lucas-clemente/quic-go/internal/protocol/perspective.go
generated
vendored
Normal file
26
vendor/github.com/lucas-clemente/quic-go/internal/protocol/perspective.go
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
package protocol
|
||||
|
||||
// Perspective determines if we're acting as a server or a client
|
||||
type Perspective int
|
||||
|
||||
// the perspectives
|
||||
const (
|
||||
PerspectiveServer Perspective = 1
|
||||
PerspectiveClient Perspective = 2
|
||||
)
|
||||
|
||||
// Opposite returns the perspective of the peer
|
||||
func (p Perspective) Opposite() Perspective {
|
||||
return 3 - p
|
||||
}
|
||||
|
||||
func (p Perspective) String() string {
|
||||
switch p {
|
||||
case PerspectiveServer:
|
||||
return "Server"
|
||||
case PerspectiveClient:
|
||||
return "Client"
|
||||
default:
|
||||
return "invalid perspective"
|
||||
}
|
||||
}
|
97
vendor/github.com/lucas-clemente/quic-go/internal/protocol/protocol.go
generated
vendored
Normal file
97
vendor/github.com/lucas-clemente/quic-go/internal/protocol/protocol.go
generated
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// The PacketType is the Long Header Type
|
||||
type PacketType uint8
|
||||
|
||||
const (
|
||||
// PacketTypeInitial is the packet type of an Initial packet
|
||||
PacketTypeInitial PacketType = 1 + iota
|
||||
// PacketTypeRetry is the packet type of a Retry packet
|
||||
PacketTypeRetry
|
||||
// PacketTypeHandshake is the packet type of a Handshake packet
|
||||
PacketTypeHandshake
|
||||
// PacketType0RTT is the packet type of a 0-RTT packet
|
||||
PacketType0RTT
|
||||
)
|
||||
|
||||
func (t PacketType) String() string {
|
||||
switch t {
|
||||
case PacketTypeInitial:
|
||||
return "Initial"
|
||||
case PacketTypeRetry:
|
||||
return "Retry"
|
||||
case PacketTypeHandshake:
|
||||
return "Handshake"
|
||||
case PacketType0RTT:
|
||||
return "0-RTT Protected"
|
||||
default:
|
||||
return fmt.Sprintf("unknown packet type: %d", t)
|
||||
}
|
||||
}
|
||||
|
||||
type ECN uint8
|
||||
|
||||
const (
|
||||
ECNNon ECN = iota // 00
|
||||
ECT1 // 01
|
||||
ECT0 // 10
|
||||
ECNCE // 11
|
||||
)
|
||||
|
||||
// A ByteCount in QUIC
|
||||
type ByteCount int64
|
||||
|
||||
// MaxByteCount is the maximum value of a ByteCount
|
||||
const MaxByteCount = ByteCount(1<<62 - 1)
|
||||
|
||||
// InvalidByteCount is an invalid byte count
|
||||
const InvalidByteCount ByteCount = -1
|
||||
|
||||
// A StatelessResetToken is a stateless reset token.
|
||||
type StatelessResetToken [16]byte
|
||||
|
||||
// MaxPacketBufferSize maximum packet size of any QUIC packet, based on
|
||||
// ethernet's max size, minus the IP and UDP headers. IPv6 has a 40 byte header,
|
||||
// UDP adds an additional 8 bytes. This is a total overhead of 48 bytes.
|
||||
// Ethernet's max packet size is 1500 bytes, 1500 - 48 = 1452.
|
||||
const MaxPacketBufferSize ByteCount = 1452
|
||||
|
||||
// MinInitialPacketSize is the minimum size an Initial packet is required to have.
|
||||
const MinInitialPacketSize = 1200
|
||||
|
||||
// MinUnknownVersionPacketSize is the minimum size a packet with an unknown version
|
||||
// needs to have in order to trigger a Version Negotiation packet.
|
||||
const MinUnknownVersionPacketSize = MinInitialPacketSize
|
||||
|
||||
// MinStatelessResetSize is the minimum size of a stateless reset packet that we send
|
||||
const MinStatelessResetSize = 1 /* first byte */ + 20 /* max. conn ID length */ + 4 /* max. packet number length */ + 1 /* min. payload length */ + 16 /* token */
|
||||
|
||||
// MinConnectionIDLenInitial is the minimum length of the destination connection ID on an Initial packet.
|
||||
const MinConnectionIDLenInitial = 8
|
||||
|
||||
// DefaultAckDelayExponent is the default ack delay exponent
|
||||
const DefaultAckDelayExponent = 3
|
||||
|
||||
// MaxAckDelayExponent is the maximum ack delay exponent
|
||||
const MaxAckDelayExponent = 20
|
||||
|
||||
// DefaultMaxAckDelay is the default max_ack_delay
|
||||
const DefaultMaxAckDelay = 25 * time.Millisecond
|
||||
|
||||
// MaxMaxAckDelay is the maximum max_ack_delay
|
||||
const MaxMaxAckDelay = (1<<14 - 1) * time.Millisecond
|
||||
|
||||
// MaxConnIDLen is the maximum length of the connection ID
|
||||
const MaxConnIDLen = 20
|
||||
|
||||
// InvalidPacketLimitAES is the maximum number of packets that we can fail to decrypt when using
|
||||
// AEAD_AES_128_GCM or AEAD_AES_265_GCM.
|
||||
const InvalidPacketLimitAES = 1 << 52
|
||||
|
||||
// InvalidPacketLimitChaCha is the maximum number of packets that we can fail to decrypt when using AEAD_CHACHA20_POLY1305.
|
||||
const InvalidPacketLimitChaCha = 1 << 36
|
76
vendor/github.com/lucas-clemente/quic-go/internal/protocol/stream.go
generated
vendored
Normal file
76
vendor/github.com/lucas-clemente/quic-go/internal/protocol/stream.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package protocol
|
||||
|
||||
// StreamType encodes if this is a unidirectional or bidirectional stream
|
||||
type StreamType uint8
|
||||
|
||||
const (
|
||||
// StreamTypeUni is a unidirectional stream
|
||||
StreamTypeUni StreamType = iota
|
||||
// StreamTypeBidi is a bidirectional stream
|
||||
StreamTypeBidi
|
||||
)
|
||||
|
||||
// InvalidPacketNumber is a stream ID that is invalid.
|
||||
// The first valid stream ID in QUIC is 0.
|
||||
const InvalidStreamID StreamID = -1
|
||||
|
||||
// StreamNum is the stream number
|
||||
type StreamNum int64
|
||||
|
||||
const (
|
||||
// InvalidStreamNum is an invalid stream number.
|
||||
InvalidStreamNum = -1
|
||||
// MaxStreamCount is the maximum stream count value that can be sent in MAX_STREAMS frames
|
||||
// and as the stream count in the transport parameters
|
||||
MaxStreamCount StreamNum = 1 << 60
|
||||
)
|
||||
|
||||
// StreamID calculates the stream ID.
|
||||
func (s StreamNum) StreamID(stype StreamType, pers Perspective) StreamID {
|
||||
if s == 0 {
|
||||
return InvalidStreamID
|
||||
}
|
||||
var first StreamID
|
||||
switch stype {
|
||||
case StreamTypeBidi:
|
||||
switch pers {
|
||||
case PerspectiveClient:
|
||||
first = 0
|
||||
case PerspectiveServer:
|
||||
first = 1
|
||||
}
|
||||
case StreamTypeUni:
|
||||
switch pers {
|
||||
case PerspectiveClient:
|
||||
first = 2
|
||||
case PerspectiveServer:
|
||||
first = 3
|
||||
}
|
||||
}
|
||||
return first + 4*StreamID(s-1)
|
||||
}
|
||||
|
||||
// A StreamID in QUIC
|
||||
type StreamID int64
|
||||
|
||||
// InitiatedBy says if the stream was initiated by the client or by the server
|
||||
func (s StreamID) InitiatedBy() Perspective {
|
||||
if s%2 == 0 {
|
||||
return PerspectiveClient
|
||||
}
|
||||
return PerspectiveServer
|
||||
}
|
||||
|
||||
// Type says if this is a unidirectional or bidirectional stream
|
||||
func (s StreamID) Type() StreamType {
|
||||
if s%4 >= 2 {
|
||||
return StreamTypeUni
|
||||
}
|
||||
return StreamTypeBidi
|
||||
}
|
||||
|
||||
// StreamNum returns how many streams in total are below this
|
||||
// Example: for stream 9 it returns 3 (i.e. streams 1, 5 and 9)
|
||||
func (s StreamID) StreamNum() StreamNum {
|
||||
return StreamNum(s/4) + 1
|
||||
}
|
134
vendor/github.com/lucas-clemente/quic-go/internal/protocol/version.go
generated
vendored
Normal file
134
vendor/github.com/lucas-clemente/quic-go/internal/protocol/version.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package protocol
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math"
|
||||
)
|
||||
|
||||
// VersionNumber is a version number as int
|
||||
type VersionNumber uint32
|
||||
|
||||
// gQUIC version range as defined in the wiki: https://github.com/quicwg/base-drafts/wiki/QUIC-Versions
|
||||
const (
|
||||
gquicVersion0 = 0x51303030
|
||||
maxGquicVersion = 0x51303439
|
||||
)
|
||||
|
||||
// The version numbers, making grepping easier
|
||||
const (
|
||||
VersionTLS VersionNumber = 0x1
|
||||
VersionWhatever VersionNumber = math.MaxUint32 - 1 // for when the version doesn't matter
|
||||
VersionUnknown VersionNumber = math.MaxUint32
|
||||
VersionDraft29 VersionNumber = 0xff00001d
|
||||
VersionDraft32 VersionNumber = 0xff000020
|
||||
VersionDraft34 VersionNumber = 0xff000022
|
||||
Version1 VersionNumber = 0x1
|
||||
)
|
||||
|
||||
// SupportedVersions lists the versions that the server supports
|
||||
// must be in sorted descending order
|
||||
var SupportedVersions = []VersionNumber{Version1, VersionDraft34, VersionDraft32, VersionDraft29}
|
||||
|
||||
// IsValidVersion says if the version is known to quic-go
|
||||
func IsValidVersion(v VersionNumber) bool {
|
||||
return v == VersionTLS || IsSupportedVersion(SupportedVersions, v)
|
||||
}
|
||||
|
||||
func (vn VersionNumber) String() string {
|
||||
// For releases, VersionTLS will be set to a draft version.
|
||||
// A switch statement can't contain duplicate cases.
|
||||
if vn == VersionTLS && VersionTLS != VersionDraft29 && VersionTLS != VersionDraft32 && VersionTLS != Version1 {
|
||||
return "TLS dev version (WIP)"
|
||||
}
|
||||
//nolint:exhaustive
|
||||
switch vn {
|
||||
case VersionWhatever:
|
||||
return "whatever"
|
||||
case VersionUnknown:
|
||||
return "unknown"
|
||||
case VersionDraft29:
|
||||
return "draft-29"
|
||||
case VersionDraft32:
|
||||
return "draft-32"
|
||||
case VersionDraft34:
|
||||
return "draft-34"
|
||||
case Version1:
|
||||
return "v1"
|
||||
default:
|
||||
if vn.isGQUIC() {
|
||||
return fmt.Sprintf("gQUIC %d", vn.toGQUICVersion())
|
||||
}
|
||||
return fmt.Sprintf("%#x", uint32(vn))
|
||||
}
|
||||
}
|
||||
|
||||
func (vn VersionNumber) isGQUIC() bool {
|
||||
return vn > gquicVersion0 && vn <= maxGquicVersion
|
||||
}
|
||||
|
||||
func (vn VersionNumber) toGQUICVersion() int {
|
||||
return int(10*(vn-gquicVersion0)/0x100) + int(vn%0x10)
|
||||
}
|
||||
|
||||
// UseRetireBugBackwardsCompatibilityMode says if it is necessary to use the backwards compatilibity mode.
|
||||
// This is only the case if it 1. is enabled and 2. draft-29 is used.
|
||||
func UseRetireBugBackwardsCompatibilityMode(enabled bool, v VersionNumber) bool {
|
||||
return enabled && v == VersionDraft29
|
||||
}
|
||||
|
||||
// IsSupportedVersion returns true if the server supports this version
|
||||
func IsSupportedVersion(supported []VersionNumber, v VersionNumber) bool {
|
||||
for _, t := range supported {
|
||||
if t == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ChooseSupportedVersion finds the best version in the overlap of ours and theirs
|
||||
// ours is a slice of versions that we support, sorted by our preference (descending)
|
||||
// theirs is a slice of versions offered by the peer. The order does not matter.
|
||||
// The bool returned indicates if a matching version was found.
|
||||
func ChooseSupportedVersion(ours, theirs []VersionNumber) (VersionNumber, bool) {
|
||||
for _, ourVer := range ours {
|
||||
for _, theirVer := range theirs {
|
||||
if ourVer == theirVer {
|
||||
return ourVer, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// generateReservedVersion generates a reserved version number (v & 0x0f0f0f0f == 0x0a0a0a0a)
|
||||
func generateReservedVersion() VersionNumber {
|
||||
b := make([]byte, 4)
|
||||
_, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything
|
||||
return VersionNumber((binary.BigEndian.Uint32(b) | 0x0a0a0a0a) & 0xfafafafa)
|
||||
}
|
||||
|
||||
// GetGreasedVersions adds one reserved version number to a slice of version numbers, at a random position
|
||||
func GetGreasedVersions(supported []VersionNumber) []VersionNumber {
|
||||
b := make([]byte, 1)
|
||||
_, _ = rand.Read(b) // ignore the error here. Failure to read random data doesn't break anything
|
||||
randPos := int(b[0]) % (len(supported) + 1)
|
||||
greased := make([]VersionNumber, len(supported)+1)
|
||||
copy(greased, supported[:randPos])
|
||||
greased[randPos] = generateReservedVersion()
|
||||
copy(greased[randPos+1:], supported[randPos:])
|
||||
return greased
|
||||
}
|
||||
|
||||
// StripGreasedVersions strips all greased versions from a slice of versions
|
||||
func StripGreasedVersions(versions []VersionNumber) []VersionNumber {
|
||||
realVersions := make([]VersionNumber, 0, len(versions))
|
||||
for _, v := range versions {
|
||||
if v&0x0f0f0f0f != 0x0a0a0a0a {
|
||||
realVersions = append(realVersions, v)
|
||||
}
|
||||
}
|
||||
return realVersions
|
||||
}
|
Reference in New Issue
Block a user