package app import ( "fmt" "strings" ) func executeTrafficAppMarksAdd(in trafficAppMarksPostInput) TrafficAppMarksResponse { if isAllDigits(in.Cgroup) { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Cgroup: in.Cgroup, Message: "cgroup must be a cgroupv2 path (ControlGroup), not a numeric id", } } ttl := in.TimeoutSec rel, level, inodeID, cgAbs, err := resolveCgroupV2PathForNft(in.Cgroup) if err != nil { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Cgroup: in.CgroupRaw, Message: err.Error(), } } vpnIface := "" if in.Target == "vpn" { traffic := loadTrafficModeState() iface, _ := resolveTrafficIface(traffic.PreferredIface) if strings.TrimSpace(iface) == "" { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Cgroup: cgAbs, CgroupID: inodeID, Message: "vpn interface not found (set preferred iface or bring VPN up)", } } vpnIface = strings.TrimSpace(iface) if err := ensureTrafficRouteBase(iface, traffic.AutoLocalBypass); err != nil { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Cgroup: cgAbs, CgroupID: inodeID, Message: "ensure vpn route base failed: " + err.Error(), } } } if err := appMarksAdd(in.Target, inodeID, cgAbs, rel, level, in.Unit, in.Command, in.AppKey, ttl, vpnIface); err != nil { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Cgroup: cgAbs, CgroupID: inodeID, TimeoutSec: ttl, Message: err.Error(), } } appendTraceLine("traffic", fmt.Sprintf("appmarks add target=%s cgroup=%s id=%d ttl=%ds", in.Target, cgAbs, inodeID, ttl)) return TrafficAppMarksResponse{ OK: true, Op: string(in.Op), Target: in.Target, Cgroup: cgAbs, CgroupID: inodeID, TimeoutSec: ttl, Message: "added", } } func executeTrafficAppMarksDelete(in trafficAppMarksPostInput) TrafficAppMarksResponse { if err := appMarksDel(in.Target, in.Cgroup); err != nil { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Cgroup: in.Cgroup, Message: err.Error(), } } appendTraceLine("traffic", fmt.Sprintf("appmarks del target=%s cgroup=%s", in.Target, in.Cgroup)) return TrafficAppMarksResponse{ OK: true, Op: string(in.Op), Target: in.Target, Cgroup: in.Cgroup, Message: "deleted", } } func executeTrafficAppMarksClear(in trafficAppMarksPostInput) TrafficAppMarksResponse { if err := appMarksClear(in.Target); err != nil { return TrafficAppMarksResponse{ OK: false, Op: string(in.Op), Target: in.Target, Message: err.Error(), } } appendTraceLine("traffic", fmt.Sprintf("appmarks clear target=%s", in.Target)) return TrafficAppMarksResponse{ OK: true, Op: string(in.Op), Target: in.Target, Message: "cleared", } }