ipset.go 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package firewall
  2. import (
  3. "os/exec"
  4. "strings"
  5. )
  6. // SyncAddressLists updates Linux ipsets to match the configured AddressList entries and referenced lists
  7. func SyncAddressLists(entries []AddressListEntry, referencedLists ...string) error {
  8. // Group addresses by list name
  9. listMap := make(map[string][]string)
  10. for _, e := range entries {
  11. if e.Disabled || e.Name == "" || e.Address == "" {
  12. continue
  13. }
  14. listMap[e.Name] = append(listMap[e.Name], e.Address)
  15. }
  16. // Ensure any custom list explicitly referenced in rules exists even if empty
  17. for _, ref := range referencedLists {
  18. ref = strings.TrimPrefix(ref, "!")
  19. if ref != "" && !strings.HasPrefix(ref, "geo:") && !strings.HasPrefix(ref, "geo_") {
  20. if _, ok := listMap[ref]; !ok {
  21. listMap[ref] = []string{}
  22. }
  23. }
  24. }
  25. // Clean up any mk_ sets that no longer exist or are now empty (ignoring mk_geo_ sets managed by GeoIP)
  26. if out, err := exec.Command("ipset", "list", "-name").Output(); err == nil {
  27. lines := strings.Split(string(out), "\n")
  28. for _, line := range lines {
  29. line = strings.TrimSpace(line)
  30. if strings.HasPrefix(line, "mk_") && !strings.HasPrefix(line, "mk_geo_") {
  31. name := strings.TrimPrefix(line, "mk_")
  32. if _, ok := listMap[name]; !ok {
  33. _ = exec.Command("ipset", "flush", line).Run()
  34. _ = exec.Command("ipset", "destroy", line).Run()
  35. }
  36. }
  37. }
  38. }
  39. for name, addrs := range listMap {
  40. setName := "mk_" + strings.ReplaceAll(name, " ", "_")
  41. // Create set if not exists
  42. _ = exec.Command("ipset", "create", setName, "hash:net", "-exist").Run()
  43. _ = exec.Command("ipset", "flush", setName).Run()
  44. for _, a := range addrs {
  45. _ = exec.Command("ipset", "add", setName, a, "-exist").Run()
  46. }
  47. }
  48. return nil
  49. }
  50. // GetIPSetName returns the internal ipset name for an address list
  51. func GetIPSetName(listName string) string {
  52. if listName == "" {
  53. return ""
  54. }
  55. clean := strings.TrimPrefix(listName, "!")
  56. if strings.HasPrefix(clean, "geo:") {
  57. code := strings.ToUpper(strings.TrimPrefix(clean, "geo:"))
  58. return "mk_geo_" + code
  59. }
  60. if strings.HasPrefix(clean, "geo_") {
  61. return "mk_" + clean
  62. }
  63. return "mk_" + strings.ReplaceAll(clean, " ", "_")
  64. }
  65. // GetGeoIPSetName returns the internal ipset name for a Geo-Location country or preset
  66. func GetGeoIPSetName(code string) string {
  67. if code == "" {
  68. return ""
  69. }
  70. clean := strings.TrimPrefix(code, "!")
  71. clean = strings.TrimPrefix(clean, "geo:")
  72. clean = strings.TrimPrefix(clean, "geo_")
  73. return "mk_geo_" + strings.ToUpper(clean)
  74. }