dissector

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: MIT Imports: 6 Imported by: 55

README

tls-dissector

Zero-dependency Go library for dissecting TLS ClientHello and ServerHello handshake messages at the record layer. Used in proxy/gateway scenarios to extract routing-relevant fields (SNI, ALPN, cipher suites, supported versions) without fully terminating TLS.

Installation

go get github.com/go-gost/tls-dissector

Requires Go 1.17+. No external dependencies.

Usage

import dissector "github.com/go-gost/tls-dissector"

// Parse a ClientHello from any io.Reader (e.g., a buffered TLS connection)
info, err := dissector.ParseClientHello(reader)
// info.ServerName        → "example.com"   (SNI)
// info.SupportedVersions → []uint16{0x0304} (TLS 1.3)
// info.SupportedProtos   → []string{"h2", "http/1.1"}  (ALPN)
// info.CipherSuites      → []uint16{0xC02B, 0xC02F}

// Parse a ServerHello
resp, err := dissector.ParseServerHello(reader)
// resp.Proto   → "h2"          (negotiated ALPN)
// resp.Version → 0x0304        (negotiated version)

How it works

Data flows through four layers:

  1. TLS RecordReadRecord consumes a 5-byte header + payload, checking the content type (Handshake, Alert, etc.)
  2. Handshake — the record payload is decoded as a ClientHelloMsg or ServerHelloMsg, with length-prefixed fields parsed sequentially
  3. Extensions — the trailing extension block is parsed into typed extension structs via the Extension interface
  4. Info extraction — relevant fields are pulled from the messages and extensions into flat ClientHelloInfo / ServerHelloInfo structs

The library is a passthrough parser: only ClientHello and ServerHello are understood. Other handshake messages are not parsed. Each handshake message is assumed to fit in a single TLS record (no fragmentation support).

API

// Top-level parse functions
func ParseClientHello(r io.Reader) (*ClientHelloInfo, error)
func ParseServerHello(r io.Reader) (*ServerHelloInfo, error)

// Record layer
func ReadRecord(r io.Reader) (*Record, error)

// Extension system
type Extension interface {
    Type() uint16
    Encode() ([]byte, error)
    Decode([]byte) error
}
func NewExtension(t uint16, data []byte) (Extension, error)
func ReadExtension(r io.Reader) (Extension, error)

// Sentinel errors
var ErrBadType = errors.New("bad type")
var ErrAlert   = errors.New("alert")

ParseServerHello handles both Handshake (0x16) and EncryptedAlert (0x15) record types. When the server responds with an alert, it returns ErrAlert wrapping the alert level and description.

Supported TLS extensions

Name Value RFC
Server Name (SNI) 0x0000 RFC 6066
Supported Groups 0x000a RFC 7919
EC Point Formats 0x000b RFC 4492
Signature Algorithms 0x000d RFC 5246
ALPN 0x0010 RFC 7301
Encrypt-then-MAC 0x0016 RFC 7366
Extended Master Secret 0x0017 RFC 7627
Session Ticket 0x0023 RFC 5077
Supported Versions 0x002b RFC 8446
Renegotiation Info 0xff01 RFC 5746

Unknown extensions are preserved as opaque bytes. New extensions can be added by implementing the Extension interface and registering in NewExtension.

Tests

go test -v -cover ./...

Coverage: 99.8% across 4 test files covering record parsing, handshake messages, all 11 extensions, and end-to-end parse functions.

License

MIT — see LICENSE.

Documentation

Index

Constants

View Source
const (
	ExtServerName           uint16 = 0x00
	ExtSupportedGroups      uint16 = 0x0a
	ExtECPointFormats       uint16 = 0x0b
	ExtSignatureAlgorithms  uint16 = 0x0d
	ExtALPN                 uint16 = 0x10
	ExtEncryptThenMac       uint16 = 0x16
	ExtExtendedMasterSecret uint16 = 0x17
	ExtSessionTicket        uint16 = 0x23
	ExtSupportedVersions    uint16 = 0x2b
	ExtRenegotiationInfo    uint16 = 0xff01
)
View Source
const (
	HelloRequest uint8 = 0
	ClientHello  uint8 = 1
	ServerHello  uint8 = 2
)
View Source
const (
	RecordHeaderLen    = 5
	MaxPlaintextLength = 16384 // 2^14, per TLS spec
)
View Source
const (
	ChangeCipherSpec = 0x14
	EncryptedAlert   = 0x15
	Handshake        = 0x16
	AppData          = 0x17
	Heartbeat        = 0x18
)

record content type

Variables

