quic

package
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 9, 2026 License: BSD-3-Clause, GPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package quic implements QUIC protocol analysis for both gQUIC and IETF QUIC. The gQUIC parsing is based on patterns from https://github.com/0x4D31/quick

Index

Constants

This section is empty.

Variables

View Source
var Decoder = &decoder.StreamDecoder{
	Type:        types.Type_NC_QUICClientHello,
	Name:        serviceQUIC,
	Description: "QUIC ClientHello extraction for JA4 fingerprinting (supports IETF QUIC and gQUIC)",
	PostInit: func(d *decoder.StreamDecoder) error {
		var err error
		quicLog, _, err = logging.InitZapLogger(
			decoderconfig.Instance.Out,
			"quic",
			decoderconfig.Instance.Debug,
		)
		return err
	},
	CanDecode: func(client, server []byte) bool {

		if len(client) >= 5 {

			if IsIETFQUICPacket(client) {
				quicLog.Debug("QUIC traffic detected - IETF QUIC",
					zap.Int("clientLen", len(client)),
					zap.Int("serverLen", len(server)),
				)
				return true
			}

			if IsGQUICPacket(client) {
				quicLog.Debug("QUIC traffic detected - gQUIC",
					zap.Int("clientLen", len(client)),
					zap.Int("serverLen", len(server)),
				)
				return true
			}
		}

		quicLog.Debug("QUIC CanDecode check failed",
			zap.Int("clientLen", len(client)),
			zap.Int("serverLen", len(server)),
		)
		return false
	},
	DeInit: func(sd *decoder.StreamDecoder) error {
		return quicLog.Sync()
	},
	Factory: &quicReader{},
	Typ:     core.UDP,
}

Decoder for QUIC protocol analysis and writing audit records to disk.

Functions

func CanDecodeQUIC

func CanDecodeQUIC(data []byte) bool

CanDecodeQUIC provides a public check for QUIC detection. This can be used by other parts of the system.

func GetQUICVersionString

func GetQUICVersionString(version uint32) string

GetQUICVersionString returns a human-readable version string for QUIC versions.

func IsGQUICPacket

func IsGQUICPacket(payload []byte) bool

IsGQUICPacket checks if the payload looks like a gQUIC packet. gQUIC packets can have two forms: 1. Long form with version (handshake): contains "Qxxx" version string 2. Short form without version (after handshake): identified by public flags pattern

func IsIETFQUICPacket

func IsIETFQUICPacket(payload []byte) bool

IsIETFQUICPacket checks if the payload looks like an IETF QUIC packet. Note: RFC 9287 allows "greasing" the fixed bit (setting it to 0 randomly), so short header detection may have false negatives for greased packets. For comprehensive detection, connection tracking context would be needed.

Types

type GQUICClientHello

type GQUICClientHello struct {
	Version    string            // QUIC version (e.g., "Q043", "Q046")
	CID        []byte            // Connection ID (8 bytes for gQUIC)
	SNI        string            // Server Name Indication
	UAID       string            // User Agent ID (e.g., "Chrome/74.0.3729.131 Intel Mac OS X 10_14_4")
	Tags       []string          // Tags in order for fingerprinting
	TagValues  map[string]string // Tag values
	PacketNum  int               // Packet number
	FrameType  byte              // Frame type
	StreamID   int               // Stream ID
	DataLength int               // Data length
	RawMAC     []byte            // Message Authentication Hash
}

GQUICClientHello represents parsed gQUIC CHLO data.

func ParseGQUICClientHello

func ParseGQUICClientHello(payload []byte) (*GQUICClientHello, error)

ParseGQUICClientHello parses a gQUIC packet and extracts CHLO information. Based on patterns from https://github.com/0x4D31/quick

gQUIC versions (Q043, Q044, Q046, Q050) use a different packet format than IETF QUIC. The format consists of: - Public Flags (1 byte) - Connection ID (8 bytes, optional based on flags) - Version (4 bytes, optional based on flags) - Packet Number (1-6 bytes based on flags) - Payload containing CHLO message

type IETFQUICClientHello

type IETFQUICClientHello struct {
	Version      uint32 // QUIC version
	DCID         []byte // Destination Connection ID
	SCID         []byte // Source Connection ID
	Token        []byte // Token (for address validation)
	PacketNumber int64

	// Embedded TLS ClientHello data
	TLSVersion         uint16   // TLS version from ClientHello
	Random             []byte   // TLS random (32 bytes)
	SessionID          []byte   // Session ID
	CipherSuites       []uint16 // Cipher suites offered
	CompressionMethods []byte   // Compression methods
	Extensions         []uint16 // Extension types
	SNI                string   // Server Name Indication
	ALPNs              []string // ALPN protocols
	SupportedGroups    []uint16 // Supported elliptic curves
	SignatureAlgs      []uint16 // Signature algorithms
	SupportedVersions  []uint16 // TLS supported versions extension

	// QUIC Transport Parameters (RFC 9000 Section 18.2)
	// Extension type: 0x39 for QUIC v1 (RFC 9001), 0x57 for QUIC v2 (RFC 9369)
	MaxIdleTimeout                 uint64 // 0x01
	MaxUDPPayloadSize              uint64 // 0x03
	InitialMaxData                 uint64 // 0x04
	InitialMaxStreamDataBidiLocal  uint64 // 0x05
	InitialMaxStreamDataBidiRemote uint64 // 0x06
	InitialMaxStreamDataUni        uint64 // 0x07
	InitialMaxStreamsBidi          uint64 // 0x08
	InitialMaxStreamsUni           uint64 // 0x09
	AckDelayExponent               uint64 // 0x0a (default: 3)
	MaxAckDelay                    uint64 // 0x0b (default: 25ms)
	DisableActiveMigration         bool   // 0x0c
	ActiveConnectionIDLimit        uint64 // 0x0e (default: 2)
	InitialSourceConnectionID      []byte // 0x0f
}

IETFQUICClientHello represents parsed IETF QUIC Initial packet data.

func ParseIETFQUICInitial

func ParseIETFQUICInitial(payload []byte) (*IETFQUICClientHello, error)

ParseIETFQUICInitial parses an IETF QUIC Initial packet and extracts the ClientHello. This requires decrypting the packet header and payload using the Initial secret.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL