platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
115
selective-vpn-api/app/trafficmode/apply.go
Normal file
115
selective-vpn-api/app/trafficmode/apply.go
Normal file
@@ -0,0 +1,115 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user