Chore: reduce dhcp dns client cost
This commit is contained in:
parent
5845420649
commit
81dd0ed2db
3 changed files with 44 additions and 35 deletions
19
dns/dhcp.go
19
dns/dhcp.go
|
@ -29,7 +29,7 @@ type dhcpClient struct {
|
||||||
|
|
||||||
ifaceAddr *net.IPNet
|
ifaceAddr *net.IPNet
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
resolver *Resolver
|
clients []dnsClient
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,15 +41,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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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()
|
d.lock.Lock()
|
||||||
|
|
||||||
invalidated, err := d.invalidate()
|
invalidated, err := d.invalidate()
|
||||||
|
@ -64,8 +64,9 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), DHCPTimeout)
|
ctx, cancel := context.WithTimeout(context.Background(), DHCPTimeout)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
var res *Resolver
|
var res []dnsClient
|
||||||
dns, err := dhcp.ResolveDNSFromDHCP(ctx, d.ifaceName)
|
dns, err := dhcp.ResolveDNSFromDHCP(ctx, d.ifaceName)
|
||||||
|
// dns never empty if err is nil
|
||||||
if err == nil {
|
if err == nil {
|
||||||
nameserver := make([]NameServer, 0, len(dns))
|
nameserver := make([]NameServer, 0, len(dns))
|
||||||
for _, item := range dns {
|
for _, item := range dns {
|
||||||
|
@ -75,9 +76,7 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
res = NewResolver(Config{
|
res = transform(nameserver, nil)
|
||||||
Main: nameserver,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d.lock.Lock()
|
d.lock.Lock()
|
||||||
|
@ -86,7 +85,7 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
|
||||||
close(done)
|
close(done)
|
||||||
|
|
||||||
d.done = nil
|
d.done = nil
|
||||||
d.resolver = res
|
d.clients = res
|
||||||
d.err = err
|
d.err = err
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -96,7 +95,7 @@ func (d *dhcpClient) resolve(ctx context.Context) (*Resolver, error) {
|
||||||
for {
|
for {
|
||||||
d.lock.Lock()
|
d.lock.Lock()
|
||||||
|
|
||||||
res, err, done := d.resolver, d.err, d.done
|
res, err, done := d.clients, d.err, d.done
|
||||||
|
|
||||||
d.lock.Unlock()
|
d.lock.Unlock()
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
"github.com/Dreamacro/clash/common/picker"
|
|
||||||
"github.com/Dreamacro/clash/component/fakeip"
|
"github.com/Dreamacro/clash/component/fakeip"
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
|
@ -187,31 +186,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) {
|
func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
|
||||||
fast, ctx := picker.WithTimeout(ctx, resolver.DefaultDNSTimeout)
|
ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDNSTimeout)
|
||||||
for _, client := range clients {
|
defer cancel()
|
||||||
r := client
|
|
||||||
fast.Go(func() (any, 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()
|
return batchExchange(ctx, clients, m)
|
||||||
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.(*D.Msg)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
|
func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient {
|
||||||
|
|
32
dns/util.go
32
dns/util.go
|
@ -1,11 +1,15 @@
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/cache"
|
"github.com/Dreamacro/clash/common/cache"
|
||||||
|
"github.com/Dreamacro/clash/common/picker"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
|
||||||
D "github.com/miekg/dns"
|
D "github.com/miekg/dns"
|
||||||
|
@ -102,3 +106,31 @@ func msgToIP(msg *D.Msg) []net.IP {
|
||||||
|
|
||||||
return ips
|
return ips
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) {
|
||||||
|
fast, ctx := picker.WithContext(ctx)
|
||||||
|
for _, client := range clients {
|
||||||
|
r := client
|
||||||
|
fast.Go(func() (any, 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.(*D.Msg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue