aboutsummaryrefslogtreecommitdiff
path: root/src/vendor/golang.org/x/net/quic/packet.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendor/golang.org/x/net/quic/packet.go')
-rw-r--r--src/vendor/golang.org/x/net/quic/packet.go267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/vendor/golang.org/x/net/quic/packet.go b/src/vendor/golang.org/x/net/quic/packet.go
new file mode 100644
index 0000000000..b9fa333c54
--- /dev/null
+++ b/src/vendor/golang.org/x/net/quic/packet.go
@@ -0,0 +1,267 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package quic
+
+import (
+ "encoding/binary"
+ "fmt"
+
+ "golang.org/x/net/internal/quic/quicwire"
+)
+
+// packetType is a QUIC packet type.
+// https://www.rfc-editor.org/rfc/rfc9000.html#section-17
+type packetType byte
+
+const (
+ packetTypeInvalid = packetType(iota)
+ packetTypeInitial
+ packetType0RTT
+ packetTypeHandshake
+ packetTypeRetry
+ packetType1RTT
+ packetTypeVersionNegotiation
+)
+
+func (p packetType) String() string {
+ switch p {
+ case packetTypeInitial:
+ return "Initial"
+ case packetType0RTT:
+ return "0-RTT"
+ case packetTypeHandshake:
+ return "Handshake"
+ case packetTypeRetry:
+ return "Retry"
+ case packetType1RTT:
+ return "1-RTT"
+ }
+ return fmt.Sprintf("unknown packet type %v", byte(p))
+}
+
+func (p packetType) qlogString() string {
+ switch p {
+ case packetTypeInitial:
+ return "initial"
+ case packetType0RTT:
+ return "0RTT"
+ case packetTypeHandshake:
+ return "handshake"
+ case packetTypeRetry:
+ return "retry"
+ case packetType1RTT:
+ return "1RTT"
+ }
+ return "unknown"
+}
+
+// Bits set in the first byte of a packet.
+const (
+ headerFormLong = 0x80 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2-3.2.1
+ headerFormShort = 0x00 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.3.1-4.2.1
+ fixedBit = 0x40 // https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2-3.4.1
+ reservedLongBits = 0x0c // https://www.rfc-editor.org/rfc/rfc9000#section-17.2-8.2.1
+ reserved1RTTBits = 0x18 // https://www.rfc-editor.org/rfc/rfc9000#section-17.3.1-4.8.1
+ keyPhaseBit = 0x04 // https://www.rfc-editor.org/rfc/rfc9000#section-17.3.1-4.10.1
+)
+
+// Long Packet Type bits.
+// https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2-3.6.1
+const (
+ longPacketTypeInitial = 0 << 4
+ longPacketType0RTT = 1 << 4
+ longPacketTypeHandshake = 2 << 4
+ longPacketTypeRetry = 3 << 4
+)
+
+// Frame types.
+// https://www.rfc-editor.org/rfc/rfc9000.html#section-19
+const (
+ frameTypePadding = 0x00
+ frameTypePing = 0x01
+ frameTypeAck = 0x02
+ frameTypeAckECN = 0x03
+ frameTypeResetStream = 0x04
+ frameTypeStopSending = 0x05
+ frameTypeCrypto = 0x06
+ frameTypeNewToken = 0x07
+ frameTypeStreamBase = 0x08 // low three bits carry stream flags
+ frameTypeMaxData = 0x10
+ frameTypeMaxStreamData = 0x11
+ frameTypeMaxStreamsBidi = 0x12
+ frameTypeMaxStreamsUni = 0x13
+ frameTypeDataBlocked = 0x14
+ frameTypeStreamDataBlocked = 0x15
+ frameTypeStreamsBlockedBidi = 0x16
+ frameTypeStreamsBlockedUni = 0x17
+ frameTypeNewConnectionID = 0x18
+ frameTypeRetireConnectionID = 0x19
+ frameTypePathChallenge = 0x1a
+ frameTypePathResponse = 0x1b
+ frameTypeConnectionCloseTransport = 0x1c
+ frameTypeConnectionCloseApplication = 0x1d
+ frameTypeHandshakeDone = 0x1e
+)
+
+// The low three bits of STREAM frames.
+// https://www.rfc-editor.org/rfc/rfc9000.html#section-19.8
+const (
+ streamOffBit = 0x04
+ streamLenBit = 0x02
+ streamFinBit = 0x01
+)
+
+// Maximum length of a connection ID.
+const maxConnIDLen = 20
+
+// isLongHeader returns true if b is the first byte of a long header.
+func isLongHeader(b byte) bool {
+ return b&headerFormLong == headerFormLong
+}
+
+// getPacketType returns the type of a packet.
+func getPacketType(b []byte) packetType {
+ if len(b) == 0 {
+ return packetTypeInvalid
+ }
+ if !isLongHeader(b[0]) {
+ if b[0]&fixedBit != fixedBit {
+ return packetTypeInvalid
+ }
+ return packetType1RTT
+ }
+ if len(b) < 5 {
+ return packetTypeInvalid
+ }
+ if b[1] == 0 && b[2] == 0 && b[3] == 0 && b[4] == 0 {
+ // Version Negotiation packets don't necessarily set the fixed bit.
+ return packetTypeVersionNegotiation
+ }
+ if b[0]&fixedBit != fixedBit {
+ return packetTypeInvalid
+ }
+ switch b[0] & 0x30 {
+ case longPacketTypeInitial:
+ return packetTypeInitial
+ case longPacketType0RTT:
+ return packetType0RTT
+ case longPacketTypeHandshake:
+ return packetTypeHandshake
+ case longPacketTypeRetry:
+ return packetTypeRetry
+ }
+ return packetTypeInvalid
+}
+
+// dstConnIDForDatagram returns the destination connection ID field of the
+// first QUIC packet in a datagram.
+func dstConnIDForDatagram(pkt []byte) (id []byte, ok bool) {
+ if len(pkt) < 1 {
+ return nil, false
+ }
+ var n int
+ var b []byte
+ if isLongHeader(pkt[0]) {
+ if len(pkt) < 6 {
+ return nil, false
+ }
+ n = int(pkt[5])
+ b = pkt[6:]
+ } else {
+ n = connIDLen
+ b = pkt[1:]
+ }
+ if len(b) < n {
+ return nil, false
+ }
+ return b[:n], true
+}
+
+// parseVersionNegotiation parses a Version Negotiation packet.
+// The returned versions is a slice of big-endian uint32s.
+// It returns (nil, nil, nil) for an invalid packet.
+func parseVersionNegotiation(pkt []byte) (dstConnID, srcConnID, versions []byte) {
+ p, ok := parseGenericLongHeaderPacket(pkt)
+ if !ok {
+ return nil, nil, nil
+ }
+ if len(p.data)%4 != 0 {
+ return nil, nil, nil
+ }
+ return p.dstConnID, p.srcConnID, p.data
+}
+
+// appendVersionNegotiation appends a Version Negotiation packet to pkt,
+// returning the result.
+func appendVersionNegotiation(pkt, dstConnID, srcConnID []byte, versions ...uint32) []byte {
+ pkt = append(pkt, headerFormLong|fixedBit) // header byte
+ pkt = append(pkt, 0, 0, 0, 0) // Version (0 for Version Negotiation)
+ pkt = quicwire.AppendUint8Bytes(pkt, dstConnID) // Destination Connection ID
+ pkt = quicwire.AppendUint8Bytes(pkt, srcConnID) // Source Connection ID
+ for _, v := range versions {
+ pkt = binary.BigEndian.AppendUint32(pkt, v) // Supported Version
+ }
+ return pkt
+}
+
+// A longPacket is a long header packet.
+type longPacket struct {
+ ptype packetType
+ version uint32
+ num packetNumber
+ dstConnID []byte
+ srcConnID []byte
+ payload []byte
+
+ // The extra data depends on the packet type:
+ // Initial: Token.
+ // Retry: Retry token and integrity tag.
+ extra []byte
+}
+
+// A shortPacket is a short header (1-RTT) packet.
+type shortPacket struct {
+ num packetNumber
+ payload []byte
+}
+
+// A genericLongPacket is a long header packet of an arbitrary QUIC version.
+// https://www.rfc-editor.org/rfc/rfc8999#section-5.1
+type genericLongPacket struct {
+ version uint32
+ dstConnID []byte
+ srcConnID []byte
+ data []byte
+}
+
+func parseGenericLongHeaderPacket(b []byte) (p genericLongPacket, ok bool) {
+ if len(b) < 5 || !isLongHeader(b[0]) {
+ return genericLongPacket{}, false
+ }
+ b = b[1:]
+ // Version (32),
+ var n int
+ p.version, n = quicwire.ConsumeUint32(b)
+ if n < 0 {
+ return genericLongPacket{}, false
+ }
+ b = b[n:]
+ // Destination Connection ID Length (8),
+ // Destination Connection ID (0..2048),
+ p.dstConnID, n = quicwire.ConsumeUint8Bytes(b)
+ if n < 0 || len(p.dstConnID) > 2048/8 {
+ return genericLongPacket{}, false
+ }
+ b = b[n:]
+ // Source Connection ID Length (8),
+ // Source Connection ID (0..2048),
+ p.srcConnID, n = quicwire.ConsumeUint8Bytes(b)
+ if n < 0 || len(p.dstConnID) > 2048/8 {
+ return genericLongPacket{}, false
+ }
+ b = b[n:]
+ p.data = b
+ return p, true
+}