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.
59 lines
1.6 KiB
Go
59 lines
1.6 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type PortGroup struct {
|
|
Proto string `yaml:"proto"`
|
|
Ports PortSpec `yaml:"ports"`
|
|
}
|
|
|
|
// ParsedPorts returns individual port numbers and ranges as (start, end) pairs.
|
|
func (pg *PortGroup) ParsedPorts() (singles []uint16, ranges [][2]uint16, err error) {
|
|
for _, p := range pg.Ports {
|
|
if strings.Contains(p, "-") {
|
|
parts := strings.SplitN(p, "-", 2)
|
|
start, err := strconv.ParseUint(parts[0], 10, 16)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("invalid port range start %q: %w", parts[0], err)
|
|
}
|
|
end, err := strconv.ParseUint(parts[1], 10, 16)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("invalid port range end %q: %w", parts[1], err)
|
|
}
|
|
if start > end {
|
|
return nil, nil, fmt.Errorf("port range %d-%d: start > end", start, end)
|
|
}
|
|
ranges = append(ranges, [2]uint16{uint16(start), uint16(end)})
|
|
} else {
|
|
port, err := strconv.ParseUint(p, 10, 16)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("invalid port %q: %w", p, err)
|
|
}
|
|
singles = append(singles, uint16(port))
|
|
}
|
|
}
|
|
return singles, ranges, nil
|
|
}
|
|
|
|
func (c *Config) validatePortGroups() error {
|
|
for name, pg := range c.PortGroups {
|
|
if pg.Proto == "" {
|
|
return fmt.Errorf("portgroup %q: proto required", name)
|
|
}
|
|
if pg.Proto != "tcp" && pg.Proto != "udp" {
|
|
return fmt.Errorf("portgroup %q: proto must be tcp or udp, got %q", name, pg.Proto)
|
|
}
|
|
if len(pg.Ports) == 0 {
|
|
return fmt.Errorf("portgroup %q: at least one port required", name)
|
|
}
|
|
if _, _, err := pg.ParsedPorts(); err != nil {
|
|
return fmt.Errorf("portgroup %q: %w", name, err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|