github.com/MerlinKodo/sing-tun@v0.1.15/monitor_linux.go (about)

     1  package tun
     2  
     3  import (
     4  	"os"
     5  	"runtime"
     6  	"sync"
     7  
     8  	"github.com/sagernet/netlink"
     9  	"github.com/sagernet/sing/common/logger"
    10  	"github.com/sagernet/sing/common/x/list"
    11  
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  type networkUpdateMonitor struct {
    16  	routeUpdate chan netlink.RouteUpdate
    17  	linkUpdate  chan netlink.LinkUpdate
    18  	close       chan struct{}
    19  
    20  	access    sync.Mutex
    21  	callbacks list.List[NetworkUpdateCallback]
    22  	logger    logger.Logger
    23  }
    24  
    25  func NewNetworkUpdateMonitor(logger logger.Logger) (NetworkUpdateMonitor, error) {
    26  	monitor := &networkUpdateMonitor{
    27  		routeUpdate: make(chan netlink.RouteUpdate, 2),
    28  		linkUpdate:  make(chan netlink.LinkUpdate, 2),
    29  		close:       make(chan struct{}),
    30  		logger:      logger,
    31  	}
    32  	// check is netlink banned by google
    33  	if runtime.GOOS == "android" {
    34  		netlinkSocket, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_DGRAM, unix.NETLINK_ROUTE)
    35  		if err != nil {
    36  			return nil, os.ErrInvalid
    37  		}
    38  		err = unix.Bind(netlinkSocket, &unix.SockaddrNetlink{
    39  			Family: unix.AF_NETLINK,
    40  		})
    41  		unix.Close(netlinkSocket)
    42  		if err != nil {
    43  			return nil, os.ErrInvalid
    44  		}
    45  	}
    46  	return monitor, nil
    47  }
    48  
    49  func (m *networkUpdateMonitor) Start() error {
    50  	err := netlink.RouteSubscribe(m.routeUpdate, m.close)
    51  	if err != nil {
    52  		return err
    53  	}
    54  	err = netlink.LinkSubscribe(m.linkUpdate, m.close)
    55  	if err != nil {
    56  		return err
    57  	}
    58  	go m.loopUpdate()
    59  	return nil
    60  }
    61  
    62  func (m *networkUpdateMonitor) loopUpdate() {
    63  	for {
    64  		select {
    65  		case <-m.close:
    66  			return
    67  		case <-m.routeUpdate:
    68  		case <-m.linkUpdate:
    69  		}
    70  		m.emit()
    71  	}
    72  }
    73  
    74  func (m *networkUpdateMonitor) Close() error {
    75  	select {
    76  	case <-m.close:
    77  		return os.ErrClosed
    78  	default:
    79  	}
    80  	close(m.close)
    81  	return nil
    82  }