net/dns/resolver: log forwarded query details when TS_DEBUG_DNS_FORWARD_SEND is enabled

Troubleshooting DNS resolution issues often requires additional information.
This PR expands the effect of the TS_DEBUG_DNS_FORWARD_SEND envknob to forwarder.forwardWithDestChan,
and includes the request type, domain name length, and the first 3 bytes of the domain's SHA-256 hash in the output.

Fixes #13070

Signed-off-by: Nick Khyl <nickk@tailscale.com>
jwhited/derp-https-tcp-connect
Nick Khyl 4 months ago committed by Nick Khyl
parent a867a4869d
commit f23932bd98

@ -6,6 +6,8 @@ package resolver
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/sha256"
"encoding/base64"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
@ -498,9 +500,10 @@ var (
func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) { func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) {
if verboseDNSForward() { if verboseDNSForward() {
id := forwarderCount.Add(1) id := forwarderCount.Add(1)
f.logf("forwarder.send(%q) [%d] ...", rr.name.Addr, id) domain, typ, _ := nameFromQuery(fq.packet)
f.logf("forwarder.send(%q, %d, %v, %d) [%d] ...", rr.name.Addr, fq.txid, typ, len(domain), id)
defer func() { defer func() {
f.logf("forwarder.send(%q) [%d] = %v, %v", rr.name.Addr, id, len(ret), err) f.logf("forwarder.send(%q, %d, %v, %d) [%d] = %v, %v", rr.name.Addr, fq.txid, typ, len(domain), id, len(ret), err)
}() }()
} }
if strings.HasPrefix(rr.name.Addr, "http://") { if strings.HasPrefix(rr.name.Addr, "http://") {
@ -866,7 +869,7 @@ type forwardQuery struct {
// node DNS proxy queries), otherwise f.resolvers is used. // node DNS proxy queries), otherwise f.resolvers is used.
func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, responseChan chan<- packet, resolvers ...resolverAndDelay) error { func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, responseChan chan<- packet, resolvers ...resolverAndDelay) error {
metricDNSFwd.Add(1) metricDNSFwd.Add(1)
domain, err := nameFromQuery(query.bs) domain, typ, err := nameFromQuery(query.bs)
if err != nil { if err != nil {
metricDNSFwdErrorName.Add(1) metricDNSFwdErrorName.Add(1)
return err return err
@ -943,6 +946,12 @@ func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, respo
} }
defer fq.closeOnCtxDone.Close() defer fq.closeOnCtxDone.Close()
if verboseDNSForward() {
domainSha256 := sha256.Sum256([]byte(domain))
domainSig := base64.RawStdEncoding.EncodeToString(domainSha256[:3])
f.logf("request(%d, %v, %d, %s) %d...", fq.txid, typ, len(domain), domainSig, len(fq.packet))
}
resc := make(chan []byte, 1) // it's fine buffered or not resc := make(chan []byte, 1) // it's fine buffered or not
errc := make(chan error, 1) // it's fine buffered or not too errc := make(chan error, 1) // it's fine buffered or not too
for i := range resolvers { for i := range resolvers {
@ -982,6 +991,9 @@ func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, respo
metricDNSFwdErrorContext.Add(1) metricDNSFwdErrorContext.Add(1)
return fmt.Errorf("waiting to send response: %w", ctx.Err()) return fmt.Errorf("waiting to send response: %w", ctx.Err())
case responseChan <- packet{v, query.family, query.addr}: case responseChan <- packet{v, query.family, query.addr}:
if verboseDNSForward() {
f.logf("response(%d, %v, %d) = %d, nil", fq.txid, typ, len(domain), len(v))
}
metricDNSFwdSuccess.Add(1) metricDNSFwdSuccess.Add(1)
f.health.SetHealthy(dnsForwarderFailing) f.health.SetHealthy(dnsForwarderFailing)
return nil return nil
@ -1009,6 +1021,9 @@ func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, respo
} }
f.health.SetUnhealthy(dnsForwarderFailing, health.Args{health.ArgDNSServers: strings.Join(resolverAddrs, ",")}) f.health.SetUnhealthy(dnsForwarderFailing, health.Args{health.ArgDNSServers: strings.Join(resolverAddrs, ",")})
case responseChan <- res: case responseChan <- res:
if verboseDNSForward() {
f.logf("forwarder response(%d, %v, %d) = %d, %v", fq.txid, typ, len(domain), len(res.bs), firstErr)
}
} }
} }
return firstErr return firstErr
@ -1037,24 +1052,28 @@ func (f *forwarder) forwardWithDestChan(ctx context.Context, query packet, respo
var initListenConfig func(_ *net.ListenConfig, _ *netmon.Monitor, tunName string) error var initListenConfig func(_ *net.ListenConfig, _ *netmon.Monitor, tunName string) error
// nameFromQuery extracts the normalized query name from bs. // nameFromQuery extracts the normalized query name from bs.
func nameFromQuery(bs []byte) (dnsname.FQDN, error) { func nameFromQuery(bs []byte) (dnsname.FQDN, dns.Type, error) {
var parser dns.Parser var parser dns.Parser
hdr, err := parser.Start(bs) hdr, err := parser.Start(bs)
if err != nil { if err != nil {
return "", err return "", 0, err
} }
if hdr.Response { if hdr.Response {
return "", errNotQuery return "", 0, errNotQuery
} }
q, err := parser.Question() q, err := parser.Question()
if err != nil { if err != nil {
return "", err return "", 0, err
} }
n := q.Name.Data[:q.Name.Length] n := q.Name.Data[:q.Name.Length]
return dnsname.ToFQDN(rawNameToLower(n)) fqdn, err := dnsname.ToFQDN(rawNameToLower(n))
if err != nil {
return "", 0, err
}
return fqdn, q.Type, nil
} }
// nxDomainResponse returns an NXDomain DNS reply for the provided request. // nxDomainResponse returns an NXDomain DNS reply for the provided request.

@ -201,7 +201,7 @@ func BenchmarkNameFromQuery(b *testing.B) {
b.ResetTimer() b.ResetTimer()
b.ReportAllocs() b.ReportAllocs()
for range b.N { for range b.N {
_, err := nameFromQuery(msg) _, _, err := nameFromQuery(msg)
if err != nil { if err != nil {
b.Fatal(err) b.Fatal(err)
} }

Loading…
Cancel
Save