diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 39b5bbdb..f475680b 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -78,7 +78,7 @@ func (h *Hysteria) genHdc(ctx context.Context, opts ...dialer.Option) utils.Pack return cDialer.ListenPacket(ctx, network, "", rAddrPort) }, remoteAddr: func(addr string) (net.Addr, error) { - return resolveUDPAddrWithPrefer(ctx, "udp", addr, h.prefer) + return resolveUDPAddr(ctx, "udp", addr, h.prefer) }, } } diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 95bbb5ec..9f4f1718 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -171,7 +171,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { CWND: option.CWND, UdpMTU: option.UdpMTU, ServerAddress: func(ctx context.Context) (*net.UDPAddr, error) { - return resolveUDPAddrWithPrefer(ctx, "udp", addr, C.NewDNSPrefer(option.IPVersion)) + return resolveUDPAddr(ctx, "udp", addr, C.NewDNSPrefer(option.IPVersion)) }, } @@ -188,7 +188,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { }) if len(serverAddress) > 0 { clientOptions.ServerAddress = func(ctx context.Context) (*net.UDPAddr, error) { - return resolveUDPAddrWithPrefer(ctx, "udp", serverAddress[randv2.IntN(len(serverAddress))], C.NewDNSPrefer(option.IPVersion)) + return resolveUDPAddr(ctx, "udp", serverAddress[randv2.IntN(len(serverAddress))], C.NewDNSPrefer(option.IPVersion)) } if option.HopInterval == 0 { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index eb21561a..11e744cc 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -197,7 +197,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial return nil, err } } - addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) + addr, err := resolveUDPAddr(ctx, "udp", ss.addr, ss.prefer) if err != nil { return nil, err } diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 7012b30b..3eefd2ac 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -102,7 +102,7 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di return nil, err } } - addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) + addr, err := resolveUDPAddr(ctx, "udp", ssr.addr, ssr.prefer) if err != nil { return nil, err } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index b8dd3b39..f7f04d09 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -147,7 +147,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, err = errors.New("invalid UDP bind address") return } else if bindUDPAddr.IP.IsUnspecified() { - serverAddr, err := resolveUDPAddr(ctx, "udp", ss.Addr()) + serverAddr, err := resolveUDPAddr(ctx, "udp", ss.Addr(), C.IPv4Prefer) if err != nil { return nil, err } diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index eaacb817..6616c652 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -130,7 +130,7 @@ func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (transport * return nil, nil, err } } - udpAddr, err := resolveUDPAddrWithPrefer(ctx, "udp", t.addr, t.prefer) + udpAddr, err := resolveUDPAddr(ctx, "udp", t.addr, t.prefer) if err != nil { return nil, nil, err } diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 9f0636a6..c80608a5 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -3,31 +3,17 @@ 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() @@ -49,67 +35,21 @@ func serializesSocksAddr(metadata *C.Metadata) []byte { 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.ResolveIPWithResolver(ctx, host, resolver.ProxyServerHostResolver) - 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) { +func resolveUDPAddr(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.ResolveIPv4WithResolver(ctx, host, resolver.ProxyServerHostResolver) case C.IPv6Only: ip, err = resolver.ResolveIPv6WithResolver(ctx, host, resolver.ProxyServerHostResolver) case C.IPv6Prefer: - var ips []netip.Addr - ips, err = resolver.LookupIPWithResolver(ctx, host, resolver.ProxyServerHostResolver) - if err == nil { - for _, addr := range ips { - if addr.Is6() { - ip = addr - break - } else { - if !fallback.IsValid() { - fallback = addr - } - } - } - } + ip, err = resolver.ResolveIPPrefer6WithResolver(ctx, host, resolver.ProxyServerHostResolver) default: - // C.IPv4Prefer, C.DualStack and other - var ips []netip.Addr - ips, err = resolver.LookupIPWithResolver(ctx, host, resolver.ProxyServerHostResolver) - 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 + ip, err = resolver.ResolveIPWithResolver(ctx, host, resolver.ProxyServerHostResolver) } if err != nil { diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 57138947..06d67f87 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -301,7 +301,7 @@ func (w *WireGuard) resolve(ctx context.Context, address M.Socksaddr) (netip.Add if address.Addr.IsValid() { return address.AddrPort(), nil } - udpAddr, err := resolveUDPAddrWithPrefer(ctx, "udp", address.String(), w.prefer) + udpAddr, err := resolveUDPAddr(ctx, "udp", address.String(), w.prefer) if err != nil { return netip.AddrPort{}, err } diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 1eb3d642..add691ad 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -196,6 +196,26 @@ func ResolveIP(ctx context.Context, host string) (netip.Addr, error) { return ResolveIPWithResolver(ctx, host, DefaultResolver) } +// ResolveIPPrefer6WithResolver same as ResolveIP, but with a resolver +func ResolveIPPrefer6WithResolver(ctx context.Context, host string, r Resolver) (netip.Addr, error) { + ips, err := LookupIPWithResolver(ctx, host, r) + if err != nil { + return netip.Addr{}, err + } else if len(ips) == 0 { + return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host) + } + ipv4s, ipv6s := SortationAddr(ips) + if len(ipv6s) > 0 { + return ipv6s[randv2.IntN(len(ipv6s))], nil + } + return ipv4s[randv2.IntN(len(ipv4s))], nil +} + +// ResolveIPPrefer6 with a host, return ip and priority return TypeAAAA +func ResolveIPPrefer6(ctx context.Context, host string) (netip.Addr, error) { + return ResolveIPPrefer6WithResolver(ctx, host, DefaultResolver) +} + func ResetConnection() { if DefaultResolver != nil { go DefaultResolver.ResetConnection()