Merge branch 'dev' of https://github.com/Dreamacro/clash into Alpha

This commit is contained in:
wwqgtxx
2022-11-12 20:43:48 +08:00
51 changed files with 641 additions and 742 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt"
tlsC "github.com/Dreamacro/clash/component/tls"
"go.uber.org/atomic"
"math/rand"
"net"
"net/netip"
"strings"
@ -34,15 +35,19 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error)
ip netip.Addr
err error
)
if ip, err = netip.ParseAddr(c.host); err != nil {
if c.r == nil {
if c.r == nil {
// a default ip dns
if ip, err = netip.ParseAddr(c.host); err != nil {
return nil, fmt.Errorf("dns %s not a valid ip", c.host)
} else {
if ip, err = resolver.ResolveIPWithResolver(ctx, c.host, c.r); err != nil {
return nil, fmt.Errorf("use default dns resolve failed: %w", err)
}
c.host = ip.String()
}
} else {
ips, err := resolver.LookupIPWithResolver(ctx, c.host, c.r)
if err != nil {
return nil, fmt.Errorf("use default dns resolve failed: %w", err)
} else if len(ips) == 0 {
return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, c.host)
}
ip = ips[rand.Intn(len(ips))]
}
network := "udp"

View File

@ -30,7 +30,7 @@ type dhcpClient struct {
ifaceAddr *netip.Prefix
done chan struct{}
resolver *Resolver
clients []dnsClient
err error
}
@ -42,15 +42,15 @@ func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) {
}
func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) {
res, err := d.resolve(ctx)
clients, err := d.resolve(ctx)
if err != nil {
return nil, err
}
return res.ExchangeContext(ctx, m)
return batchExchange(ctx, clients, m)
}
func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) {
d.lock.Lock()
invalidated, err := d.invalidate()
@ -65,8 +65,9 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
ctx, cancel := context.WithTimeout(context.Background(), DHCPTimeout)
defer cancel()
var res *Resolver
var res []dnsClient
dns, err := dhcp.ResolveDNSFromDHCP(ctx, d.ifaceName)
// dns never empty if err is nil
if err == nil {
nameserver := make([]NameServer, 0, len(dns))
for _, item := range dns {
@ -76,9 +77,7 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
})
}
res = NewResolver(Config{
Main: nameserver,
})
res = transform(nameserver, nil)
}
d.lock.Lock()
@ -87,7 +86,7 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
close(done)
d.done = nil
d.resolver = res
d.clients = res
d.err = err
}()
}
@ -97,7 +96,7 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
for {
d.lock.Lock()
res, err, done := d.resolver, d.err, d.done
res, err, done := d.clients, d.err, d.done
d.lock.Unlock()

View File

@ -109,7 +109,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer {
if cfg.EnhancedMode != C.DNSNormal {
fakePool = cfg.Pool
mapping = cache.NewLRUCache[netip.Addr, string](cache.WithSize[netip.Addr, string](4096), cache.WithStale[netip.Addr, string](true))
mapping = cache.New[netip.Addr, string](cache.WithSize[netip.Addr, string](4096), cache.WithStale[netip.Addr, string](true))
}
return &ResolverEnhancer{

View File

@ -3,14 +3,12 @@ package dns
import (
"context"
"errors"
"fmt"
"go.uber.org/atomic"
"math/rand"
"net/netip"
"time"
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/common/picker"
"github.com/Dreamacro/clash/component/fakeip"
"github.com/Dreamacro/clash/component/geodata/router"
"github.com/Dreamacro/clash/component/resolver"
@ -48,14 +46,14 @@ func (r *Resolver) LookupIPPrimaryIPv4(ctx context.Context, host string) (ips []
ch := make(chan []netip.Addr, 1)
go func() {
defer close(ch)
ip, err := r.resolveIP(ctx, host, D.TypeAAAA)
ip, err := r.lookupIP(ctx, host, D.TypeAAAA)
if err != nil {
return
}
ch <- ip
}()
ips, err = r.resolveIP(ctx, host, D.TypeA)
ips, err = r.lookupIP(ctx, host, D.TypeA)
if err == nil {
return
}
@ -72,7 +70,7 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr,
ch := make(chan []netip.Addr, 1)
go func() {
defer close(ch)
ip, err := r.resolveIP(ctx, host, D.TypeAAAA)
ip, err := r.lookupIP(ctx, host, D.TypeAAAA)
if err != nil {
return
}
@ -80,7 +78,7 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr,
ch <- ip
}()
ips, err = r.resolveIP(ctx, host, D.TypeA)
ips, err = r.lookupIP(ctx, host, D.TypeA)
select {
case ipv6s, open := <-ch:
@ -96,11 +94,11 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr,
}
func (r *Resolver) LookupIPv4(ctx context.Context, host string) (ips []netip.Addr, err error) {
return r.resolveIP(ctx, host, D.TypeA)
return r.lookupIP(ctx, host, D.TypeA)
}
func (r *Resolver) LookupIPv6(ctx context.Context, host string) (ips []netip.Addr, err error) {
return r.resolveIP(ctx, host, D.TypeAAAA)
return r.lookupIP(ctx, host, D.TypeAAAA)
}
// ResolveIP request with TypeA and TypeAAAA, priority return TypeA
@ -213,31 +211,10 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M
}
func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout)
for _, client := range clients {
r := client
fast.Go(func() (*D.Msg, error) {
m, err := r.ExchangeContext(ctx, m)
if err != nil {
return nil, err
} else if m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused {
return nil, errors.New("server failure")
}
return m, nil
})
}
ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDNSTimeout)
defer cancel()
elm := fast.Wait()
if elm == nil {
err := errors.New("all DNS requests failed")
if fErr := fast.Error(); fErr != nil {
err = fmt.Errorf("%w, first error: %s", err, fErr.Error())
}
return nil, err
}
msg = elm
return
return batchExchange(ctx, clients, m)
}
func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
@ -315,7 +292,7 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er
return
}
func (r *Resolver) resolveIP(ctx context.Context, host string, dnsType uint16) (ips []netip.Addr, err error) {
func (r *Resolver) lookupIP(ctx context.Context, host string, dnsType uint16) (ips []netip.Addr, err error) {
ip, err := netip.ParseAddr(host)
if err == nil {
isIPv4 := ip.Is4()
@ -391,13 +368,13 @@ type Config struct {
func NewResolver(config Config) *Resolver {
defaultResolver := &Resolver{
main: transform(config.Default, nil),
lruCache: cache.NewLRUCache[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)),
lruCache: cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)),
}
r := &Resolver{
ipv6: config.IPv6,
main: transform(config.Main, defaultResolver),
lruCache: cache.NewLRUCache[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)),
lruCache: cache.New[string, *D.Msg](cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)),
hosts: config.Hosts,
}

View File

@ -3,6 +3,7 @@ package dns
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/netip"
@ -11,7 +12,9 @@ import (
"github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/common/nnip"
"github.com/Dreamacro/clash/common/picker"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
@ -71,8 +74,8 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient {
case "quic":
if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter); err == nil {
ret = append(ret, doq)
}else{
log.Fatalln("DoQ format error: %v",err)
} else {
log.Fatalln("DoQ format error: %v", err)
}
continue
}
@ -208,3 +211,31 @@ func dialContextExtra(ctx context.Context, adapterName string, network string, d
return adapter.DialContext(ctx, metadata, opts...)
}
func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout)
for _, client := range clients {
r := client
fast.Go(func() (*D.Msg, error) {
m, err := r.ExchangeContext(ctx, m)
if err != nil {
return nil, err
} else if m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused {
return nil, errors.New("server failure")
}
return m, nil
})
}
elm := fast.Wait()
if elm == nil {
err := errors.New("all DNS requests failed")
if fErr := fast.Error(); fErr != nil {
err = fmt.Errorf("%w, first error: %s", err, fErr.Error())
}
return nil, err
}
msg = elm
return
}