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  }