github.com/MerlinKodo/sing-tun@v0.1.15/monitor_linux.go (about) 1 package tun 2 3 import ( 4 "os" 5 "runtime" 6 "sync" 7 8 "github.com/sagernet/netlink" 9 "github.com/sagernet/sing/common/logger" 10 "github.com/sagernet/sing/common/x/list" 11 12 "golang.org/x/sys/unix" 13 ) 14 15 type networkUpdateMonitor struct { 16 routeUpdate chan netlink.RouteUpdate 17 linkUpdate chan netlink.LinkUpdate 18 close chan struct{} 19 20 access sync.Mutex 21 callbacks list.List[NetworkUpdateCallback] 22 logger logger.Logger 23 } 24 25 func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) { 26 monitor := &networkUpdateMonitor{ 27 routeUpdate: make(chan netlink.RouteUpdate, 2), 28 linkUpdate: make(chan netlink.LinkUpdate, 2), 29 close: make(chan struct{}), 30 logger: logger, 31 } 32 // check is netlink banned by google 33 if runtime.GOOS == "android" { 34 netlinkSocket, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_DGRAM, unix.NETLINK_ROUTE) 35 if err != nil { 36 return nil, os.ErrInvalid 37 } 38 err = unix.Bind(netlinkSocket, &unix.SockaddrNetlink{ 39 Family: unix.AF_NETLINK, 40 }) 41 unix.Close(netlinkSocket) 42 if err != nil { 43 return nil, os.ErrInvalid 44 } 45 } 46 return monitor, nil 47 } 48 49 func (m *networkUpdateMonitor) Start() error { 50 err := netlink.RouteSubscribe(m.routeUpdate, m.close) 51 if err != nil { 52 return err 53 } 54 err = netlink.LinkSubscribe(m.linkUpdate, m.close) 55 if err != nil { 56 return err 57 } 58 go m.loopUpdate() 59 return nil 60 } 61 62 func (m *networkUpdateMonitor) loopUpdate() { 63 for { 64 select { 65 case <-m.close: 66 return 67 case <-m.routeUpdate: 68 case <-m.linkUpdate: 69 } 70 m.emit() 71 } 72 } 73 74 func (m *networkUpdateMonitor) Close() error { 75 select { 76 case <-m.close: 77 return os.ErrClosed 78 default: 79 } 80 close(m.close) 81 return nil 82 }