clienthellod

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jul 4, 2023 License: Apache-2.0 Imports: 17 Imported by: 4

README

clienthellod

ClientHello Parser/Resolver as a Service from tlsfingerprint.io.

Develop and Test

Build
xcaddy build --with github.com/gaukas/clienthellod/modcaddy --with github.com/gaukas/clienthellod/=./

Documentation

Index

Constants

View Source
const (
	QUICFrame_PADDING uint64 = 0 // 0
	QUICFrame_PING    uint64 = 1 // 1
	QUICFrame_CRYPTO  uint64 = 6 // 6
)
View Source
const (
	QTP_GREASE = 27

	UNSET_VLI_BITS = true // if false, unsetVLIBits() will be nop
)

Variables

View Source
var (
	ErrNotQUICLongHeaderFormat = errors.New("packet is not in QUIC Long Header Format")
	ErrNotQUICInitialPacket    = errors.New("packet is not a QUIC Initial Packet")
)
View Source
var (
	ErrNoQUICClientHello = errors.New("no QUIC ClientHello found in the packet")
)

Functions

func ClientInitialKeysCalc added in v0.3.0

func ClientInitialKeysCalc(initialRandom []byte) (clientKey, clientIV, clientHpKey []byte, err error)

func ComputeHeaderProtection added in v0.3.0

func ComputeHeaderProtection(clientHpKey, sample []byte) ([]byte, error)

func DecodeVLI added in v0.3.0

func DecodeVLI(vli []byte) (val uint64, err error)

func DecryptAES128GCM added in v0.3.0

func DecryptAES128GCM(iv []byte, recordNum uint64, key, ciphertext, recdata, authtag []byte) (plaintext []byte, err error)

func IsGREASETransportParameter added in v0.3.0

func IsGREASETransportParameter(paramType uint64) bool

func ReadNextVLI added in v0.3.0

func ReadNextVLI(r io.Reader) (val uint64, n int, err error)

ReadNextVLI unpacks the next variable-length integer from the given io.Reader. It returns the decoded value and the number of bytes read. For example:

0x0a -> 0xa, 1
0x80 0x10 0x00 0x00 -> 0x100000, 4

func ReassembleCRYPTOFrames added in v0.3.0

func ReassembleCRYPTOFrames(frames []Frame) ([]byte, error)

Types

type CRYPTO added in v0.3.0

type CRYPTO struct {
	Offset uint64 `json:"offset,omitempty"` // offset of crypto data, from VLI
	Length uint64 `json:"length,omitempty"` // length of crypto data, from VLI
	Data   []byte `json:"data,omitempty"`   // crypto data
}

CRYPTO frame

func (*CRYPTO) FrameType added in v0.3.0

func (f *CRYPTO) FrameType() uint64

FrameType implements Frame interface.

func (*CRYPTO) ReadReader added in v0.3.0

func (f *CRYPTO) ReadReader(r io.Reader) (rr io.Reader, err error)

ReadFrom implements Frame interface. It reads the offset, length and crypto data from the input reader.

type ClientHello

type ClientHello struct {
	TLSRecordVersion    uint16 `json:"tls_record_version"`    // TLS record version (major, minor)
	TLSHandshakeVersion uint16 `json:"tls_handshake_version"` // TLS handshake version (major, minor)

	CipherSuites         []uint16       `json:"cipher_suites"`
	CompressionMethods   utils.Uint8Arr `json:"compression_methods"`
	Extensions           []uint16       `json:"extensions"`            // extension IDs in original order
	ExtensionsNormalized []uint16       `json:"extensions_normalized"` // sorted extension IDs

	ServerName          string         `json:"server_name"`            // server_name(0)
	NamedGroupList      []uint16       `json:"supported_groups"`       // supported_groups(10) a.k.a elliptic_curves
	ECPointFormatList   utils.Uint8Arr `json:"ec_point_formats"`       // ec_point_formats(11)
	SignatureSchemeList []uint16       `json:"signature_algorithms"`   // signature_algorithms(13)
	ALPN                []string       `json:"alpn"`                   // alpn(16)
	CertCompressAlgo    []uint16       `json:"compress_certificate"`   // compress_certificate(27)
	RecordSizeLimit     utils.Uint8Arr `json:"record_size_limit"`      // record_size_limit(28)
	SupportedVersions   []uint16       `json:"supported_versions"`     // supported_versions(43)
	PSKKeyExchangeModes utils.Uint8Arr `json:"psk_key_exchange_modes"` // psk_key_exchange_modes(45)
	KeyShare            []uint16       `json:"key_share"`              // key_share(51)
	ApplicationSettings []string       `json:"application_settings"`   // application_settings(17513) a.k.a ALPS

	UserAgent string `json:"user_agent,omitempty"` // User-Agent header, set by the caller

	NID     int64  `json:"nid,omitempty"`      // NID of the fingerprint
	NormNID int64  `json:"norm_nid,omitempty"` // Normalized NID of the fingerprint
	ID      string `json:"id,omitempty"`       // ID of the fingerprint (hex string)
	NormID  string `json:"norm_id,omitempty"`  // Normalized ID of the fingerprint (hex string)
	// contains filtered or unexported fields
}

