ipset.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. package firewall
  2. import (
  3. "crypto/sha256"
  4. "fmt"
  5. "net"
  6. "os/exec"
  7. "strings"
  8. )
  9. func listToken(name string) string { h := sha256.Sum256([]byte(name)); return fmt.Sprintf("%x", h[:8]) }
  10. func GetIPSetName(name string) string {
  11. name = strings.TrimPrefix(name, "!")
  12. if strings.HasPrefix(name, "geo:") {
  13. return GetGeoIPSetName(name)
  14. }
  15. if strings.HasPrefix(name, "geo_") {
  16. return GetGeoIPSetName(name)
  17. }
  18. return "dt_al_" + listToken(name)
  19. }
  20. func GetDynamicIPSetName(name string) string { return "dt_ad_" + listToken(name) }
  21. func staticIPSetName(name string) string { return "dt_as_" + listToken(name) }
  22. func GetGeoIPSetName(code string) string {
  23. code = strings.TrimPrefix(code, "!")
  24. code = strings.TrimPrefix(code, "geo:")
  25. code = strings.TrimPrefix(code, "geo_")
  26. return "mk_geo_" + strings.ToUpper(code)
  27. }
  28. func SyncAddressLists(entries []AddressListEntry, referenced ...string) error {
  29. lists := map[string][]string{}
  30. // Retain empty lists represented by disabled entries, so disabling the last
  31. // static entry clears its addresses without deleting a dynamic collection.
  32. for _, e := range entries {
  33. if err := validateListName(e.Name); err != nil {
  34. return err
  35. }
  36. if _, ok := lists[e.Name]; !ok {
  37. lists[e.Name] = nil
  38. }
  39. if !e.Disabled {
  40. if e.Address == "" {
  41. return fmt.Errorf("address is required")
  42. }
  43. lists[e.Name] = append(lists[e.Name], e.Address)
  44. }
  45. }
  46. for _, name := range referenced {
  47. name = strings.TrimPrefix(name, "!")
  48. if name != "" && !strings.HasPrefix(name, "geo:") && !strings.HasPrefix(name, "geo_") {
  49. if err := validateListName(name); err != nil {
  50. return err
  51. }
  52. if _, ok := lists[name]; !ok {
  53. lists[name] = nil
  54. }
  55. }
  56. }
  57. desired := map[string]bool{}
  58. for name, addrs := range lists {
  59. families := map[string][]string{"inet": nil, "inet6": nil}
  60. for _, address := range addrs {
  61. ip := net.ParseIP(address)
  62. if ip == nil {
  63. ip, _, _ = net.ParseCIDR(address)
  64. }
  65. if ip == nil {
  66. return fmt.Errorf("invalid address: %s", address)
  67. }
  68. family := "inet6"
  69. if ip.To4() != nil {
  70. family = "inet"
  71. }
  72. families[family] = append(families[family], address)
  73. }
  74. for family, addresses := range families {
  75. suffix := ""
  76. if family == "inet6" {
  77. suffix = "_v6"
  78. }
  79. static, dynamic, union := staticIPSetName(name)+suffix, GetDynamicIPSetName(name)+suffix, GetIPSetName(name)+suffix
  80. desired[static] = true
  81. desired[dynamic] = true
  82. desired[union] = true
  83. if err := replaceSet(static, family, addresses); err != nil {
  84. return err
  85. }
  86. if err := runIPSet("create", dynamic, "hash:net", "family", family, "timeout", "0", "maxelem", "262144", "-exist"); err != nil {
  87. return err
  88. }
  89. if err := runIPSet("create", union, "list:set", "size", "2", "-exist"); err != nil {
  90. return err
  91. }
  92. for _, child := range []string{static, dynamic} {
  93. if err := runIPSet("add", union, child, "-exist"); err != nil {
  94. return err
  95. }
  96. }
  97. }
  98. }
  99. // Only collect our own sets and only if the kernel reports no references.
  100. out, err := exec.Command("ipset", "list", "-name").Output()
  101. if err != nil {
  102. return err
  103. }
  104. for _, prefix := range []string{"dt_al_", "dt_as_", "dt_ad_"} {
  105. for _, name := range strings.Fields(string(out)) {
  106. if strings.HasPrefix(name, prefix) && !desired[name] {
  107. _ = exec.Command("ipset", "destroy", name).Run()
  108. }
  109. }
  110. }
  111. return nil
  112. }
  113. func collectUnusedAddressLists(entries []AddressListEntry, refs []string) {
  114. desired := map[string]bool{}
  115. for _, e := range entries {
  116. refs = append(refs, e.Name)
  117. }
  118. for _, name := range refs {
  119. name = strings.TrimPrefix(name, "!")
  120. if name == "" || strings.HasPrefix(name, "geo:") || strings.HasPrefix(name, "geo_") {
  121. continue
  122. }
  123. for _, suffix := range []string{"", "_v6"} {
  124. desired[GetIPSetName(name)+suffix] = true
  125. desired[GetDynamicIPSetName(name)+suffix] = true
  126. desired[staticIPSetName(name)+suffix] = true
  127. }
  128. }
  129. out, err := exec.Command("ipset", "list", "-name").Output()
  130. if err != nil {
  131. return
  132. }
  133. for _, prefix := range []string{"dt_al_", "dt_as_", "dt_ad_"} {
  134. for _, name := range strings.Fields(string(out)) {
  135. if strings.HasPrefix(name, prefix) && !desired[name] {
  136. if exec.Command("ipset", "destroy", name).Run() == nil {
  137. setApplyMu.Lock()
  138. delete(setDigests, name)
  139. setApplyMu.Unlock()
  140. }
  141. }
  142. }
  143. }
  144. }