Files

116 lines
3.0 KiB
Go

package trafficmode
import (
"fmt"
"strconv"
"strings"
)
type RunCommandSimpleFunc func(name string, args ...string) (stdout string, stderr string, code int, err error)
type OverrideConfig struct {
RoutesTableName string
RulePerKindLimit int
PrefManagedMin int
PrefManagedMax int
PrefDirectSubnetBase int
PrefDirectUIDBase int
PrefVPNSubnetBase int
PrefVPNUIDBase int
}
type EffectiveOverrides struct {
VPNSubnets []string
VPNUIDs []string
DirectSubnets []string
DirectUIDs []string
}
func RemoveRulesForTable(cfg OverrideConfig, run RunCommandSimpleFunc) {
if run == nil {
return
}
out, _, _, _ := run("ip", "rule", "show")
for _, line := range strings.Split(out, "\n") {
line = strings.TrimSpace(line)
if line == "" {
continue
}
fields := strings.Fields(line)
if len(fields) == 0 {
continue
}
pref := strings.TrimSuffix(fields[0], ":")
if pref == "" {
continue
}
prefNum, _ := strconv.Atoi(pref)
low := strings.ToLower(line)
managed := prefNum >= cfg.PrefManagedMin && prefNum <= cfg.PrefManagedMax
legacy := strings.Contains(low, "lookup "+cfg.RoutesTableName)
if !managed && !legacy {
continue
}
_, _, _, _ = run("ip", "rule", "del", "pref", pref)
}
}
func ApplyRule(pref int, run RunCommandSimpleFunc, args ...string) error {
if run == nil {
return fmt.Errorf("run command func is nil")
}
if pref <= 0 {
return fmt.Errorf("invalid pref: %d", pref)
}
cmd := []string{"rule", "add"}
cmd = append(cmd, args...)
cmd = append(cmd, "pref", PrefStr(pref))
_, _, code, err := run("ip", cmd...)
if err != nil || code != 0 {
if err == nil {
err = fmt.Errorf("ip %s exited with %d", strings.Join(cmd, " "), code)
}
return err
}
return nil
}
func ApplyOverrides(cfg OverrideConfig, e EffectiveOverrides, applyRule func(pref int, args ...string) error) (int, error) {
applied := 0
if applyRule == nil {
return 0, fmt.Errorf("applyRule callback is nil")
}
if len(e.DirectSubnets) > cfg.RulePerKindLimit ||
len(e.DirectUIDs) > cfg.RulePerKindLimit ||
len(e.VPNSubnets) > cfg.RulePerKindLimit ||
len(e.VPNUIDs) > cfg.RulePerKindLimit {
return 0, fmt.Errorf("override list too large (max %d entries per kind)", cfg.RulePerKindLimit)
}
for i, cidr := range e.DirectSubnets {
if err := applyRule(cfg.PrefDirectSubnetBase+i, "from", cidr, "lookup", "main"); err != nil {
return applied, err
}
applied++
}
for i, uidr := range e.DirectUIDs {
if err := applyRule(cfg.PrefDirectUIDBase+i, "uidrange", uidr, "lookup", "main"); err != nil {
return applied, err
}
applied++
}
for i, cidr := range e.VPNSubnets {
if err := applyRule(cfg.PrefVPNSubnetBase+i, "from", cidr, "lookup", cfg.RoutesTableName); err != nil {
return applied, err
}
applied++
}
for i, uidr := range e.VPNUIDs {
if err := applyRule(cfg.PrefVPNUIDBase+i, "uidrange", uidr, "lookup", cfg.RoutesTableName); err != nil {
return applied, err
}
applied++
}
return applied, nil
}