feat: support tcp concurrent, Separate dialing and dns resolver ipv6
tcp-concurrent:true
This commit is contained in:
@ -3,12 +3,15 @@ package dialer
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/Dreamacro/clash/log"
|
||||
"net"
|
||||
"net/netip"
|
||||
|
||||
"github.com/Dreamacro/clash/component/resolver"
|
||||
)
|
||||
|
||||
var DisableIPv6 = false
|
||||
|
||||
func DialContext(ctx context.Context, network, address string, options ...Option) (net.Conn, error) {
|
||||
opt := &option{
|
||||
interfaceName: DefaultInterface.Load(),
|
||||
@ -51,7 +54,11 @@ func DialContext(ctx context.Context, network, address string, options ...Option
|
||||
|
||||
return dialContext(ctx, network, ip, port, opt)
|
||||
case "tcp", "udp":
|
||||
return dualStackDialContext(ctx, network, address, opt)
|
||||
if TCPConcurrent && network == "tcp" {
|
||||
return concurrentDialContext(ctx, network, address, opt)
|
||||
} else {
|
||||
return dualStackDialContext(ctx, network, address, opt)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New("network invalid")
|
||||
}
|
||||
@ -183,3 +190,73 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt
|
||||
|
||||
return nil, errors.New("never touched")
|
||||
}
|
||||
|
||||
func concurrentDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) {
|
||||
host, port, err := net.SplitHostPort(address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
returned := make(chan struct{})
|
||||
defer close(returned)
|
||||
|
||||
type dialResult struct {
|
||||
ip netip.Addr
|
||||
net.Conn
|
||||
error
|
||||
resolved bool
|
||||
}
|
||||
|
||||
results := make(chan dialResult)
|
||||
var ips []netip.Addr
|
||||
|
||||
if opt.direct {
|
||||
ips, err = resolver.ResolveAllIP(host)
|
||||
} else {
|
||||
ips, err = resolver.ResolveAllIPProxyServerHost(host)
|
||||
}
|
||||
|
||||
tcpRacer := func(ctx context.Context, ip netip.Addr) {
|
||||
result := dialResult{ip: ip}
|
||||
|
||||
defer func() {
|
||||
select {
|
||||
case results <- result:
|
||||
case <-returned:
|
||||
if result.Conn != nil {
|
||||
result.Conn.Close()
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
v := "4"
|
||||
if ip.Is6() {
|
||||
v = "6"
|
||||
}
|
||||
|
||||
log.Debugln("[%s] try use [%s] connected", host, ip.String())
|
||||
result.Conn, result.error = dialContext(ctx, network+v, ip, port, opt)
|
||||
}
|
||||
|
||||
for _, ip := range ips {
|
||||
go tcpRacer(ctx, ip)
|
||||
}
|
||||
|
||||
connCount := len(ips)
|
||||
for res := range results {
|
||||
connCount--
|
||||
if res.error == nil {
|
||||
connIp := res.Conn.RemoteAddr()
|
||||
log.Debugln("[%s] used [%s] connected", host, connIp)
|
||||
return res.Conn, nil
|
||||
}
|
||||
|
||||
log.Errorln("connect error:%v", res.error)
|
||||
if connCount == 0 {
|
||||
log.Errorln("connect [%s] all ip failed", host)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.New("all ip tcp shakeHands failed")
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ var (
|
||||
DefaultOptions []Option
|
||||
DefaultInterface = atomic.NewString("")
|
||||
DefaultRoutingMark = atomic.NewInt32(0)
|
||||
TCPConcurrent = false
|
||||
)
|
||||
|
||||
type option struct {
|
||||
|
@ -40,6 +40,10 @@ type Resolver interface {
|
||||
ResolveIP(host string) (ip netip.Addr, err error)
|
||||
ResolveIPv4(host string) (ip netip.Addr, err error)
|
||||
ResolveIPv6(host string) (ip netip.Addr, err error)
|
||||
ResolveAllIP(host string) (ip []netip.Addr, err error)
|
||||
ResolveAllIPPrimaryIPv4(host string) (ips []netip.Addr, err error)
|
||||
ResolveAllIPv4(host string) (ips []netip.Addr, err error)
|
||||
ResolveAllIPv6(host string) (ips []netip.Addr, err error)
|
||||
}
|
||||
|
||||
// ResolveIPv4 with a host, return ipv4
|
||||
@ -191,3 +195,51 @@ func ResolveProxyServerHost(host string) (netip.Addr, error) {
|
||||
}
|
||||
return ResolveIP(host)
|
||||
}
|
||||
|
||||
func ResolveAllIPv6WithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
||||
return r.ResolveAllIPv6(host)
|
||||
}
|
||||
|
||||
func ResolveAllIPv4WithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
||||
return r.ResolveAllIPv4(host)
|
||||
}
|
||||
|
||||
func ResolveAllIPWithResolver(host string, r Resolver) ([]netip.Addr, error) {
|
||||
return r.ResolveAllIP(host)
|
||||
}
|
||||
|
||||
func ResolveAllIP(host string) ([]netip.Addr, error) {
|
||||
return ResolveAllIPWithResolver(host, DefaultResolver)
|
||||
}
|
||||
|
||||
func ResolveAllIPv4(host string) ([]netip.Addr, error) {
|
||||
return ResolveAllIPv4WithResolver(host, DefaultResolver)
|
||||
}
|
||||
|
||||
func ResolveAllIPv6(host string) ([]netip.Addr, error) {
|
||||
return ResolveAllIPv6WithResolver(host, DefaultResolver)
|
||||
}
|
||||
|
||||
func ResolveAllIPv6ProxyServerHost(host string) ([]netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveAllIPv6WithResolver(host, ProxyServerHostResolver)
|
||||
}
|
||||
|
||||
return ResolveAllIPv6(host)
|
||||
}
|
||||
|
||||
func ResolveAllIPv4ProxyServerHost(host string) ([]netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveAllIPv4WithResolver(host, ProxyServerHostResolver)
|
||||
}
|
||||
|
||||
return ResolveAllIPv4(host)
|
||||
}
|
||||
|
||||
func ResolveAllIPProxyServerHost(host string) ([]netip.Addr, error) {
|
||||
if ProxyServerHostResolver != nil {
|
||||
return ResolveAllIPWithResolver(host, ProxyServerHostResolver)
|
||||
}
|
||||
|
||||
return ResolveAllIP(host)
|
||||
}
|
||||
|
Reference in New Issue
Block a user