View Source
var (
	ErrShortBuffer  = errors.New("short buffer")
	ErrTypeMismatch = errors.New("type mismatch")
)
View Source
var (
	ErrBadType = errors.New("bad type")
	ErrAlert   = errors.New("alert")
)

Functions

This section is empty.

Types

type ALPNExtension added in v0.1.0

type ALPNExtension struct {
	Protos []string
}

func (*ALPNExtension) Decode added in v0.1.0

func (ext *ALPNExtension) Decode(b []byte) error

func (*ALPNExtension) Encode added in v0.1.0

func (ext *ALPNExtension) Encode() ([]byte, error)

func (*ALPNExtension) Type added in v0.1.0

func (ext *ALPNExtension) Type() uint16

type AlertDescription added in v0.1.1

type AlertDescription uint8

func (AlertDescription) String added in v0.1.1

func (d AlertDescription) String() string

type AlertLevel added in v0.1.1

type AlertLevel uint8

func (AlertLevel) String added in v0.1.1

func (l AlertLevel) String() string

type AlertMsg added in v0.1.1

type AlertMsg struct {
	Level       AlertLevel
	Description AlertDescription
}

func (*AlertMsg) Decode added in v0.1.1

func (m *AlertMsg) Decode(data []byte) (err error)

func (*AlertMsg) Encode added in v0.1.1

func (m *AlertMsg) Encode() (data []byte, err error)

func (*AlertMsg) String added in v0.1.1

func (m *AlertMsg) String() string

type ClientHelloInfo added in v0.1.0

type ClientHelloInfo struct {
	SessionID          []byte
	CipherSuites       []uint16
	CompressionMethods []uint8
	SupportedProtos    []string
	SupportedVersions  []uint16
	ServerName         string
}

func ParseClientHello added in v0.1.0

func ParseClientHello(r io.Reader) (*ClientHelloInfo, error)

type ClientHelloMsg added in v0.1.0

type ClientHelloMsg struct {
	Version            Version
	Random             Random
	SessionID          []byte
	CipherSuites       []uint16
	CompressionMethods []uint8
	Extensions         []Extension
}

func (*ClientHelloMsg) Decode added in v0.1.0

func (m *ClientHelloMsg) Decode(data []byte) (err error)

func (*ClientHelloMsg) Encode added in v0.1.0

func (m *ClientHelloMsg) Encode() (data []byte, err error)

func (*ClientHelloMsg) ReadFrom added in v0.1.0

func (m *ClientHelloMsg) ReadFrom(r io.Reader) (n int64, err error)

func (*ClientHelloMsg) WriteTo added in v0.1.0

func (m *ClientHelloMsg) WriteTo(w io.Writer) (n int64, err error)

type ECPointFormatsExtension added in v0.1.0

type ECPointFormatsExtension struct {
	Formats []uint8
}

func (*ECPointFormatsExtension) Decode added in v0.1.0

func (ext *ECPointFormatsExtension) Decode(b []byte) error

func (*ECPointFormatsExtension) Encode added in v0.1.0

func (ext *ECPointFormatsExtension) Encode() ([]byte, error)

func (*ECPointFormatsExtension) Type added in v0.1.0

func (ext *ECPointFormatsExtension) Type() uint16

type EncryptThenMacExtension added in v0.1.0

type EncryptThenMacExtension struct {
	Data []byte
}

func (*EncryptThenMacExtension) Decode added in v0.1.0

func (ext *EncryptThenMacExtension) Decode(b []byte) error

func (*EncryptThenMacExtension) Encode added in v0.1.0

func (ext *EncryptThenMacExtension) Encode() ([]byte, error)

func (*EncryptThenMacExtension) Type added in v0.1.0

func (ext *EncryptThenMacExtension) Type() uint16

type ExtendedMasterSecretExtension added in v0.1.0

type ExtendedMasterSecretExtension struct {
	Data []byte
}

func (*ExtendedMasterSecretExtension) Decode added in v0.1.0

func (ext *ExtendedMasterSecretExtension) Decode(b []byte) error

func (*ExtendedMasterSecretExtension) Encode added in v0.1.0

func (ext *ExtendedMasterSecretExtension) Encode() ([]byte, error)

func (*ExtendedMasterSecretExtension) Type added in v0.1.0

type Extension

type Extension interface {
	Type() uint16
	Encode() ([]byte, error)
	Decode([]byte) error
}

func NewExtension

func NewExtension(t uint16, data []byte) (ext Extension, err error)

func ReadExtension

func ReadExtension(r io.Reader) (Extension, error)

type Random

type Random struct {
	Time   uint32
	Opaque [28]byte
}

type Record

type Record struct {
	Type    uint8
	Version Version
	Opaque  []byte
}

