123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- package outbound
- import (
- "bytes"
- "context"
- "crypto/tls"
- "fmt"
- "net"
- "net/netip"
- "regexp"
- "strconv"
- "sync"
- "github.com/metacubex/mihomo/component/resolver"
- C "github.com/metacubex/mihomo/constant"
- "github.com/metacubex/mihomo/transport/socks5"
- )
- var (
- globalClientSessionCache tls.ClientSessionCache
- once sync.Once
- )
- func getClientSessionCache() tls.ClientSessionCache {
- once.Do(func() {
- globalClientSessionCache = tls.NewLRUClientSessionCache(128)
- })
- return globalClientSessionCache
- }
- func serializesSocksAddr(metadata *C.Metadata) []byte {
- var buf [][]byte
- addrType := metadata.AddrType()
- aType := uint8(addrType)
- p := uint(metadata.DstPort)
- port := []byte{uint8(p >> 8), uint8(p & 0xff)}
- switch addrType {
- case socks5.AtypDomainName:
- lenM := uint8(len(metadata.Host))
- host := []byte(metadata.Host)
- buf = [][]byte{{aType, lenM}, host, port}
- case socks5.AtypIPv4:
- host := metadata.DstIP.AsSlice()
- buf = [][]byte{{aType}, host, port}
- case socks5.AtypIPv6:
- host := metadata.DstIP.AsSlice()
- buf = [][]byte{{aType}, host, port}
- }
- return bytes.Join(buf, nil)
- }
- func resolveUDPAddr(ctx context.Context, network, address string) (*net.UDPAddr, error) {
- host, port, err := net.SplitHostPort(address)
- if err != nil {
- return nil, err
- }
- ip, err := resolver.ResolveProxyServerHost(ctx, host)
- if err != nil {
- return nil, err
- }
- return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
- }
- func resolveUDPAddrWithPrefer(ctx context.Context, network, address string, prefer C.DNSPrefer) (*net.UDPAddr, error) {
- host, port, err := net.SplitHostPort(address)
- if err != nil {
- return nil, err
- }
- var ip netip.Addr
- var fallback netip.Addr
- switch prefer {
- case C.IPv4Only:
- ip, err = resolver.ResolveIPv4ProxyServerHost(ctx, host)
- case C.IPv6Only:
- ip, err = resolver.ResolveIPv6ProxyServerHost(ctx, host)
- case C.IPv6Prefer:
- var ips []netip.Addr
- ips, err = resolver.LookupIPProxyServerHost(ctx, host)
- if err == nil {
- for _, addr := range ips {
- if addr.Is6() {
- ip = addr
- break
- } else {
- if !fallback.IsValid() {
- fallback = addr
- }
- }
- }
- }
- default:
- // C.IPv4Prefer, C.DualStack and other
- var ips []netip.Addr
- ips, err = resolver.LookupIPProxyServerHost(ctx, host)
- if err == nil {
- for _, addr := range ips {
- if addr.Is4() {
- ip = addr
- break
- } else {
- if !fallback.IsValid() {
- fallback = addr
- }
- }
- }
- }
- }
- if !ip.IsValid() && fallback.IsValid() {
- ip = fallback
- }
- if err != nil {
- return nil, err
- }
- return net.ResolveUDPAddr(network, net.JoinHostPort(ip.String(), port))
- }
- func safeConnClose(c net.Conn, err error) {
- if err != nil && c != nil {
- _ = c.Close()
- }
- }
- var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`)
- func StringToBps(s string) uint64 {
- if s == "" {
- return 0
- }
- // when have not unit, use Mbps
- if v, err := strconv.Atoi(s); err == nil {
- return StringToBps(fmt.Sprintf("%d Mbps", v))
- }
- m := rateStringRegexp.FindStringSubmatch(s)
- if m == nil {
- return 0
- }
- var n uint64 = 1
- switch m[2] {
- case "T":
- n *= 1000
- fallthrough
- case "G":
- n *= 1000
- fallthrough
- case "M":
- n *= 1000
- fallthrough
- case "K":
- n *= 1000
- }
- v, _ := strconv.ParseUint(m[1], 10, 64)
- n *= v
- if m[3] == "b" {
- // Bits, need to convert to bytes
- n /= 8
- }
- return n
- }
|