Documentation
¶
Index ¶
- Constants
- func AppendAudit(statePath, action, ip, reason, source string, duration time.Duration)
- func FetchCloudflareIPs() (ipv4, ipv6 []string, err error)
- func InferProvenance(action, reason string) string
- func LoadCFRefreshTime(statePath string) time.Time
- func LoadCFState(statePath string) (ipv4, ipv6 []string)
- func LookupIP(dbPath string, ip string) []string
- func SaveCFState(statePath string, ipv4, ipv6 []string, refreshed time.Time)
- func UpdateGeoIPDB(dbPath string, countryCodes []string) (int, error)
- type AllowedEntry
- type AuditEntry
- type BlockedEntry
- type DynDNSResolver
- type Engine
- func (e *Engine) AllowIP(ip string, reason string) error
- func (e *Engine) AllowIPPort(ip string, port int, proto string, reason string) error
- func (e *Engine) Apply() error
- func (e *Engine) BlockIP(ip string, reason string, timeout time.Duration) error
- func (e *Engine) BlockSubnet(cidr string, reason string, timeout time.Duration) error
- func (e *Engine) CleanExpiredAllows() int
- func (e *Engine) CleanExpiredSubnets() int
- func (e *Engine) CloudflareIPs() (ipv4, ipv6 []string)
- func (e *Engine) FlushBlocked() error
- func (e *Engine) IsBlocked(ip string) bool
- func (e *Engine) RemoveAllowIP(ip string) error
- func (e *Engine) RemoveAllowIPBySource(ip, source string) error
- func (e *Engine) RemoveAllowIPPort(ip string, port int, proto string) error
- func (e *Engine) Status() map[string]interface{}
- func (e *Engine) TempAllowIP(ip string, reason string, timeout time.Duration) error
- func (e *Engine) UnblockIP(ip string) error
- func (e *Engine) UnblockSubnet(cidr string) error
- func (e *Engine) UpdateCloudflareSet(ipv4, ipv6 []string) error
- type FirewallConfig
- type FirewallState
- type PortAllowEntry
- type PortFloodRule
- type SubnetEntry
Constants ¶
const ( SourceUnknown = "unknown" SourceWebUI = "web_ui" SourceCLI = "cli" SourceAutoResponse = "auto_response" SourceChallenge = "challenge" SourceWhitelist = "whitelist" SourceDynDNS = "dyndns" SourceSystem = "system" )
Variables ¶
This section is empty.
Functions ¶
func AppendAudit ¶
AppendAudit writes an audit entry to the JSONL audit log. Rotates the log when it exceeds 10 MB.
func FetchCloudflareIPs ¶
FetchCloudflareIPs downloads the current Cloudflare IP ranges.
func InferProvenance ¶
InferProvenance classifies a firewall entry source from structured action/reason text. This keeps provenance logic centralized instead of spreading fragile string checks throughout the web UI and firewall call sites.
func LoadCFRefreshTime ¶
LoadCFRefreshTime reads the last CF refresh time from state.
func LoadCFState ¶
LoadCFState reads the cached Cloudflare CIDRs.
func LookupIP ¶
LookupIP finds which country CIDR files contain the given IP. Returns matching country codes.
func SaveCFState ¶
SaveCFState persists the Cloudflare CIDRs for status display.
Types ¶
type AllowedEntry ¶
type AllowedEntry struct {
IP string `json:"ip"`
Reason string `json:"reason"`
Source string `json:"source,omitempty"`
Port int `json:"port,omitempty"` // 0 = all ports
ExpiresAt time.Time `json:"expires_at,omitempty"` // zero = permanent
}
AllowedEntry represents an allowed IP with metadata.
type AuditEntry ¶
type AuditEntry struct {
Timestamp time.Time `json:"timestamp"`
Action string `json:"action"` // block, unblock, allow, remove_allow, flush, apply
IP string `json:"ip,omitempty"`
Reason string `json:"reason,omitempty"`
Source string `json:"source,omitempty"`
Duration string `json:"duration,omitempty"`
}
AuditEntry records a firewall modification for compliance and forensics.
func ReadAuditLog ¶
func ReadAuditLog(statePath string, limit int) []AuditEntry
ReadAuditLog returns the last N audit entries from the log.
type BlockedEntry ¶
type BlockedEntry struct {
IP string `json:"ip"`
Reason string `json:"reason"`
Source string `json:"source,omitempty"`
BlockedAt time.Time `json:"blocked_at"`
ExpiresAt time.Time `json:"expires_at"` // zero = permanent
}
BlockedEntry represents a blocked IP with metadata.
type DynDNSResolver ¶
type DynDNSResolver struct {
// contains filtered or unexported fields
}
DynDNSResolver periodically resolves hostnames and updates the firewall allowed set.
func NewDynDNSResolver ¶
func NewDynDNSResolver(hosts []string, engine interface { AllowIP(ip string, reason string) error RemoveAllowIPBySource(ip string, source string) error }) *DynDNSResolver
NewDynDNSResolver creates a resolver for the given hostnames.
func (*DynDNSResolver) Run ¶
func (d *DynDNSResolver) Run(stopCh <-chan struct{})
Run starts the periodic resolver. Blocks until stopCh is closed.
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine manages the nftables firewall ruleset. Manages the nftables ruleset via netlink.
func ConnectExisting ¶
func ConnectExisting(cfg *FirewallConfig, statePath string) (*Engine, error)
ConnectExisting connects to an already-running CSM firewall. Used by CLI commands to modify the live ruleset without reapplying all rules.
func NewEngine ¶
func NewEngine(cfg *FirewallConfig, statePath string) (*Engine, error)
NewEngine creates a new nftables firewall engine.
func (*Engine) AllowIP ¶
AllowIP adds an IP to the allowed set and persists it. If the IP is currently blocked, the block is removed first.
func (*Engine) AllowIPPort ¶
AllowIPPort adds a port-specific IP allow. The rule is persisted to state and applied on the next Apply(). For immediate effect, call Apply() after.
func (*Engine) Apply ¶
Apply builds and atomically applies the complete nftables ruleset. All operations (delete old table + create new table/rules) are batched into a single netlink transaction. If the flush fails, the kernel keeps whatever ruleset was running before - the server is never left without a firewall.
func (*Engine) BlockIP ¶
BlockIP adds an IP to the blocked set with optional timeout. timeout 0 = permanent block.
func (*Engine) BlockSubnet ¶
BlockSubnet adds a CIDR range to the blocked subnets set (IPv4 or IPv6). timeout 0 = permanent block.
func (*Engine) CleanExpiredAllows ¶
CleanExpiredAllows removes expired temporary allows from the set and state. An IP is only removed from nftables if no non-expired entries remain for it. Called periodically by the daemon.
func (*Engine) CleanExpiredSubnets ¶
CleanExpiredSubnets removes expired temporary subnet blocks from nftables and state.
func (*Engine) CloudflareIPs ¶
CloudflareIPs returns the currently configured Cloudflare CIDRs from the cached state.
func (*Engine) FlushBlocked ¶
FlushBlocked removes all IPs from the blocked set and clears persisted state.
func (*Engine) IsBlocked ¶
IsBlocked returns true if the IP is currently in the engine's blocked state. Uses the persisted state file (which is cleaned of expired entries on load).
func (*Engine) RemoveAllowIP ¶
RemoveAllowIP removes an IP from the allowed set and state.
func (*Engine) RemoveAllowIPBySource ¶
RemoveAllowIPBySource removes only allow entries from a specific source. The IP is only removed from the nftables set if no other sources remain.
func (*Engine) RemoveAllowIPPort ¶
RemoveAllowIPPort removes a port-specific IP allow from state.
func (*Engine) TempAllowIP ¶
TempAllowIP adds a temporary allow with expiry. Uses the same allowed set but tracks expiry in state - CleanExpiredAllows removes them periodically.
func (*Engine) UnblockSubnet ¶
UnblockSubnet removes a CIDR range from the blocked subnets set (IPv4 or IPv6).
func (*Engine) UpdateCloudflareSet ¶
UpdateCloudflareSet flushes and repopulates the Cloudflare nftables sets.
type FirewallConfig ¶
type FirewallConfig struct {
Enabled bool `yaml:"enabled"`
// Open ports (IPv4)
TCPIn []int `yaml:"tcp_in"`
TCPOut []int `yaml:"tcp_out"`
UDPIn []int `yaml:"udp_in"`
UDPOut []int `yaml:"udp_out"`
// IPv6 - enable dual-stack filtering
IPv6 bool `yaml:"ipv6"`
TCP6In []int `yaml:"tcp6_in"` // if empty, uses tcp_in
TCP6Out []int `yaml:"tcp6_out"` // if empty, uses tcp_out
UDP6In []int `yaml:"udp6_in"` // if empty, uses udp_in
UDP6Out []int `yaml:"udp6_out"` // if empty, uses udp_out
// Ports restricted to infra IPs only
RestrictedTCP []int `yaml:"restricted_tcp"`
// Passive FTP range
PassiveFTPStart int `yaml:"passive_ftp_start"`
PassiveFTPEnd int `yaml:"passive_ftp_end"`
// Infra IPs (CIDR notation)
InfraIPs []string `yaml:"infra_ips"`
// Rate limiting (per-source-IP via nftables meters)
ConnRateLimit int `yaml:"conn_rate_limit"` // new connections per minute per IP
SYNFloodProtection bool `yaml:"syn_flood_protection"`
ConnLimit int `yaml:"conn_limit"` // max concurrent connections per IP (0 = disabled)
// Per-port flood protection - per-source rate limit per port
PortFlood []PortFloodRule `yaml:"port_flood"`
// UDP flood protection - per-source rate limit on UDP packets
UDPFlood bool `yaml:"udp_flood"`
UDPFloodRate int `yaml:"udp_flood_rate"` // packets per second
UDPFloodBurst int `yaml:"udp_flood_burst"` // burst allowance
// Country blocking
CountryBlock []string `yaml:"country_block"` // ISO country codes
CountryDBPath string `yaml:"country_db_path"`
// Ports to drop silently without logging (reduces log noise from scanners)
DropNoLog []int `yaml:"drop_nolog"`
// Max blocked IPs (prevents memory exhaustion, 0 = unlimited)
DenyIPLimit int `yaml:"deny_ip_limit"`
DenyTempIPLimit int `yaml:"deny_temp_ip_limit"`
// Outbound SMTP restriction - block outgoing mail except from allowed users
SMTPBlock bool `yaml:"smtp_block"`
SMTPAllowUsers []string `yaml:"smtp_allow_users"` // usernames allowed to send
SMTPPorts []int `yaml:"smtp_ports"`
// Dynamic DNS - resolve hostnames to IPs, update allowed set periodically
DynDNSHosts []string `yaml:"dyndns_hosts"`
// Logging
LogDropped bool `yaml:"log_dropped"`
LogRate int `yaml:"log_rate"` // log entries per minute
}
FirewallConfig defines the nftables firewall configuration.
func DefaultConfig ¶
func DefaultConfig() *FirewallConfig
DefaultConfig returns a sensible default firewall configuration matching a typical cPanel server.
type FirewallState ¶
type FirewallState struct {
Blocked []BlockedEntry `json:"blocked"`
BlockedNet []SubnetEntry `json:"blocked_nets"`
Allowed []AllowedEntry `json:"allowed"`
PortAllowed []PortAllowEntry `json:"port_allowed"`
}
FirewallState is persisted to disk for restore on restart.
func LoadState ¶
func LoadState(statePath string) (*FirewallState, error)
LoadState reads the firewall state file directly without requiring a running engine. Used by CLI commands that only need to display state. Note: callers that have access to the store package should check store.Global() first for bbolt-backed state. This function reads flat-file state.json only.
type PortAllowEntry ¶
type PortAllowEntry struct {
IP string `json:"ip"`
Port int `json:"port"`
Proto string `json:"proto"` // "tcp" or "udp"
Reason string `json:"reason"`
Source string `json:"source,omitempty"`
}
PortAllowEntry represents a port-specific IP allow (e.g. tcp|in|d=PORT|s=IP).