Skip to content

Commit

Permalink
Simple RFC 2782 support with optional .service tag
Browse files Browse the repository at this point in the history
Add support for SRV queries of names matching:
_<service>._<protocol>.[.service][.datacenter]<.domain>
  • Loading branch information
sodre committed Jan 31, 2017
1 parent a64dea8 commit c135c08
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 74 deletions.
10 changes: 9 additions & 1 deletion command/agent/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,20 @@ func (d *DNSServer) dispatch(network string, req, resp *dns.Msg) {
// Split into the label parts
labels := dns.SplitDomainName(qName)

// The last label is either "node", "service", "query", or a datacenter name
// The last label is either "node", "service", "query", "_<protocol>", or a datacenter name
PARSE:
n := len(labels)
if n == 0 {
goto INVALID
}

// If this is a SRV query the "service" label is optional, we add it back to use the
// existing code-path.
if req.Question[0].Qtype == dns.TypeSRV && strings.HasPrefix(labels[n-1], "_") {
labels = append(labels, "service")
n = n + 1
}

switch labels[n-1] {
case "service":
if n == 1 {
Expand Down
164 changes: 92 additions & 72 deletions command/agent/dns_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3393,47 +3393,57 @@ func TestDNS_ServiceLookup_SRV_RFC(t *testing.T) {
t.Fatalf("err: %v", err)
}

m := new(dns.Msg)
m.SetQuestion("_db._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 {
t.Fatalf("err: %v", err)
questions := []string{
"_db._master.service.dc1.consul.",
"_db._master.service.consul.",
"_db._master.dc1.consul.",
"_db._master.consul.",
}

if len(in.Answer) != 1 {
t.Fatalf("Bad: %#v", in)
}
for _, question := range questions {
m := new(dns.Msg)
m.SetQuestion(question, dns.TypeSRV)

srvRec, ok := in.Answer[0].(*dns.SRV)
if !ok {
t.Fatalf("Bad: %#v", in.Answer[0])
}
if srvRec.Port != 12345 {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Target != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Answer[0])
}
c := new(dns.Client)
addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS)
in, _, err := c.Exchange(m, addr.String())
if err != nil {
t.Fatalf("err: %v", err)
}

aRec, ok := in.Extra[0].(*dns.A)
if !ok {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Name != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.A.String() != "127.0.0.1" {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Extra[0])
if len(in.Answer) != 1 {
t.Fatalf("Bad: %#v", in)
}

srvRec, ok := in.Answer[0].(*dns.SRV)
if !ok {
t.Fatalf("Bad: %#v", in.Answer[0])
}
if srvRec.Port != 12345 {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Target != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Answer[0])
}

aRec, ok := in.Extra[0].(*dns.A)
if !ok {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Name != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.A.String() != "127.0.0.1" {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Extra[0])
}
}

}

func TestDNS_ServiceLookup_SRV_RFC_TCP_Default(t *testing.T) {
Expand All @@ -3460,47 +3470,57 @@ func TestDNS_ServiceLookup_SRV_RFC_TCP_Default(t *testing.T) {
t.Fatalf("err: %v", err)
}

m := new(dns.Msg)
m.SetQuestion("_db._tcp.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 {
t.Fatalf("err: %v", err)
questions := []string{
"_db._tcp.service.dc1.consul.",
"_db._tcp.service.consul.",
"_db._tcp.dc1.consul.",
"_db._tcp.consul.",
}

if len(in.Answer) != 1 {
t.Fatalf("Bad: %#v", in)
}
for _, question := range questions {
m := new(dns.Msg)
m.SetQuestion(question, dns.TypeSRV)

srvRec, ok := in.Answer[0].(*dns.SRV)
if !ok {
t.Fatalf("Bad: %#v", in.Answer[0])
}
if srvRec.Port != 12345 {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Target != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Answer[0])
}
c := new(dns.Client)
addr, _ := srv.agent.config.ClientListener("", srv.agent.config.Ports.DNS)
in, _, err := c.Exchange(m, addr.String())
if err != nil {
t.Fatalf("err: %v", err)
}

aRec, ok := in.Extra[0].(*dns.A)
if !ok {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Name != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.A.String() != "127.0.0.1" {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Extra[0])
if len(in.Answer) != 1 {
t.Fatalf("Bad: %#v", in)
}

srvRec, ok := in.Answer[0].(*dns.SRV)
if !ok {
t.Fatalf("Bad: %#v", in.Answer[0])
}
if srvRec.Port != 12345 {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Target != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", srvRec)
}
if srvRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Answer[0])
}

aRec, ok := in.Extra[0].(*dns.A)
if !ok {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Name != "foo.node.dc1.consul." {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.A.String() != "127.0.0.1" {
t.Fatalf("Bad: %#v", in.Extra[0])
}
if aRec.Hdr.Ttl != 0 {
t.Fatalf("Bad: %#v", in.Extra[0])
}
}

}

func TestDNS_ServiceLookup_FilterACL(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion website/source/docs/agent/dns.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ foobar.node.dc1.consul. 0 IN A 10.1.10.12

The format for RFC 2782 SRV lookups is:

_<service>._<protocol>.service[.datacenter][.domain]
_<service>._<protocol>[.service][.datacenter][.domain]

Per [RFC 2782](https://tools.ietf.org/html/rfc2782), SRV queries should use
underscores, `_`, as a prefix to the `service` and `protocol` values in a query to
Expand Down

0 comments on commit c135c08

Please sign in to comment.