decisioncache

package
v1.192.0 Latest Latest
Warning

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

Go to latest
Published: Jun 16, 2026 License: MPL-2.0 Imports: 4 Imported by: 0

Documentation

Index

Constants

View Source
const ModuleBotGuard = "botguard"

ModuleBotGuard is the only module that owns this cache in v1.191.

Variables

View Source
var (
	// ErrInvalidState is returned when a Put targets a state outside the allowed
	// temporary set — including any durable trust/block-equivalent state.
	ErrInvalidState = errors.New("decisioncache: invalid or durable state not allowed")
	// ErrInvalidTransition is returned when a state transition is not permitted.
	ErrInvalidTransition = errors.New("decisioncache: invalid state transition")
	// ErrBlockedNeedsTTL is returned when blocked_temporarily is stored without a positive TTL.
	ErrBlockedNeedsTTL = errors.New("decisioncache: blocked_temporarily requires a positive ban TTL")
	// ErrOverflow is returned when the entry could not be stored because the cache is full
	// of non-evictable (blocked, unexpired) entries.
	ErrOverflow = errors.New("decisioncache: cache full, entry dropped")
	// ErrInvalidIP is returned for an unparseable / zero address.
	ErrInvalidIP = errors.New("decisioncache: invalid IP")
)

Functions

This section is empty.

Types

type Cache

type Cache struct {
	// contains filtered or unexported fields
}

Cache is a concurrency-safe temporary decision cache.

func New

func New(cfg Config) *Cache

New constructs a Cache with the given Config (zero fields filled from DefaultConfig).

func (*Cache) Delete

func (c *Cache) Delete(ip netip.Addr)

Delete forgets an IP (returns it to the unknown state). Safe if absent.

func (*Cache) DistinctCandidatePrefixes

func (c *Cache) DistinctCandidatePrefixes() int

DistinctCandidatePrefixes returns the number of distinct aggregated prefixes that currently hold at least one candidate (IPv6 aggregated to V6PrefixBits, IPv4 per-IP).

func (*Cache) Get

func (c *Cache) Get(ip netip.Addr) (Record, bool)

Get returns the live record for ip (a copy). Expired entries are treated as absent and are lazily purged (a side effect — for a pure read use Peek).

func (*Cache) Len

func (c *Cache) Len() int

Len returns the number of map entries (including not-yet-purged expired ones). Use Stats for state-accurate live accounting in tests.

func (*Cache) Peek

func (c *Cache) Peek(ip netip.Addr) (Record, bool)

Peek returns the live record for ip WITHOUT any side effect: no purge, no stat change, no LastSeen update. Expired entries are reported as absent.

func (*Cache) Put

func (c *Cache) Put(rec Record, ttl time.Duration) error

Put inserts or updates a temporary decision for rec.IP. ttl<=0 uses the state's default; blocked_temporarily REQUIRES ttl>0 (it follows the ban TTL). It validates the target state and transition, enforces caps with bounded eviction, and never creates a durable state. The Module field is always stamped to ModuleBotGuard.

func (*Cache) Stats

func (c *Cache) Stats() Stats

Stats returns a bounded snapshot. ByState counts only live (non-expired) entries.

func (*Cache) TTLRemaining

func (c *Cache) TTLRemaining(ip netip.Addr) (time.Duration, bool)

TTLRemaining returns the remaining TTL for ip and whether it is live. Uses monotonic time.

type Config

type Config struct {
	MaxEntries    int // hard cap on total live entries
	MaxCandidates int // hard cap on candidate-state entries
	PerFamilyCap  int // optional per-family cap (0 = disabled)
	PerHostCap    int // optional per-host/site cap (0 = disabled; needs Host set)
	V6PrefixBits  int // IPv6 candidate-accounting aggregation width (default 64; e.g. 56)

	CandidateTTL time.Duration // default TTL for candidate
	CheckingTTL  time.Duration // default TTL for checking
	LegitTTL     time.Duration // default TTL for legit_temporarily
	AmbiguousTTL time.Duration // default TTL for ambiguous

}

Config bounds the cache. Zero values fall back to DefaultConfig() values via New.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns conservative bounds suitable for a single busy host.

type Record

type Record struct {
	Module          string     // always ModuleBotGuard
	IP              netip.Addr // per-IP key
	Family          string     // "ipv4" | "ipv6"
	RequestClass    string     // from the BotScan structured signal (increment 3 taxonomy)
	Host            string     // optional site/vhost
	State           State      // temporary state
	Reason          string     // short why
	EvidenceSummary string     // compact evidence (for later observability)
	FirstSeen       time.Time  // wall-clock, for display/logging only
	LastSeen        time.Time  // wall-clock, for display/logging only
	ExpiresAt       time.Time  // wall-clock approximation of expiry (display only)
	// contains filtered or unexported fields
}

Record is a single temporary decision. Enforcement is always per-IP; IPv6 prefix aggregation (below) affects candidate COST ACCOUNTING only, never the record key.

type State

type State string

State is a TEMPORARY decision state. Durable trust/block states are intentionally absent from this type and rejected by the cache — durable decisions live in nft sets.

const (
	// StateUnknown is the absence sentinel: an IP with no live record is "unknown".
	// It is never stored; Put(StateUnknown) is rejected (use Delete to forget an IP).
	StateUnknown State = "unknown"

	StateCandidate          State = "candidate"           // seen, not yet classified
	StateChecking           State = "checking"            // verification in flight
	StateLegitTemporarily   State = "legit_temporarily"   // temporarily suppressed (looks legit)
	StateBlockedTemporarily State = "blocked_temporarily" // temporarily blocked (ban-TTL driven)
	StateAmbiguous          State = "ambiguous"           // conflicting evidence, hold briefly
)

type Stats

type Stats struct {
	TotalEntries              int
	ByState                   map[State]int
	CandidateEntries          int
	DistinctCandidatePrefix   int
	Evictions                 int64
	ExpiredPurges             int64
	OverflowDrops             int64
	InvalidStateAttempts      int64
	InvalidTransitionAttempts int64
}

Stats is a bounded, internal-only snapshot for later observability. It is NOT wired to health/schema in this increment.

Jump to

Keyboard shortcuts

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