Skip to content

Commit

Permalink
Fix monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
nekohasekai committed Aug 7, 2023
1 parent 59b8600 commit 89eb525
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 85 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
11 changes: 5 additions & 6 deletions monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,21 @@ 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 {
Start() error
Close() error
RegisterCallback(callback NetworkUpdateCallback) *list.Element[NetworkUpdateCallback]
UnregisterCallback(element *list.Element[NetworkUpdateCallback])
E.Handler
}

type DefaultInterfaceMonitor interface {
Expand Down
75 changes: 38 additions & 37 deletions monitor_darwin.go
Original file line number Diff line number Diff line change
@@ -1,78 +1,79 @@
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"
"golang.org/x/sys/unix"
)

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 {
Expand Down Expand Up @@ -116,7 +117,7 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
continue
}
if routeMessage.Flags&unix.RTF_IFSCOPE != 0 {
continue
// continue
}
defaultInterface = routeInterface
break
Expand Down
20 changes: 10 additions & 10 deletions monitor_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
7 changes: 3 additions & 4 deletions monitor_other.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
package tun

import (
"github.com/sagernet/sing/common/logger"
"os"

E "github.com/sagernet/sing/common/exceptions"
)

func NewNetworkUpdateMonitor(errorHandler E.Handler) (NetworkUpdateMonitor, error) {
func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) {
return nil, os.ErrInvalid
}

func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) {
func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, logger logger.Logger, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) {
return nil, os.ErrInvalid
}
29 changes: 10 additions & 19 deletions monitor_shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
package tun

import (
"context"
"errors"
"net"
"net/netip"
"sync"
"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"
)
Expand All @@ -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
Expand All @@ -54,6 +46,7 @@ type defaultInterfaceMonitor struct {
element *list.Element[NetworkUpdateCallback]
access sync.Mutex
callbacks list.List[DefaultInterfaceUpdateCallback]
logger logger.Logger
}

type networkAddress struct {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
}
}
6 changes: 4 additions & 2 deletions monitor_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
}

Expand Down
2 changes: 2 additions & 0 deletions tun.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -47,6 +48,7 @@ type Options struct {
InterfaceMonitor DefaultInterfaceMonitor
TableIndex int
FileDescriptor int
Logger logger.Logger
}

func CalculateInterfaceName(name string) (tunName string) {
Expand Down
9 changes: 5 additions & 4 deletions tun_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down

0 comments on commit 89eb525

Please sign in to comment.