74 lines
1.6 KiB
Go
74 lines
1.6 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
func snapshotNftSetToFile(setName, dst string) (int, error) {
|
|
elems, err := readNftSetElements(setName)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if err := writeLinesFile(dst, elems); err != nil {
|
|
return 0, err
|
|
}
|
|
return len(elems), nil
|
|
}
|
|
|
|
func readNftSetElements(setName string) ([]string, error) {
|
|
out, stderr, code, err := runCommandTimeout(
|
|
8*time.Second, "nft", "list", "set", "inet", "agvpn", setName,
|
|
)
|
|
if err != nil || code != 0 {
|
|
msg := strings.ToLower(strings.TrimSpace(out + " " + stderr))
|
|
if strings.Contains(msg, "no such file") ||
|
|
strings.Contains(msg, "not found") ||
|
|
strings.Contains(msg, "does not exist") {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, fmt.Errorf("nft list set %s failed: %w", setName, err)
|
|
}
|
|
return nil, fmt.Errorf("nft list set %s failed: %s", setName, strings.TrimSpace(stderr))
|
|
}
|
|
return parseNftSetElementsText(out), nil
|
|
}
|
|
|
|
func parseNftSetElementsText(raw string) []string {
|
|
idx := strings.Index(raw, "elements =")
|
|
if idx < 0 {
|
|
return nil
|
|
}
|
|
chunk := raw[idx:]
|
|
open := strings.Index(chunk, "{")
|
|
if open < 0 {
|
|
return nil
|
|
}
|
|
body := chunk[open+1:]
|
|
closeIdx := strings.Index(body, "}")
|
|
if closeIdx >= 0 {
|
|
body = body[:closeIdx]
|
|
}
|
|
body = strings.ReplaceAll(body, "\r", " ")
|
|
body = strings.ReplaceAll(body, "\n", " ")
|
|
|
|
seen := map[string]struct{}{}
|
|
out := make([]string, 0, 1024)
|
|
for _, tok := range strings.Split(body, ",") {
|
|
val := strings.TrimSpace(tok)
|
|
if val == "" {
|
|
continue
|
|
}
|
|
if _, ok := seen[val]; ok {
|
|
continue
|
|
}
|
|
seen[val] = struct{}{}
|
|
out = append(out, val)
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|