func ReadClientHello

func ReadClientHello(r io.Reader) (ch *ClientHello, err error)

ReadClientHello reads a ClientHello from a connection (io.Reader) and returns a ClientHello struct.

It will return an error if the reader does not give a stream of bytes representing a valid ClientHello. But all bytes read from the reader will be stored in the ClientHello struct to be rewinded by the caller.

func (*ClientHello) FingerprintID

func (ch *ClientHello) FingerprintID(normalized bool) string

FingerprintID calculates fingerprint ID of ClientHello and represents it as hexadecimal string.

func (*ClientHello) FingerprintNID

func (ch *ClientHello) FingerprintNID(normalized bool) int64

FingerprintNID calculates fingerprint Numerical ID of ClientHello. Fingerprint is defined by

func (*ClientHello) ParseClientHello

func (ch *ClientHello) ParseClientHello() error

ParseClientHello parses the raw bytes of a ClientHello into a ClientHello struct.

func (*ClientHello) Raw

func (ch *ClientHello) Raw() []byte

type ClientInitialPacket added in v0.3.0

type ClientInitialPacket struct {
	QHdr *QUICHeader              `json:"quic_header,omitempty"`               // QUIC header, set by the caller
	QCH  *QUICClientHello         `json:"quic_client_hello,omitempty"`         // TLS ClientHello, set by the caller
	QTP  *QUICTransportParameters `json:"quic_transport_parameters,omitempty"` // QUIC Transport Parameters, set by the caller

	UserAgent string `json:"user_agent,omitempty"` // User-Agent header, set by the caller
	// contains filtered or unexported fields
}

func ParseQUICCIP added in v0.3.0

func ParseQUICCIP(p []byte) (*ClientInitialPacket, error)

type Frame added in v0.3.0

type Frame interface {
	// FrameType returns the type of the frame.
	FrameType() uint64

	// ReadReader takes a Reader and reads the rest of the frame from it,
	// starting from the first byte after the frame type.
	//
	// The returned io.Reader contains the rest of the frame, it could be
	// the input Reader itself (if no extra bytes are read) or a rewinded
	// Reader (if extra bytes are read and rewinding is needed).
	ReadReader(io.Reader) (io.Reader, error)
}

func ReadAllFrames added in v0.3.0

func ReadAllFrames(r io.Reader) ([]Frame, error)

type PADDING added in v0.3.0

type PADDING struct {
	Length uint64 `json:"length,omitempty"` // count 0x00 bytes until not 0x00
}

PADDING frame

func (*PADDING) FrameType added in v0.3.0

func (f *PADDING) FrameType() uint64

FrameType implements Frame interface.

func (*PADDING) ReadReader added in v0.3.0

func (f *PADDING) ReadReader(r io.Reader) (rr io.Reader, err error)

ReadFrom implements Frame interface. It keeps reading until it finds a non-zero byte, then the non-zero byte is rewinded back to the reader and the reader is returned.

type PING added in v0.3.0

type PING struct{}

PING frame

func (*PING) FrameType added in v0.3.0

func (f *PING) FrameType() uint64

FrameType implements Frame interface.

func (*PING) ReadReader added in v0.3.0

func (f *PING) ReadReader(r io.Reader) (rr io.Reader, err error)

ReadFrom implements Frame interface. It does nothing and returns the input reader.

type QUICClientHello added in v0.3.0

type QUICClientHello struct {
	ClientHello
}

func ParseQUICClientHello added in v0.3.0

func ParseQUICClientHello(p []byte) (*QUICClientHello, error)

