github.com/metacubex/sing-tun@v0.2.7-0.20240512075008-89e7c6208eec/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 routeSocketFile := os.NewFile(uintptr(routeSocket), "route") 61 m.routeSocketFile = routeSocketFile 62 m.loopUpdate1(routeSocketFile) 63 return nil 64 } 65 66 func (m *networkUpdateMonitor) loopUpdate1(routeSocketFile *os.File) { 67 defer routeSocketFile.Close() 68 buffer := buf.NewPacket() 69 defer buffer.Release() 70 done := make(chan struct{}) 71 go func() { 72 select { 73 case <-m.done: 74 routeSocketFile.Close() 75 case <-done: 76 } 77 }() 78 n, err := routeSocketFile.Read(buffer.FreeBytes()) 79 close(done) 80 if err != nil { 81 return 82 } 83 buffer.Truncate(n) 84 messages, err := route.ParseRIB(route.RIBTypeRoute, buffer.Bytes()) 85 if err != nil { 86 return 87 } 88 for _, message := range messages { 89 if _, isRouteMessage := message.(*route.RouteMessage); isRouteMessage { 90 m.emit() 91 return 92 } 93 } 94 } 95 96 func (m *networkUpdateMonitor) Close() error { 97 m.closeOnce.Do(func() { 98 close(m.done) 99 }) 100 return nil 101 } 102 103 func (m *defaultInterfaceMonitor) checkUpdate() error { 104 var ( 105 defaultInterface *net.Interface 106 err error 107 ) 108 if m.options.UnderNetworkExtension { 109 defaultInterface, err = getDefaultInterfaceBySocket() 110 if err != nil { 111 return err 112 } 113 } else { 114 ribMessage, err := route.FetchRIB(unix.AF_UNSPEC, route.RIBTypeRoute, 0) 115 if err != nil { 116 return err 117 } 118 routeMessages, err := route.ParseRIB(route.RIBTypeRoute, ribMessage) 119 if err != nil { 120 return err 121 } 122 for _, rawRouteMessage := range routeMessages { 123 routeMessage := rawRouteMessage.(*route.RouteMessage) 124 if len(routeMessage.Addrs) <= unix.RTAX_NETMASK { 125 continue 126 } 127 destination, isIPv4Destination := routeMessage.Addrs[unix.RTAX_DST].(*route.Inet4Addr) 128 if !isIPv4Destination { 129 continue 130 } 131 if destination.IP != netip.IPv4Unspecified().As4() { 132 continue 133 } 134 mask, isIPv4Mask := routeMessage.Addrs[unix.RTAX_NETMASK].(*route.Inet4Addr) 135 if !isIPv4Mask { 136 continue 137 } 138 ones, _ := net.IPMask(mask.IP[:]).Size() 139 if ones != 0 { 140 continue 141 } 142 routeInterface, err := net.InterfaceByIndex(routeMessage.Index) 143 if err != nil { 144 return err 145 } 146 if routeMessage.Flags&unix.RTF_UP == 0 { 147 continue 148 } 149 if routeMessage.Flags&unix.RTF_GATEWAY == 0 { 150 continue 151 } 152 if routeMessage.Flags&unix.RTF_IFSCOPE != 0 { 153 // continue 154 } 155 if routeInterface.Flags&net.FlagLoopback != 0 { 156 continue 157 } 158 defaultInterface = routeInterface 159 break 160 } 161 } 162 if defaultInterface == nil { 163 return ErrNoRoute 164 } 165 oldInterface := m.defaultInterfaceName 166 oldIndex := m.defaultInterfaceIndex 167 m.defaultInterfaceIndex = defaultInterface.Index 168 m.defaultInterfaceName = defaultInterface.Name 169 if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex { 170 return nil 171 } 172 m.emit(EventInterfaceUpdate) 173 return nil 174 } 175 176 func getDefaultInterfaceBySocket() (*net.Interface, error) { 177 socketFd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) 178 if err != nil { 179 return nil, E.Cause(err, "create file descriptor") 180 } 181 defer unix.Close(socketFd) 182 go unix.Connect(socketFd, &unix.SockaddrInet4{ 183 Addr: [4]byte{10, 255, 255, 255}, 184 Port: 80, 185 }) 186 result := make(chan netip.Addr, 1) 187 done := make(chan struct{}) 188 defer close(done) 189 go func() { 190 for { 191 sockname, sockErr := unix.Getsockname(socketFd) 192 if sockErr != nil { 193 break 194 } 195 sockaddr, isInet4Sockaddr := sockname.(*unix.SockaddrInet4) 196 if !isInet4Sockaddr { 197 break 198 } 199 addr := netip.AddrFrom4(sockaddr.Addr) 200 if addr.IsUnspecified() { 201 select { 202 case <-done: 203 break 204 default: 205 time.Sleep(10 * time.Millisecond) 206 continue 207 } 208 } 209 result <- addr 210 break 211 } 212 }() 213 var selectedAddr netip.Addr 214 select { 215 case selectedAddr = <-result: 216 case <-time.After(time.Second): 217 return nil, nil 218 } 219 interfaces, err := net.Interfaces() 220 if err != nil { 221 return nil, E.Cause(err, "net.Interfaces") 222 } 223 for _, netInterface := range interfaces { 224 interfaceAddrs, err := netInterface.Addrs() 225 if err != nil { 226 return nil, E.Cause(err, "net.Interfaces.Addrs") 227 } 228 for _, interfaceAddr := range interfaceAddrs { 229 ipNet, isIPNet := interfaceAddr.(*net.IPNet) 230 if !isIPNet { 231 continue 232 } 233 if ipNet.Contains(selectedAddr.AsSlice()) { 234 return &netInterface, nil 235 } 236 } 237 } 238 return nil, E.New("no interface found for address ", selectedAddr) 239 }