refactor: Platform Interfaces

This commit is contained in:
世界 2024-11-11 16:23:45 +08:00
parent ac115e4f42
commit 99a9637b32
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
15 changed files with 264 additions and 248 deletions

View file

@ -9,6 +9,8 @@ type NetworkManager interface {
Lifecycle
InterfaceFinder() control.InterfaceFinder
UpdateInterfaces() error
DefaultNetworkInterface() *NetworkInterface
NetworkInterfaces() []NetworkInterface
DefaultInterface() string
AutoDetectInterface() bool
AutoDetectInterfaceFunc() control.Func
@ -21,3 +23,20 @@ type NetworkManager interface {
WIFIState() WIFIState
ResetNetwork()
}
type InterfaceUpdateListener interface {
InterfaceUpdated()
}
type WIFIState struct {
SSID string
BSSID string
}
type NetworkInterface struct {
control.Interface
Type string
DNSServers []string
Expensive bool
Constrained bool
}

View file

@ -119,12 +119,3 @@ func (c *HTTPStartContext) Close() {
client.CloseIdleConnections()
}
}
type InterfaceUpdateListener interface {
InterfaceUpdated()
}
type WIFIState struct {
SSID string
BSSID string
}

View file

@ -2,7 +2,6 @@ package settings
import (
"context"
"net/netip"
"strconv"
"strings"
@ -77,14 +76,14 @@ func (p *DarwinSystemProxy) update(event int) {
}
func (p *DarwinSystemProxy) update0() error {
newInterfaceName := p.monitor.DefaultInterfaceName(netip.IPv4Unspecified())
if p.interfaceName == newInterfaceName {
newInterface := p.monitor.DefaultInterface()
if p.interfaceName == newInterface.Name {
return nil
}
if p.interfaceName != "" {
_ = p.Disable()
}
p.interfaceName = newInterfaceName
p.interfaceName = newInterface.Name
interfaceDisplayName, err := getInterfaceDisplayName(p.interfaceName)
if err != nil {
return err

8
constant/network.go Normal file
View file

@ -0,0 +1,8 @@
package constant
const (
InterfaceTypeWIFI = "wifi"
InterfaceTypeCellular = "cellular"
InterfaceTypeEthernet = "ethernet"
InterfaceTypeOther = "other"
)

View file

@ -6,7 +6,7 @@ import (
const IsAndroid = goos.IsAndroid == 1
const IsDarwin = goos.IsDarwin == 1
const IsDarwin = goos.IsDarwin == 1 || goos.IsIos == 1
const IsDragonfly = goos.IsDragonfly == 1

View file

@ -74,11 +74,7 @@ func (s *platformInterfaceStub) CreateDefaultInterfaceMonitor(logger logger.Logg
return (*interfaceMonitorStub)(nil)
}
func (s *platformInterfaceStub) UsePlatformInterfaceGetter() bool {
return true
}
func (s *platformInterfaceStub) Interfaces() ([]control.Interface, error) {
func (s *platformInterfaceStub) Interfaces() ([]adapter.NetworkInterface, error) {
return nil, os.ErrInvalid
}
@ -111,16 +107,8 @@ func (s *interfaceMonitorStub) Close() error {
return os.ErrInvalid
}
func (s *interfaceMonitorStub) DefaultInterfaceName(destination netip.Addr) string {
return ""
}
func (s *interfaceMonitorStub) DefaultInterfaceIndex(destination netip.Addr) int {
return -1
}
func (s *interfaceMonitorStub) DefaultInterface(destination netip.Addr) (string, int) {
return "", -1
func (s *interfaceMonitorStub) DefaultInterface() *control.Interface {
return nil
}
func (s *interfaceMonitorStub) OverrideAndroidVPN() bool {

View file

@ -1,4 +1,4 @@
//go:build !linux
//go:build !unix
package libbox

View file

@ -1,3 +1,5 @@
//go:build unix
package libbox
import (

View file

@ -1,15 +1,10 @@
package libbox
import (
"net"
"net/netip"
"sync"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/x/list"
)
@ -20,19 +15,9 @@ var (
type platformDefaultInterfaceMonitor struct {
*platformInterfaceWrapper
networkAddresses []networkAddress
defaultInterfaceName string
defaultInterfaceIndex int
element *list.Element[tun.NetworkUpdateCallback]
access sync.Mutex
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
logger logger.Logger
}
type networkAddress struct {
interfaceName string
interfaceIndex int
addresses []netip.Prefix
element *list.Element[tun.NetworkUpdateCallback]
callbacks list.List[tun.DefaultInterfaceUpdateCallback]
logger logger.Logger
}
func (m *platformDefaultInterfaceMonitor) Start() error {
@ -43,37 +28,10 @@ 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) DefaultInterface(destination netip.Addr) (string, int) {
for _, address := range m.networkAddresses {
for _, prefix := range address.addresses {
if prefix.Contains(destination) {
return address.interfaceName, address.interfaceIndex
}
}
}
return m.defaultInterfaceName, m.defaultInterfaceIndex
func (m *platformDefaultInterfaceMonitor) DefaultInterface() *control.Interface {
m.defaultInterfaceAccess.Lock()
defer m.defaultInterfaceAccess.Unlock()
return m.defaultInterface
}
func (m *platformDefaultInterfaceMonitor) OverrideAndroidVPN() bool {
@ -85,96 +43,49 @@ func (m *platformDefaultInterfaceMonitor) AndroidVPNEnabled() bool {
}
func (m *platformDefaultInterfaceMonitor) RegisterCallback(callback tun.DefaultInterfaceUpdateCallback) *list.Element[tun.DefaultInterfaceUpdateCallback] {
m.access.Lock()
defer m.access.Unlock()
m.defaultInterfaceAccess.Lock()
defer m.defaultInterfaceAccess.Unlock()
return m.callbacks.PushBack(callback)
}
func (m *platformDefaultInterfaceMonitor) UnregisterCallback(element *list.Element[tun.DefaultInterfaceUpdateCallback]) {
m.access.Lock()
defer m.access.Unlock()
m.defaultInterfaceAccess.Lock()
defer m.defaultInterfaceAccess.Unlock()
m.callbacks.Remove(element)
}
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32) {
if interfaceName == "" || interfaceIndex32 == -1 {
m.defaultInterfaceName = ""
m.defaultInterfaceIndex = -1
m.access.Lock()
callbacks := m.callbacks.Array()
m.access.Unlock()
for _, callback := range callbacks {
callback(tun.EventNoRoute)
}
return
}
var err error
if m.iif.UsePlatformInterfaceGetter() {
err = m.updateInterfacesPlatform()
} else {
err = m.updateInterfaces()
}
if err == nil {
err = m.networkManager.UpdateInterfaces()
}
func (m *platformDefaultInterfaceMonitor) UpdateDefaultInterface(interfaceName string, interfaceIndex32 int32, isExpensive bool, isConstrained bool) {
m.isExpensive = isExpensive
m.isConstrained = isConstrained
err := m.networkManager.UpdateInterfaces()
if err != nil {
m.logger.Error(E.Cause(err, "update interfaces"))
}
interfaceIndex := int(interfaceIndex32)
if m.defaultInterfaceName == interfaceName && m.defaultInterfaceIndex == interfaceIndex {
m.defaultInterfaceAccess.Lock()
if interfaceIndex32 == -1 {
m.defaultInterface = nil
callbacks := m.callbacks.Array()
m.defaultInterfaceAccess.Unlock()
for _, callback := range callbacks {
callback(tun.EventInterfaceUpdate)
}
return
}
oldInterface := m.defaultInterface
newInterface, err := m.networkManager.InterfaceFinder().ByIndex(int(interfaceIndex32))
if err != nil {
m.defaultInterfaceAccess.Unlock()
m.logger.Error(E.Cause(err, "find updated interface: ", interfaceName))
return
}
m.defaultInterface = newInterface
if oldInterface != nil && oldInterface.Name == m.defaultInterface.Name && oldInterface.Index == m.defaultInterface.Index {
m.defaultInterfaceAccess.Unlock()
return
}
m.defaultInterfaceName = interfaceName
m.defaultInterfaceIndex = interfaceIndex
m.access.Lock()
callbacks := m.callbacks.Array()
m.access.Unlock()
m.defaultInterfaceAccess.Unlock()
for _, callback := range callbacks {
callback(tun.EventInterfaceUpdate)
}
}
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
}

View file

@ -1,6 +1,7 @@
package libbox
import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/option"
)
@ -13,10 +14,8 @@ type PlatformInterface interface {
FindConnectionOwner(ipProtocol int32, sourceAddress string, sourcePort int32, destinationAddress string, destinationPort int32) (int32, error)
PackageNameByUid(uid int32) (string, error)
UIDByPackageName(packageName string) (int32, error)
UsePlatformDefaultInterfaceMonitor() bool
StartDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
CloseDefaultInterfaceMonitor(listener InterfaceUpdateListener) error
UsePlatformInterfaceGetter() bool
GetInterfaces() (NetworkInterfaceIterator, error)
UnderNetworkExtension() bool
IncludeAllNetworks() bool
@ -31,15 +30,26 @@ type TunInterface interface {
}
type InterfaceUpdateListener interface {
UpdateDefaultInterface(interfaceName string, interfaceIndex int32)
UpdateDefaultInterface(interfaceName string, interfaceIndex int32, isExpensive bool, isConstrained bool)
}
const (
InterfaceTypeWIFI = C.InterfaceTypeWIFI
InterfaceTypeCellular = C.InterfaceTypeCellular
InterfaceTypeEthernet = C.InterfaceTypeEthernet
InterfaceTypeOther = C.InterfaceTypeOther
)
type NetworkInterface struct {
Index int32
MTU int32
Name string
Addresses StringIterator
Flags int32
Type string
DNSServer StringIterator
Metered bool
}
type WIFIState struct {

View file

@ -5,7 +5,6 @@ import (
"github.com/sagernet/sing-box/common/process"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common/control"
"github.com/sagernet/sing/common/logger"
)
@ -14,10 +13,8 @@ type Interface interface {
UsePlatformAutoDetectInterfaceControl() bool
AutoDetectInterfaceControl(fd int) error
OpenTun(options *tun.Options, platformOptions option.TunPlatformOptions) (tun.Tun, error)
UsePlatformDefaultInterfaceMonitor() bool
CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor
UsePlatformInterfaceGetter() bool
Interfaces() ([]control.Interface, error)
Interfaces() ([]adapter.NetworkInterface, error)
UnderNetworkExtension() bool
IncludeAllNetworks() bool
ClearDNSCache()

View file

@ -6,6 +6,7 @@ import (
"os"
"runtime"
runtimeDebug "runtime/debug"
"sync"
"syscall"
"time"
@ -54,7 +55,10 @@ func NewService(configContent string, platformInterface PlatformInterface) (*Box
ctx, cancel := context.WithCancel(ctx)
urlTestHistoryStorage := urltest.NewHistoryStorage()
ctx = service.ContextWithPtr(ctx, urlTestHistoryStorage)
platformWrapper := &platformInterfaceWrapper{iif: platformInterface, useProcFS: platformInterface.UseProcFS()}
platformWrapper := &platformInterfaceWrapper{
iif: platformInterface,
useProcFS: platformInterface.UseProcFS(),
}
service.MustRegister[platform.Interface](ctx, platformWrapper)
instance, err := box.New(box.Options{
Context: ctx,
@ -106,9 +110,14 @@ var (
)
type platformInterfaceWrapper struct {
iif PlatformInterface
useProcFS bool
networkManager adapter.NetworkManager
iif PlatformInterface
useProcFS bool
networkManager adapter.NetworkManager
myTunName string
defaultInterfaceAccess sync.Mutex
defaultInterface *control.Interface
isExpensive bool
isConstrained bool
}
func (w *platformInterfaceWrapper) Initialize(networkManager adapter.NetworkManager) error {
@ -148,38 +157,42 @@ func (w *platformInterfaceWrapper) OpenTun(options *tun.Options, platformOptions
return nil, E.Cause(err, "dup tun file descriptor")
}
options.FileDescriptor = dupFd
w.myTunName = options.Name
return tun.New(*options)
}
func (w *platformInterfaceWrapper) UsePlatformDefaultInterfaceMonitor() bool {
return w.iif.UsePlatformDefaultInterfaceMonitor()
}
func (w *platformInterfaceWrapper) CreateDefaultInterfaceMonitor(logger logger.Logger) tun.DefaultInterfaceMonitor {
return &platformDefaultInterfaceMonitor{
platformInterfaceWrapper: w,
defaultInterfaceIndex: -1,
logger: logger,
}
}
func (w *platformInterfaceWrapper) UsePlatformInterfaceGetter() bool {
return w.iif.UsePlatformInterfaceGetter()
}
func (w *platformInterfaceWrapper) Interfaces() ([]control.Interface, error) {
func (w *platformInterfaceWrapper) Interfaces() ([]adapter.NetworkInterface, error) {
interfaceIterator, err := w.iif.GetInterfaces()
if err != nil {
return nil, err
}
var interfaces []control.Interface
var interfaces []adapter.NetworkInterface
for _, netInterface := range iteratorToArray[*NetworkInterface](interfaceIterator) {
interfaces = append(interfaces, control.Interface{
Index: int(netInterface.Index),
MTU: int(netInterface.MTU),
Name: netInterface.Name,
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
Flags: linkFlags(uint32(netInterface.Flags)),
if netInterface.Name == w.myTunName {
continue
}
w.defaultInterfaceAccess.Lock()
isDefault := w.defaultInterface != nil && int(netInterface.Index) == w.defaultInterface.Index
w.defaultInterfaceAccess.Unlock()
interfaces = append(interfaces, adapter.NetworkInterface{
Interface: control.Interface{
Index: int(netInterface.Index),
MTU: int(netInterface.MTU),
Name: netInterface.Name,
Addresses: common.Map(iteratorToArray[string](netInterface.Addresses), netip.MustParsePrefix),
Flags: linkFlags(uint32(netInterface.Flags)),
},
Type: netInterface.Type,
DNSServers: iteratorToArray[string](netInterface.DNSServer),
Expensive: netInterface.Metered || isDefault && w.isExpensive,
Constrained: isDefault && w.isConstrained,
})
}
return interfaces, nil

View file

@ -33,7 +33,7 @@ func (l *loopBackDetector) NewConn(conn net.Conn) net.Conn {
}
if udpConn, isUDPConn := conn.(abstractUDPConn); isUDPConn {
if !source.Addr().IsLoopback() {
_, err := l.networkManager.InterfaceFinder().InterfaceByAddr(source.Addr())
_, err := l.networkManager.InterfaceFinder().ByAddr(source.Addr())
if err != nil {
return conn
}
@ -59,7 +59,7 @@ func (l *loopBackDetector) NewPacketConn(conn N.NetPacketConn, destination M.Soc
return conn
}
if !source.Addr().IsLoopback() {
_, err := l.networkManager.InterfaceFinder().InterfaceByAddr(source.Addr())
_, err := l.networkManager.InterfaceFinder().ByAddr(source.Addr())
if err != nil {
return conn
}
@ -82,7 +82,7 @@ func (l *loopBackDetector) CheckPacketConn(source netip.AddrPort, local netip.Ad
return false
}
if !source.Addr().IsLoopback() {
_, err := l.networkManager.InterfaceFinder().InterfaceByAddr(source.Addr())
_, err := l.networkManager.InterfaceFinder().ByAddr(source.Addr())
if err != nil {
return false
}

View file

@ -3,9 +3,10 @@ package route
import (
"context"
"errors"
"net/netip"
"net"
"os"
"runtime"
"strings"
"syscall"
"github.com/sagernet/sing-box/adapter"
@ -15,33 +16,41 @@ import (
"github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-tun"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/atomic"
"github.com/sagernet/sing/common/control"
E "github.com/sagernet/sing/common/exceptions"
F "github.com/sagernet/sing/common/format"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/winpowrprof"
"github.com/sagernet/sing/service"
"github.com/sagernet/sing/service/pause"
"golang.org/x/exp/slices"
)
var _ adapter.NetworkManager = (*NetworkManager)(nil)
type NetworkManager struct {
logger logger.ContextLogger
interfaceFinder *control.DefaultInterfaceFinder
logger logger.ContextLogger
interfaceFinder *control.DefaultInterfaceFinder
networkInterfaces atomic.TypedValue[[]adapter.NetworkInterface]
autoDetectInterface bool
defaultInterface string
defaultMark uint32
autoRedirectOutputMark uint32
networkMonitor tun.NetworkUpdateMonitor
interfaceMonitor tun.DefaultInterfaceMonitor
packageManager tun.PackageManager
powerListener winpowrprof.EventListener
pauseManager pause.Manager
platformInterface platform.Interface
outboundManager adapter.OutboundManager
wifiState adapter.WIFIState
started bool
networkMonitor tun.NetworkUpdateMonitor
interfaceMonitor tun.DefaultInterfaceMonitor
packageManager tun.PackageManager
powerListener winpowrprof.EventListener
pauseManager pause.Manager
platformInterface platform.Interface
outboundManager adapter.OutboundManager
wifiState adapter.WIFIState
started bool
}
func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOptions option.RouteOptions) (*NetworkManager, error) {
@ -55,7 +64,7 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, routeOp
platformInterface: service.FromContext[platform.Interface](ctx),
outboundManager: service.FromContext[adapter.OutboundManager](ctx),
}
usePlatformDefaultInterfaceMonitor := nm.platformInterface != nil && nm.platformInterface.UsePlatformDefaultInterfaceMonitor()
usePlatformDefaultInterfaceMonitor := nm.platformInterface != nil
enforceInterfaceMonitor := routeOptions.AutoDetectInterface
if !usePlatformDefaultInterfaceMonitor {
networkMonitor, err := tun.NewNetworkUpdateMonitor(logger)
@ -90,17 +99,17 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
monitor := taskmonitor.New(r.logger, C.StartTimeout)
switch stage {
case adapter.StartStateInitialize:
if r.interfaceMonitor != nil {
monitor.Start("initialize interface monitor")
err := r.interfaceMonitor.Start()
if r.networkMonitor != nil {
monitor.Start("initialize network monitor")
err := r.networkMonitor.Start()
monitor.Finish()
if err != nil {
return err
}
}
if r.networkMonitor != nil {
monitor.Start("initialize network monitor")
err := r.networkMonitor.Start()
if r.interfaceMonitor != nil {
monitor.Start("initialize interface monitor")
err := r.interfaceMonitor.Start()
monitor.Finish()
if err != nil {
return err
@ -151,20 +160,6 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
func (r *NetworkManager) Close() error {
monitor := taskmonitor.New(r.logger, C.StopTimeout)
var err error
if r.interfaceMonitor != nil {
monitor.Start("close interface monitor")
err = E.Append(err, r.interfaceMonitor.Close(), func(err error) error {
return E.Cause(err, "close interface monitor")
})
monitor.Finish()
}
if r.networkMonitor != nil {
monitor.Start("close network monitor")
err = E.Append(err, r.networkMonitor.Close(), func(err error) error {
return E.Cause(err, "close network monitor")
})
monitor.Finish()
}
if r.packageManager != nil {
monitor.Start("close package manager")
err = E.Append(err, r.packageManager.Close(), func(err error) error {
@ -179,6 +174,20 @@ func (r *NetworkManager) Close() error {
})
monitor.Finish()
}
if r.interfaceMonitor != nil {
monitor.Start("close interface monitor")
err = E.Append(err, r.interfaceMonitor.Close(), func(err error) error {
return E.Cause(err, "close interface monitor")
})
monitor.Finish()
}
if r.networkMonitor != nil {
monitor.Start("close network monitor")
err = E.Append(err, r.networkMonitor.Close(), func(err error) error {
return E.Cause(err, "close network monitor")
})
monitor.Finish()
}
return nil
}
@ -187,18 +196,75 @@ func (r *NetworkManager) InterfaceFinder() control.InterfaceFinder {
}
func (r *NetworkManager) UpdateInterfaces() error {
if r.platformInterface == nil || !r.platformInterface.UsePlatformInterfaceGetter() {
if r.platformInterface == nil {
return r.interfaceFinder.Update()
} else {
interfaces, err := r.platformInterface.Interfaces()
if err != nil {
return err
}
r.interfaceFinder.UpdateInterfaces(interfaces)
if C.IsDarwin {
err = r.interfaceFinder.Update()
if err != nil {
return err
}
// NEInterface only provides name,index and type
interfaces = common.Map(interfaces, func(it adapter.NetworkInterface) adapter.NetworkInterface {
iif, _ := r.interfaceFinder.ByIndex(it.Index)
if iif != nil {
it.Interface = *iif
}
return it
})
} else {
r.interfaceFinder.UpdateInterfaces(common.Map(interfaces, func(it adapter.NetworkInterface) control.Interface { return it.Interface }))
}
oldInterfaces := r.networkInterfaces.Load()
newInterfaces := common.Filter(interfaces, func(it adapter.NetworkInterface) bool {
return it.Flags&net.FlagUp != 0
})
r.networkInterfaces.Store(newInterfaces)
if !slices.EqualFunc(oldInterfaces, newInterfaces, func(oldInterface adapter.NetworkInterface, newInterface adapter.NetworkInterface) bool {
return oldInterface.Interface.Index == newInterface.Interface.Index &&
oldInterface.Interface.Name == newInterface.Interface.Name &&
oldInterface.Interface.Flags == newInterface.Interface.Flags &&
oldInterface.Type == newInterface.Type &&
oldInterface.Expensive == newInterface.Expensive &&
oldInterface.Constrained == newInterface.Constrained
}) {
r.logger.Info("updated available networks: ", strings.Join(common.Map(newInterfaces, func(it adapter.NetworkInterface) string {
var options []string
options = append(options, F.ToString(it.Type))
if it.Expensive {
options = append(options, "expensive")
}
if it.Constrained {
options = append(options, "constrained")
}
return F.ToString(it.Name, " (", strings.Join(options, ", "), ")")
}), ", "))
}
return nil
}
}
func (r *NetworkManager) DefaultNetworkInterface() *adapter.NetworkInterface {
iif := r.interfaceMonitor.DefaultInterface()
if iif == nil {
return nil
}
for _, it := range r.networkInterfaces.Load() {
if it.Interface.Index == iif.Index {
return &it
}
}
return &adapter.NetworkInterface{Interface: *iif}
}
func (r *NetworkManager) NetworkInterfaces() []adapter.NetworkInterface {
return r.networkInterfaces.Load()
}
func (r *NetworkManager) DefaultInterface() string {
return r.defaultInterface
}
@ -220,18 +286,17 @@ func (r *NetworkManager) AutoDetectInterfaceFunc() control.Func {
}
return control.BindToInterfaceFunc(r.interfaceFinder, func(network string, address string) (interfaceName string, interfaceIndex int, err error) {
remoteAddr := M.ParseSocksaddr(address).Addr
if C.IsLinux {
interfaceName, interfaceIndex = r.interfaceMonitor.DefaultInterface(remoteAddr)
if interfaceIndex == -1 {
err = tun.ErrNoRoute
}
} else {
interfaceIndex = r.interfaceMonitor.DefaultInterfaceIndex(remoteAddr)
if interfaceIndex == -1 {
err = tun.ErrNoRoute
if remoteAddr.IsValid() {
iif, err := r.interfaceFinder.ByAddr(remoteAddr)
if err == nil {
return iif.Name, iif.Index, nil
}
}
return
defaultInterface := r.interfaceMonitor.DefaultInterface()
if defaultInterface == nil {
return "", -1, tun.ErrNoRoute
}
return defaultInterface.Name, defaultInterface.Index, nil
})
}
}
@ -285,6 +350,12 @@ func (r *NetworkManager) notifyNetworkUpdate(event int) {
r.logger.Error("missing default interface")
} else {
r.pauseManager.NetworkWake()
defaultInterface := r.DefaultNetworkInterface()
if defaultInterface == nil {
panic("invalid interface context")
}
var options []string
options = append(options, F.ToString("index ", defaultInterface.Index))
if C.IsAndroid && r.platformInterface == nil {
var vpnStatus string
if r.interfaceMonitor.AndroidVPNEnabled() {
@ -292,17 +363,24 @@ func (r *NetworkManager) notifyNetworkUpdate(event int) {
} else {
vpnStatus = "disabled"
}
r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()), ", vpn ", vpnStatus)
options = append(options, "vpn "+vpnStatus)
} else {
r.logger.Info("updated default interface ", r.interfaceMonitor.DefaultInterfaceName(netip.IPv4Unspecified()), ", index ", r.interfaceMonitor.DefaultInterfaceIndex(netip.IPv4Unspecified()))
if defaultInterface.Type != "" {
options = append(options, F.ToString("type ", defaultInterface.Type))
}
if defaultInterface.Expensive {
options = append(options, "expensive")
}
if defaultInterface.Constrained {
options = append(options, "constrained")
}
}
r.logger.Info("updated default interface ", defaultInterface.Name, ", ", strings.Join(options, ", "))
if r.platformInterface != nil {
state := r.platformInterface.ReadWIFIState()
if state != r.wifiState {
r.wifiState = state
if state.SSID == "" && state.BSSID == "" {
r.logger.Info("updated WIFI state: disconnected")
} else {
if state.SSID != "" {
r.logger.Info("updated WIFI state: SSID=", state.SSID, ", BSSID=", state.BSSID)
}
}
@ -312,7 +390,6 @@ func (r *NetworkManager) notifyNetworkUpdate(event int) {
if !r.started {
return
}
r.ResetNetwork()
}

View file

@ -119,18 +119,19 @@ func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg,
return nil, err
}
func (t *Transport) fetchInterface() (*net.Interface, error) {
interfaceName := t.interfaceName
func (t *Transport) fetchInterface() (*control.Interface, error) {
if t.autoInterface {
if t.networkManager.InterfaceMonitor() == nil {
return nil, E.New("missing monitor for auto DHCP, set route.auto_detect_interface")
}
interfaceName = t.networkManager.InterfaceMonitor().DefaultInterfaceName(netip.Addr{})
defaultInterface := t.networkManager.InterfaceMonitor().DefaultInterface()
if defaultInterface == nil {
return nil, E.New("missing default interface")
}
return defaultInterface, nil
} else {
return t.networkManager.InterfaceFinder().ByName(t.interfaceName)
}
if interfaceName == "" {
return nil, E.New("missing default interface")
}
return net.InterfaceByName(interfaceName)
}
func (t *Transport) fetchServers() error {
@ -172,7 +173,7 @@ func (t *Transport) interfaceUpdated(int) {
}
}
func (t *Transport) fetchServers0(ctx context.Context, iface *net.Interface) error {
func (t *Transport) fetchServers0(ctx context.Context, iface *control.Interface) error {
var listener net.ListenConfig
listener.Control = control.Append(listener.Control, control.BindToInterface(t.networkManager.InterfaceFinder(), iface.Name, iface.Index))
listener.Control = control.Append(listener.Control, control.ReuseAddr())
@ -206,7 +207,7 @@ func (t *Transport) fetchServers0(ctx context.Context, iface *net.Interface) err
return group.Run(ctx)
}
func (t *Transport) fetchServersResponse(iface *net.Interface, packetConn net.PacketConn, transactionID dhcpv4.TransactionID) error {
func (t *Transport) fetchServersResponse(iface *control.Interface, packetConn net.PacketConn, transactionID dhcpv4.TransactionID) error {
buffer := buf.NewSize(dhcpv4.MaxMessageSize)
defer buffer.Release()
@ -246,7 +247,7 @@ func (t *Transport) fetchServersResponse(iface *net.Interface, packetConn net.Pa
}
}
func (t *Transport) recreateServers(iface *net.Interface, serverAddrs []netip.Addr) error {
func (t *Transport) recreateServers(iface *control.Interface, serverAddrs []netip.Addr) error {
if len(serverAddrs) > 0 {
t.options.Logger.Info("dhcp: updated DNS servers from ", iface.Name, ": [", strings.Join(common.Map(serverAddrs, func(it netip.Addr) string {
return it.String()