sing-box/route/rule/rule_network_interface_address.go
2025-08-14 14:24:58 +08:00

65 lines
2.1 KiB
Go

package rule
import (
"net/netip"
"strings"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/json/badjson"
"github.com/sagernet/sing/common/json/badoption"
)
var _ RuleItem = (*NetworkInterfaceAddressItem)(nil)
type NetworkInterfaceAddressItem struct {
networkManager adapter.NetworkManager
interfaceAddresses map[C.InterfaceType][]netip.Prefix
description string
}
func NewNetworkInterfaceAddressItem(networkManager adapter.NetworkManager, interfaceAddresses *badjson.TypedMap[option.InterfaceType, badoption.Listable[badoption.Prefixable]]) *NetworkInterfaceAddressItem {
item := &NetworkInterfaceAddressItem{
networkManager: networkManager,
interfaceAddresses: make(map[C.InterfaceType][]netip.Prefix, interfaceAddresses.Size()),
}
var entryDescriptions []string
for _, entry := range interfaceAddresses.Entries() {
prefixes := make([]netip.Prefix, 0, len(entry.Value))
for _, prefixable := range entry.Value {
prefixes = append(prefixes, prefixable.Build(netip.Prefix{}))
}
item.interfaceAddresses[entry.Key.Build()] = prefixes
entryDescriptions = append(entryDescriptions, entry.Key.Build().String()+"="+strings.Join(common.Map(prefixes, netip.Prefix.String), ","))
}
item.description = "network_interface_address=[" + strings.Join(entryDescriptions, " ") + "]"
return item
}
func (r *NetworkInterfaceAddressItem) Match(metadata *adapter.InboundContext) bool {
interfaces := r.networkManager.NetworkInterfaces()
match:
for ifType, addresses := range r.interfaceAddresses {
for _, networkInterface := range interfaces {
if networkInterface.Type != ifType {
continue
}
if common.Any(networkInterface.Addresses, func(it netip.Prefix) bool {
return common.Any(addresses, func(prefix netip.Prefix) bool {
return prefix.Overlaps(it)
})
}) {
continue match
}
}
return false
}
return true
}
func (r *NetworkInterfaceAddressItem) String() string {
return r.description
}