platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
95
selective-vpn-api/app/routes_cache_helpers_routes.go
Normal file
95
selective-vpn-api/app/routes_cache_helpers_routes.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func readCurrentRoutesTableLines() ([]string, error) {
|
||||
out, _, code, err := runCommandTimeout(5*time.Second, "ip", "-4", "route", "show", "table", routesTableName())
|
||||
if err != nil && code != 0 {
|
||||
return nil, err
|
||||
}
|
||||
lines := make([]string, 0, 32)
|
||||
for _, raw := range strings.Split(out, "\n") {
|
||||
ln := strings.TrimSpace(raw)
|
||||
if ln == "" {
|
||||
continue
|
||||
}
|
||||
lines = append(lines, ln)
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
|
||||
func detectIfaceFromRoutes(lines []string) string {
|
||||
for _, ln := range lines {
|
||||
fields := strings.Fields(ln)
|
||||
for i := 0; i+1 < len(fields); i++ {
|
||||
if fields[i] == "dev" {
|
||||
return strings.TrimSpace(fields[i+1])
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func restoreRouteLine(line string) error {
|
||||
fields := strings.Fields(strings.TrimSpace(line))
|
||||
if len(fields) == 0 {
|
||||
return nil
|
||||
}
|
||||
args := []string{"-4", "route", "replace"}
|
||||
args = append(args, fields...)
|
||||
hasTable := false
|
||||
for i := 0; i+1 < len(fields); i++ {
|
||||
if fields[i] == "table" {
|
||||
hasTable = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !hasTable {
|
||||
args = append(args, "table", routesTableName())
|
||||
}
|
||||
_, _, code, err := runCommandTimeout(5*time.Second, "ip", args...)
|
||||
if err != nil || code != 0 {
|
||||
if err == nil {
|
||||
err = fmt.Errorf("exit code %d", code)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func shouldIgnoreRestoreRouteError(line string, err error) bool {
|
||||
ln := strings.ToLower(strings.TrimSpace(line))
|
||||
if strings.Contains(ln, " linkdown") {
|
||||
return true
|
||||
}
|
||||
|
||||
dev := routeLineDevice(ln)
|
||||
if dev != "" && !strings.HasPrefix(ln, "default ") && !ifaceExists(dev) {
|
||||
return true
|
||||
}
|
||||
|
||||
msg := strings.ToLower(strings.TrimSpace(fmt.Sprintf("%v", err)))
|
||||
if strings.HasPrefix(ln, "default ") {
|
||||
return false
|
||||
}
|
||||
if strings.Contains(msg, "cannot find device") ||
|
||||
strings.Contains(msg, "no such device") ||
|
||||
strings.Contains(msg, "network is down") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func routeLineDevice(line string) string {
|
||||
fields := strings.Fields(strings.TrimSpace(line))
|
||||
for i := 0; i+1 < len(fields); i++ {
|
||||
if fields[i] == "dev" {
|
||||
return strings.TrimSpace(fields[i+1])
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in New Issue
Block a user