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

     1  //go:build linux || windows || darwin
     2  
     3  package tun
     4  
     5  import (
     6  	"errors"
     7  	"net"
     8  	"net/netip"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/sagernet/sing/common"
    13  	"github.com/sagernet/sing/common/logger"
    14  	M "github.com/sagernet/sing/common/metadata"
    15  	"github.com/sagernet/sing/common/x/list"
    16  )
    17  
    18  func (m *networkUpdateMonitor) RegisterCallback(callback NetworkUpdateCallback) *list.Element[NetworkUpdateCallback] {
    19  	m.access.Lock()
    20  	defer m.access.Unlock()
    21  	return m.callbacks.PushBack(callback)
    22  }
    23  
    24  func (m *networkUpdateMonitor) UnregisterCallback(element *list.Element[NetworkUpdateCallback]) {
    25  	m.access.Lock()
    26  	defer m.access.Unlock()
    27  	m.callbacks.Remove(element)
    28  }
    29  
    30  func (m *networkUpdateMonitor) emit() {
    31  	m.access.Lock()
    32  	callbacks := m.callbacks.Array()
    33  	m.access.Unlock()
    34  	for _, callback := range callbacks {
    35  		callback()
    36  	}
    37  }
    38  
    39  type defaultInterfaceMonitor struct {
    40  	options               DefaultInterfaceMonitorOptions
    41  	networkAddresses      []networkAddress
    42  	defaultInterfaceName  string
    43  	defaultInterfaceIndex int
    44  	androidVPNEnabled     bool
    45  	networkMonitor        NetworkUpdateMonitor
    46  	element               *list.Element[NetworkUpdateCallback]
    47  	access                sync.Mutex
    48  	callbacks             list.List[DefaultInterfaceUpdateCallback]
    49  	logger                logger.Logger
    50  }
    51  
    52  type networkAddress struct {
    53  	interfaceName  string
    54  	interfaceIndex int
    55  	addresses      []netip.Prefix
    56  }
    57  
    58  func NewDefaultInterfaceMonitor(networkMonitor NetworkUpdateMonitor, logger logger.Logger, options DefaultInterfaceMonitorOptions) (DefaultInterfaceMonitor, error) {
    59  	return &defaultInterfaceMonitor{
    60  		options:               options,
    61  		networkMonitor:        networkMonitor,
    62  		defaultInterfaceIndex: -1,
    63  		logger: logger,
    64  	}, nil
    65  }
    66  
    67  func (m *defaultInterfaceMonitor) Start() error {
    68  	_ = m.checkUpdate()
    69  	m.element = m.networkMonitor.RegisterCallback(m.delayCheckUpdate)
    70  	return nil
    71  }
    72  
    73  func (m *defaultInterfaceMonitor) delayCheckUpdate() {
    74  	time.Sleep(time.Second)
    75  	err := m.updateInterfaces()
    76  	if err != nil {
    77  		m.logger.Error("update interfaces: ", err)
    78  	}
    79  	err = m.checkUpdate()
    80  	if errors.Is(err, ErrNoRoute) {
    81  		m.defaultInterfaceName = ""
    82  		m.defaultInterfaceIndex = -1
    83  		m.emit(EventNoRoute)
    84  	}
    85  }
    86  
    87  func (m *defaultInterfaceMonitor) updateInterfaces() error {
    88  	interfaces, err := net.Interfaces()
    89  	if err != nil {
    90  		return err
    91  	}
    92  	var addresses []networkAddress
    93  	for _, iif := range interfaces {
    94  		var netAddresses []net.Addr
    95  		netAddresses, err = iif.Addrs()
    96  		if err != nil {
    97  			return err
    98  		}
    99  		var address networkAddress
   100  		address.interfaceName = iif.Name
   101  		address.interfaceIndex = iif.Index
   102  		address.addresses = common.Map(common.FilterIsInstance(netAddresses, func(it net.Addr) (*net.IPNet, bool) {
   103  			value, loaded := it.(*net.IPNet)
   104  			return value, loaded
   105  		}), func(it *net.IPNet) netip.Prefix {
   106  			bits, _ := it.Mask.Size()
   107  			return netip.PrefixFrom(M.AddrFromIP(it.IP), bits)
   108  		})
   109  		addresses = append(addresses, address)
   110  	}
   111  	m.networkAddresses = addresses
   112  	return nil
   113  }
   114  
   115  func (m *defaultInterfaceMonitor) Close() error {
   116  	if m.element != nil {
   117  		m.networkMonitor.UnregisterCallback(m.element)
   118  	}
   119  	return nil
   120  }
   121  
   122  func (m *defaultInterfaceMonitor) DefaultInterfaceName(destination netip.Addr) string {
   123  	for _, address := range m.networkAddresses {
   124  		for _, prefix := range address.addresses {
   125  			if prefix.Contains(destination) {
   126  				return address.interfaceName
   127  			}
   128  		}
   129  	}
   130  	if m.defaultInterfaceIndex == -1 {
   131  		m.checkUpdate()
   132  	}
   133  	return m.defaultInterfaceName
   134  }
   135  
   136  func (m *defaultInterfaceMonitor) DefaultInterfaceIndex(destination netip.Addr) int {
   137  	for _, address := range m.networkAddresses {
   138  		for _, prefix := range address.addresses {
   139  			if prefix.Contains(destination) {
   140  				return address.interfaceIndex
   141  			}
   142  		}
   143  	}
   144  	if m.defaultInterfaceIndex == -1 {
   145  		m.checkUpdate()
   146  	}
   147  	return m.defaultInterfaceIndex
   148  }
   149  
   150  func (m *defaultInterfaceMonitor) DefaultInterface(destination netip.Addr) (string, int) {
   151  	for _, address := range m.networkAddresses {
   152  		for _, prefix := range address.addresses {
   153  			if prefix.Contains(destination) {
   154  				return address.interfaceName, address.interfaceIndex
   155  			}
   156  		}
   157  	}
   158  	if m.defaultInterfaceIndex == -1 {
   159  		m.checkUpdate()
   160  	}
   161  	return m.defaultInterfaceName, m.defaultInterfaceIndex
   162  }
   163  
   164  func (m *defaultInterfaceMonitor) OverrideAndroidVPN() bool {
   165  	return m.options.OverrideAndroidVPN
   166  }
   167  
   168  func (m *defaultInterfaceMonitor) AndroidVPNEnabled() bool {
   169  	return m.androidVPNEnabled
   170  }
   171  
   172  func (m *defaultInterfaceMonitor) RegisterCallback(callback DefaultInterfaceUpdateCallback) *list.Element[DefaultInterfaceUpdateCallback] {
   173  	m.access.Lock()
   174  	defer m.access.Unlock()
   175  	return m.callbacks.PushBack(callback)
   176  }
   177  
   178  func (m *defaultInterfaceMonitor) UnregisterCallback(element *list.Element[DefaultInterfaceUpdateCallback]) {
   179  	m.access.Lock()
   180  	defer m.access.Unlock()
   181  	m.callbacks.Remove(element)
   182  }
   183  
   184  func (m *defaultInterfaceMonitor) emit(event int) {
   185  	m.access.Lock()
   186  	callbacks := m.callbacks.Array()
   187  	m.access.Unlock()
   188  	for _, callback := range callbacks {
   189  		callback(event)
   190  	}
   191  }