diff --git a/dns/client.go b/dns/client.go index fe9362bb..211eb91f 100644 --- a/dns/client.go +++ b/dns/client.go @@ -25,6 +25,26 @@ type client struct { host string iface *atomic.String proxyAdapter string + addr string +} + +var _ dnsClient = (*client)(nil) + +// Address implements dnsClient +func (c *client) Address() string { + if len(c.addr) != 0 { + return c.addr + } + schema := "udp" + if strings.HasPrefix(c.Client.Net, "tcp") { + schema = "tcp" + if strings.HasSuffix(c.Client.Net, "tls") { + schema = "tls" + } + } + + c.addr = fmt.Sprintf("%s//:%s", schema, net.JoinHostPort(c.host, c.port)) + return c.addr } func (c *client) Exchange(m *D.Msg) (*D.Msg, error) { diff --git a/dns/dhcp.go b/dns/dhcp.go index 1efa3bd1..151e4421 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -2,12 +2,14 @@ package dns import ( "context" - "go.uber.org/atomic" "net" "net/netip" + "strings" "sync" "time" + "go.uber.org/atomic" + "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/resolver" @@ -34,6 +36,17 @@ type dhcpClient struct { err error } +var _ dnsClient = (*dhcpClient)(nil) + +// Address implements dnsClient +func (d *dhcpClient) Address() string { + addrs := make([]string, 0) + for _, c := range d.clients { + addrs = append(addrs, c.Address()) + } + return strings.Join(addrs, ",") +} + func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) defer cancel() diff --git a/dns/doh.go b/dns/doh.go index 5abd0479..df3df6b4 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -64,6 +64,7 @@ type dnsOverHTTPS struct { r *Resolver httpVersions []C.HTTPVersion proxyAdapter string + addr string } // type check @@ -83,6 +84,7 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin doh := &dnsOverHTTPS{ url: u, + addr: u.String(), r: r, proxyAdapter: proxyAdapter, quicConfig: &quic.Config{ @@ -98,7 +100,9 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin } // Address implements the Upstream interface for *dnsOverHTTPS. -func (doh *dnsOverHTTPS) Address() string { return doh.url.String() } +func (doh *dnsOverHTTPS) Address() string { + return doh.addr +} func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { // Quote from https://www.rfc-editor.org/rfc/rfc8484.html: // In order to maximize HTTP cache friendliness, DoH clients using media diff --git a/dns/middleware.go b/dns/middleware.go index 28ced849..7dc9622d 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -164,7 +164,6 @@ func withResolver(resolver *Resolver) handler { msg.SetRcode(r, msg.Rcode) msg.Authoritative = true - log.Debugln("[DNS] %s --> %s", msgToDomain(r), msgToIP(msg)) return msg, nil } } diff --git a/dns/resolver.go b/dns/resolver.go index 8784dd78..895b7393 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -26,6 +26,7 @@ import ( type dnsClient interface { Exchange(m *D.Msg) (msg *D.Msg, err error) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) + Address() string } type result struct { diff --git a/dns/util.go b/dns/util.go index e53abab0..203ab615 100644 --- a/dns/util.go +++ b/dns/util.go @@ -235,15 +235,18 @@ func listenPacket(ctx context.Context, proxyAdapter string, network string, addr func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) { fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) + domain := msgToDomain(m) for _, client := range clients { r := client fast.Go(func() (*D.Msg, error) { + log.Debugln("[DNS] resolve %s from %s", domain, r.Address()) 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") } + log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), r.Address()) return m, nil }) } @@ -256,7 +259,6 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M } return nil, err } - msg = elm return }