package firewall import ( "fmt" "os/exec" "strings" ) func (m *FirewallManager) ResetRuleCounters(kind, id string) error { m.mu.Lock() defer m.mu.Unlock() found := false switch kind { case "filter": for _, r := range m.filterRules { found = found || r.ID == id } case "nat": for _, r := range m.natRules { found = found || r.ID == id } case "mangle": for _, r := range m.mangleRules { found = found || r.ID == id } default: return fmt.Errorf("unknown rule kind") } if !found { return fmt.Errorf("rule not found") } for _, binary := range []string{"iptables", "ip6tables"} { out, err := exec.Command(binary + "-save").Output() if err != nil { return err } table := "" numbers := map[string]int{} for _, line := range strings.Split(string(out), "\n") { if strings.HasPrefix(line, "*") { table = line[1:] numbers = map[string]int{} } if !strings.HasPrefix(line, "-A ") { continue } fields := strings.Fields(line) chain := fields[1] numbers[chain]++ if table != kind && !(kind == "filter" && table == "filter") { continue } if !strings.HasPrefix(chain, "DT_") { continue } if strings.Contains(line, "--comment "+quote("id:"+id)) || strings.Contains(line, "--comment "+quote("id:"+id+":log")) { if out, err := exec.Command(binary, "-t", table, "-Z", chain, fmt.Sprint(numbers[chain])).CombinedOutput(); err != nil { return fmt.Errorf("reset counter: %s: %w", out, err) } } } } return nil }