- New Capabilities: PortPair, Negation, RejectAction, FamilyWithoutAddress, DenyActionFromConfig, advertised per backend. - coversDirection isolates DirForward even when output is unowned; add splitNATDualRow so a concrete-family removal re-adds the opposite family's NAT translation. - Resolve ip6tables/ufw ICMPv6 type aliases; ParseNATKind rejects the "invalid" sentinel as input while JSON round-trips it. - Sync counts additions on mid-batch failure and uses RuleBatcher. - NewManager runs a probe loop joining each backend's reason for diagnosability; services.go drops "generated" from enabled, handles it on enable, clears start-limit-hit on restart, and matches rc.local by token. - nftables: per-source connection limits (meter set), quoted-token parsing preserving log-prefix spacing, digit-led prefix sanitizing. - apf/csf: deny-action-from-config with cached STOP settings, port lists and inexpressible shapes routed through the pre-hook, confKeyApplies guard against a missing config line. - atomic config writes fsync before rename and resolve symlinks; readConfValue is last-assignment-wins; runCommand preserves the exit code through the wrapped error. - Move coreos/go-systemd to the maintained v22 module directly.
39 lines
1.5 KiB
Go
39 lines
1.5 KiB
Go
package firewall
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// NewManager gets a firewall manager for this server, probing the higher-level
|
|
// managers first: firewalld, then ufw/csf/apf, then plain iptables, and
|
|
// nftables last, so a manager that is itself backed by iptables or nftables is
|
|
// preferred over managing its tables behind its back. The context bounds the
|
|
// detection probes (each shells out or opens a D-Bus/systemd connection).
|
|
func NewManager(ctx context.Context, rulePrefix string) (Manager, error) {
|
|
// A probe error usually means "not installed", but it can also be a
|
|
// transient failure on a host whose firewall IS that manager (a D-Bus
|
|
// hiccup with firewalld running); every probe's reason is carried in the
|
|
// final error so a mis-detection is diagnosable.
|
|
var errs []error
|
|
probes := []struct {
|
|
name string
|
|
try func() (Manager, error)
|
|
}{
|
|
{"firewalld", func() (Manager, error) { return NewFirewallD(ctx, rulePrefix) }},
|
|
{"ufw", func() (Manager, error) { return NewUFW(ctx, rulePrefix) }},
|
|
{"csf", func() (Manager, error) { return NewCSF(ctx, rulePrefix) }},
|
|
{"apf", func() (Manager, error) { return NewAPF(ctx, rulePrefix) }},
|
|
{"iptables", func() (Manager, error) { return NewIPTables(ctx, rulePrefix) }},
|
|
{"nftables", func() (Manager, error) { return NewNFT(ctx, rulePrefix) }},
|
|
}
|
|
for _, p := range probes {
|
|
mgr, err := p.try()
|
|
if err == nil {
|
|
return mgr, nil
|
|
}
|
|
errs = append(errs, fmt.Errorf("%s: %w", p.name, err))
|
|
}
|
|
return nil, fmt.Errorf("no firewall manager found: %w", errors.Join(errs...))
|
|
}
|