Documentation
¶
Index ¶
- Constants
- Variables
- type Cache
- func (c *Cache) Delete(ip netip.Addr)
- func (c *Cache) DistinctCandidatePrefixes() int
- func (c *Cache) Get(ip netip.Addr) (Record, bool)
- func (c *Cache) Len() int
- func (c *Cache) Peek(ip netip.Addr) (Record, bool)
- func (c *Cache) Put(rec Record, ttl time.Duration) error
- func (c *Cache) Stats() Stats
- func (c *Cache) TTLRemaining(ip netip.Addr) (time.Duration, bool)
- type Config
- type Record
- type State
- type Stats
Constants ¶
const ModuleBotGuard = "botguard"
ModuleBotGuard is the only module that owns this cache in v1.191.
Variables ¶
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 (*Cache) DistinctCandidatePrefixes ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
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.