Documentation
¶
Overview ¶
Package ratelimit is Ken's application-layer abuse defense: a per-IP token-bucket "first filter" (allowlist bypass, auto-block for repeat offenders, 429 + Retry-After otherwise) plus a reusable per-key bucket the MCP layer uses for per-token limits. This is app-layer abuse control — NOT volumetric L3/4 DDoS mitigation, which belongs upstream at the proxy / kernel / edge.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Bucket ¶
type Bucket struct {
// contains filtered or unexported fields
}
Bucket is a token-bucket rate limiter keyed by an arbitrary string (an IP key or a token id). It refills at rate tokens/sec up to burst. Safe for concurrent use; a nil *Bucket allows everything (so callers can hold an optional limiter).
type Config ¶
type Config struct {
Enabled bool
IPPerMin int
IPBurst int
TokenPerMin int
TokenBurst int
BlockAfter int // consecutive over-limit rejections (since the last allowed request) before an IP is auto-blocked
Lockout time.Duration // how long an auto-block lasts
Allow []*net.IPNet // extra allowlisted CIDRs (loopback is always allowed)
// OnReject/OnBlock are optional observability hooks fired when the guard
// throttles (429) or refuses an auto-blocked IP (403). Kept as callbacks so
// this package stays decoupled from the metrics package.
OnReject func()
OnBlock func()
}
Config is the resolved rate-limit configuration.
func FromEnv ¶
func FromEnv() Config
FromEnv resolves the config from KEN_RATELIMIT* (on by default, generous limits). Non-positive limits/bursts are clamped to the defaults so an "enabled" limiter always limits; the lockout is bounded to guard against an overflowing integer.
func (Config) TokenBucket ¶
TokenBucket builds the per-token limiter from c (nil when disabled).
type IPGuard ¶
type IPGuard struct {
// contains filtered or unexported fields
}
IPGuard is the outermost middleware: it resolves the client IP, bypasses the allowlist (loopback + configured CIDRs) and the /healthz probe, rejects an auto-blocked IP with 403, throttles the rest with a per-IP token bucket (429 + Retry-After) and auto-blocks repeat offenders. IP keys are normalized by network (IPv6 -> /64) so address rotation cannot evade the limit.
func NewIPGuard ¶
NewIPGuard builds the per-IP guard, or nil when rate limiting is disabled.
type Limiter ¶
Limiter is the per-token limit the MCP layer applies (satisfied by *Bucket and *ReloadableBucket).
type ReloadableBucket ¶
type ReloadableBucket struct {
// contains filtered or unexported fields
}
ReloadableBucket wraps a token Bucket that can be swapped live.
func (*ReloadableBucket) Allow ¶
func (rb *ReloadableBucket) Allow(key string) (bool, time.Duration)
Allow delegates to the current bucket (a nil bucket is nil-safe -> allowed).
func (*ReloadableBucket) Store ¶
func (rb *ReloadableBucket) Store(b *Bucket)
Store swaps in a new bucket (may be nil to disable — Allow then passes through).
type ReloadableGuard ¶
type ReloadableGuard struct {
// contains filtered or unexported fields
}
ReloadableGuard is a per-IP guard that can be swapped live (when settings change) behind a stable http.Handler. A nil current guard passes through.
func (*ReloadableGuard) Store ¶
func (rg *ReloadableGuard) Store(g *IPGuard)
Store swaps in a new guard (may be nil to disable).