Categorygithub.com/refraction-networking/clienthellod
modulepackage
0.5.0-alpha2
Repository: https://github.com/refraction-networking/clienthellod.git
Documentation: pkg.go.dev

# README

clienthellod: TLS ClientHello/QUIC Initial Packet reflection service

Go Build Status Go Report Card FOSSA Status Go Doc

clienthellod, read as "client-hello-D", is a TLS ClientHello/QUIC Initial Packet reflection service. It can be used to parses TLS ClientHello messages and QUIC Initial Packets into human-readable and highly programmable formats such as JSON.

Is is a part of the TLS fingerprintability research project which spans tlsfingerprint.io and quic.tlsfingerprint.io. It parses the ClientHello messages sent by TLS clients and QUIC Client Initial Packets sent by QUIC clients and display the parsed information in a human-readable format with high programmability.

See tlsfingerprint.io and quic.tlsfingerprint.io for more details about the project.

Quick Start

clienthellod comes as a Go library, which can be used to parse both TLS and QUIC protocols.

TLS/QUIC Fingerprinter

    tlsFingerprinter := clienthellod.NewTLSFingerprinter()
    quicFingerprinter := clienthellod.NewQUICFingerprinter()

TLS ClientHello

From a net.Conn

    tcpLis, err := net.Listen("tcp", ":443")
    defer tcpLis.Close()

    conn, err := tcpLis.Accept()
	if err != nil {
        panic(err)
	}
    defer conn.Close()

	ch, err := clienthellod.ReadClientHello(conn) // reads ClientHello from the connection
    if err != nil {
        panic(err)
    }

    err := ch.ParseClientHello() // parses ClientHello's fields
    if err != nil {
        panic(err)
    }

    jsonB, err = json.MarshalIndent(ch, "", "  ")
    if err != nil {
        panic(err)
    }

    fmt.Println(string(jsonB))
    fmt.Println("ClientHello ID: " + ch.HexID) // prints ClientHello's original fingerprint ID calculated using observed TLS extension order
    fmt.Println("ClientHello NormID: " + ch.NormHexID) // prints ClientHello's normalized fingerprint ID calculated using sorted TLS extension list

From raw []byte

    ch, err := clienthellod.UnmarshalClientHello(raw)
    if err != nil {
        panic(err)
    }

    // err := ch.ParseClientHello() // no need to call again, UnmarshalClientHello automatically calls ParseClientHello

QUIC Initial Packets (Client-sourced)

Single packet

    udpConn, err := net.ListenUDP("udp", ":443")
    defer udpConn.Close()

    buf := make([]byte, 65535)
    n, addr, err := udpConn.ReadFromUDP(buf)
    if err != nil {
        panic(err)
    }

    ci, err := clienthellod.UnmarshalQUICClientInitialPacket(buf[:n]) // decodes QUIC Client Initial Packet
    if err != nil {
        panic(err)
    }

    jsonB, err = json.MarshalIndent(cip, "", "  ")
    if err != nil {
        panic(err)
    }

    fmt.Println(string(jsonB)) // including fingerprint IDs of: ClientInitialPacket, QUIC Header, QUIC ClientHello, QUIC Transport Parameters' combination

Multiple packets

Implementations including Chrome/Chromium sends oversized Client Hello which does not fit into one single QUIC packet, in which case multiple QUIC Initial Packets are sent.

    gci := GatherClientInitials() // Each GatherClientInitials reassembles one QUIC Client Initial Packets stream. Use a QUIC Fingerprinter for multiple potential senders, which automatically demultiplexes the packets based on the source address.

    udpConn, err := net.ListenUDP("udp", ":443")
    defer udpConn.Close()

    for {
        buf := make([]byte, 65535)
        n, addr, err := udpConn.ReadFromUDP(buf)
        if err != nil {
            panic(err)
        }

        if addr != knownSenderAddr {
            continue
        }

        ci, err := clienthellod.UnmarshalQUICClientInitialPacket(buf[:n]) // decodes QUIC Client Initial Packet
        if err != nil {
            panic(err)
        }

        err = gci.AddPacket(ci)
        if err != nil {
            panic(err)
        }
    }

