mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-03-03 20:27:31 +00:00
chore: support longest-prefix matches in local interface finding
This commit is contained in:
@@ -7,6 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/metacubex/mihomo/common/singledo"
|
||||
|
||||
"github.com/metacubex/bart"
|
||||
)
|
||||
|
||||
type Interface struct {
|
||||
@@ -23,16 +25,23 @@ var (
|
||||
ErrAddrNotFound = errors.New("addr not found")
|
||||
)
|
||||
|
||||
var interfaces = singledo.NewSingle[map[string]*Interface](time.Second * 20)
|
||||
type ifaceCache struct {
|
||||
ifMap map[string]*Interface
|
||||
ifTable bart.Table[*Interface]
|
||||
}
|
||||
|
||||
func Interfaces() (map[string]*Interface, error) {
|
||||
value, err, _ := interfaces.Do(func() (map[string]*Interface, error) {
|
||||
var caches = singledo.NewSingle[*ifaceCache](time.Second * 20)
|
||||
|
||||
func getCache() (*ifaceCache, error) {
|
||||
value, err, _ := caches.Do(func() (*ifaceCache, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r := map[string]*Interface{}
|
||||
cache := &ifaceCache{
|
||||
ifMap: make(map[string]*Interface),
|
||||
}
|
||||
|
||||
for _, iface := range ifaces {
|
||||
addrs, err := iface.Addrs()
|
||||
@@ -61,7 +70,7 @@ func Interfaces() (map[string]*Interface, error) {
|
||||
}
|
||||
}
|
||||
|
||||
r[iface.Name] = &Interface{
|
||||
ifaceObj := &Interface{
|
||||
Index: iface.Index,
|
||||
MTU: iface.MTU,
|
||||
Name: iface.Name,
|
||||
@@ -69,13 +78,26 @@ func Interfaces() (map[string]*Interface, error) {
|
||||
Flags: iface.Flags,
|
||||
Addresses: ipNets,
|
||||
}
|
||||
cache.ifMap[iface.Name] = ifaceObj
|
||||
|
||||
for _, prefix := range ipNets {
|
||||
cache.ifTable.Insert(prefix, ifaceObj)
|
||||
}
|
||||
}
|
||||
|
||||
return r, nil
|
||||
return cache, nil
|
||||
})
|
||||
return value, err
|
||||
}
|
||||
|
||||
func Interfaces() (map[string]*Interface, error) {
|
||||
cache, err := getCache()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return cache.ifMap, nil
|
||||
}
|
||||
|
||||
func ResolveInterface(name string) (*Interface, error) {
|
||||
ifaces, err := Interfaces()
|
||||
if err != nil {
|
||||
@@ -90,23 +112,29 @@ func ResolveInterface(name string) (*Interface, error) {
|
||||
return iface, nil
|
||||
}
|
||||
|
||||
func IsLocalIp(ip netip.Addr) (bool, error) {
|
||||
ifaces, err := Interfaces()
|
||||
func ResolveInterfaceByAddr(addr netip.Addr) (*Interface, error) {
|
||||
cache, err := getCache()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
iface, ok := cache.ifTable.Lookup(addr)
|
||||
if !ok {
|
||||
return nil, ErrIfaceNotFound
|
||||
}
|
||||
|
||||
return iface, nil
|
||||
}
|
||||
|
||||
func IsLocalIp(addr netip.Addr) (bool, error) {
|
||||
cache, err := getCache()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
for _, addr := range iface.Addresses {
|
||||
if addr.Contains(ip) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
return cache.ifTable.Contains(addr), nil
|
||||
}
|
||||
|
||||
func FlushCache() {
|
||||
interfaces.Reset()
|
||||
caches.Reset()
|
||||
}
|
||||
|
||||
func (iface *Interface) PickIPv4Addr(destination netip.Addr) (netip.Prefix, error) {
|
||||
|
||||
Reference in New Issue
Block a user