@@ -5,10 +5,9 @@ import (
55 "net"
66 "net/netip"
77 "os"
8- "runtime"
9- "strings"
108 "sync"
119 "syscall"
10+ "time"
1211
1312 "github.com/sagernet/sing/common"
1413 E "github.com/sagernet/sing/common/exceptions"
@@ -85,32 +84,114 @@ func (m *defaultInterfaceMonitor) checkUpdate() error {
8584 if err != nil {
8685 return err
8786 }
87+ var defaultInterface * net.Interface
8888 for _ , rawRouteMessage := range routeMessages {
8989 routeMessage := rawRouteMessage .(* route.RouteMessage )
90+ if len (routeMessage .Addrs ) <= unix .RTAX_NETMASK {
91+ continue
92+ }
93+ destination , isIPv4Destination := routeMessage .Addrs [unix .RTAX_DST ].(* route.Inet4Addr )
94+ if ! isIPv4Destination {
95+ continue
96+ }
97+ if destination .IP != netip .IPv4Unspecified ().As4 () {
98+ continue
99+ }
100+ mask , isIPv4Mask := routeMessage .Addrs [unix .RTAX_NETMASK ].(* route.Inet4Addr )
101+ if ! isIPv4Mask {
102+ continue
103+ }
104+ ones , _ := net .IPMask (mask .IP [:]).Size ()
105+ if ones != 0 {
106+ continue
107+ }
90108 routeInterface , err := net .InterfaceByIndex (routeMessage .Index )
91109 if err != nil {
92110 return err
93111 }
94- if runtime .GOOS == "ios" && strings .HasPrefix (routeInterface .Name , "utun" ) {
112+ if routeMessage .Flags & unix .RTF_UP == 0 {
113+ continue
114+ }
115+ if routeMessage .Flags & unix .RTF_GATEWAY == 0 {
116+ continue
117+ }
118+ if routeMessage .Flags & unix .RTF_IFSCOPE != 0 {
95119 continue
96120 }
97- if common .Any (common .FilterIsInstance (routeMessage .Addrs , func (it route.Addr ) (* route.Inet4Addr , bool ) {
98- addr , loaded := it .(* route.Inet4Addr )
99- return addr , loaded
100- }), func (addr * route.Inet4Addr ) bool {
101- return addr .IP == netip .IPv4Unspecified ().As4 ()
102- }) {
103- oldInterface := m .defaultInterfaceName
104- oldIndex := m .defaultInterfaceIndex
121+ defaultInterface = routeInterface
122+ break
123+ }
124+ if defaultInterface == nil {
125+ defaultInterface , err = getDefaultInterfaceBySocket ()
126+ if err != nil {
127+ return err
128+ }
129+ }
130+ oldInterface := m .defaultInterfaceName
131+ oldIndex := m .defaultInterfaceIndex
132+ m .defaultInterfaceIndex = defaultInterface .Index
133+ m .defaultInterfaceName = defaultInterface .Name
134+ if oldInterface == m .defaultInterfaceName && oldIndex == m .defaultInterfaceIndex {
135+ return nil
136+ }
137+ m .emit (EventInterfaceUpdate )
138+ return nil
139+ }
105140
106- m .defaultInterfaceIndex = routeMessage .Index
107- m .defaultInterfaceName = routeInterface .Name
108- if oldInterface == m .defaultInterfaceName && oldIndex == m .defaultInterfaceIndex {
109- return nil
141+ func getDefaultInterfaceBySocket () (* net.Interface , error ) {
142+ socketFd , err := unix .Socket (unix .AF_INET , unix .SOCK_STREAM , 0 )
143+ if err != nil {
144+ return nil , E .Cause (err , "create file descriptor" )
145+ }
146+ defer unix .Close (socketFd )
147+ go unix .Connect (socketFd , & unix.SockaddrInet4 {
148+ Addr : [4 ]byte {10 , 255 , 255 , 255 },
149+ Port : 80 ,
150+ })
151+ result := make (chan netip.Addr , 1 )
152+ go func () {
153+ for {
154+ sockname , sockErr := unix .Getsockname (socketFd )
155+ if sockErr != nil {
156+ break
157+ }
158+ sockaddr , isInet4Sockaddr := sockname .(* unix.SockaddrInet4 )
159+ if ! isInet4Sockaddr {
160+ break
161+ }
162+ addr := netip .AddrFrom4 (sockaddr .Addr )
163+ if addr .IsUnspecified () {
164+ time .Sleep (time .Millisecond )
165+ continue
166+ }
167+ result <- addr
168+ break
169+ }
170+ }()
171+ var selectedAddr netip.Addr
172+ select {
173+ case selectedAddr = <- result :
174+ case <- time .After (time .Second ):
175+ return nil , os .ErrDeadlineExceeded
176+ }
177+ interfaces , err := net .Interfaces ()
178+ if err != nil {
179+ return nil , E .Cause (err , "net.Interfaces" )
180+ }
181+ for _ , netInterface := range interfaces {
182+ interfaceAddrs , err := netInterface .Addrs ()
183+ if err != nil {
184+ return nil , E .Cause (err , "net.Interfaces.Addrs" )
185+ }
186+ for _ , interfaceAddr := range interfaceAddrs {
187+ ipNet , isIPNet := interfaceAddr .(* net.IPNet )
188+ if ! isIPNet {
189+ continue
190+ }
191+ if ipNet .Contains (selectedAddr .AsSlice ()) {
192+ return & netInterface , nil
110193 }
111- m .emit (EventInterfaceUpdate )
112- return nil
113194 }
114195 }
115- return ErrNoRoute
196+ return nil , E . New ( "no interface found for address " , selectedAddr )
116197}
0 commit comments