Use with Caddy

We also provide clienthellod as a Caddy Module in modcaddy, which you can use with Caddy to capture ClientHello messages and QUIC Client Initial Packets. See modcaddy for more details.

License

This project is developed and distributed under Apache-2.0 license.

FOSSA Status

# Packages

No description provided by the author

# Functions

ClientInitialKeysCalc calculates the client key, IV and header protection key from the initial random.
ComputeHeaderProtection computes the header protection for the client.
DecodeQUICHeaderAndFrames decodes a QUIC initial packet and returns a QUICHeader.
DecodeVLI decodes a variable-length integer from the given byte slice.
DecryptAES128GCM decrypts the AES-128-GCM encrypted data.
GatherClientInitialPackets reads a series of Client Initial Packets from the input channel and returns the result of the gathered packets.
GatherClientInitialsWithDeadline is a helper function to create a GatheredClientInitials with a deadline.
GenerateQUICFingerprint generates a QUICFingerprint from the gathered ClientInitials.
IsGREASETransportParameter checks if the given transport parameter type is a GREASE value.
NewQUICClientHelloReconstructor creates a new QUICClientHelloReconstructor.
NewQUICFingerprinter creates a new QUICFingerprinter.
NewQUICFingerprinterWithTimeout creates a new QUICFingerprinter with a timeout.
NewTLSFingerprinter creates a new TLSFingerprinter.
NewTLSFingerprinterWithTimeout creates a new TLSFingerprinter with a timeout.
ParseQUICClientHello parses a QUIC ClientHello from a QUIC Initial Packet.
ParseQUICTransportParameters parses the transport parameters from the extension data of TLS Extension "QUIC Transport Parameters" (57) If any error occurs, the returned struct will have parseError set to the error.
ReadAllFrames reads all QUIC frames from the input reader.
ReadClientHello reads a ClientHello from a connection (io.Reader) and returns a ClientHello struct.
ReadNextVLI unpacks the next variable-length integer from the given io.Reader.
ReassembleCRYPTOFrames reassembles CRYPTO frames into a single byte slice that consists of the entire CRYPTO data.
UnmarshalClientHello unmarshals a ClientHello from a byte slice and returns a ClientHello struct.
UnmarshalQUICClientInitialPacket is similar to ParseQUICCIP, but on error such as ClientHello cannot be parsed, it returns a partially completed ClientInitialPacket instead of nil.

# Constants

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
6.
0.
1.
No description provided by the author
No description provided by the author
if false, unsetVLIBits() will be nop.

# Variables

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author

# Structs

ClientHello represents a captured ClientHello message with all fingerprintable fields.
ClientInitial represents a QUIC Initial Packet sent by the Client.
CRYPTO frame.
GatheredClientInitials represents a series of Initial Packets sent by the Client to initiate the QUIC handshake.
PADDING frame.
PING frame.
QUICClientHello represents a QUIC ClientHello.
QUICClientHello can be used to parse fragments of a QUIC ClientHello.
QUICFingerprint can be used to generate a fingerprint of a QUIC connection.
QUICFingerprinter can be used to fingerprint QUIC connections.
QUICHeader includes header fields of a QUIC packet and the following frames.
QUICTransportParameters is a struct to hold the parsed QUIC transport parameters as a combination.
TLSFingerprinter can be used to fingerprint TLS connections.

# Interfaces

QUICFrame is the interface that wraps the basic methods of a QUIC frame.

# Type aliases

FingerprintID is the type of fingerprint ID.
This is an old name reserved for compatibility purpose, it is equivalent to [QUICFrame].
QUICFrames is a slice of QUICFrame.