platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
116
selective-vpn-api/app/trafficmode/rules.go
Normal file
116
selective-vpn-api/app/trafficmode/rules.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package trafficmode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RunCommandFunc func(name string, args ...string) (stdout string, stderr string, code int, err error)
|
||||
|
||||
type RulesConfig struct {
|
||||
RoutesTableName string
|
||||
Mark string
|
||||
MarkIngress string
|
||||
PrefSelective int
|
||||
PrefFull int
|
||||
PrefMarkIngressReply int
|
||||
ModeFull string
|
||||
ModeSelective string
|
||||
ModeDirect string
|
||||
}
|
||||
|
||||
type RulesState struct {
|
||||
Mark bool
|
||||
Full bool
|
||||
IngressReply bool
|
||||
}
|
||||
|
||||
func PrefStr(v int) string {
|
||||
return strconv.Itoa(v)
|
||||
}
|
||||
|
||||
func ReadRules(cfg RulesConfig, run RunCommandFunc) RulesState {
|
||||
if run == nil {
|
||||
return RulesState{}
|
||||
}
|
||||
out, _, _, _ := run("ip", "rule", "show")
|
||||
var st RulesState
|
||||
for _, line := range strings.Split(out, "\n") {
|
||||
l := strings.ToLower(strings.TrimSpace(line))
|
||||
if l == "" {
|
||||
continue
|
||||
}
|
||||
fields := strings.Fields(l)
|
||||
if len(fields) == 0 {
|
||||
continue
|
||||
}
|
||||
prefRaw := strings.TrimSuffix(fields[0], ":")
|
||||
pref, _ := strconv.Atoi(prefRaw)
|
||||
switch pref {
|
||||
case cfg.PrefSelective:
|
||||
if strings.Contains(l, "lookup "+cfg.RoutesTableName) {
|
||||
st.Mark = true
|
||||
}
|
||||
case cfg.PrefFull:
|
||||
if strings.Contains(l, "lookup "+cfg.RoutesTableName) {
|
||||
st.Full = true
|
||||
}
|
||||
case cfg.PrefMarkIngressReply:
|
||||
if strings.Contains(l, "fwmark "+strings.ToLower(cfg.MarkIngress)) && strings.Contains(l, "lookup main") {
|
||||
st.IngressReply = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func DetectAppliedMode(cfg RulesConfig, rules RulesState) string {
|
||||
if rules.Full {
|
||||
return cfg.ModeFull
|
||||
}
|
||||
if rules.Mark {
|
||||
return cfg.ModeSelective
|
||||
}
|
||||
return cfg.ModeDirect
|
||||
}
|
||||
|
||||
func ProbeMode(cfg RulesConfig, mode string, iface string, run RunCommandFunc) (bool, string) {
|
||||
if run == nil {
|
||||
return false, "run command func is nil"
|
||||
}
|
||||
mode = strings.ToLower(strings.TrimSpace(mode))
|
||||
iface = strings.TrimSpace(iface)
|
||||
|
||||
args := []string{"-4", "route", "get", "1.1.1.1"}
|
||||
if mode == strings.ToLower(cfg.ModeSelective) {
|
||||
args = append(args, "mark", cfg.Mark)
|
||||
}
|
||||
|
||||
out, _, code, err := run("ip", args...)
|
||||
if err != nil || code != 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("ip route get exited with %d", code)
|
||||
}
|
||||
return false, err.Error()
|
||||
}
|
||||
|
||||
text := strings.ToLower(out)
|
||||
switch mode {
|
||||
case strings.ToLower(cfg.ModeDirect):
|
||||
if strings.Contains(text, " table "+strings.ToLower(cfg.RoutesTableName)) {
|
||||
return false, "route probe still uses agvpn table"
|
||||
}
|
||||
return true, "route probe direct path ok"
|
||||
case strings.ToLower(cfg.ModeFull), strings.ToLower(cfg.ModeSelective):
|
||||
if iface == "" {
|
||||
return false, "route probe has empty iface"
|
||||
}
|
||||
if !strings.Contains(text, "dev "+strings.ToLower(iface)) {
|
||||
return false, fmt.Sprintf("route probe mismatch: expected dev %s", iface)
|
||||
}
|
||||
return true, "route probe vpn path ok"
|
||||
default:
|
||||
return false, "route probe unknown mode"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user