Add Android support for MAC and hostname rule items
This commit is contained in:
@@ -5,9 +5,19 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type NeighborEntry struct {
|
||||||
|
Address netip.Addr
|
||||||
|
MACAddress net.HardwareAddr
|
||||||
|
Hostname string
|
||||||
|
}
|
||||||
|
|
||||||
type NeighborResolver interface {
|
type NeighborResolver interface {
|
||||||
LookupMAC(address netip.Addr) (net.HardwareAddr, bool)
|
LookupMAC(address netip.Addr) (net.HardwareAddr, bool)
|
||||||
LookupHostname(address netip.Addr) (string, bool)
|
LookupHostname(address netip.Addr) (string, bool)
|
||||||
Start() error
|
Start() error
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NeighborUpdateListener interface {
|
||||||
|
UpdateNeighborTable(entries []NeighborEntry)
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ type PlatformInterface interface {
|
|||||||
|
|
||||||
UsePlatformNotification() bool
|
UsePlatformNotification() bool
|
||||||
SendNotification(notification *Notification) error
|
SendNotification(notification *Notification) error
|
||||||
|
|
||||||
|
UsePlatformNeighborResolver() bool
|
||||||
|
StartNeighborMonitor(listener NeighborUpdateListener) error
|
||||||
|
CloseNeighborMonitor(listener NeighborUpdateListener) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type FindConnectionOwnerRequest struct {
|
type FindConnectionOwnerRequest struct {
|
||||||
|
|||||||
@@ -144,6 +144,18 @@ func (s *platformInterfaceStub) SendNotification(notification *adapter.Notificat
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *platformInterfaceStub) UsePlatformNeighborResolver() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *platformInterfaceStub) StartNeighborMonitor(listener adapter.NeighborUpdateListener) error {
|
||||||
|
return os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *platformInterfaceStub) CloseNeighborMonitor(listener adapter.NeighborUpdateListener) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *platformInterfaceStub) UsePlatformLocalDNSTransport() bool {
|
func (s *platformInterfaceStub) UsePlatformLocalDNSTransport() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,135 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/route"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
|
"github.com/mdlayher/netlink"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NeighborEntry struct {
|
||||||
|
Address string
|
||||||
|
MACAddress string
|
||||||
|
Hostname string
|
||||||
|
}
|
||||||
|
|
||||||
|
type NeighborEntryIterator interface {
|
||||||
|
Next() *NeighborEntry
|
||||||
|
HasNext() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type NeighborSubscription struct {
|
||||||
|
done chan struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func SubscribeNeighborTable(listener NeighborUpdateListener) (*NeighborSubscription, error) {
|
||||||
|
entries, err := route.ReadNeighborEntries()
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "initial neighbor dump")
|
||||||
|
}
|
||||||
|
table := make(map[netip.Addr]net.HardwareAddr)
|
||||||
|
for _, entry := range entries {
|
||||||
|
table[entry.Address] = entry.MACAddress
|
||||||
|
}
|
||||||
|
listener.UpdateNeighborTable(tableToIterator(table))
|
||||||
|
connection, err := netlink.Dial(unix.NETLINK_ROUTE, &netlink.Config{
|
||||||
|
Groups: 1 << (unix.RTNLGRP_NEIGH - 1),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "subscribe neighbor updates")
|
||||||
|
}
|
||||||
|
subscription := &NeighborSubscription{
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
go subscription.loop(listener, connection, table)
|
||||||
|
return subscription, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NeighborSubscription) Close() {
|
||||||
|
close(s.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NeighborSubscription) loop(listener NeighborUpdateListener, connection *netlink.Conn, table map[netip.Addr]net.HardwareAddr) {
|
||||||
|
defer connection.Close()
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
err := connection.SetReadDeadline(time.Now().Add(3 * time.Second))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messages, err := connection.Receive()
|
||||||
|
if err != nil {
|
||||||
|
if nerr, ok := err.(net.Error); ok && nerr.Timeout() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-s.done:
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
changed := false
|
||||||
|
for _, message := range messages {
|
||||||
|
address, mac, isDelete, ok := route.ParseNeighborMessage(message)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if isDelete {
|
||||||
|
if _, exists := table[address]; exists {
|
||||||
|
delete(table, address)
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
existing, exists := table[address]
|
||||||
|
if !exists || !slices.Equal(existing, mac) {
|
||||||
|
table[address] = mac
|
||||||
|
changed = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if changed {
|
||||||
|
listener.UpdateNeighborTable(tableToIterator(table))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableToIterator(table map[netip.Addr]net.HardwareAddr) NeighborEntryIterator {
|
||||||
|
entries := make([]*NeighborEntry, 0, len(table))
|
||||||
|
for address, mac := range table {
|
||||||
|
entries = append(entries, &NeighborEntry{
|
||||||
|
Address: address.String(),
|
||||||
|
MACAddress: mac.String(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return &neighborEntryIterator{entries}
|
||||||
|
}
|
||||||
|
|
||||||
|
type neighborEntryIterator struct {
|
||||||
|
entries []*NeighborEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *neighborEntryIterator) HasNext() bool {
|
||||||
|
return len(i.entries) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *neighborEntryIterator) Next() *NeighborEntry {
|
||||||
|
if len(i.entries) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
entry := i.entries[0]
|
||||||
|
i.entries = i.entries[1:]
|
||||||
|
return entry
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//go:build !linux
|
||||||
|
|
||||||
|
package libbox
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type NeighborEntry struct {
|
||||||
|
Address string
|
||||||
|
MACAddress string
|
||||||
|
Hostname string
|
||||||
|
}
|
||||||
|
|
||||||
|
type NeighborEntryIterator interface {
|
||||||
|
Next() *NeighborEntry
|
||||||
|
HasNext() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type NeighborSubscription struct{}
|
||||||
|
|
||||||
|
func SubscribeNeighborTable(listener NeighborUpdateListener) (*NeighborSubscription, error) {
|
||||||
|
return nil, os.ErrInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *NeighborSubscription) Close() {}
|
||||||
@@ -21,6 +21,12 @@ type PlatformInterface interface {
|
|||||||
SystemCertificates() StringIterator
|
SystemCertificates() StringIterator
|
||||||
ClearDNSCache()
|
ClearDNSCache()
|
||||||
SendNotification(notification *Notification) error
|
SendNotification(notification *Notification) error
|
||||||
|
StartNeighborMonitor(listener NeighborUpdateListener) error
|
||||||
|
CloseNeighborMonitor(listener NeighborUpdateListener) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type NeighborUpdateListener interface {
|
||||||
|
UpdateNeighborTable(entries NeighborEntryIterator)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectionOwner struct {
|
type ConnectionOwner struct {
|
||||||
|
|||||||
@@ -220,6 +220,43 @@ func (w *platformInterfaceWrapper) SendNotification(notification *adapter.Notifi
|
|||||||
return w.iif.SendNotification((*Notification)(notification))
|
return w.iif.SendNotification((*Notification)(notification))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) UsePlatformNeighborResolver() bool {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) StartNeighborMonitor(listener adapter.NeighborUpdateListener) error {
|
||||||
|
return w.iif.StartNeighborMonitor(&neighborUpdateListenerWrapper{listener: listener})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *platformInterfaceWrapper) CloseNeighborMonitor(listener adapter.NeighborUpdateListener) error {
|
||||||
|
return w.iif.CloseNeighborMonitor(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
type neighborUpdateListenerWrapper struct {
|
||||||
|
listener adapter.NeighborUpdateListener
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *neighborUpdateListenerWrapper) UpdateNeighborTable(entries NeighborEntryIterator) {
|
||||||
|
var result []adapter.NeighborEntry
|
||||||
|
for entries.HasNext() {
|
||||||
|
entry := entries.Next()
|
||||||
|
address, err := netip.ParseAddr(entry.Address)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
macAddress, err := net.ParseMAC(entry.MACAddress)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result = append(result, adapter.NeighborEntry{
|
||||||
|
Address: address,
|
||||||
|
MACAddress: macAddress,
|
||||||
|
Hostname: entry.Hostname,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
w.listener.UpdateNeighborTable(result)
|
||||||
|
}
|
||||||
|
|
||||||
func AvailablePort(startPort int32) (int32, error) {
|
func AvailablePort(startPort int32) (int32, error) {
|
||||||
for port := int(startPort); ; port++ {
|
for port := int(startPort); ; port++ {
|
||||||
if port > 65535 {
|
if port > 65535 {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ package route
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/binary"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
@@ -204,43 +203,17 @@ func (r *neighborResolver) subscribeNeighborUpdates() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, message := range messages {
|
for _, message := range messages {
|
||||||
switch message.Header.Type {
|
address, mac, isDelete, ok := ParseNeighborMessage(message)
|
||||||
case unix.RTM_NEWNEIGH:
|
if !ok {
|
||||||
var neighMessage rtnetlink.NeighMessage
|
continue
|
||||||
unmarshalErr := neighMessage.UnmarshalBinary(message.Data)
|
|
||||||
if unmarshalErr != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if neighMessage.Attributes == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if neighMessage.Attributes.LLAddress == nil || len(neighMessage.Attributes.Address) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
address, ok := netip.AddrFromSlice(neighMessage.Attributes.Address)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r.access.Lock()
|
|
||||||
r.neighborIPToMAC[address] = slices.Clone(neighMessage.Attributes.LLAddress)
|
|
||||||
r.access.Unlock()
|
|
||||||
case unix.RTM_DELNEIGH:
|
|
||||||
var neighMessage rtnetlink.NeighMessage
|
|
||||||
unmarshalErr := neighMessage.UnmarshalBinary(message.Data)
|
|
||||||
if unmarshalErr != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if neighMessage.Attributes == nil || len(neighMessage.Attributes.Address) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
address, ok := netip.AddrFromSlice(neighMessage.Attributes.Address)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
r.access.Lock()
|
|
||||||
delete(r.neighborIPToMAC, address)
|
|
||||||
r.access.Unlock()
|
|
||||||
}
|
}
|
||||||
|
r.access.Lock()
|
||||||
|
if isDelete {
|
||||||
|
delete(r.neighborIPToMAC, address)
|
||||||
|
} else {
|
||||||
|
r.neighborIPToMAC[address] = mac
|
||||||
|
}
|
||||||
|
r.access.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -554,43 +527,3 @@ func (r *neighborResolver) parseKeaCSV6(file *os.File, ipToMAC map[netip.Addr]ne
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractMACFromDUID(duid []byte) (net.HardwareAddr, bool) {
|
|
||||||
if len(duid) < 4 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
duidType := binary.BigEndian.Uint16(duid[0:2])
|
|
||||||
hwType := binary.BigEndian.Uint16(duid[2:4])
|
|
||||||
if hwType != 1 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
switch duidType {
|
|
||||||
case 1:
|
|
||||||
if len(duid) < 14 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return net.HardwareAddr(slices.Clone(duid[8:14])), true
|
|
||||||
case 3:
|
|
||||||
if len(duid) < 10 {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return net.HardwareAddr(slices.Clone(duid[4:10])), true
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func extractMACFromEUI64(address netip.Addr) (net.HardwareAddr, bool) {
|
|
||||||
if !address.Is6() {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
b := address.As16()
|
|
||||||
if b[11] != 0xff || b[12] != 0xfe {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
return net.HardwareAddr{b[8] ^ 0x02, b[9], b[10], b[13], b[14], b[15]}, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseDUID(s string) ([]byte, error) {
|
|
||||||
cleaned := strings.ReplaceAll(s, ":", "")
|
|
||||||
return hex.DecodeString(cleaned)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/hex"
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func extractMACFromDUID(duid []byte) (net.HardwareAddr, bool) {
|
||||||
|
if len(duid) < 4 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
duidType := binary.BigEndian.Uint16(duid[0:2])
|
||||||
|
hwType := binary.BigEndian.Uint16(duid[2:4])
|
||||||
|
if hwType != 1 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
switch duidType {
|
||||||
|
case 1:
|
||||||
|
if len(duid) < 14 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return net.HardwareAddr(slices.Clone(duid[8:14])), true
|
||||||
|
case 3:
|
||||||
|
if len(duid) < 10 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return net.HardwareAddr(slices.Clone(duid[4:10])), true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractMACFromEUI64(address netip.Addr) (net.HardwareAddr, bool) {
|
||||||
|
if !address.Is6() {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
b := address.As16()
|
||||||
|
if b[11] != 0xff || b[12] != 0xfe {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
return net.HardwareAddr{b[8] ^ 0x02, b[9], b[10], b[13], b[14], b[15]}, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseDUID(s string) ([]byte, error) {
|
||||||
|
cleaned := strings.ReplaceAll(s, ":", "")
|
||||||
|
return hex.DecodeString(cleaned)
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
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) 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")
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package route
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"net/netip"
|
||||||
|
"slices"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing-box/adapter"
|
||||||
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
|
||||||
|
"github.com/jsimonetti/rtnetlink"
|
||||||
|
"github.com/mdlayher/netlink"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReadNeighborEntries() ([]adapter.NeighborEntry, error) {
|
||||||
|
connection, err := rtnetlink.Dial(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "dial rtnetlink")
|
||||||
|
}
|
||||||
|
defer connection.Close()
|
||||||
|
neighbors, err := connection.Neigh.List()
|
||||||
|
if err != nil {
|
||||||
|
return nil, E.Cause(err, "list neighbors")
|
||||||
|
}
|
||||||
|
var entries []adapter.NeighborEntry
|
||||||
|
for _, neighbor := range neighbors {
|
||||||
|
if neighbor.Attributes == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if neighbor.Attributes.LLAddress == nil || len(neighbor.Attributes.Address) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
address, ok := netip.AddrFromSlice(neighbor.Attributes.Address)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
entries = append(entries, adapter.NeighborEntry{
|
||||||
|
Address: address,
|
||||||
|
MACAddress: slices.Clone(neighbor.Attributes.LLAddress),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return entries, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseNeighborMessage(message netlink.Message) (address netip.Addr, macAddress net.HardwareAddr, isDelete bool, ok bool) {
|
||||||
|
var neighMessage rtnetlink.NeighMessage
|
||||||
|
err := neighMessage.UnmarshalBinary(message.Data)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if neighMessage.Attributes == nil || len(neighMessage.Attributes.Address) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
address, ok = netip.AddrFromSlice(neighMessage.Attributes.Address)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
isDelete = message.Header.Type == unix.RTM_DELNEIGH
|
||||||
|
if !isDelete && neighMessage.Attributes.LLAddress == nil {
|
||||||
|
ok = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
macAddress = slices.Clone(neighMessage.Attributes.LLAddress)
|
||||||
|
return
|
||||||
|
}
|
||||||
+23
-10
@@ -159,21 +159,34 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
|||||||
}
|
}
|
||||||
r.needFindNeighbor = needFindNeighbor
|
r.needFindNeighbor = needFindNeighbor
|
||||||
if needFindNeighbor {
|
if needFindNeighbor {
|
||||||
monitor.Start("initialize neighbor resolver")
|
if r.platformInterface != nil && r.platformInterface.UsePlatformNeighborResolver() {
|
||||||
resolver, err := newNeighborResolver(r.logger, r.leaseFiles)
|
monitor.Start("initialize neighbor resolver")
|
||||||
monitor.Finish()
|
resolver := newPlatformNeighborResolver(r.logger, r.platformInterface)
|
||||||
if err != nil {
|
err := resolver.Start()
|
||||||
if err != os.ErrInvalid {
|
monitor.Finish()
|
||||||
r.logger.Warn(E.Cause(err, "create neighbor resolver"))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
err = resolver.Start()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
r.logger.Warn(E.Cause(err, "start neighbor resolver"))
|
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||||
} else {
|
} else {
|
||||||
r.neighborResolver = resolver
|
r.neighborResolver = resolver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if r.neighborResolver == nil {
|
||||||
|
monitor.Start("initialize neighbor resolver")
|
||||||
|
resolver, err := newNeighborResolver(r.logger, r.leaseFiles)
|
||||||
|
monitor.Finish()
|
||||||
|
if err != nil {
|
||||||
|
if err != os.ErrInvalid {
|
||||||
|
r.logger.Error(E.Cause(err, "create neighbor resolver"))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = resolver.Start()
|
||||||
|
if err != nil {
|
||||||
|
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||||
|
} else {
|
||||||
|
r.neighborResolver = resolver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case adapter.StartStatePostStart:
|
case adapter.StartStatePostStart:
|
||||||
for i, rule := range r.rules {
|
for i, rule := range r.rules {
|
||||||
|
|||||||
Reference in New Issue
Block a user