diff --git a/net/dns/resolver/forwarder.go b/net/dns/resolver/forwarder.go index 8459c28fa..162fd5f15 100644 --- a/net/dns/resolver/forwarder.go +++ b/net/dns/resolver/forwarder.go @@ -41,6 +41,19 @@ // headerBytes is the number of bytes in a DNS message header. const headerBytes = 12 +// dnsFlagTruncated is set in the flags word when the packet is truncated. +const dnsFlagTruncated = 0x200 + +// truncatedFlagSet returns true if the DNS packet signals that it has +// been truncated. False is also returned if the packet was too small +// to be valid. +func truncatedFlagSet(pkt []byte) bool { + if len(pkt) < headerBytes { + return false + } + return (binary.BigEndian.Uint16(pkt[2:4]) & dnsFlagTruncated) != 0 +} + const ( // responseTimeout is the maximal amount of time to wait for a DNS response. responseTimeout = 5 * time.Second @@ -420,6 +433,9 @@ func (f *forwarder) sendDoH(ctx context.Context, urlBase string, c *http.Client, if err != nil { metricDNSFwdDoHErrorBody.Add(1) } + if truncatedFlagSet(res) { + metricDNSFwdTruncated.Add(1) + } return res, err } @@ -456,13 +472,18 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe metricDNSFwdErrorType.Add(1) return nil, fmt.Errorf("tls:// resolvers not supported yet") } + + return f.sendUDP(ctx, fq, rr) +} + +func (f *forwarder) sendUDP(ctx context.Context, fq *forwardQuery, rr resolverAndDelay) (ret []byte, err error) { ipp, ok := rr.name.IPPort() if !ok { metricDNSFwdErrorType.Add(1) return nil, fmt.Errorf("unrecognized resolver type %q", rr.name.Addr) } - metricDNSFwdUDP.Add(1) + ln, err := f.packetListener(ipp.IP()) if err != nil { return nil, err @@ -522,7 +543,7 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe } if truncated { - const dnsFlagTruncated = 0x200 + // Set the truncated bit if it wasn't already. flags := binary.BigEndian.Uint16(out[2:4]) flags |= dnsFlagTruncated binary.BigEndian.PutUint16(out[2:4], flags) @@ -534,6 +555,10 @@ func (f *forwarder) send(ctx context.Context, fq *forwardQuery, rr resolverAndDe // best we can do. } + if truncatedFlagSet(out) { + metricDNSFwdTruncated.Add(1) + } + clampEDNSSize(out, maxResponseBytes) metricDNSFwdUDPSuccess.Add(1) return out, nil diff --git a/net/dns/resolver/tsdns.go b/net/dns/resolver/tsdns.go index 792a2e522..5d2b71107 100644 --- a/net/dns/resolver/tsdns.go +++ b/net/dns/resolver/tsdns.go @@ -1340,6 +1340,7 @@ func unARPA(a string) (ipStr string, ok bool) { metricDNSFwdErrorType = clientmetric.NewCounter("dns_query_fwd_error_type") metricDNSFwdErrorParseAddr = clientmetric.NewCounter("dns_query_fwd_error_parse_addr") + metricDNSFwdTruncated = clientmetric.NewCounter("dns_query_fwd_truncated") metricDNSFwdUDP = clientmetric.NewCounter("dns_query_fwd_udp") // on entry metricDNSFwdUDPWrote = clientmetric.NewCounter("dns_query_fwd_udp_wrote") // sent UDP packet