rule_item_cidr.go 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package rule
  2. import (
  3. "net/netip"
  4. "strings"
  5. "github.com/sagernet/sing-box/adapter"
  6. E "github.com/sagernet/sing/common/exceptions"
  7. "go4.org/netipx"
  8. )
  9. var _ RuleItem = (*IPCIDRItem)(nil)
  10. type IPCIDRItem struct {
  11. ipSet *netipx.IPSet
  12. isSource bool
  13. description string
  14. }
  15. func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
  16. var builder netipx.IPSetBuilder
  17. for i, prefixString := range prefixStrings {
  18. prefix, err := netip.ParsePrefix(prefixString)
  19. if err == nil {
  20. builder.AddPrefix(prefix)
  21. continue
  22. }
  23. addr, addrErr := netip.ParseAddr(prefixString)
  24. if addrErr == nil {
  25. builder.Add(addr)
  26. continue
  27. }
  28. return nil, E.Cause(err, "parse [", i, "]")
  29. }
  30. var description string
  31. if isSource {
  32. description = "source_ip_cidr="
  33. } else {
  34. description = "ip_cidr="
  35. }
  36. if dLen := len(prefixStrings); dLen == 1 {
  37. description += prefixStrings[0]
  38. } else if dLen > 3 {
  39. description += "[" + strings.Join(prefixStrings[:3], " ") + "...]"
  40. } else {
  41. description += "[" + strings.Join(prefixStrings, " ") + "]"
  42. }
  43. ipSet, err := builder.IPSet()
  44. if err != nil {
  45. return nil, err
  46. }
  47. return &IPCIDRItem{
  48. ipSet: ipSet,
  49. isSource: isSource,
  50. description: description,
  51. }, nil
  52. }
  53. func NewRawIPCIDRItem(isSource bool, ipSet *netipx.IPSet) *IPCIDRItem {
  54. var description string
  55. if isSource {
  56. description = "source_ip_cidr="
  57. } else {
  58. description = "ip_cidr="
  59. }
  60. description += "<binary>"
  61. return &IPCIDRItem{
  62. ipSet: ipSet,
  63. isSource: isSource,
  64. description: description,
  65. }
  66. }
  67. func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
  68. if r.isSource || metadata.IPCIDRMatchSource {
  69. return r.ipSet.Contains(metadata.Source.Addr)
  70. }
  71. if metadata.Destination.IsIP() {
  72. return r.ipSet.Contains(metadata.Destination.Addr)
  73. }
  74. if len(metadata.DestinationAddresses) > 0 {
  75. for _, address := range metadata.DestinationAddresses {
  76. if r.ipSet.Contains(address) {
  77. return true
  78. }
  79. }
  80. return false
  81. }
  82. return metadata.IPCIDRAcceptEmpty
  83. }
  84. func (r *IPCIDRItem) String() string {
  85. return r.description
  86. }