瀏覽代碼

Fix interface monitor for android

世界 2 年之前
父節點
當前提交
b498a22972

+ 1 - 0
adapter/router.go

@@ -32,6 +32,7 @@ type Router interface {
 	LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
 	LookupDefault(ctx context.Context, domain string) ([]netip.Addr, error)
 
 
 	InterfaceFinder() control.InterfaceFinder
 	InterfaceFinder() control.InterfaceFinder
+	UpdateInterfaces() error
 	DefaultInterface() string
 	DefaultInterface() string
 	AutoDetectInterface() bool
 	AutoDetectInterface() bool
 	AutoDetectInterfaceFunc() control.Func
 	AutoDetectInterfaceFunc() control.Func

+ 6 - 0
box.go

@@ -133,6 +133,12 @@ func New(options Options) (*Box, error) {
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
+	if options.PlatformInterface != nil {
+		err = options.PlatformInterface.Initialize(ctx, router)
+		if err != nil {
+			return nil, E.Cause(err, "initialize platform interface")
+		}
+	}
 	preServices := make(map[string]adapter.Service)
 	preServices := make(map[string]adapter.Service)
 	postServices := make(map[string]adapter.Service)
 	postServices := make(map[string]adapter.Service)
 	if needClashAPI {
 	if needClashAPI {

+ 16 - 0
experimental/libbox/iterator.go

@@ -29,3 +29,19 @@ func (i *iterator[T]) Next() T {
 func (i *iterator[T]) HasNext() bool {
 func (i *iterator[T]) HasNext() bool {
 	return len(i.values) > 0
 	return len(i.values) > 0
 }
 }
+
+type abstractIterator[T any] interface {
+	Next() T
+	HasNext() bool
+}
+
+func iteratorToArray[T any](iterator abstractIterator[T]) []T {
+	if iterator == nil {
+		return nil
+	}
+	var values []T
+	for iterator.HasNext() {
+		values = append(values, iterator.Next())
+	}
+	return values
+}

+ 183 - 0
experimental/libbox/monitor.go

@@ -0,0 +1,183 @@
+package libbox
+
+import (
+	"context"
+	"net"
+	"net/netip"
+	"sync"
+
+	"github.com/sagernet/sing-tun"
+	"github.com/sagernet/sing/common"
+	E "github.com/sagernet/sing/common/exceptions"
+	M "github.com/sagernet/sing/common/metadata"
+	"github.com/sagernet/sing/common/x/list"
+)
+
+var (
+	_ tun.DefaultInterfaceMonitor = (*platformDefaultInterfaceMonitor)(nil)
+	_ InterfaceUpdateListener     = (*platformDefaultInterfaceMonitor)(nil)
+)
+
+type platformDefaultInterfaceMonitor struct {
+	*platformInterfaceWrapper
+	errorHandler          E.Handler
+	networkAddresses      []networkAddress
+	defaultInterfaceName  string
+	defaultInterfaceIndex int
+	element               *list.Element[tun.NetworkUpdateCallback]
+	access                sync.Mutex
+	callbacks             list.List[tun.DefaultInterfaceUpdateCallback]
+}
+
+type networkAddress struct {
+	interfaceName  string
+	interfaceIndex int
+	addresses      []netip.Prefix
+}
+
+func (m *platformDefaultInterfaceMonitor) Start() error {
+	return m.iif.StartDefaultInterfaceMonitor(m)
+}
+
+func (m *platformDefaultInterfaceMonitor) Close() error {
+	return m.iif.CloseDefaultInterfaceMonitor(m)
+}
+
+func (m *platformDefaultInterfaceMonitor) DefaultInterfaceName(destination netip.Addr) string {
+	for _, address := range m.networkAddresses {
+		for _, prefix := range address.addresses {
+			if prefix.Contains(destination) {
+				return address.interfaceName
+			}
+		}
+	}
+	return m.defaultInterfaceName
+}
+
+func (m *platformDefaultInterfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
+	for _, address := range m.networkAddresses {
+		for _, prefix := range address.addresses {
+			if prefix.Contains(destination) {
+				return address.interfaceIndex
+			}
+		}
+	}
+	return m.defaultInterfaceIndex
+}
+
+func (m *platformDefaultInterfaceMonitor) OverrideAndroidVPN() bool {
+	return false
+}
+
+func (m *platformDefaultInterfaceMonitor) AndroidVPNEnabled() bool {
+	return false
+}
+
+func (m *platformDefaultInterfaceMonitor) RegisterCallback(callback tun.DefaultInterfaceUpdateCallback) *list.Element[tun.DefaultInterfaceUpdateCallback] {
+	m.access.Lock()
+	defer m.access.Unlock()
+	return m.callbacks.PushBack(callback)
+}
+
+func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
+	m.access.Lock()
+	defer m.access.Unlock()
+	m.callbacks.Remove(element)
+}
+
+func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32) {
+	var err error
+	if m.iif.UsePlatformInterfaceGetter() {
+		err = m.updateInterfacesPlatform()
+	} else {
+		err = m.updateInterfaces()
+	}
+	if err == nil {
+		err = m.router.UpdateInterfaces()
+	}
+	if err != nil {
+		m.errorHandler.NewError(context.Background(), E.Cause(err, "update interfaces"))
+	}
+	interfaceIndex := int(interfaceIndex32)
+	if interfaceName == "" {
+		for _, netIf := range m.networkAddresses {
+			if netIf.interfaceIndex == interfaceIndex {
+				interfaceName = netIf.interfaceName
+				break
+			}
+		}
+	} else if interfaceIndex == -1 {
+		for _, netIf := range m.networkAddresses {
+			if netIf.interfaceName == interfaceName {
+				interfaceIndex = netIf.interfaceIndex
+				break
+			}
+		}
+	}
+	if interfaceName == "" {
+		m.errorHandler.NewError(context.Background(), E.New("invalid interface name for ", interfaceIndex))
+		return
+	} else if interfaceIndex == -1 {
+		m.errorHandler.NewError(context.Background(), E.New("invalid interface index for ", interfaceName))
+		return
+	}
+	if m.defaultInterfaceName == interfaceName && m.defaultInterfaceIndex == interfaceIndex {
+		return
+	}
+	m.defaultInterfaceName = interfaceName
+	m.defaultInterfaceIndex = interfaceIndex
+	m.access.Lock()
+	callbacks := m.callbacks.Array()
+	m.access.Unlock()
+	for _, callback := range callbacks {
+		err = callback(tun.EventInterfaceUpdate)
+		if err != nil {
+			m.errorHandler.NewError(context.Background(), err)
+		}
+	}
+}
+
+func (m *platformDefaultInterfaceMonitor) updateInterfaces() error {
+	interfaces, err := net.Interfaces()
+	if err != nil {
+		return err
+	}
+	var addresses []networkAddress
+	for _, iif := range interfaces {
+		var netAddresses []net.Addr
+		netAddresses, err = iif.Addrs()
+		if err != nil {
+			return err
+		}
+		var address networkAddress
+		address.interfaceName = iif.Name
+		address.interfaceIndex = iif.Index
+		address.addresses = common.Map(common.FilterIsInstance(netAddresses, func(it net.Addr) (*net.IPNet, bool) {
+			value, loaded := it.(*net.IPNet)
+			return value, loaded
+		}), func(it *net.IPNet) netip.Prefix {
+			bits, _ := it.Mask.Size()
+			return netip.PrefixFrom(M.AddrFromIP(it.IP), bits)
+		})
+		addresses = append(addresses, address)
+	}
+	m.networkAddresses = addresses
+	return nil
+}
+
+func (m *platformDefaultInterfaceMonitor) updateInterfacesPlatform() error {
+	interfaces, err := m.Interfaces()
+	if err != nil {
+		return err
+	}
+	var addresses []networkAddress
+	for _, iif := range interfaces {
+		var address networkAddress
+		address.interfaceName = iif.Name
+		address.interfaceIndex = iif.Index
+		// address.addresses = common.Map(iif.Addresses, netip.MustParsePrefix)
+		addresses = append(addresses, address)
+	}
+	m.networkAddresses = addresses
+	return nil
+}

+ 26 - 3
experimental/libbox/platform.go

@@ -1,6 +1,8 @@
 package libbox
 package libbox
 
 
-import "github.com/sagernet/sing-box/option"
+import (
+	"github.com/sagernet/sing-box/option"
+)
 
 
 type PlatformInterface interface {
 type PlatformInterface interface {
 	AutoDetectInterfaceControl(fd int32) error
 	AutoDetectInterfaceControl(fd int32) error
@@ -10,6 +12,11 @@ type PlatformInterface interface {
 	FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
 	FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
 	PackageNameByUid(uid int32) (string, error)
 	PackageNameByUid(uid int32) (string, error)
 	UIDByPackageName(packageName string) (int32, error)
 	UIDByPackageName(packageName string) (int32, error)
+	UsePlatformDefaultInterfaceMonitor() bool
+	StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
+	CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
+	UsePlatformInterfaceGetter() bool
+	GetInterfaces() (NetworkInterfaceIterator, error)
 }
 }
 
 
 type TunInterface interface {
 type TunInterface interface {
@@ -17,8 +24,19 @@ type TunInterface interface {
 	Close() error
 	Close() error
 }
 }
 
 
-type OnDemandRuleIterator interface {
-	Next() OnDemandRule
+type InterfaceUpdateListener interface {
+	UpdateDefaultInterface(interfaceName string, interfaceIndex int32)
+}
+
+type NetworkInterface struct {
+	Index     int32
+	MTU       int32
+	Name      string
+	Addresses StringIterator
+}
+
+type NetworkInterfaceIterator interface {
+	Next() *NetworkInterface
 	HasNext() bool
 	HasNext() bool
 }
 }
 
 
@@ -31,6 +49,11 @@ type OnDemandRule interface {
 	ProbeURL() string
 	ProbeURL() string
 }
 }
 
 
+type OnDemandRuleIterator interface {
+	Next() OnDemandRule
+	HasNext() bool
+}
+
 type onDemandRule struct {
 type onDemandRule struct {
 	option.OnDemandRule
 	option.OnDemandRule
 }
 }

+ 16 - 0
experimental/libbox/platform/interface.go

@@ -1,17 +1,33 @@
 package platform
 package platform
 
 
 import (
 import (
+	"context"
 	"io"
 	"io"
+	"net/netip"
 
 
+	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-box/common/process"
 	"github.com/sagernet/sing-box/common/process"
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing-tun"
 	"github.com/sagernet/sing-tun"
 	"github.com/sagernet/sing/common/control"
 	"github.com/sagernet/sing/common/control"
+	E "github.com/sagernet/sing/common/exceptions"
 )
 )
 
 
 type Interface interface {
 type Interface interface {
+	Initialize(ctx context.Context, router adapter.Router) error
 	AutoDetectInterfaceControl() control.Func
 	AutoDetectInterfaceControl() control.Func
 	OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
 	OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
+	UsePlatformDefaultInterfaceMonitor() bool
+	CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor
+	UsePlatformInterfaceGetter() bool
+	Interfaces() ([]NetworkInterface, error)
 	process.Searcher
 	process.Searcher
 	io.Writer
 	io.Writer
 }
 }
+
+type NetworkInterface struct {
+	Index     int
+	MTU       int
+	Name      string
+	Addresses []netip.Prefix
+}

+ 42 - 1
experimental/libbox/service.go

@@ -6,11 +6,13 @@ import (
 	"syscall"
 	"syscall"
 
 
 	"github.com/sagernet/sing-box"
 	"github.com/sagernet/sing-box"
+	"github.com/sagernet/sing-box/adapter"
 	"github.com/sagernet/sing-box/common/process"
 	"github.com/sagernet/sing-box/common/process"
 	"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
 	"github.com/sagernet/sing-box/experimental/libbox/internal/procfs"
 	"github.com/sagernet/sing-box/experimental/libbox/platform"
 	"github.com/sagernet/sing-box/experimental/libbox/platform"
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing-box/option"
 	"github.com/sagernet/sing-tun"
 	"github.com/sagernet/sing-tun"
+	"github.com/sagernet/sing/common"
 	"github.com/sagernet/sing/common/control"
 	"github.com/sagernet/sing/common/control"
 	E "github.com/sagernet/sing/common/exceptions"
 	E "github.com/sagernet/sing/common/exceptions"
 	N "github.com/sagernet/sing/common/network"
 	N "github.com/sagernet/sing/common/network"
@@ -31,7 +33,7 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
 	instance, err := box.New(box.Options{
 	instance, err := box.New(box.Options{
 		Context:           ctx,
 		Context:           ctx,
 		Options:           options,
 		Options:           options,
-		PlatformInterface: &platformInterfaceWrapper{platformInterface, platformInterface.UseProcFS()},
+		PlatformInterface: &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()},
 	})
 	})
 	if err != nil {
 	if err != nil {
 		cancel()
 		cancel()
@@ -58,6 +60,12 @@ var _ platform.Interface = (*platformInterfaceWrapper)(nil)
 type platformInterfaceWrapper struct {
 type platformInterfaceWrapper struct {
 	iif       PlatformInterface
 	iif       PlatformInterface
 	useProcFS bool
 	useProcFS bool
+	router    adapter.Router
+}
+
+func (w *platformInterfaceWrapper) Initialize(ctx context.Context, router adapter.Router) error {
+	w.router = router
+	return nil
 }
 }
 
 
 func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
 func (w *platformInterfaceWrapper) AutoDetectInterfaceControl() control.Func {
@@ -122,3 +130,36 @@ func (w *platformInterfaceWrapper) FindProcessInfo(ctx context.Context, network
 	packageName, _ := w.iif.PackageNameByUid(uid)
 	packageName, _ := w.iif.PackageNameByUid(uid)
 	return &process.Info{UserId: uid, PackageName: packageName}, nil
 	return &process.Info{UserId: uid, PackageName: packageName}, nil
 }
 }
+
+func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
+	return w.iif.UsePlatformDefaultInterfaceMonitor()
+}
+
+func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(errorHandler E.Handler) tun.DefaultInterfaceMonitor {
+	return &platformDefaultInterfaceMonitor{
+		platformInterfaceWrapper: w,
+		errorHandler:             errorHandler,
+		defaultInterfaceIndex:    -1,
+	}
+}
+
+func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
+	return w.iif.UsePlatformInterfaceGetter()
+}
+
+func (w *platformInterfaceWrapper) Interfaces() ([]platform.NetworkInterface, error) {
+	interfaceIterator, err := w.iif.GetInterfaces()
+	if err != nil {
+		return nil, err
+	}
+	var interfaces []platform.NetworkInterface
+	for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
+		interfaces = append(interfaces, platform.NetworkInterface{
+			Index:     int(netInterface.Index),
+			MTU:       int(netInterface.MTU),
+			Name:      netInterface.Name,
+			Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
+		})
+	}
+	return interfaces, nil
+}

+ 8 - 4
route/interface_finder.go

@@ -9,7 +9,7 @@ import (
 var _ control.InterfaceFinder = (*myInterfaceFinder)(nil)
 var _ control.InterfaceFinder = (*myInterfaceFinder)(nil)
 
 
 type myInterfaceFinder struct {
 type myInterfaceFinder struct {
-	ifs []net.Interface
+	interfaces []net.Interface
 }
 }
 
 
 func (f *myInterfaceFinder) update() error {
 func (f *myInterfaceFinder) update() error {
@@ -17,12 +17,16 @@ func (f *myInterfaceFinder) update() error {
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	f.ifs = ifs
+	f.interfaces = ifs
 	return nil
 	return nil
 }
 }
 
 
+func (f *myInterfaceFinder) updateInterfaces(interfaces []net.Interface) {
+	f.interfaces = interfaces
+}
+
 func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex int, err error) {
 func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex int, err error) {
-	for _, netInterface := range f.ifs {
+	for _, netInterface := range f.interfaces {
 		if netInterface.Name == name {
 		if netInterface.Name == name {
 			return netInterface.Index, nil
 			return netInterface.Index, nil
 		}
 		}
@@ -36,7 +40,7 @@ func (f *myInterfaceFinder) InterfaceIndexByName(name string) (interfaceIndex in
 }
 }
 
 
 func (f *myInterfaceFinder) InterfaceNameByIndex(index int) (interfaceName string, err error) {
 func (f *myInterfaceFinder) InterfaceNameByIndex(index int) (interfaceName string, err error) {
-	for _, netInterface := range f.ifs {
+	for _, netInterface := range f.interfaces {
 		if netInterface.Index == index {
 		if netInterface.Index == index {
 			return netInterface.Name, nil
 			return netInterface.Name, nil
 		}
 		}

+ 43 - 20
route/router.go

@@ -269,27 +269,31 @@ func NewRouter(
 	router.transportMap = transportMap
 	router.transportMap = transportMap
 	router.transportDomainStrategy = transportDomainStrategy
 	router.transportDomainStrategy = transportDomainStrategy
 
 
+	usePlatformDefaultInterfaceMonitor := platformInterface != nil && platformInterface.UsePlatformDefaultInterfaceMonitor()
 	needInterfaceMonitor := options.AutoDetectInterface || common.Any(inbounds, func(inbound option.Inbound) bool {
 	needInterfaceMonitor := options.AutoDetectInterface || common.Any(inbounds, func(inbound option.Inbound) bool {
 		return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || inbound.TunOptions.AutoRoute
 		return inbound.HTTPOptions.SetSystemProxy || inbound.MixedOptions.SetSystemProxy || inbound.TunOptions.AutoRoute
 	})
 	})
 
 
 	if needInterfaceMonitor {
 	if needInterfaceMonitor {
-		networkMonitor, err := tun.NewNetworkUpdateMonitor(router)
-		if err == nil {
-			router.networkMonitor = networkMonitor
-			networkMonitor.RegisterCallback(router.interfaceFinder.update)
-		}
-	}
-
-	if router.networkMonitor != nil && needInterfaceMonitor {
-		interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, tun.DefaultInterfaceMonitorOptions{
-			OverrideAndroidVPN: options.OverrideAndroidVPN,
-		})
-		if err != nil {
-			return nil, E.New("auto_detect_interface unsupported on current platform")
+		if !usePlatformDefaultInterfaceMonitor {
+			networkMonitor, err := tun.NewNetworkUpdateMonitor(router)
+			if err == nil {
+				router.networkMonitor = networkMonitor
+				networkMonitor.RegisterCallback(router.interfaceFinder.update)
+			}
+			interfaceMonitor, err := tun.NewDefaultInterfaceMonitor(router.networkMonitor, tun.DefaultInterfaceMonitorOptions{
+				OverrideAndroidVPN: options.OverrideAndroidVPN,
+			})
+			if err != nil {
+				return nil, E.New("auto_detect_interface unsupported on current platform")
+			}
+			interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
+			router.interfaceMonitor = interfaceMonitor
+		} else {
+			interfaceMonitor := platformInterface.CreateDefaultInterfaceMonitor(router)
+			interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
+			router.interfaceMonitor = interfaceMonitor
 		}
 		}
-		interfaceMonitor.RegisterCallback(router.notifyNetworkUpdate)
-		router.interfaceMonitor = interfaceMonitor
 	}
 	}
 
 
 	needFindProcess := hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess
 	needFindProcess := hasRule(options.Rules, isProcessRule) || hasDNSRule(dnsOptions.Rules, isProcessDNSRule) || options.FindProcess
@@ -824,6 +828,25 @@ func (r *Router) InterfaceFinder() control.InterfaceFinder {
 	return &r.interfaceFinder
 	return &r.interfaceFinder
 }
 }
 
 
+func (r *Router) UpdateInterfaces() error {
+	if r.platformInterface == nil || !r.platformInterface.UsePlatformInterfaceGetter() {
+		return r.interfaceFinder.update()
+	} else {
+		interfaces, err := r.platformInterface.Interfaces()
+		if err != nil {
+			return err
+		}
+		r.interfaceFinder.updateInterfaces(common.Map(interfaces, func(it platform.NetworkInterface) net.Interface {
+			return net.Interface{
+				Name:  it.Name,
+				Index: it.Index,
+				MTU:   it.MTU,
+			}
+		}))
+		return nil
+	}
+}
+
 func (r *Router) AutoDetectInterface() bool {
 func (r *Router) AutoDetectInterface() bool {
 	return r.autoDetectInterface
 	return r.autoDetectInterface
 }
 }
@@ -1137,7 +1160,7 @@ func (r *Router) NewError(ctx context.Context, err error) {
 }
 }
 
 
 func (r *Router) notifyNetworkUpdate(int) error {
 func (r *Router) notifyNetworkUpdate(int) error {
-	if C.IsAndroid {
+	if C.IsAndroid && r.platformInterface == nil {
 		var vpnStatus string
 		var vpnStatus string
 		if r.interfaceMonitor.AndroidVPNEnabled() {
 		if r.interfaceMonitor.AndroidVPNEnabled() {
 			vpnStatus = "enabled"
 			vpnStatus = "enabled"
@@ -1149,6 +1172,10 @@ func (r *Router) notifyNetworkUpdate(int) error {
 		r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()))
 		r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()))
 	}
 	}
 
 
+	if conntrack.Enabled {
+		conntrack.Close()
+	}
+
 	for _, outbound := range r.outbounds {
 	for _, outbound := range r.outbounds {
 		listener, isListener := outbound.(adapter.InterfaceUpdateListener)
 		listener, isListener := outbound.(adapter.InterfaceUpdateListener)
 		if isListener {
 		if isListener {
@@ -1158,9 +1185,5 @@ func (r *Router) notifyNetworkUpdate(int) error {
 			}
 			}
 		}
 		}
 	}
 	}
-
-	if conntrack.Enabled {
-		conntrack.Close()
-	}
 	return nil
 	return nil
 }
 }

+ 1 - 1
transport/dhcp/server.go

@@ -119,7 +119,7 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
 func (t *Transport) fetchInterface() (*net.Interface, error) {
 func (t *Transport) fetchInterface() (*net.Interface, error) {
 	interfaceName := t.interfaceName
 	interfaceName := t.interfaceName
 	if t.autoInterface {
 	if t.autoInterface {
-		if t.router.NetworkMonitor() == nil {
+		if t.router.InterfaceMonitor() == nil {
 			return nil, E.New("missing monitor for auto DHCP, set route.auto_detect_interface")
 			return nil, E.New("missing monitor for auto DHCP, set route.auto_detect_interface")
 		}
 		}
 		interfaceName = t.router.InterfaceMonitor().DefaultInterfaceName(netip.Addr{})
 		interfaceName = t.router.InterfaceMonitor().DefaultInterfaceName(netip.Addr{})