tracker

package
v0.0.0-...-45fb939 Latest Latest
Warning

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

Go to latest
Published: May 9, 2026 License: BSD-3-Clause Imports: 5 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func MakeKey

func MakeKey(srcIP string, srcPort uint16, dstIP string, dstPort uint16, proto string) string

MakeKey builds the connection map key from a 5-tuple.

Types

type Connection

type Connection struct {
	ID       string // 5-tuple key
	SrcIP    string
	SrcPort  uint16
	DstIP    string
	DstPort  uint16
	Protocol string // "tcp", "udp"

	FirstSeen   time.Time
	LastSeen    time.Time
	PacketCount uint64
	ByteCount   uint64

	// Fingerprints stores history per type with timestamps.
	// Keyed by fingerprint type (lowercase: "ja4", "ja4s", "ja4h", ...).
	Fingerprints map[string][]FingerprintEvent
	// RawFPs stores raw (unhashed) fingerprints per type. Same cap policy.
	RawFPs map[string][]FingerprintEvent

	// Enrichment
	IdentifiedApp   string
	IsKnownBad      bool
	IsNew           bool   // first-seen fingerprint on this network
	MSSValue        int    // extracted from JA4T
	TunnelIndicator string // VPN/tunnel detection from MSS
	// SSHSessionType is populated from ja4plus.InterpretJA4SSH when a
	// JA4SSH fingerprint is observed. Values include "Interactive SSH
	// Session", "Reverse SSH Session", "SSH File Transfer", "SSH File
	// Transfer (Upload)", or "Unknown". Empty string for non-SSH
	// connections or when the JA4SSH fingerprint is malformed.
	SSHSessionType string

	// Anomalies triggered on this connection (human-readable descriptions).
	Anomalies []string
}

Connection represents a network flow with accumulated fingerprints.

Connection lifecycle:
  New (from Tracker.Update)
    └─► Active (packets arrive, fingerprints added via AddFingerprint)
          └─► Evicted (idle timeout or LRU)
                └─► OnEvict callback → Store + Processor cleanup

Connection values are mutated by a single shard goroutine. To hand a Connection to any other goroutine (TUI, export), use Snapshot() to get an independent deep copy.

func NewConnection

func NewConnection(srcIP string, srcPort uint16, dstIP string, dstPort uint16, proto string, ts time.Time) *Connection

NewConnection creates a Connection from a 5-tuple.

func (*Connection) AddFingerprint

func (c *Connection) AddFingerprint(fpType, fingerprint string, seenAt time.Time, packetNum uint64)

AddFingerprint appends a fingerprint event to the history for the given type. Deduplicates consecutive identical values. Caps the history at maxEventsPerType per type.

The cap policy preserves the first 100 events (handshake context) plus the most recent 900, so you always see how the connection started AND what it's been doing recently.

func (*Connection) AddRawFingerprint

func (c *Connection) AddRawFingerprint(fpType, raw string, seenAt time.Time, packetNum uint64)

AddRawFingerprint appends a raw (unhashed) fingerprint event to the history.

func (*Connection) LatestFingerprint

func (c *Connection) LatestFingerprint(fpType string) string

LatestFingerprint returns the most recent fingerprint value for a given type, or "" if none. Preserved signature so rules in internal/anomaly still work without modification.

func (*Connection) LatestPacketNum

func (c *Connection) LatestPacketNum(fpType string) uint64

LatestPacketNum returns the PacketNum of the most recent fingerprint event for the given type, or 0 if none. Used by the anomaly evaluator to link alerts to the fingerprint event that triggered them.

func (*Connection) PrimaryFingerprint

func (c *Connection) PrimaryFingerprint() (fpType, fingerprint string)

PrimaryFingerprint returns the most relevant fingerprint for display. Prefers JA4 (TLS client), falls back to other types in priority order.

func (*Connection) Snapshot

func (c *Connection) Snapshot() *Connection

Snapshot returns a deep copy of this Connection that is safe to read from any goroutine. The shard goroutine mutates the original; the TUI and export code read snapshots.

Deep copies: Fingerprints, RawFPs, and Anomalies. All other fields are either values or strings (immutable).

type FingerprintEvent

type FingerprintEvent struct {
	Value     string    `json:"value"`
	SeenAt    time.Time `json:"seen_at"`
	PacketNum uint64    `json:"packet_num"`
}

FingerprintEvent is one observed fingerprint with when and which packet produced it. Used for the detail panel timeline and for linking alerts back to the specific fingerprint that triggered them.

Replaces the previous map[string][]string storage, which threw away the timing information needed for investigation.

type Tracker

type Tracker struct {

	// Callback when a connection is evicted (for storage and Processor cleanup)
	OnEvict func(conn *Connection)
	// contains filtered or unexported fields
}

Tracker maintains a table of active connections and evicts idle ones.

Two data structures are kept in sync:

connections: map[id]*Connection — O(1) lookup
lru:         doubly-linked list  — O(1) insert/move/remove

On every Update we move the connection's list element to the back (most recently used). On LRU eviction we pop from the front (least recently used). This replaces the previous O(N) full-map scan that happened once per over-max insertion, which was a real scalability bug under SYN flood / high-churn workloads.

        most recent
      ┌──────────────┐
      │              │
back  │  conn3       │  ← Update bumps to back
      ├──────────────┤
      │  conn2       │
      ├──────────────┤
      │  conn1       │
front │  conn0       │  ← LRU eviction pops from front
      │              │
      └──────────────┘
       least recent

func NewTracker

func NewTracker(maxConns int) *Tracker

NewTracker creates a Tracker with the given max connection table size.

func (*Tracker) All

func (t *Tracker) All() []*Connection

All returns a snapshot of all current connections.

func (*Tracker) Count

func (t *Tracker) Count() int

Count returns the current number of tracked connections.

func (*Tracker) Evict

func (t *Tracker) Evict(now time.Time) []*Connection

Evict runs a single pass of idle connection eviction. Call this periodically (e.g., every 1 second).

Two phases:

  1. Idle eviction: scan the map and drop connections whose LastSeen exceeds the per-protocol timeout. O(N) but only fires for actually idle connections.
  2. LRU eviction: while we're over maxConns, pop from the front of the LRU list. O(1) per eviction (was O(N) per eviction in v0.2).

func (*Tracker) Get

func (t *Tracker) Get(key string) *Connection

Get returns a connection by key, or nil if not found.

func (*Tracker) Update

func (t *Tracker) Update(srcIP string, srcPort uint16, dstIP string, dstPort uint16, proto string, ts time.Time, packetLen uint64) *Connection

Update processes a packet's metadata and returns the associated Connection. Creates a new Connection if this is the first packet for this 5-tuple. O(1): map lookup + list move-to-back.

Jump to

Keyboard shortcuts

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