github.com/yaling888/clash@v1.53.0/component/iface/iface.go (about)

     1  package iface
     2  
     3  import (
     4  	"errors"
     5  	"net"
     6  	"net/netip"
     7  	"time"
     8  
     9  	"github.com/yaling888/clash/common/singledo"
    10  )
    11  
    12  type Interface struct {
    13  	Index        int
    14  	Name         string
    15  	Addrs        []*netip.Prefix
    16  	HardwareAddr net.HardwareAddr
    17  }
    18  
    19  var (
    20  	ErrIfaceNotFound = errors.New("interface not found")
    21  	ErrAddrNotFound  = errors.New("addr not found")
    22  )
    23  
    24  var interfaces = singledo.NewSingle[map[string]*Interface](time.Second * 20)
    25  
    26  func ResolveInterface(name string) (*Interface, error) {
    27  	value, err, _ := interfaces.Do(func() (map[string]*Interface, error) {
    28  		ifaces, err := net.Interfaces()
    29  		if err != nil {
    30  			return nil, err
    31  		}
    32  
    33  		r := map[string]*Interface{}
    34  
    35  		for _, iface := range ifaces {
    36  			addrs, err := iface.Addrs()
    37  			if err != nil {
    38  				continue
    39  			}
    40  
    41  			ipNets := make([]*netip.Prefix, 0, len(addrs))
    42  			for _, addr := range addrs {
    43  				ipNet := addr.(*net.IPNet)
    44  				ip, _ := netip.AddrFromSlice(ipNet.IP)
    45  
    46  				ones, bits := ipNet.Mask.Size()
    47  				if bits == 32 {
    48  					ip = ip.Unmap()
    49  				}
    50  
    51  				pf := netip.PrefixFrom(ip, ones)
    52  				ipNets = append(ipNets, &pf)
    53  			}
    54  
    55  			r[iface.Name] = &Interface{
    56  				Index:        iface.Index,
    57  				Name:         iface.Name,
    58  				Addrs:        ipNets,
    59  				HardwareAddr: iface.HardwareAddr,
    60  			}
    61  		}
    62  
    63  		return r, nil
    64  	})
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	ifaces := value
    70  	iface, ok := ifaces[name]
    71  	if !ok {
    72  		return nil, ErrIfaceNotFound
    73  	}
    74  
    75  	return iface, nil
    76  }
    77  
    78  func FlushCache() {
    79  	interfaces.Reset()
    80  }
    81  
    82  func (iface *Interface) PickIPv4Addr(destination netip.Addr) (*netip.Prefix, error) {
    83  	return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool {
    84  		return addr.Addr().Is4()
    85  	})
    86  }
    87  
    88  func (iface *Interface) PickIPv6Addr(destination netip.Addr) (*netip.Prefix, error) {
    89  	return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool {
    90  		return addr.Addr().Is6()
    91  	})
    92  }
    93  
    94  func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *netip.Prefix) bool) (*netip.Prefix, error) {
    95  	var fallback *netip.Prefix
    96  
    97  	for _, addr := range iface.Addrs {
    98  		if !accept(addr) {
    99  			continue
   100  		}
   101  
   102  		if fallback == nil && !addr.Addr().IsLinkLocalUnicast() {
   103  			fallback = addr
   104  
   105  			if !destination.IsValid() {
   106  				break
   107  			}
   108  		}
   109  
   110  		if destination.IsValid() && addr.Contains(destination) {
   111  			return addr, nil
   112  		}
   113  	}
   114  
   115  	if fallback == nil {
   116  		return nil, ErrAddrNotFound
   117  	}
   118  
   119  	return fallback, nil
   120  }