github.com/sagernet/sing-tun@v0.3.0-beta.5/monitor_darwin.go (about) 1 package tun 2 3 import ( 4 "net" 5 "net/netip" 6 "os" 7 "sync" 8 "time" 9 10 "github.com/sagernet/sing/common/buf" 11 E "github.com/sagernet/sing/common/exceptions" 12 "github.com/sagernet/sing/common/logger" 13 "github.com/sagernet/sing/common/x/list" 14 15 "golang.org/x/net/route" 16 "golang.org/x/sys/unix" 17 ) 18 19 type networkUpdateMonitor struct { 20 access sync.Mutex 21 callbacks list.List[NetworkUpdateCallback] 22 routeSocketFile *os.File 23 closeOnce sync.Once 24 done chan struct{} 25 logger logger.Logger 26 } 27 28 func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) { 29 return &networkUpdateMonitor{ 30 logger: logger, 31 done: make(chan struct{}), 32 }, nil 33 } 34 35 func (m *networkUpdateMonitor) Start() error { 36 go m.loopUpdate() 37 return nil 38 } 39 40 func (m *networkUpdateMonitor) loopUpdate() { 41 for { 42 select { 43 case <-m.done: 44 return 45 default: 46 } 47 err := m.loopUpdate0() 48 if err != nil { 49 m.logger.Error("listen network update: ", err) 50 return 51 } 52 } 53 } 54 55 func (m *networkUpdateMonitor) loopUpdate0() error { 56 routeSocket, err := unix.Socket(unix.AF_ROUTE, unix.SOCK_RAW, 0) 57 if err != nil { 58 return err 59 } 60 err = unix.SetNonblock(routeSocket, true) 61 if err != nil { 62 unix.Close(routeSocket) 63 return err 64 } 65 routeSocketFile := os.NewFile(uintptr(routeSocket), "route") 66 defer routeSocketFile.Close() 67 m.routeSocketFile = routeSocketFile 68 m.loopUpdate1(routeSocketFile) 69 return nil 70 } 71 72 func (m *networkUpdateMonitor) loopUpdate1(routeSocketFile *os.File) { 73 buffer := buf.NewPacket() 74 defer buffer.Release() 75 done := make(chan struct{}) 76 go func() { 77 select { 78 case <-m.done: 79 routeSocketFile.Close() 80 case <-done: 81 } 82 }() 83 n, err := routeSocketFile.Read(buffer.FreeBytes()) 84 close(done) 85 if err != nil { 86 return 87 } 88 buffer.Truncate(n) 89 messages, err := route.ParseRIB(route.RIBTypeRoute, buffer.Bytes()) 90 if err != nil { 91 return 92 } 93 for _, message := range messages { 94 if _, isRouteMessage := message.(*route.RouteMessage); isRouteMessage { 95 m.emit() 96 return 97 } 98 } 99 } 100 101 func (m *networkUpdateMonitor) Close() error { 102 m.closeOnce.Do(func() { 103 close(m.done) 104 }) 105 return nil 106 } 107 108 func (m *defaultInterfaceMonitor) checkUpdate() error { 109 var ( 110 defaultInterface *net.Interface 111 err error 112 ) 113 if m.options.UnderNetworkExtension { 114 defaultInterface, err = getDefaultInterfaceBySocket() 115 if err != nil { 116 return err 117 } 118 } else { 119 ribMessage, err := route.FetchRIB(unix.AF_UNSPEC, route.RIBTypeRoute, 0) 120 if err != nil { 121 return err 122 } 123 routeMessages, err := route.ParseRIB(route.RIBTypeRoute, ribMessage) 124 if err != nil { 125 return err 126 } 127 for _, rawRouteMessage := range routeMessages { 128 routeMessage := rawRouteMessage.(*route.RouteMessage) 129 if len(routeMessage.Addrs) <= unix.RTAX_NETMASK { 130 continue 131 } 132 destination, isIPv4Destination := routeMessage.Addrs[unix.RTAX_DST].(*route.Inet4Addr) 133 if !isIPv4Destination { 134 continue 135 } 136 if destination.IP != netip.IPv4Unspecified().As4() { 137 continue 138 } 139 mask, isIPv4Mask := routeMessage.Addrs[unix.RTAX_NETMASK].(*route.Inet4Addr) 140 if !isIPv4Mask { 141 continue 142 } 143 ones, _ := net.IPMask(mask.IP[:]).Size() 144 if ones != 0 { 145 continue 146 } 147 routeInterface, err := net.InterfaceByIndex(routeMessage.Index) 148 if err != nil { 149 return err 150 } 151 if routeMessage.Flags&unix.RTF_UP == 0 { 152 continue 153 } 154 if routeMessage.Flags&unix.RTF_GATEWAY == 0 { 155 continue 156 } 157 if routeMessage.Flags&unix.RTF_IFSCOPE != 0 { 158 // continue 159 } 160 defaultInterface = routeInterface 161 break 162 } 163 } 164 if defaultInterface == nil { 165 return ErrNoRoute 166 } 167 oldInterface := m.defaultInterfaceName 168 oldIndex := m.defaultInterfaceIndex 169 m.defaultInterfaceIndex = defaultInterface.Index 170 m.defaultInterfaceName = defaultInterface.Name 171 if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex { 172 return nil 173 } 174 m.emit(EventInterfaceUpdate) 175 return nil 176 } 177 178 func getDefaultInterfaceBySocket() (*net.Interface, error) { 179 socketFd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) 180 if err != nil { 181 return nil, E.Cause(err, "create file descriptor") 182 } 183 defer unix.Close(socketFd) 184 go unix.Connect(socketFd, &unix.SockaddrInet4{ 185 Addr: [4]byte{10, 255, 255, 255}, 186 Port: 80, 187 }) 188 result := make(chan netip.Addr, 1) 189 done := make(chan struct{}) 190 defer close(done) 191 go func() { 192 for { 193 sockname, sockErr := unix.Getsockname(socketFd) 194 if sockErr != nil { 195 break 196 } 197 sockaddr, isInet4Sockaddr := sockname.(*unix.SockaddrInet4) 198 if !isInet4Sockaddr { 199 break 200 } 201 addr := netip.AddrFrom4(sockaddr.Addr) 202 if addr.IsUnspecified() { 203 select { 204 case <-done: 205 break 206 default: 207 time.Sleep(10 * time.Millisecond) 208 continue 209 } 210 } 211 result <- addr 212 break 213 } 214 }() 215 var selectedAddr netip.Addr 216 select { 217 case selectedAddr = <-result: 218 case <-time.After(time.Second): 219 return nil, nil 220 } 221 interfaces, err := net.Interfaces() 222 if err != nil { 223 return nil, E.Cause(err, "net.Interfaces") 224 } 225 for _, netInterface := range interfaces { 226 interfaceAddrs, err := netInterface.Addrs() 227 if err != nil { 228 return nil, E.Cause(err, "net.Interfaces.Addrs") 229 } 230 for _, interfaceAddr := range interfaceAddrs { 231 ipNet, isIPNet := interfaceAddr.(*net.IPNet) 232 if !isIPNet { 233 continue 234 } 235 if ipNet.Contains(selectedAddr.AsSlice()) { 236 return &netInterface, nil 237 } 238 } 239 } 240 return nil, E.New("no interface found for address ", selectedAddr) 241 }