Documentation
¶
Overview ¶
Package assemble turns a packet stream into completed TLS handshake observations.
It exists because a naive "parse the ClientHello out of one packet" approach is wrong in exactly the case that matters most. A post-quantum key share is over a kilobyte on its own, so a ClientHello offering X25519MLKEM768 routinely exceeds a single TCP segment. A parser that does not reassemble silently drops the handshakes a post-quantum inventory exists to count, and reports a cleaner, more classical world than the one on the wire.
TCP reassembly is delegated to gopacket's reassembly package, which handles retransmission, overlap and reordering. What this package adds is a bounded prefix per direction, content-based TLS detection, and the pairing of the two directions into one observation.
Index ¶
Constants ¶
const ( // DefaultMaxStreamPrefix bounds how much of each direction is retained. // A handshake is decided in the first few kilobytes; beyond that is // application data of no inventory interest. 32 KiB comfortably holds a // post-quantum ClientHello and a TLS 1.2 certificate chain with a long // intermediate list, which an 8 KiB cap would truncate. DefaultMaxStreamPrefix = 32 << 10 // DefaultCloseTimeout is how long a quiet stream is kept before it is // flushed and reported with whatever was seen. DefaultCloseTimeout = 2 * time.Minute // DefaultMaxStreams caps concurrently tracked connections. // // M1 bounded memory per stream but not the number of streams, which is // fine for a capture file and not fine for a live host: a SYN flood, a // port scan, or simply a busy server multiplies the per-stream prefix // by an unbounded factor. At this cap the worst case is roughly // MaxStreams * MaxStreamPrefix * 2, so 64Ki * 32KiB * 2 would be far // too much — hence a cap chosen for an endpoint, not a tap. DefaultMaxStreams = 8192 )
Defaults chosen for endpoint inventory rather than for bulk capture.
const ( TransportTCP = "tcp" TransportQUIC = "quic" )
Transport names the protocol carrying the handshake.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Assembler ¶
type Assembler struct {
// contains filtered or unexported fields
}
Assembler feeds packets through TCP reassembly and reports TLS flows. It is not safe for concurrent use.
func (*Assembler) Close ¶
func (a *Assembler) Close()
Close flushes every remaining stream, emitting partial handshakes.
func (*Assembler) FlushOlderThan ¶
FlushOlderThan closes streams idle since before t, emitting whatever they yielded.
Live capture needs this on a timer rather than on packet arrival: a flow that completes on a quiet interface would otherwise sit unreported until the next packet from anyone, which on an idle host can be minutes.
func (*Assembler) Packet ¶
Packet feeds one captured packet.
Every TCP port is examined, not just 443. Restricting an inventory to the well-known port is how STARTTLS on 587, a database on 5432 and an internal service on 8443 all end up invisible, and "we found no weak ciphers" then means "we did not look". Non-TLS flows are rejected cheaply by content, on the first few bytes of each direction.
type Flow ¶
type Flow struct {
// Transport is "tcp" or "quic". The handshake is the same either way —
// QUIC carries TLS 1.3 — but what is visible differs: over QUIC the
// certificate is at the Handshake level and never readable.
Transport string
ClientIP netip.Addr
ServerIP netip.Addr
ClientPort uint16
ServerPort uint16
FirstSeen time.Time
LastSeen time.Time
Client *tlsparse.ClientHello
Server *tlsparse.ServerHello
// PrefixTruncated is set when a direction hit MaxStreamPrefix, meaning
// later handshake messages may have been dropped.
PrefixTruncated bool
}
Flow is one observed connection and whatever of its TLS handshake was visible. Server is nil when the response was never captured; Client is never nil in an emitted flow.
type Options ¶
type Options struct {
MaxStreamPrefix int
CloseTimeout time.Duration
// MaxStreams caps concurrently tracked connections. Beyond it, new
// connections are counted and ignored rather than tracked.
MaxStreams int
}
Options configures an Assembler. The zero value is usable.
type Stats ¶
type Stats struct {
Packets int64
TCPPackets int64
UDPPackets int64
Streams int64
TLSFlows int64
RejectedTCP int64
// StreamsDropped counts connections ignored because MaxStreams was
// already reached. A non-zero value means the inventory is incomplete,
// so it is reported rather than silently absorbed.
StreamsDropped int64
// LiveStreams is the number currently tracked.
LiveStreams int64
}
Stats reports what the assembler saw. Streams counts every TCP connection examined; TLSFlows counts those that yielded a ClientHello.