rule_interface_address.go 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. package rule
  2. import (
  3. "net/netip"
  4. "strings"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing/common"
  7. "github.com/sagernet/sing/common/control"
  8. "github.com/sagernet/sing/common/json/badjson"
  9. "github.com/sagernet/sing/common/json/badoption"
  10. )
  11. var _ RuleItem = (*InterfaceAddressItem)(nil)
  12. type InterfaceAddressItem struct {
  13. networkManager adapter.NetworkManager
  14. interfaceAddresses map[string][]netip.Prefix
  15. description string
  16. }
  17. func NewInterfaceAddressItem(networkManager adapter.NetworkManager, interfaceAddresses *badjson.TypedMap[string, badoption.Listable[*badoption.Prefixable]]) *InterfaceAddressItem {
  18. item := &InterfaceAddressItem{
  19. networkManager: networkManager,
  20. interfaceAddresses: make(map[string][]netip.Prefix, interfaceAddresses.Size()),
  21. }
  22. var entryDescriptions []string
  23. for _, entry := range interfaceAddresses.Entries() {
  24. prefixes := make([]netip.Prefix, 0, len(entry.Value))
  25. for _, prefixable := range entry.Value {
  26. prefixes = append(prefixes, prefixable.Build(netip.Prefix{}))
  27. }
  28. item.interfaceAddresses[entry.Key] = prefixes
  29. entryDescriptions = append(entryDescriptions, entry.Key+"="+strings.Join(common.Map(prefixes, netip.Prefix.String), ","))
  30. }
  31. item.description = "interface_address=[" + strings.Join(entryDescriptions, " ") + "]"
  32. return item
  33. }
  34. func (r *InterfaceAddressItem) Match(metadata *adapter.InboundContext) bool {
  35. interfaces := r.networkManager.InterfaceFinder().Interfaces()
  36. for ifName, addresses := range r.interfaceAddresses {
  37. iface := common.Find(interfaces, func(it control.Interface) bool {
  38. return it.Name == ifName
  39. })
  40. if iface.Name == "" {
  41. return false
  42. }
  43. if common.All(addresses, func(address netip.Prefix) bool {
  44. return common.All(iface.Addresses, func(it netip.Prefix) bool {
  45. return !address.Overlaps(it)
  46. })
  47. }) {
  48. return false
  49. }
  50. }
  51. return true
  52. }
  53. func (r *InterfaceAddressItem) String() string {
  54. return r.description
  55. }