agent: Improve DNS parser. Fixes #39.

This commit is contained in:
Armon Dadgar 2014-04-21 15:33:01 -07:00
parent 48ce8e3e86
commit c7605f070d
2 changed files with 125 additions and 13 deletions

View File

@ -254,31 +254,40 @@ func (d *DNSServer) dispatch(network string, req, resp *dns.Msg) {
// The last label is either "node", "service" or a datacenter name
PARSE:
if len(labels) == 0 {
n := len(labels)
if n == 0 {
goto INVALID
}
switch labels[len(labels)-1] {
switch labels[n-1] {
case "service":
// Handle lookup with and without tag
switch len(labels) {
case 2:
d.serviceLookup(network, datacenter, labels[0], "", req, resp)
case 3:
d.serviceLookup(network, datacenter, labels[1], labels[0], req, resp)
default:
if n == 1 {
goto INVALID
}
// Extract the service
service := labels[n-2]
// Support "." in the label, re-join all the parts
tag := ""
if n >= 3 {
tag = strings.Join(labels[:n-2], ".")
}
// Handle lookup with and without tag
d.serviceLookup(network, datacenter, service, tag, req, resp)
case "node":
if len(labels) != 2 {
if len(labels) == 1 {
goto INVALID
}
d.nodeLookup(network, datacenter, labels[0], req, resp)
// Allow a "." in the node name, just join all the parts
node := strings.Join(labels[:n-1], ".")
d.nodeLookup(network, datacenter, node, req, resp)
default:
// Store the DC, and re-parse
datacenter = labels[len(labels)-1]
labels = labels[:len(labels)-1]
datacenter = labels[n-1]
labels = labels[:n-1]
goto PARSE
}
return

View File

@ -124,6 +124,48 @@ func TestDNS_NodeLookup(t *testing.T) {
}
}
func TestDNS_NodeLookup_PeriodName(t *testing.T) {
dir, srv := makeDNSServer(t)
defer os.RemoveAll(dir)
defer srv.agent.Shutdown()
// Wait for leader
time.Sleep(100 * time.Millisecond)
// Register node with period in name
args := &structs.RegisterRequest{
Datacenter: "dc1",
Node: "foo.bar",
Address: "127.0.0.1",
}
var out struct{}
if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil {
t.Fatalf("err: %v", err)
}
m := new(dns.Msg)
m.SetQuestion("foo.bar.node.consul.", dns.TypeANY)
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)
}
if len(in.Answer) != 1 {
t.Fatalf("Bad: %#v", in)
}
aRec, ok := in.Answer[0].(*dns.A)
if !ok {
t.Fatalf("Bad: %#v", in.Answer[0])
}
if aRec.A.String() != "127.0.0.1" {
t.Fatalf("Bad: %#v", in.Answer[0])
}
}
func TestDNS_NodeLookup_AAAA(t *testing.T) {
dir, srv := makeDNSServer(t)
defer os.RemoveAll(dir)
@ -270,6 +312,67 @@ func TestDNS_ServiceLookup(t *testing.T) {
}
}
func TestDNS_ServiceLookup_TagPeriod(t *testing.T) {
dir, srv := makeDNSServer(t)
defer os.RemoveAll(dir)
defer srv.agent.Shutdown()
// Wait for leader
time.Sleep(100 * time.Millisecond)
// Register node
args := &structs.RegisterRequest{
Datacenter: "dc1",
Node: "foo",
Address: "127.0.0.1",
Service: &structs.NodeService{
Service: "db",
Tags: []string{"v1.master"},
Port: 12345,
},
}
var out struct{}
if err := srv.agent.RPC("Catalog.Register", args, &out); err != nil {
t.Fatalf("err: %v", err)
}
m := new(dns.Msg)
m.SetQuestion("v1.master.db.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)
}
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)
}
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])
}
}
func TestDNS_ServiceLookup_Dedup(t *testing.T) {
dir, srv := makeDNSServer(t)
defer os.RemoveAll(dir)