ipset_atomic.go 1.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. package firewall
  2. import (
  3. "crypto/sha256"
  4. "fmt"
  5. "net"
  6. "os/exec"
  7. "sync"
  8. )
  9. var setApplyMu sync.Mutex
  10. func replaceSet(name, family string, addresses []string) error {
  11. setApplyMu.Lock()
  12. defer setApplyMu.Unlock()
  13. if len(name) > 31 {
  14. return fmt.Errorf("address list name too long: %s", name)
  15. }
  16. for _, address := range addresses {
  17. ip := net.ParseIP(address)
  18. if ip == nil {
  19. ip, _, _ = net.ParseCIDR(address)
  20. }
  21. if ip == nil || (ip.To4() != nil) != (family == "inet") {
  22. return fmt.Errorf("invalid %s address: %s", family, address)
  23. }
  24. }
  25. hash := sha256.Sum256([]byte(name))
  26. temp := fmt.Sprintf("dt_tmp_%x", hash[:8])
  27. run := func(args ...string) error {
  28. out, err := exec.Command("ipset", args...).CombinedOutput()
  29. if err != nil {
  30. return fmt.Errorf("ipset %v: %s: %w", args, out, err)
  31. }
  32. return nil
  33. }
  34. if err := run("create", temp, "hash:net", "family", family, "maxelem", "262144", "-exist"); err != nil {
  35. return err
  36. }
  37. defer exec.Command("ipset", "destroy", temp).Run()
  38. if err := run("flush", temp); err != nil {
  39. return err
  40. }
  41. for _, address := range addresses {
  42. if err := run("add", temp, address, "-exist"); err != nil {
  43. return err
  44. }
  45. }
  46. if err := run("create", name, "hash:net", "family", family, "maxelem", "262144", "-exist"); err != nil {
  47. return err
  48. }
  49. return run("swap", temp, name)
  50. }