116 lines
3.0 KiB
Go
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
|
|
}
|