Files
tomswall/internal/config/rtrules.go
T
unkinben 8d9a76c751 Add comprehensive nftables compiler with shorewall feature parity
Rewrites the compiler from ~440 to ~1700 lines covering all major shorewall
firewall features: loopback, conntrack fast-path, anti-spoof, DHCP, intra-zone,
blacklist/whitelist, conntrack notrack, tunnels (13 types), rules with sections,
DNAT/redirect, SNAT/masquerade, static NAT, policies with zone exclusions,
MSS clamping, rate limiting, connection limiting, negated addresses, ICMP type
matching, TCP RST reject, user/UID matching, mark match/set, NFQUEUE, NONAT,
and policy-level rate/conn limiting.

Adds full config types for all shorewall subsystems (mangle, accounting, maclist,
netmap, providers, tunnels, conntrack, blrules, proxyarp/ndp, routes, tc, secmarks),
shorewall migration tooling, expanded CLI commands, expression-level diff engine,
and 49 unit tests.
2026-07-01 23:56:44 +10:00

63 lines
1.9 KiB
Go

package config
import "fmt"
// RoutingRule directs traffic matching source/dest criteria to a specific
// provider's routing table. Requires providers to be configured.
type RoutingRule struct {
// Source address, interface, or interface:address. Use "&interface" for interface's
// primary IP. "lo" matches firewall-originated traffic.
Source string `yaml:"source,omitempty"`
// Destination address or network in CIDR format.
Dest string `yaml:"dest,omitempty"`
// Provider name, provider number, or "main" (254) for the main routing table.
Provider string `yaml:"provider"`
// Numeric priority determining rule evaluation order.
// 1000-1999: before mark rules, 11000-11999: after mark rules,
// 26000-26999: after ISP interface rules.
Priority int `yaml:"priority"`
// Persist rule even if the provider's interface is disabled.
Persistent bool `yaml:"persistent,omitempty"`
// Packet mark match. Format: mark[/mask].
Mark string `yaml:"mark,omitempty"`
Comment string `yaml:"comment,omitempty"`
}
func (c *Config) validateRoutingRules() error {
if len(c.RoutingRules) > 0 && len(c.Providers) == 0 {
return fmt.Errorf("rtrules require providers to be configured")
}
providerNames := make(map[string]bool)
providerNames["main"] = true
for _, p := range c.Providers {
providerNames[p.Name] = true
providerNames[fmt.Sprintf("%d", p.Number)] = true
}
providerNames["254"] = true
for i, r := range c.RoutingRules {
if r.Source == "" && r.Dest == "" {
return fmt.Errorf("rtrules[%d]: source or dest required", i)
}
if r.Provider == "" {
return fmt.Errorf("rtrules[%d]: provider required", i)
}
if !providerNames[r.Provider] {
return fmt.Errorf("rtrules[%d]: provider %q not defined", i, r.Provider)
}
if r.Priority < 1000 || r.Priority > 26999 {
return fmt.Errorf("rtrules[%d]: priority must be 1000-26999", i)
}
}
return nil
}