mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-04-11 17:47:20 +10:00
Add Android support for MAC and hostname rule items
This commit is contained in:
@@ -144,6 +144,18 @@ func (s *platformInterfaceStub) SendNotification(notification *adapter.Notificat
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
|
||||
135
experimental/libbox/neighbor.go
Normal file
135
experimental/libbox/neighbor.go
Normal file
@@ -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
|
||||
}
|
||||
24
experimental/libbox/neighbor_stub.go
Normal file
24
experimental/libbox/neighbor_stub.go
Normal file
@@ -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
|
||||
ClearDNSCache()
|
||||
SendNotification(notification *Notification) error
|
||||
StartNeighborMonitor(listener NeighborUpdateListener) error
|
||||
CloseNeighborMonitor(listener NeighborUpdateListener) error
|
||||
}
|
||||
|
||||
type NeighborUpdateListener interface {
|
||||
UpdateNeighborTable(entries NeighborEntryIterator)
|
||||
}
|
||||
|
||||
type ConnectionOwner struct {
|
||||
|
||||
@@ -220,6 +220,43 @@ func (w *platformInterfaceWrapper) SendNotification(notification *adapter.Notifi
|
||||
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) {
|
||||
for port := int(startPort); ; port++ {
|
||||
if port > 65535 {
|
||||
|
||||
Reference in New Issue
Block a user