iface.go 2.9 KB

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