firewall

package
v0.0.0-...-20b3c94 Latest Latest
Warning

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

Go to latest
Published: Apr 19, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Index

Constants

View Source
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

func AppendAudit(statePath, action, ip, reason, source string, duration time.Duration)

AppendAudit writes an audit entry to the JSONL audit log. Rotates the log when it exceeds 10 MB.

func FetchCloudflareIPs

func FetchCloudflareIPs() (ipv4, ipv6 []string, err error)

FetchCloudflareIPs downloads the current Cloudflare IP ranges.

func InferProvenance

func InferProvenance(action, reason string) string

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

func LoadCFRefreshTime(statePath string) time.Time

LoadCFRefreshTime reads the last CF refresh time from state.

func LoadCFState

func LoadCFState(statePath string) (ipv4, ipv6 []string)

LoadCFState reads the cached Cloudflare CIDRs.

func LookupIP

func LookupIP(dbPath string, ip string) []string

LookupIP finds which country CIDR files contain the given IP. Returns matching country codes.

func SaveCFState

func SaveCFState(statePath string, ipv4, ipv6 []string, refreshed time.Time)

SaveCFState persists the Cloudflare CIDRs for status display.

func UpdateGeoIPDB

func UpdateGeoIPDB(dbPath string, countryCodes []string) (int, error)

UpdateGeoIPDB downloads country CIDR lists from a public source. Creates one file per country code: {dbPath}/{CC}.cidr

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

func (e *Engine) AllowIP(ip string, reason string) error

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

func (e *Engine) AllowIPPort(ip string, port int, proto string, reason string) error

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

func (e *Engine) Apply() error

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

func (e *Engine) BlockIP(ip string, reason string, timeout time.Duration) error

BlockIP adds an IP to the blocked set with optional timeout. timeout 0 = permanent block.

func (*Engine) BlockSubnet

func (e *Engine) BlockSubnet(cidr string, reason string, timeout time.Duration) error

BlockSubnet adds a CIDR range to the blocked subnets set (IPv4 or IPv6). timeout 0 = permanent block.

func (*Engine) CleanExpiredAllows

func (e *Engine) CleanExpiredAllows() int

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

func (e *Engine) CleanExpiredSubnets() int

CleanExpiredSubnets removes expired temporary subnet blocks from nftables and state.

func (*Engine) CloudflareIPs

func (e *Engine) CloudflareIPs() (ipv4, ipv6 []string)

CloudflareIPs returns the currently configured Cloudflare CIDRs from the cached state.

func (*Engine) FlushBlocked

func (e *Engine) FlushBlocked() error

FlushBlocked removes all IPs from the blocked set and clears persisted state.

func (*Engine) IsBlocked

func (e *Engine) IsBlocked(ip string) bool

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

func (e *Engine) RemoveAllowIP(ip string) error

RemoveAllowIP removes an IP from the allowed set and state.

func (*Engine) RemoveAllowIPBySource

func (e *Engine) RemoveAllowIPBySource(ip, source string) error

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

func (e *Engine) RemoveAllowIPPort(ip string, port int, proto string) error

RemoveAllowIPPort removes a port-specific IP allow from state.

func (*Engine) Status

func (e *Engine) Status() map[string]interface{}

Status returns current firewall statistics.

func (*Engine) TempAllowIP

func (e *Engine) TempAllowIP(ip string, reason string, timeout time.Duration) error

TempAllowIP adds a temporary allow with expiry. Uses the same allowed set but tracks expiry in state - CleanExpiredAllows removes them periodically.

func (*Engine) UnblockIP

func (e *Engine) UnblockIP(ip string) error

UnblockIP removes an IP from the blocked set and state.

func (*Engine) UnblockSubnet

func (e *Engine) UnblockSubnet(cidr string) error

UnblockSubnet removes a CIDR range from the blocked subnets set (IPv4 or IPv6).

func (*Engine) UpdateCloudflareSet

func (e *Engine) UpdateCloudflareSet(ipv4, ipv6 []string) error

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).

type PortFloodRule

type PortFloodRule struct {
	Port    int    `yaml:"port"`
	Proto   string `yaml:"proto"`   // "tcp" or "udp"
	Hits    int    `yaml:"hits"`    // max new connections
	Seconds int    `yaml:"seconds"` // time window in seconds
}

PortFloodRule defines per-port connection rate limiting.

type SubnetEntry

type SubnetEntry struct {
	CIDR      string    `json:"cidr"`
	Reason    string    `json:"reason"`
	Source    string    `json:"source,omitempty"`
	BlockedAt time.Time `json:"blocked_at"`
	ExpiresAt time.Time `json:"expires_at,omitempty"`
}

SubnetEntry represents a blocked CIDR range.

Jump to

Keyboard shortcuts

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