ipset.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. package firewall
  2. import (
  3. "fmt"
  4. "net"
  5. "strings"
  6. )
  7. // SyncAddressLists updates Linux ipsets to match the configured AddressList entries and referenced lists
  8. func SyncAddressLists(entries []AddressListEntry, referencedLists ...string) error {
  9. // Group addresses by list name
  10. listMap := make(map[string][]string)
  11. for _, e := range entries {
  12. if e.Disabled || e.Name == "" || e.Address == "" {
  13. continue
  14. }
  15. listMap[e.Name] = append(listMap[e.Name], e.Address)
  16. }
  17. // Ensure any custom list explicitly referenced in rules exists even if empty
  18. for _, ref := range referencedLists {
  19. ref = strings.TrimPrefix(ref, "!")
  20. if ref != "" && !strings.HasPrefix(ref, "geo:") && !strings.HasPrefix(ref, "geo_") {
  21. if _, ok := listMap[ref]; !ok {
  22. listMap[ref] = []string{}
  23. }
  24. }
  25. }
  26. for name, addrs := range listMap {
  27. var v4, v6 []string
  28. for _, address := range addrs {
  29. ip := net.ParseIP(address)
  30. if ip == nil {
  31. ip, _, _ = net.ParseCIDR(address)
  32. }
  33. if ip == nil {
  34. return fmt.Errorf("invalid address: %s", address)
  35. }
  36. if ip.To4() != nil {
  37. v4 = append(v4, address)
  38. } else {
  39. v6 = append(v6, address)
  40. }
  41. }
  42. if err := replaceSet(GetIPSetName(name), "inet", v4); err != nil {
  43. return err
  44. }
  45. if err := replaceSet(GetIPSetName(name)+"_v6", "inet6", v6); err != nil {
  46. return err
  47. }
  48. }
  49. return nil
  50. }
  51. // GetIPSetName returns the internal ipset name for an address list
  52. func GetIPSetName(listName string) string {
  53. if listName == "" {
  54. return ""
  55. }
  56. clean := strings.TrimPrefix(listName, "!")
  57. if strings.HasPrefix(clean, "geo:") {
  58. code := strings.ToUpper(strings.TrimPrefix(clean, "geo:"))
  59. return "mk_geo_" + code
  60. }
  61. if strings.HasPrefix(clean, "geo_") {
  62. return "mk_" + clean
  63. }
  64. return "mk_" + strings.ReplaceAll(clean, " ", "_")
  65. }
  66. // GetGeoIPSetName returns the internal ipset name for a Geo-Location country or preset
  67. func GetGeoIPSetName(code string) string {
  68. if code == "" {
  69. return ""
  70. }
  71. clean := strings.TrimPrefix(code, "!")
  72. clean = strings.TrimPrefix(clean, "geo:")
  73. clean = strings.TrimPrefix(clean, "geo_")
  74. return "mk_geo_" + strings.ToUpper(clean)
  75. }