github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/monitor_linux.go (about) 1 package tun 2 3 import ( 4 "os" 5 "runtime" 6 "sync" 7 "time" 8 9 "github.com/sagernet/netlink" 10 E "github.com/sagernet/sing/common/exceptions" 11 "github.com/sagernet/sing/common/logger" 12 "github.com/sagernet/sing/common/x/list" 13 14 "golang.org/x/sys/unix" 15 ) 16 17 type networkUpdateMonitor struct { 18 routeUpdate chan netlink.RouteUpdate 19 linkUpdate chan netlink.LinkUpdate 20 close chan struct{} 21 22 access sync.Mutex 23 callbacks list.List[NetworkUpdateCallback] 24 logger logger.Logger 25 } 26 27 var ErrNetlinkBanned = E.New( 28 "netlink socket in Android is banned by Google, " + 29 "use the root or system (ADB) user to run sing-box, " + 30 "or switch to the sing-box Adnroid graphical interface client", 31 ) 32 33 func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) { 34 monitor := &networkUpdateMonitor{ 35 routeUpdate: make(chan netlink.RouteUpdate, 2), 36 linkUpdate: make(chan netlink.LinkUpdate, 2), 37 close: make(chan struct{}), 38 logger: logger, 39 } 40 // check is netlink banned by google 41 if runtime.GOOS == "android" { 42 netlinkSocket, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_DGRAM, unix.NETLINK_ROUTE) 43 if err != nil { 44 return nil, ErrNetlinkBanned 45 } 46 err = unix.Bind(netlinkSocket, &unix.SockaddrNetlink{ 47 Family: unix.AF_NETLINK, 48 }) 49 unix.Close(netlinkSocket) 50 if err != nil { 51 return nil, ErrNetlinkBanned 52 } 53 } 54 return monitor, nil 55 } 56 57 func (m *networkUpdateMonitor) Start() error { 58 err := netlink.RouteSubscribe(m.routeUpdate, m.close) 59 if err != nil { 60 return err 61 } 62 err = netlink.LinkSubscribe(m.linkUpdate, m.close) 63 if err != nil { 64 return err 65 } 66 go m.loopUpdate() 67 return nil 68 } 69 70 func (m *networkUpdateMonitor) loopUpdate() { 71 const minDuration = time.Second 72 timer := time.NewTimer(minDuration) 73 defer timer.Stop() 74 for { 75 select { 76 case <-m.close: 77 return 78 case <-m.routeUpdate: 79 case <-m.linkUpdate: 80 } 81 m.emit() 82 select { 83 case <-m.close: 84 return 85 case <-timer.C: 86 timer.Reset(minDuration) 87 } 88 } 89 } 90 91 func (m *networkUpdateMonitor) Close() error { 92 select { 93 case <-m.close: 94 return os.ErrClosed 95 default: 96 } 97 close(m.close) 98 return nil 99 }