Documentation
¶
Index ¶
- Constants
- type BanEvent
- type BanRecord
- type BlockEvent
- type Config
- type GeoLookup
- type GeoMode
- type Guard
- func (g *Guard) Close()
- func (g *Guard) IsBlocked(ip string) (bool, string)
- func (g *Guard) PermaBan(ip string) bool
- func (g *Guard) Reconfigure(cfg Config) error
- func (g *Guard) RecordFailure(ip, transport string)
- func (g *Guard) SetGeoLookup(gl GeoLookup)
- func (g *Guard) Snapshot() Snapshot
- func (g *Guard) Start(ctx context.Context)
- func (g *Guard) Unban(ip string) bool
- func (g *Guard) WrapErrorLog(fallback *log.Logger) *log.Logger
- func (g *Guard) WrapHandler(h http.Handler, opts ...HandlerOption) (http.Handler, error)
- func (g *Guard) WrapListener(ln net.Listener, transport string) net.Listener
- func (g *Guard) WrapListenerProxyProto(ln net.Listener, transport string, trusted []string, opts ...ProxyProtoOption) (net.Listener, error)
- type HandlerOption
- type Hooks
- type Logger
- type Option
- type PermaBanEvent
- type ProxyProtoOption
- type Snapshot
- type Stats
- type UnbanEvent
Constants ¶
const ( ReasonBlacklist = "blacklist" ReasonAutoBan = "auto_ban" ReasonPermaBan = "permanent_ban" ReasonGeo = "geo" ReasonInvalidIP = "invalid_ip" )
Reason constants returned by Guard.IsBlocked. Whitelisted IPs return (false, ""), not a reason string, because they are allowed rather than blocked.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BanEvent ¶
type BanEvent struct {
IP string
Transport string
Failures int
BanCount int // total times this IP has been banned (including this one)
Country string // from current geo data, "" if unavailable
}
BanEvent is emitted when an IP is auto-banned after exceeding the failure threshold.
type BanRecord ¶
type BanRecord struct {
IP string
BannedAt time.Time
ExpiresAt time.Time // zero value for permanent bans
Failures int
Permanent bool
BanCount int
Country string // derived from current GeoLookup, "" if unavailable
}
BanRecord represents a single active ban entry.
type BlockEvent ¶
type BlockEvent struct {
IP string
Reason string // one of the Reason* constants
Transport string
Country string // from current geo data, "" if unavailable
}
BlockEvent is emitted when a connection or request is blocked.
type Config ¶
type Config struct {
Whitelist []string // IPs/CIDRs that are never blocked
Blacklist []string // IPs/CIDRs that are always blocked
MaxRetry int // failures within FindTime to trigger a ban (0 = disabled)
FindTime time.Duration // sliding window for counting failures
BanTime time.Duration // how long an auto-ban lasts
MaxTrackedIPs int // max IPs tracked for auto-ban (0 = default 1,000,000)
PermaBanAfter int // auto-promote to permanent after N bans (0 = disabled)
RecidivismWindow time.Duration // how long ban history is remembered (0 = forever)
GeoMode GeoMode // GeoDisabled, GeoAllow, or GeoBlock
GeoCountries []string // ISO 3166-1 alpha-2 country codes
}
Config controls the behavior of a Guard instance. Zero values disable each feature: an empty Config produces a guard that blocks nothing.
- Whitelist/Blacklist: CIDR notation ("10.0.0.0/8") or bare IPs ("1.2.3.4")
- MaxRetry == 0: auto-ban disabled
- GeoMode == GeoDisabled: no geographic filtering
type GeoLookup ¶
GeoLookup is the interface for geographic IP lookups. The tgeo.Table type satisfies this interface, but any implementation will work.
type Guard ¶
type Guard struct {
// contains filtered or unexported fields
}
Guard provides IP filtering with whitelist/blacklist, auto-banning, and optional geographic filtering. It is safe for concurrent use.
func New ¶
New creates a Guard with the given configuration and options. Returns an error if the config contains invalid CIDRs or conflicting geo settings.
func (*Guard) IsBlocked ¶
IsBlocked checks whether an IP address should be blocked. Evaluation order: whitelist (bypass) -> blacklist -> permanent_ban -> auto_ban -> geo. Returns (blocked, reason) where reason is one of the Reason* constants.
func (*Guard) PermaBan ¶
PermaBan permanently bans an IP. If the IP is already permanently banned, this is a no-op (returns true without firing hooks). Works on IPs with an active temp ban, an expired ban, or no prior record.
func (*Guard) Reconfigure ¶
Reconfigure applies a new configuration to a running guard. Returns an error if the new config is invalid.
func (*Guard) RecordFailure ¶
RecordFailure records an authentication or handshake failure for an IP. When failures within FindTime reach MaxRetry, the IP is auto-banned.
func (*Guard) SetGeoLookup ¶
SetGeoLookup atomically replaces the geographic lookup implementation. This is used for hot-reloading geo data without restarting the guard.
func (*Guard) Snapshot ¶
Snapshot returns a consistent, read-only view of the guard's current state.
func (*Guard) Start ¶
Start begins background cleanup and summary goroutines. The goroutines run until ctx is cancelled or Close is called.
func (*Guard) Unban ¶
Unban manually removes a ban (temporary or permanent) for the given IP. Also clears the IP's ban history. Returns true if the IP was banned.
func (*Guard) WrapErrorLog ¶ added in v0.1.2
WrapErrorLog returns a *log.Logger suitable for http.Server.ErrorLog. It intercepts Go's TLS handshake error messages, extracts the client IP, and calls RecordFailure so the existing auto-ban logic can act on repeated TLS failures (scanners probing with bad SNI, unsupported versions, etc.).
The fallback logger receives all messages (TLS and non-TLS) at whatever level the consumer configured. If fallback is nil, messages are forwarded to the guard's own logger (set via WithLogger). If both are nil, messages are silently consumed.
Typical usage:
errorLog := slog.NewLogLogger(logger.Handler(), slog.LevelError)
srv := &http.Server{
ErrorLog: guard.WrapErrorLog(errorLog),
}
func (*Guard) WrapHandler ¶ added in v0.1.1
WrapHandler returns an http.Handler that checks IsBlocked before passing requests to h, and optionally records failures based on response status codes. Returns an error if options are misconfigured.
func (*Guard) WrapListener ¶
WrapListener wraps a net.Listener so that connections from blocked IPs are dropped at the TCP level before any protocol handshake.
func (*Guard) WrapListenerProxyProto ¶ added in v0.1.1
func (g *Guard) WrapListenerProxyProto(ln net.Listener, transport string, trusted []string, opts ...ProxyProtoOption) (net.Listener, error)
WrapListenerProxyProto wraps a net.Listener to decode PROXY protocol v1/v2 headers from trusted proxy sources and filter connections using the real client IP. The trusted parameter is required and must contain at least one valid CIDR or IP for the upstream load balancer(s).
type HandlerOption ¶ added in v0.1.1
type HandlerOption func(*handlerConfig)
HandlerOption configures the HTTP middleware returned by WrapHandler.
func WithFailureCodes ¶ added in v0.1.1
func WithFailureCodes(codes ...int) HandlerOption
WithFailureCodes configures HTTP status codes that automatically trigger RecordFailure after the inner handler responds (e.g. 401, 404).
func WithIPExtractor ¶ added in v0.1.1
func WithIPExtractor(fn func(*http.Request) string) HandlerOption
WithIPExtractor sets a custom function to extract the client IP from the request. When set, trusted proxy validation is bypassed entirely.
func WithIPHeader ¶ added in v0.1.1
func WithIPHeader(header string) HandlerOption
WithIPHeader sets the HTTP header to read for the real client IP (e.g. "X-Forwarded-For", "CF-Connecting-IP", "X-Real-IP"). Requires WithTrustedProxies to also be set.
func WithTransport ¶ added in v0.1.1
func WithTransport(transport string) HandlerOption
WithTransport overrides the auto-detected transport string. By default, transport is "https" when r.TLS != nil, "http" otherwise.
func WithTrustedProxies ¶ added in v0.1.1
func WithTrustedProxies(cidrs ...string) HandlerOption
WithTrustedProxies declares which CIDRs are trusted reverse proxies. Only requests arriving from these IPs will have their forwarding headers consulted for the real client IP.
type Hooks ¶
type Hooks struct {
OnBlocked func(BlockEvent)
OnBanned func(BanEvent)
OnUnbanned func(UnbanEvent)
OnPermaBanned func(PermaBanEvent)
OnWarning func(message string, data map[string]string)
}
Hooks provides optional callbacks for guard events. Set any function field to receive notifications; nil fields are silently skipped.
type Option ¶
type Option func(*Guard)
Option configures a Guard during construction.
func WithLogger ¶
WithLogger sets the logger for block/ban/summary output.
func WithPermaBans ¶
WithPermaBans loads a set of permanently banned IPs at construction time. These IPs are blocked immediately without expiry. This is used to restore permanent bans from consumer-managed persistence on startup. Pass WithClock before WithPermaBans if deterministic timestamps are needed.
type PermaBanEvent ¶
type PermaBanEvent struct {
IP string
Transport string // empty for manual PermaBan()
BanCount int
Country string
}
PermaBanEvent is emitted when an IP is promoted to a permanent ban, either by recidivist auto-escalation or manual PermaBan() call.
type ProxyProtoOption ¶ added in v0.1.1
type ProxyProtoOption func(*proxyProtoConfig)
ProxyProtoOption configures the PROXY protocol listener.
func WithProxyProtoTimeout ¶ added in v0.1.1
func WithProxyProtoTimeout(d time.Duration) ProxyProtoOption
WithProxyProtoTimeout sets the read deadline for parsing the PROXY protocol header from trusted sources. Default is 5 seconds.
type Snapshot ¶
Snapshot is a read-only point-in-time view of the guard's state, suitable for dashboard integration.
type Stats ¶
type Stats struct {
BlacklistBlocks int64
AutoBanBlocks int64
PermaBanBlocks int64
GeoBlocks int64
ActiveBans int // total: temp + permanent
PermanentBans int // subset of ActiveBans that are permanent
BanHistorySize int // number of IPs in recidivism tracking
}
Stats holds cumulative counters for guard activity since the last summary reset.
type UnbanEvent ¶
UnbanEvent is emitted when a ban is removed, either by expiry or manual action.