rule_cidr.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package route
  2. import (
  3. "net/netip"
  4. "strings"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing/common"
  7. E "github.com/sagernet/sing/common/exceptions"
  8. F "github.com/sagernet/sing/common/format"
  9. )
  10. var _ RuleItem = (*IPCIDRItem)(nil)
  11. type IPCIDRItem struct {
  12. prefixes []netip.Prefix
  13. isSource bool
  14. }
  15. func NewIPCIDRItem(isSource bool, prefixStrings []string) (*IPCIDRItem, error) {
  16. prefixes := make([]netip.Prefix, 0, len(prefixStrings))
  17. for i, prefixString := range prefixStrings {
  18. prefix, err := netip.ParsePrefix(prefixString)
  19. if err != nil {
  20. return nil, E.Cause(err, "parse prefix [", i, "]")
  21. }
  22. prefixes = append(prefixes, prefix)
  23. }
  24. return &IPCIDRItem{
  25. prefixes: prefixes,
  26. isSource: isSource,
  27. }, nil
  28. }
  29. func (r *IPCIDRItem) Match(metadata *adapter.InboundContext) bool {
  30. if r.isSource {
  31. for _, prefix := range r.prefixes {
  32. if prefix.Contains(metadata.Source.Addr) {
  33. return true
  34. }
  35. }
  36. } else {
  37. if metadata.Destination.IsFqdn() {
  38. return false
  39. }
  40. for _, prefix := range r.prefixes {
  41. if prefix.Contains(metadata.Destination.Addr) {
  42. return true
  43. }
  44. }
  45. }
  46. return false
  47. }
  48. func (r *IPCIDRItem) String() string {
  49. var description string
  50. if r.isSource {
  51. description = "source_ipcidr="
  52. } else {
  53. description = "ipcidr="
  54. }
  55. pLen := len(r.prefixes)
  56. if pLen == 1 {
  57. description += r.prefixes[0].String()
  58. } else {
  59. description += "[" + strings.Join(common.Map(r.prefixes, F.ToString0[netip.Prefix]), " ") + "]"
  60. }
  61. return description
  62. }