mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-04-03 20:07:36 +03:00
refactor: Platform Interfaces
This commit is contained in:
parent
9afe75586a
commit
ecf82d197c
15 changed files with 267 additions and 251 deletions
179
route/network.go
179
route/network.go
|
@ -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)
|
||||
|
@ -87,17 +96,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
|
||||
|
@ -148,20 +157,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 {
|
||||
|
@ -176,6 +171,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
|
||||
}
|
||||
|
||||
|
@ -184,18 +193,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 len(newInterfaces) > 0 && !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
|
||||
}
|
||||
|
@ -217,18 +283,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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -282,6 +347,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() {
|
||||
|
@ -289,17 +360,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)
|
||||
}
|
||||
}
|
||||
|
@ -309,7 +387,6 @@ func (r *NetworkManager) notifyNetworkUpdate(event int) {
|
|||
if !r.started {
|
||||
return
|
||||
}
|
||||
|
||||
r.ResetNetwork()
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue