diff --git a/command/agent/dns.go b/command/agent/dns.go index c0ee3f773..409fca710 100644 --- a/command/agent/dns.go +++ b/command/agent/dns.go @@ -487,22 +487,20 @@ func (d *DNSServer) formatNodeRecord(node *structs.Node, addr, qName string, qTy return records } -// trimAnswers makes sure a UDP response is not longer than allowed by RFC 1035 +// trimAnswers makes sure a UDP response is not longer than allowed by RFC 1035. +// We first enforce an arbitrary limit, and then make sure the response doesn't +// exceed 512 bytes. func trimAnswers(resp *dns.Msg) (trimmed bool) { numAnswers := len(resp.Answer) + // This cuts UDP responses to a useful but limited number of responses. if numAnswers > maxServiceResponses { resp.Answer = resp.Answer[:maxServiceResponses] } - // Check that the response isn't more than 512 bytes - for respBytes := resp.Len(); respBytes > 512; respBytes = resp.Len() { + // This enforces the hard limit of 512 bytes per the RFC. + for len(resp.Answer) > 0 && resp.Len() > 512 { resp.Answer = resp.Answer[:len(resp.Answer)-1] - - if len(resp.Answer) == 0 { - // We've done all we can - break - } } return len(resp.Answer) < numAnswers diff --git a/command/agent/dns_test.go b/command/agent/dns_test.go index afbd6ebbc..94cc1e14d 100644 --- a/command/agent/dns_test.go +++ b/command/agent/dns_test.go @@ -1991,29 +1991,55 @@ func TestDNS_ServiceLookup_LargeResponses(t *testing.T) { } } - m := new(dns.Msg) - m.SetQuestion("_"+longServiceName+"._master.service.consul.", dns.TypeSRV) - - c := new(dns.Client) - addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) - in, _, err := c.Exchange(m, addr.String()) - if err != nil && err != dns.ErrTruncated { - t.Fatalf("err: %v", err) + // Register an equivalent prepared query. + { + args := &structs.PreparedQueryRequest{ + Datacenter: "dc1", + Op: structs.PreparedQueryCreate, + Query: &structs.PreparedQuery{ + Name: longServiceName, + Service: structs.ServiceQuery{ + Service: longServiceName, + Tags: []string{"master"}, + }, + }, + } + var id string + if err := srv.agent.RPC("PreparedQuery.Apply", args, &id); err != nil { + t.Fatalf("err: %v", err) + } } - // Make sure the response size is RFC 1035-compliant for UDP messages - if in.Len() > 512 { - t.Fatalf("Bad: %#v", in.Len()) + // Look up the service directly and via prepared query. + questions := []string{ + "_" + longServiceName + "._master.service.consul.", + longServiceName + ".query.consul.", } + for _, question := range questions { + m := new(dns.Msg) + m.SetQuestion(question, dns.TypeSRV) - // We should only have two answers now - if len(in.Answer) != 2 { - t.Fatalf("Bad: %#v", len(in.Answer)) - } + c := new(dns.Client) + addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS) + in, _, err := c.Exchange(m, addr.String()) + if err != nil && err != dns.ErrTruncated { + t.Fatalf("err: %v", err) + } - // Check for the truncate bit - if !in.Truncated { - t.Fatalf("should have truncate bit") + // Make sure the response size is RFC 1035-compliant for UDP messages + if in.Len() > 512 { + t.Fatalf("Bad: %#v", in.Len()) + } + + // We should only have two answers now + if len(in.Answer) != 2 { + t.Fatalf("Bad: %#v", len(in.Answer)) + } + + // Check for the truncate bit + if !in.Truncated { + t.Fatalf("should have truncate bit") + } } }