From 0ba0bd50902943b6a004de9a1bed9093374a5cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Mon, 7 Aug 2023 19:17:36 +0800 Subject: [PATCH] Fix monitor --- go.mod | 2 +- go.sum | 4 +-- monitor.go | 11 ++++--- monitor_darwin.go | 75 +++++++++++++++++++++++----------------------- monitor_linux.go | 20 ++++++------- monitor_other.go | 4 +-- monitor_shared.go | 29 +++++++----------- monitor_windows.go | 6 ++-- tun.go | 2 ++ tun_linux.go | 9 +++--- 10 files changed, 78 insertions(+), 84 deletions(-) diff --git a/go.mod b/go.mod index 580a84e..8c679e1 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.9 + github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 golang.org/x/net v0.12.0 golang.org/x/sys v0.10.0 diff --git a/go.sum b/go.sum index 659cb62..5ef8dd7 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,8 @@ github.com/sagernet/gvisor v0.0.0-20230627031050-1ab0276e0dd2/go.mod h1:1JUiV7nG github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.9 h1:3wsTz+JG5Wzy65eZnh6AuCrD2QqcRF6Iq6f7ttmJsAo= -github.com/sagernet/sing v0.2.9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4= +github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= diff --git a/monitor.go b/monitor.go index 327eff5..b424256 100644 --- a/monitor.go +++ b/monitor.go @@ -10,14 +10,14 @@ import ( var ErrNoRoute = E.New("no route to internet") type ( - NetworkUpdateCallback = func() error - DefaultInterfaceUpdateCallback = func(event int) error + NetworkUpdateCallback = func() + DefaultInterfaceUpdateCallback = func(event int) ) const ( - EventInterfaceUpdate = iota - EventAndroidVPNUpdate - EventNoRoute + EventInterfaceUpdate = 1 + EventAndroidVPNUpdate = 2 + EventNoRoute = 4 ) type NetworkUpdateMonitor interface { @@ -25,7 +25,6 @@ type NetworkUpdateMonitor interface { Close() error RegisterCallback(callback NetworkUpdateCallback) *list.Element[NetworkUpdateCallback] UnregisterCallback(element *list.Element[NetworkUpdateCallback]) - E.Handler } type DefaultInterfaceMonitor interface { diff --git a/monitor_darwin.go b/monitor_darwin.go index 1df1f21..9455ac3 100644 --- a/monitor_darwin.go +++ b/monitor_darwin.go @@ -1,16 +1,15 @@ package tun import ( - "context" "net" "net/netip" "os" "sync" - "syscall" "time" - "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/x/list" "golang.org/x/net/route" @@ -18,61 +17,63 @@ import ( ) type networkUpdateMonitor struct { - errorHandler E.Handler - access sync.Mutex callbacks list.List[NetworkUpdateCallback] - routeSocket *os.File + routeSocket int + logger logger.Logger } -func NewNetworkUpdateMonitor(errorHandler E.Handler) (NetworkUpdateMonitor, error) { - return &networkUpdateMonitor{ - errorHandler: errorHandler, - }, nil +func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) { + return &networkUpdateMonitor{logger: logger}, nil } func (m *networkUpdateMonitor) Start() error { - routeSocket, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0) - if err != nil { - return err + go m.loopUpdate() + return nil +} + +func (m *networkUpdateMonitor) loopUpdate() { + for { + err := m.loopUpdate0() + if err != nil { + m.logger.Error("listen network update: ", err) + return + } } - err = unix.SetNonblock(routeSocket, true) +} + +func (m *networkUpdateMonitor) loopUpdate0() error { + routeSocket, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0) if err != nil { return err } - m.routeSocket = os.NewFile(uintptr(routeSocket), "route") - go m.loopUpdate() + m.loopUpdate1(os.NewFile(uintptr(routeSocket), "route")) return nil } -func (m *networkUpdateMonitor) loopUpdate() { - rawConn, err := m.routeSocket.SyscallConn() +func (m *networkUpdateMonitor) loopUpdate1(routeSocketFile *os.File) { + defer routeSocketFile.Close() + buffer := buf.NewPacket() + defer buffer.Release() + n, err := routeSocketFile.Read(buffer.FreeBytes()) if err != nil { - m.errorHandler.NewError(context.Background(), E.Cause(err, "create raw route connection")) return } - for { - var innerErr error - err = rawConn.Read(func(fd uintptr) (done bool) { - var msg [2048]byte - _, innerErr = unix.Read(int(fd), msg[:]) - return innerErr != unix.EWOULDBLOCK - }) - if innerErr != nil { - err = innerErr - } - if err != nil { - break - } - m.emit() + buffer.Truncate(n) + messages, err := route.ParseRIB(route.RIBTypeRoute, buffer.Bytes()) + if err != nil { + return } - if err != syscall.EAGAIN { - m.errorHandler.NewError(context.Background(), E.Cause(err, "read route message")) + for _, message := range messages { + if _, isRouteMessage := message.(*route.RouteMessage); isRouteMessage { + m.emit() + return + } } } func (m *networkUpdateMonitor) Close() error { - return common.Close(common.PtrOrNil(m.routeSocket)) + return unix.Close(m.routeSocket) } func (m *defaultInterfaceMonitor) checkUpdate() error { @@ -116,7 +117,7 @@ func (m *defaultInterfaceMonitor) checkUpdate() error { continue } if routeMessage.Flags&unix.RTF_IFSCOPE != 0 { - continue + // continue } defaultInterface = routeInterface break diff --git a/monitor_linux.go b/monitor_linux.go index 32f4537..50885d9 100644 --- a/monitor_linux.go +++ b/monitor_linux.go @@ -5,26 +5,26 @@ import ( "sync" "github.com/sagernet/netlink" - E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/x/list" ) type networkUpdateMonitor struct { - routeUpdate chan netlink.RouteUpdate - linkUpdate chan netlink.LinkUpdate - close chan struct{} - errorHandler E.Handler + routeUpdate chan netlink.RouteUpdate + linkUpdate chan netlink.LinkUpdate + close chan struct{} access sync.Mutex callbacks list.List[NetworkUpdateCallback] + logger logger.Logger } -func NewNetworkUpdateMonitor(errorHandler E.Handler) (NetworkUpdateMonitor, error) { +func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) { return &networkUpdateMonitor{ - routeUpdate: make(chan netlink.RouteUpdate, 2), - linkUpdate: make(chan netlink.LinkUpdate, 2), - close: make(chan struct{}), - errorHandler: errorHandler, + routeUpdate: make(chan netlink.RouteUpdate, 2), + linkUpdate: make(chan netlink.LinkUpdate, 2), + close: make(chan struct{}), + logger: logger, }, nil } diff --git a/monitor_other.go b/monitor_other.go index 388c219..d031a57 100644 --- a/monitor_other.go +++ b/monitor_other.go @@ -4,11 +4,9 @@ package tun import ( "os" - - E "github.com/sagernet/sing/common/exceptions" ) -func NewNetworkUpdateMonitor(errorHandler E.Handler) (NetworkUpdateMonitor, error) { +func NewNetworkUpdateMonitor() (NetworkUpdateMonitor, error) { return nil, os.ErrInvalid } diff --git a/monitor_shared.go b/monitor_shared.go index f6460d4..35abf6e 100644 --- a/monitor_shared.go +++ b/monitor_shared.go @@ -3,7 +3,6 @@ package tun import ( - "context" "errors" "net" "net/netip" @@ -11,7 +10,7 @@ import ( "time" "github.com/sagernet/sing/common" - 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" ) @@ -33,17 +32,10 @@ func (m *networkUpdateMonitor) emit() { callbacks := m.callbacks.Array() m.access.Unlock() for _, callback := range callbacks { - err := callback() - if err != nil { - m.NewError(context.Background(), err) - } + callback() } } -func (m *networkUpdateMonitor) NewError(ctx context.Context, err error) { - m.errorHandler.NewError(ctx, err) -} - type defaultInterfaceMonitor struct { options DefaultInterfaceMonitorOptions networkAddresses []networkAddress @@ -54,6 +46,7 @@ type defaultInterfaceMonitor struct { element *list.Element[NetworkUpdateCallback] access sync.Mutex callbacks list.List[DefaultInterfaceUpdateCallback] + logger logger.Logger } type networkAddress struct { @@ -62,34 +55,35 @@ type networkAddress struct { addresses []netip.Prefix } -func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) { +func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, logger logger.Logger, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) { return &defaultInterfaceMonitor{ options: options, networkMonitor: networkMonitor, defaultInterfaceIndex: -1, + logger: logger, }, nil } func (m *defaultInterfaceMonitor) Start() error { err := m.checkUpdate() if err != nil { - m.networkMonitor.NewError(context.Background(), err) + m.logger.Error("initialize default interface: ", err) } m.element = m.networkMonitor.RegisterCallback(m.delayCheckUpdate) return nil } -func (m *defaultInterfaceMonitor) delayCheckUpdate() error { +func (m *defaultInterfaceMonitor) delayCheckUpdate() { time.Sleep(time.Second) err := m.updateInterfaces() if err != nil { - m.networkMonitor.NewError(context.Background(), E.Cause(err, "update interfaces")) + m.logger.Error("update interfaces: ", err) } err = m.checkUpdate() if errors.Is(err, ErrNoRoute) { + m.defaultInterfaceIndex = -1 m.emit(EventNoRoute) } - return err } func (m *defaultInterfaceMonitor) updateInterfaces() error { @@ -180,9 +174,6 @@ func (m *defaultInterfaceMonitor) emit(event int) { callbacks := m.callbacks.Array() m.access.Unlock() for _, callback := range callbacks { - err := callback(event) - if err != nil { - m.networkMonitor.NewError(context.Background(), err) - } + callback(event) } } diff --git a/monitor_windows.go b/monitor_windows.go index db36d9e..8bd0be4 100644 --- a/monitor_windows.go +++ b/monitor_windows.go @@ -5,6 +5,7 @@ import ( "github.com/sagernet/sing-tun/internal/winipcfg" E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" "github.com/sagernet/sing/common/x/list" "golang.org/x/sys/windows" @@ -17,11 +18,12 @@ type networkUpdateMonitor struct { access sync.Mutex callbacks list.List[NetworkUpdateCallback] + logger logger.Logger } -func NewNetworkUpdateMonitor(errorHandler E.Handler) (NetworkUpdateMonitor, error) { +func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) { return &networkUpdateMonitor{ - errorHandler: errorHandler, + logger: logger, }, nil } diff --git a/tun.go b/tun.go index 57df563..2784339 100644 --- a/tun.go +++ b/tun.go @@ -10,6 +10,7 @@ import ( E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" + "github.com/sagernet/sing/common/logger" N "github.com/sagernet/sing/common/network" "github.com/sagernet/sing/common/ranges" ) @@ -47,6 +48,7 @@ type Options struct { InterfaceMonitor DefaultInterfaceMonitor TableIndex int FileDescriptor int + Logger logger.Logger } func CalculateInterfaceName(name string) (tunName string) { diff --git a/tun_linux.go b/tun_linux.go index 1751737..597881f 100644 --- a/tun_linux.go +++ b/tun_linux.go @@ -588,15 +588,16 @@ func (t *NativeTun) resetRules() error { return t.setRules() } -func (t *NativeTun) routeUpdate(event int) error { +func (t *NativeTun) routeUpdate(event int) { if event&EventAndroidVPNUpdate == 0 { - return nil + return } err := t.resetRules() if err != nil { - return E.Cause(err, "reset route") + if t.options.Logger != nil { + t.options.Logger.Error(E.Cause(err, "reset route")) + } } - return nil } func (t *NativeTun) setSearchDomainForSystemdResolved() {