tracker

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 13, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package tracker implements a per-rule sliding-window strike counter.

State is sharded across N small maps each with its own mutex, keyed by a cheap hash of the IP. The single-mutex pattern in v1 was fine but became a gratuitous contention point as soon as we started imagining concurrent rules sharing a source; sharding removes that ceiling at no cost when only one goroutine is calling Hit (one shard is just as fast as the v1 mutex).

Each Hit records a single offence by an IP. The Hit returns true when the IP has accumulated at least Threshold offences within the FindTime window — the caller is then expected to ban the IP and call Reset for that IP.

A Sweep operation drops records whose newest strike is older than FindTime so the map doesn't grow unboundedly under sustained attack.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Tracker

type Tracker struct {

	// Now is the clock; tests inject a fake. Defaults to time.Now.
	Now func() time.Time
	// contains filtered or unexported fields
}

Tracker counts strikes per IP within a sliding time window.

func New

func New(threshold int, findtime time.Duration) *Tracker

New constructs a Tracker.

func (*Tracker) FindTime

func (t *Tracker) FindTime() time.Duration

FindTime returns the configured sliding-window length.

func (*Tracker) Hit

func (t *Tracker) Hit(addr netip.Addr) bool

Hit registers a single offence at wall-clock time and returns true when the strike count within the sliding window has reached the threshold. The caller is responsible for calling Reset after a successful ban so the record is cleared.

Thin shim around HitAt for callers that don't have an external event time.

func (*Tracker) HitAt

func (t *Tracker) HitAt(addr netip.Addr, eventTime time.Time) bool

HitAt registers a single offence with an explicit event time. The strike is recorded at eventTime; pruning still uses wall-clock so backfilled events don't artificially extend the sliding window.

eventTime should be the time the log entry was generated (parsed from the line via the rule's datepattern), not the time GoBan received it. Rules that don't have a datepattern simply pass time.Now() — equivalent to Hit.

func (*Tracker) Load

func (t *Tracker) Load(r io.Reader) error

Load reads a previously-Saved state from r and merges it into the tracker. A version mismatch returns a non-nil error AND leaves the tracker unchanged — callers should log a warning and continue with a clean start.

Load is not concurrency-safe with Hit; callers should invoke it before the daemon starts processing lines (typically right after construction).

func (*Tracker) Reset

func (t *Tracker) Reset(addr netip.Addr)

Reset removes all strike state for addr.

func (*Tracker) Save

func (t *Tracker) Save(w io.Writer) error

Save writes the tracker's strike state to w as a gob-encoded blob. Safe for concurrent use with Hit/Reset — each shard's snapshot is taken under its own mutex.

func (*Tracker) Size

func (t *Tracker) Size() int

Size returns the number of tracked IPs across all shards.

func (*Tracker) Snapshot

func (t *Tracker) Snapshot() map[netip.Addr]int

Snapshot returns a copy of current strike counts per IP across all shards. Strikes outside the window are pruned in the snapshot view.

func (*Tracker) Sweep

func (t *Tracker) Sweep() int

Sweep removes records whose newest strike is older than findtime. Returns the number of records dropped (useful for metrics/tests). Iterates each shard independently so a long sweep on one shard doesn't block Hits on others.

func (*Tracker) Threshold

func (t *Tracker) Threshold() int

Threshold returns the configured threshold.

Jump to

Keyboard shortcuts

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