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