2a3eb3b04d
Spiritual successor to shorewall — manages nftables directly via google/nftables. Reads a single YAML config covering zones, interfaces, hosts, policy, rules, snat, and named portgroups. Computes differential changes against the running nftables state and applies them atomically. Supports detecting and purging rules added outside of tomswall.
102 lines
2.2 KiB
Go
102 lines
2.2 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
type Config struct {
|
|
Settings Settings `yaml:"settings"`
|
|
PortGroups map[string]PortGroup `yaml:"portgroups"`
|
|
Zones map[string]Zone `yaml:"zones"`
|
|
Interfaces []Interface `yaml:"interfaces"`
|
|
Hosts []Host `yaml:"hosts"`
|
|
Policy []Policy `yaml:"policy"`
|
|
Rules []Rule `yaml:"rules"`
|
|
SNAT []SNATRule `yaml:"snat"`
|
|
}
|
|
|
|
type Settings struct {
|
|
IPForwarding bool `yaml:"ip_forwarding"`
|
|
LogLevel string `yaml:"log_level"`
|
|
TableName string `yaml:"table_name"`
|
|
}
|
|
|
|
func Load(path string) (*Config, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("reading config %s: %w", path, err)
|
|
}
|
|
|
|
var cfg Config
|
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("parsing config: %w", err)
|
|
}
|
|
|
|
cfg.applyDefaults()
|
|
return &cfg, nil
|
|
}
|
|
|
|
func (c *Config) applyDefaults() {
|
|
if c.Settings.TableName == "" {
|
|
c.Settings.TableName = "tomswall"
|
|
}
|
|
if c.Settings.LogLevel == "" {
|
|
c.Settings.LogLevel = "info"
|
|
}
|
|
}
|
|
|
|
func (c *Config) Validate() error {
|
|
if err := c.validateZones(); err != nil {
|
|
return fmt.Errorf("zones: %w", err)
|
|
}
|
|
if err := c.validateInterfaces(); err != nil {
|
|
return fmt.Errorf("interfaces: %w", err)
|
|
}
|
|
if err := c.validateHosts(); err != nil {
|
|
return fmt.Errorf("hosts: %w", err)
|
|
}
|
|
if err := c.validatePortGroups(); err != nil {
|
|
return fmt.Errorf("portgroups: %w", err)
|
|
}
|
|
if err := c.validatePolicy(); err != nil {
|
|
return fmt.Errorf("policy: %w", err)
|
|
}
|
|
if err := c.validateRules(); err != nil {
|
|
return fmt.Errorf("rules: %w", err)
|
|
}
|
|
if err := c.validateSNAT(); err != nil {
|
|
return fmt.Errorf("snat: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Config) FirewallZone() string {
|
|
for name, z := range c.Zones {
|
|
if z.Type == ZoneFirewall {
|
|
return name
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (c *Config) ZoneInterfaces(zone string) []string {
|
|
var ifaces []string
|
|
for _, iface := range c.Interfaces {
|
|
if iface.Zone == zone {
|
|
ifaces = append(ifaces, iface.Interface)
|
|
}
|
|
}
|
|
return ifaces
|
|
}
|
|
|
|
func (c *Config) ResolvePortGroup(name string) (*PortGroup, bool) {
|
|
pg, ok := c.PortGroups[name]
|
|
if !ok {
|
|
return nil, false
|
|
}
|
|
return &pg, true
|
|
}
|