func ReadRecord

func ReadRecord(r io.Reader) (*Record, error)

func (*Record) ReadFrom

func (rec *Record) ReadFrom(r io.Reader) (n int64, err error)

func (*Record) WriteTo

func (rec *Record) WriteTo(w io.Writer) (n int64, err error)

type RenegotiationInfoExtension added in v0.1.0

type RenegotiationInfoExtension struct {
	Data []byte
}

func (*RenegotiationInfoExtension) Decode added in v0.1.0

func (ext *RenegotiationInfoExtension) Decode(b []byte) error

func (*RenegotiationInfoExtension) Encode added in v0.1.0

func (ext *RenegotiationInfoExtension) Encode() ([]byte, error)

func (*RenegotiationInfoExtension) Type added in v0.1.0

func (ext *RenegotiationInfoExtension) Type() uint16

type ServerHelloInfo added in v0.1.0

type ServerHelloInfo struct {
	SessionID         []byte
	CipherSuite       uint16
	CompressionMethod uint8
	Proto             string
	Version           uint16
}

func ParseServerHello added in v0.1.0

func ParseServerHello(r io.Reader) (*ServerHelloInfo, error)

type ServerHelloMsg added in v0.1.0

type ServerHelloMsg struct {
	Version           Version
	Random            Random
	SessionID         []byte
	CipherSuite       uint16
	CompressionMethod uint8
	Extensions        []Extension
}

func (*ServerHelloMsg) Decode added in v0.1.0

func (m *ServerHelloMsg) Decode(data []byte) (err error)

func (*ServerHelloMsg) Encode added in v0.1.0

func (m *ServerHelloMsg) Encode() (data []byte, err error)

func (*ServerHelloMsg) ReadFrom added in v0.1.0

func (m *ServerHelloMsg) ReadFrom(r io.Reader) (n int64, err error)

func (*ServerHelloMsg) WriteTo added in v0.1.0

func (m *ServerHelloMsg) WriteTo(w io.Writer) (n int64, err error)

type ServerNameExtension

type ServerNameExtension struct {
	NameType uint8
	Name     string
}

func (*ServerNameExtension) Decode added in v0.1.0

func (ext *ServerNameExtension) Decode(b []byte) error

func (*ServerNameExtension) Encode added in v0.1.0

func (ext *ServerNameExtension) Encode() ([]byte, error)

func (*ServerNameExtension) Type

func (ext *ServerNameExtension) Type() uint16

type SessionTicketExtension added in v0.1.0

type SessionTicketExtension struct {
	Data []byte
}

func (*SessionTicketExtension) Decode added in v0.1.0

func (ext *SessionTicketExtension) Decode(b []byte) error

func (*SessionTicketExtension) Encode added in v0.1.0

func (ext *SessionTicketExtension) Encode() ([]byte, error)

func (*SessionTicketExtension) Type added in v0.1.0

func (ext *SessionTicketExtension) Type() uint16

type SignatureAlgorithmsExtension added in v0.1.0

type SignatureAlgorithmsExtension struct {
	Algorithms []uint16
}

func (*SignatureAlgorithmsExtension) Decode added in v0.1.0

func (ext *SignatureAlgorithmsExtension) Decode(b []byte) error

func (*SignatureAlgorithmsExtension) Encode added in v0.1.0

func (ext *SignatureAlgorithmsExtension) Encode() ([]byte, error)

func (*SignatureAlgorithmsExtension) Type added in v0.1.0

type SupportedGroupsExtension added in v0.1.0

type SupportedGroupsExtension struct {
	Groups []uint16
}

func (*SupportedGroupsExtension) Decode added in v0.1.0

func (ext *SupportedGroupsExtension) Decode(b []byte) error

func (*SupportedGroupsExtension) Encode added in v0.1.0

func (ext *SupportedGroupsExtension) Encode() ([]byte, error)

func (*SupportedGroupsExtension) Type added in v0.1.0

func (ext *SupportedGroupsExtension) Type() uint16

type SupportedVersionsExtension added in v0.1.0

type SupportedVersionsExtension struct {
	Versions []uint16
	Server   bool
}

func (*SupportedVersionsExtension) Decode added in v0.1.0

func (ext *SupportedVersionsExtension) Decode(b []byte) error

func (*SupportedVersionsExtension) Encode added in v0.1.0

func (ext *SupportedVersionsExtension) Encode() ([]byte, error)

func (*SupportedVersionsExtension) Type added in v0.1.0

func (ext *SupportedVersionsExtension) Type() uint16

type Version

type Version uint16

Jump to

Keyboard shortcuts

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