func (*QUICClientHello) Raw added in v0.3.0

func (qch *QUICClientHello) Raw() []byte

type QUICHeader added in v0.3.0

type QUICHeader struct {
	InitialPacketNumberLength uint32         `json:"pn_len,omitempty"`  // TODO: from Packet Header Byte, +1 or not?
	VersionLength             uint32         `json:"ver_len,omitempty"` // TODO: is it not fixed 4-byte?
	Version                   utils.Uint8Arr `json:"version,omitempty"` // 4-byte version
	DCIDLength                uint32         `json:"dcid_len,omitempty"`
	SCIDLength                uint32         `json:"scid_len,omitempty"`
	TokenLength               uint32         `json:"token_len,omitempty"`
	InitialPacketNumber       uint32         `json:"pn,omitempty"` // TODO: protected or unprotected?

	// These two fields are not strictly part of QUIC header, but we need them before parsing QUIC ClientHello
	FramesPresentLength uint32   `json:"frames_present_len,omitempty"` // TODO: length of all frames OR number of frames?
	FrameIDs            []uint32 `json:"frame_id,omitempty"`           // sorted
	// contains filtered or unexported fields
}

func DecodeQUICHeaderAndFrames added in v0.3.0

func DecodeQUICHeaderAndFrames(p []byte) (*QUICHeader, error)

type QUICTransportParameters added in v0.3.0

type QUICTransportParameters struct {
	MaxIdleTimeoutLength                 uint32         `json:"max_idle_timeout_len,omitempty"`
	MaxIdleTimeout                       utils.Uint8Arr `json:"max_idle_timeout,omitempty"`
	MaxUDPPayloadSizeLength              uint32         `json:"max_udp_payload_size_len,omitempty"`
	MaxUDPPayloadSize                    utils.Uint8Arr `json:"max_udp_payload_size,omitempty"`
	InitialMaxDataLength                 uint32         `json:"initial_max_data_len,omitempty"`
	InitialMaxData                       utils.Uint8Arr `json:"initial_max_data,omitempty"`
	InitialMaxStreamDataBidiLocalLength  uint32         `json:"initial_max_stream_data_bidi_local_len,omitempty"`
	InitialMaxStreamDataBidiLocal        utils.Uint8Arr `json:"initial_max_stream_data_bidi_local,omitempty"`
	InitialMaxStreamDataBidiRemoteLength uint32         `json:"initial_max_stream_data_bidi_remote_len,omitempty"`
	InitialMaxStreamDataBidiRemote       utils.Uint8Arr `json:"initial_max_stream_data_bidi_remote,omitempty"`
	InitialMaxStreamDataUniLength        uint32         `json:"initial_max_stream_data_uni_len,omitempty"`
	InitialMaxStreamDataUni              utils.Uint8Arr `json:"initial_max_stream_data_uni,omitempty"`
	InitialMaxStreamsBidiLength          uint32         `json:"initial_max_streams_bidi_len,omitempty"`
	InitialMaxStreamsBidi                utils.Uint8Arr `json:"initial_max_streams_bidi,omitempty"`
	InitialMaxStreamsUniLength           uint32         `json:"initial_max_streams_uni_len,omitempty"`
	InitialMaxStreamsUni                 utils.Uint8Arr `json:"initial_max_streams_uni,omitempty"`
	AckDelayExponentLength               uint32         `json:"ack_delay_exponent_len,omitempty"`
	AckDelayExponent                     utils.Uint8Arr `json:"ack_delay_exponent,omitempty"`
	MaxAckDelayLength                    uint32         `json:"max_ack_delay_len,omitempty"`
	MaxAckDelay                          utils.Uint8Arr `json:"max_ack_delay,omitempty"`
	ActiveConnectionIDLimitLength        uint32         `json:"active_connection_id_limit_len,omitempty"`
	ActiveConnectionIDLimit              utils.Uint8Arr `json:"active_connection_id_limit,omitempty"`
	QTPIDs                               []uint64       `json:"qtpid,omitempty"` // sorted
	QTPIDSum                             uint64         `json:"qtpid_sum,omitempty"`
	// contains filtered or unexported fields
}

func ParseQUICTransportParameters added in v0.3.0

func ParseQUICTransportParameters(extData []byte) *QUICTransportParameters

Directories

Path Synopsis
internal
app

Jump to

Keyboard shortcuts

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