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 }