cloudflared/quic/v3/request.go
Devin Carr 6a6c890700 TUN-8667: Add datagram v3 session manager
New session manager leverages similar functionality that was previously
provided with datagram v2, with the distinct difference that the sessions
are registered via QUIC Datagrams and unregistered via timeouts only; the
sessions will no longer attempt to unregister sessions remotely with the
edge service.

The Session Manager is shared across all QUIC connections that cloudflared
uses to connect to the edge (typically 4). This will help cloudflared be
able to monitor all sessions across the connections and help correlate
in the future if sessions migrate across connections.

The UDP payload size is still limited to 1280 bytes across all OS's. Any
UDP packet that provides a payload size of greater than 1280 will cause
cloudflared to report (as it currently does) a log error and drop the packet.

Closes TUN-8667
2024-10-31 14:05:15 -07:00

78 lines
2.0 KiB
Go

package v3
import (
"encoding/binary"
"errors"
"fmt"
)
const (
datagramRequestIdLen = 16
)
var (
// ErrInvalidRequestIDLen is returned when the provided request id can not be parsed from the provided byte slice.
ErrInvalidRequestIDLen error = errors.New("invalid request id length provided")
// ErrInvalidPayloadDestLen is returned when the provided destination byte slice cannot fit the whole request id.
ErrInvalidPayloadDestLen error = errors.New("invalid payload size provided")
)
// RequestID is the request-id-v2 identifier, it is used to distinguish between specific flows or sessions proxied
// from the edge to cloudflared.
type RequestID uint128
type uint128 struct {
hi uint64
lo uint64
}
// RequestIDFromSlice reads a request ID from a byte slice.
func RequestIDFromSlice(data []byte) (RequestID, error) {
if len(data) != datagramRequestIdLen {
return RequestID{}, ErrInvalidRequestIDLen
}
return RequestID{
hi: binary.BigEndian.Uint64(data[:8]),
lo: binary.BigEndian.Uint64(data[8:]),
}, nil
}
func (id RequestID) String() string {
return fmt.Sprintf("%016x%016x", id.hi, id.lo)
}
// Compare returns an integer comparing two IPs.
// The result will be 0 if id == id2, -1 if id < id2, and +1 if id > id2.
// The definition of "less than" is the same as the [RequestID.Less] method.
func (id RequestID) Compare(id2 RequestID) int {
hi1, hi2 := id.hi, id2.hi
if hi1 < hi2 {
return -1
}
if hi1 > hi2 {
return 1
}
lo1, lo2 := id.lo, id2.lo
if lo1 < lo2 {
return -1
}
if lo1 > lo2 {
return 1
}
return 0
}
// Less reports whether id sorts before id2.
func (id RequestID) Less(id2 RequestID) bool { return id.Compare(id2) == -1 }
// MarshalBinaryTo writes the id to the provided destination byte slice; the byte slice must be of at least size 16.
func (id RequestID) MarshalBinaryTo(data []byte) error {
if len(data) < datagramRequestIdLen {
return ErrInvalidPayloadDestLen
}
binary.BigEndian.PutUint64(data[:8], id.hi)
binary.BigEndian.PutUint64(data[8:], id.lo)
return nil
}