github.com/apernet/sing-tun@v0.2.6-0.20240323130332-b9f6511036ad/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 defaultInterface = routeInterface 156 break 157 } 158 } 159 if defaultInterface == nil { 160 return ErrNoRoute 161 } 162 oldInterface := m.defaultInterfaceName 163 oldIndex := m.defaultInterfaceIndex 164 m.defaultInterfaceIndex = defaultInterface.Index 165 m.defaultInterfaceName = defaultInterface.Name 166 if oldInterface == m.defaultInterfaceName && oldIndex == m.defaultInterfaceIndex { 167 return nil 168 } 169 m.emit(EventInterfaceUpdate) 170 return nil 171 } 172 173 func getDefaultInterfaceBySocket() (*net.Interface, error) { 174 socketFd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) 175 if err != nil { 176 return nil, E.Cause(err, "create file descriptor") 177 } 178 defer unix.Close(socketFd) 179 go unix.Connect(socketFd, &unix.SockaddrInet4{ 180 Addr: [4]byte{10, 255, 255, 255}, 181 Port: 80, 182 }) 183 result := make(chan netip.Addr, 1) 184 done := make(chan struct{}) 185 defer close(done) 186 go func() { 187 for { 188 sockname, sockErr := unix.Getsockname(socketFd) 189 if sockErr != nil { 190 break 191 } 192 sockaddr, isInet4Sockaddr := sockname.(*unix.SockaddrInet4) 193 if !isInet4Sockaddr { 194 break 195 } 196 addr := netip.AddrFrom4(sockaddr.Addr) 197 if addr.IsUnspecified() { 198 select { 199 case <-done: 200 break 201 default: 202 time.Sleep(10 * time.Millisecond) 203 continue 204 } 205 } 206 result <- addr 207 break 208 } 209 }() 210 var selectedAddr netip.Addr 211 select { 212 case selectedAddr = <-result: 213 case <-time.After(time.Second): 214 return nil, nil 215 } 216 interfaces, err := net.Interfaces() 217 if err != nil { 218 return nil, E.Cause(err, "net.Interfaces") 219 } 220 for _, netInterface := range interfaces { 221 interfaceAddrs, err := netInterface.Addrs() 222 if err != nil { 223 return nil, E.Cause(err, "net.Interfaces.Addrs") 224 } 225 for _, interfaceAddr := range interfaceAddrs { 226 ipNet, isIPNet := interfaceAddr.(*net.IPNet) 227 if !isIPNet { 228 continue 229 } 230 if ipNet.Contains(selectedAddr.AsSlice()) { 231 return &netInterface, nil 232 } 233 } 234 } 235 return nil, E.New("no interface found for address ", selectedAddr) 236 }