util.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package outbound
  2. import (
  3. "bytes"
  4. "context"
  5. "crypto/tls"
  6. "fmt"
  7. "net"
  8. "net/netip"
  9. "regexp"
  10. "strconv"
  11. "sync"
  12. "github.com/metacubex/mihomo/component/resolver"
  13. C "github.com/metacubex/mihomo/constant"
  14. "github.com/metacubex/mihomo/transport/socks5"
  15. )
  16. var (
  17. globalClientSessionCache tls.ClientSessionCache
  18. once sync.Once
  19. )
  20. func getClientSessionCache() tls.ClientSessionCache {
  21. once.Do(func() {
  22. globalClientSessionCache = tls.NewLRUClientSessionCache(128)
  23. })
  24. return globalClientSessionCache
  25. }
  26. func serializesSocksAddr(metadata *C.Metadata) []byte {
  27. var buf [][]byte
  28. addrType := metadata.AddrType()
  29. aType := uint8(addrType)
  30. p := uint(metadata.DstPort)
  31. port := []byte{uint8(p >> 8), uint8(p & 0xff)}
  32. switch addrType {
  33. case socks5.AtypDomainName:
  34. lenM := uint8(len(metadata.Host))
  35. host := []byte(metadata.Host)
  36. buf = [][]byte{{aType, lenM}, host, port}
  37. case socks5.AtypIPv4:
  38. host := metadata.DstIP.AsSlice()
  39. buf = [][]byte{{aType}, host, port}
  40. case socks5.AtypIPv6:
  41. host := metadata.DstIP.AsSlice()
  42. buf = [][]byte{{aType}, host, port}
  43. }
  44. return bytes.Join(buf, nil)
  45. }
  46. func resolveUDPAddr(ctx context.Context, network, address string) (*net.UDPAddr, error) {
  47. host, port, err := net.SplitHostPort(address)
  48. if err != nil {
  49. return nil, err
  50. }
  51. ip, err := resolver.ResolveProxyServerHost(ctx, host)
  52. if err != nil {
  53. return nil, err
  54. }
  55. return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
  56. }
  57. func resolveUDPAddrWithPrefer(ctx context.Context, network, address string, prefer C.DNSPrefer) (*net.UDPAddr, error) {
  58. host, port, err := net.SplitHostPort(address)
  59. if err != nil {
  60. return nil, err
  61. }
  62. var ip netip.Addr
  63. var fallback netip.Addr
  64. switch prefer {
  65. case C.IPv4Only:
  66. ip, err = resolver.ResolveIPv4ProxyServerHost(ctx, host)
  67. case C.IPv6Only:
  68. ip, err = resolver.ResolveIPv6ProxyServerHost(ctx, host)
  69. case C.IPv6Prefer:
  70. var ips []netip.Addr
  71. ips, err = resolver.LookupIPProxyServerHost(ctx, host)
  72. if err == nil {
  73. for _, addr := range ips {
  74. if addr.Is6() {
  75. ip = addr
  76. break
  77. } else {
  78. if !fallback.IsValid() {
  79. fallback = addr
  80. }
  81. }
  82. }
  83. }
  84. default:
  85. // C.IPv4Prefer, C.DualStack and other
  86. var ips []netip.Addr
  87. ips, err = resolver.LookupIPProxyServerHost(ctx, host)
  88. if err == nil {
  89. for _, addr := range ips {
  90. if addr.Is4() {
  91. ip = addr
  92. break
  93. } else {
  94. if !fallback.IsValid() {
  95. fallback = addr
  96. }
  97. }
  98. }
  99. }
  100. }
  101. if !ip.IsValid() && fallback.IsValid() {
  102. ip = fallback
  103. }
  104. if err != nil {
  105. return nil, err
  106. }
  107. return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
  108. }
  109. func safeConnClose(c net.Conn, err error) {
  110. if err != nil && c != nil {
  111. _ = c.Close()
  112. }
  113. }
  114. var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`)
  115. func StringToBps(s string) uint64 {
  116. if s == "" {
  117. return 0
  118. }
  119. // when have not unit, use Mbps
  120. if v, err := strconv.Atoi(s); err == nil {
  121. return StringToBps(fmt.Sprintf("%d Mbps", v))
  122. }
  123. m := rateStringRegexp.FindStringSubmatch(s)
  124. if m == nil {
  125. return 0
  126. }
  127. var n uint64 = 1
  128. switch m[2] {
  129. case "T":
  130. n *= 1000
  131. fallthrough
  132. case "G":
  133. n *= 1000
  134. fallthrough
  135. case "M":
  136. n *= 1000
  137. fallthrough
  138. case "K":
  139. n *= 1000
  140. }
  141. v, _ := strconv.ParseUint(m[1], 10, 64)
  142. n *= v
  143. if m[3] == "b" {
  144. // Bits, need to convert to bytes
  145. n /= 8
  146. }
  147. return n
  148. }