diff --git a/agent/dns.go b/agent/dns.go index 1d3c46d972..e014c1330d 100644 --- a/agent/dns.go +++ b/agent/dns.go @@ -337,7 +337,7 @@ func (d *DNSServer) addSOA(msg *dns.Msg) { // nameservers returns the names and ip addresses of up to three random servers // in the current cluster which serve as authoritative name servers for zone. func (d *DNSServer) nameservers(edns bool) (ns []dns.RR, extra []dns.RR) { - out, err := d.lookupServiceNodes(d.agent.config.Datacenter, structs.ConsulServiceName, "") + out, err := d.lookupServiceNodes(d.agent.config.Datacenter, structs.ConsulServiceName, "", false) if err != nil { d.logger.Printf("[WARN] dns: Unable to get list of servers: %s", err) return nil, nil @@ -415,7 +415,7 @@ PARSE: n = n + 1 } - switch labels[n-1] { + switch kind := labels[n-1]; kind { case "service": if n == 1 { goto INVALID @@ -433,7 +433,7 @@ PARSE: } // _name._tag.service.consul - d.serviceLookup(network, datacenter, labels[n-3][1:], tag, req, resp) + d.serviceLookup(network, datacenter, labels[n-3][1:], tag, false, req, resp) // Consul 0.3 and prior format for SRV queries } else { @@ -445,9 +445,17 @@ PARSE: } // tag[.tag].name.service.consul - d.serviceLookup(network, datacenter, labels[n-2], tag, req, resp) + d.serviceLookup(network, datacenter, labels[n-2], tag, false, req, resp) } + case "connect": + if n == 1 { + goto INVALID + } + + // name.connect.consul + d.serviceLookup(network, datacenter, labels[n-2], "", true, req, resp) + case "node": if n == 1 { goto INVALID @@ -898,8 +906,9 @@ func (d *DNSServer) trimDNSResponse(network string, req, resp *dns.Msg) (trimmed } // lookupServiceNodes returns nodes with a given service. -func (d *DNSServer) lookupServiceNodes(datacenter, service, tag string) (structs.IndexedCheckServiceNodes, error) { +func (d *DNSServer) lookupServiceNodes(datacenter, service, tag string, connect bool) (structs.IndexedCheckServiceNodes, error) { args := structs.ServiceSpecificRequest{ + Connect: connect, Datacenter: datacenter, ServiceName: service, ServiceTag: tag, @@ -935,8 +944,8 @@ func (d *DNSServer) lookupServiceNodes(datacenter, service, tag string) (structs } // serviceLookup is used to handle a service query -func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, req, resp *dns.Msg) { - out, err := d.lookupServiceNodes(datacenter, service, tag) +func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, connect bool, req, resp *dns.Msg) { + out, err := d.lookupServiceNodes(datacenter, service, tag, connect) if err != nil { d.logger.Printf("[ERR] dns: rpc error: %v", err) resp.SetRcode(req, dns.RcodeServerFailure) diff --git a/agent/dns_test.go b/agent/dns_test.go index 41aca8e0e2..5d10828880 100644 --- a/agent/dns_test.go +++ b/agent/dns_test.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/serf/coordinate" "github.com/miekg/dns" "github.com/pascaldekloe/goe/verify" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1041,6 +1042,48 @@ func TestDNS_ServiceLookupWithInternalServiceAddress(t *testing.T) { verify.Values(t, "extra", in.Extra, wantExtra) } +func TestDNS_ConnectServiceLookup(t *testing.T) { + t.Parallel() + + assert := assert.New(t) + a := NewTestAgent(t.Name(), "") + defer a.Shutdown() + + // Register a node with an external service. + { + args := structs.TestRegisterRequestProxy(t) + args.Service.ProxyDestination = "db" + args.Service.Port = 12345 + var out struct{} + assert.Nil(a.RPC("Catalog.Register", args, &out)) + } + + // Look up the service + questions := []string{ + "db.connect.consul.", + } + for _, question := range questions { + m := new(dns.Msg) + m.SetQuestion(question, dns.TypeSRV) + + c := new(dns.Client) + in, _, err := c.Exchange(m, a.DNSAddr()) + assert.Nil(err) + assert.Len(in.Answer, 1) + + srvRec, ok := in.Answer[0].(*dns.SRV) + assert.True(ok) + assert.Equal(12345, srvRec.Port) + assert.Equal("foo.node.dc1.consul.", srvRec.Target) + assert.Equal(0, srvRec.Hdr.Ttl) + + cnameRec, ok := in.Extra[0].(*dns.CNAME) + assert.True(ok) + assert.Equal("foo.node.dc1.consul.", cnameRec.Hdr.Name) + assert.Equal(0, srvRec.Hdr.Ttl) + } +} + func TestDNS_ExternalServiceLookup(t *testing.T) { t.Parallel() a := NewTestAgent(t.Name(), "")