package route import ( "net" "net/netip" "sync" "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing/common/logger" ) type platformNeighborResolver struct { logger logger.ContextLogger platform adapter.PlatformInterface access sync.RWMutex ipToMAC map[netip.Addr]net.HardwareAddr ipToHostname map[netip.Addr]string macToHostname map[string]string } func newPlatformNeighborResolver(resolverLogger logger.ContextLogger, platform adapter.PlatformInterface) adapter.NeighborResolver { return &platformNeighborResolver{ logger: resolverLogger, platform: platform, ipToMAC: make(map[netip.Addr]net.HardwareAddr), ipToHostname: make(map[netip.Addr]string), macToHostname: make(map[string]string), } } func (r *platformNeighborResolver) Start() error { return r.platform.StartNeighborMonitor(r) } func (r *platformNeighborResolver) Close() error { return r.platform.CloseNeighborMonitor(r) } func (r *platformNeighborResolver) LookupMAC(address netip.Addr) (net.HardwareAddr, bool) { r.access.RLock() defer r.access.RUnlock() mac, found := r.ipToMAC[address] if found { return mac, true } return extractMACFromEUI64(address) } func (r *platformNeighborResolver) LookupAddresses(hostname string) []netip.Addr { r.access.RLock() defer r.access.RUnlock() return lookupAddressesByHostname(hostname, r.ipToHostname, r.macToHostname, r.ipToMAC) } func (r *platformNeighborResolver) LookupHostname(address netip.Addr) (string, bool) { r.access.RLock() defer r.access.RUnlock() hostname, found := r.ipToHostname[address] if found { return hostname, true } mac, found := r.ipToMAC[address] if !found { mac, found = extractMACFromEUI64(address) } if !found { return "", false } hostname, found = r.macToHostname[mac.String()] return hostname, found } func (r *platformNeighborResolver) UpdateNeighborTable(entries []adapter.NeighborEntry) { ipToMAC := make(map[netip.Addr]net.HardwareAddr) ipToHostname := make(map[netip.Addr]string) macToHostname := make(map[string]string) for _, entry := range entries { ipToMAC[entry.Address] = entry.MACAddress if entry.Hostname != "" { ipToHostname[entry.Address] = entry.Hostname macToHostname[entry.MACAddress.String()] = entry.Hostname } } r.access.Lock() r.ipToMAC = ipToMAC r.ipToHostname = ipToHostname r.macToHostname = macToHostname r.access.Unlock() r.logger.Info("updated neighbor table: ", len(entries), " entries") }