package app import ( "encoding/json" "fmt" "os" trafficmodepkg "selective-vpn-api/app/trafficmode" "strings" ) func ensureRoutesTableEntry() { data, _ := os.ReadFile("/etc/iproute2/rt_tables") want := fmt.Sprintf("%s %s", routesTableNum(), routesTableName()) if strings.Contains(string(data), "\n"+want) || strings.HasPrefix(string(data), want) { return } f, err := os.OpenFile("/etc/iproute2/rt_tables", os.O_APPEND|os.O_WRONLY, 0o644) if err != nil { return } defer f.Close() _, _ = fmt.Fprintf(f, "%s\n", want) } func ifaceExists(iface string) bool { return trafficmodepkg.IfaceExists(iface, runCommand) } func statusIfaceFromFile() string { data, err := os.ReadFile(statusFilePath) if err != nil { return "" } var st Status if json.Unmarshal(data, &st) != nil { return "" } return strings.TrimSpace(st.Iface) } func listUpIfaces() []string { return trafficmodepkg.ListUpIfaces(runCommand) } func listSelectableIfaces(preferred string) []string { return trafficmodepkg.ListSelectableIfaces(listUpIfaces(), preferred) } func isVPNLikeIface(iface string) bool { return trafficmodepkg.IsVPNLikeIface(iface) } func resolveTrafficIface(preferred string) (string, string) { return trafficmodepkg.ResolveTrafficIface(preferred, ifaceExists, statusIfaceFromFile, listUpIfaces) } type autoLocalRoute = trafficmodepkg.AutoLocalRoute func parseRouteDevice(fields []string) string { return trafficmodepkg.ParseRouteDevice(fields) } func isContainerIface(iface string) bool { return trafficmodepkg.IsContainerIface(iface) } func routeLineIsLinkDown(line string) bool { return trafficmodepkg.RouteLineIsLinkDown(line) } func isAutoBypassDestination(dst string) bool { return trafficmodepkg.IsAutoBypassDestination(dst) } func detectAutoLocalBypassRoutes(vpnIface string) []autoLocalRoute { vpnIface = strings.TrimSpace(vpnIface) out, _, code, _ := runCommand("ip", "-4", "route", "show", "table", "main") if code != 0 { return nil } return trafficmodepkg.ParseAutoBypassRoutes(out, vpnIface, isVPNLikeIface) } func applyAutoLocalBypass(vpnIface string) { for _, rt := range detectAutoLocalBypassRoutes(vpnIface) { _, _, _, _ = runCommand( "ip", "-4", "route", "replace", rt.Dst, "dev", rt.Dev, "table", routesTableName(), ) } } func ingressBypassConfig() trafficmodepkg.IngressBypassConfig { return trafficmodepkg.IngressBypassConfig{ TableName: routesTableName(), PreroutingChain: trafficIngressPreroutingChain, OutputChain: trafficIngressOutputChain, MarkIngress: MARK_INGRESS, CaptureComment: trafficIngressCaptureComment, RestoreComment: trafficIngressRestoreComment, } } func ensureIngressReplyBypassChains() { trafficmodepkg.EnsureIngressReplyBypassChains(ingressBypassConfig(), runCommandTimeout) } func flushIngressReplyBypassChains() error { return trafficmodepkg.FlushIngressReplyBypassChains(ingressBypassConfig(), runCommandTimeout) } func enableIngressReplyBypass(vpnIface string) error { return trafficmodepkg.EnableIngressReplyBypass(ingressBypassConfig(), strings.TrimSpace(vpnIface), runCommandTimeout) } func disableIngressReplyBypass() error { return trafficmodepkg.DisableIngressReplyBypass(ingressBypassConfig(), runCommandTimeout) } func ingressReplyNftActive() bool { return trafficmodepkg.IngressReplyNftActive(ingressBypassConfig(), runCommandTimeout) } func prefStr(v int) string { return trafficmodepkg.PrefStr(v) } func trafficModeRulesConfig() trafficmodepkg.RulesConfig { return trafficmodepkg.RulesConfig{ RoutesTableName: routesTableName(), Mark: MARK, MarkIngress: MARK_INGRESS, PrefSelective: trafficRulePrefSelective, PrefFull: trafficRulePrefFull, PrefMarkIngressReply: trafficRulePrefMarkIngressReply, ModeFull: string(TrafficModeFullTunnel), ModeSelective: string(TrafficModeSelective), ModeDirect: string(TrafficModeDirect), } } func trafficModeOverrideConfig() trafficmodepkg.OverrideConfig { return trafficmodepkg.OverrideConfig{ RoutesTableName: routesTableName(), RulePerKindLimit: trafficRulePerKindLimit, PrefManagedMin: trafficRulePrefManagedMin, PrefManagedMax: trafficRulePrefManagedMax, PrefDirectSubnetBase: trafficRulePrefDirectSubnetStart, PrefDirectUIDBase: trafficRulePrefDirectUIDStart, PrefVPNSubnetBase: trafficRulePrefVPNSubnetStart, PrefVPNUIDBase: trafficRulePrefVPNUIDStart, } } func removeTrafficRulesForTable() { trafficmodepkg.RemoveRulesForTable(trafficModeOverrideConfig(), runCommand) }