mirror of https://github.com/status-im/consul.git
Merge pull request #475 from sequenceiq/reverse-lookup
feature: handle PTR requests to implement dns reverse lookup
This commit is contained in:
commit
31083ca1cd
|
@ -66,6 +66,9 @@ func NewDNSServer(agent *Agent, config *DNSConfig, logOutput io.Writer, domain s
|
||||||
logger: log.New(logOutput, "", log.LstdFlags),
|
logger: log.New(logOutput, "", log.LstdFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register mux handler, for reverse lookup
|
||||||
|
mux.HandleFunc("arpa.", srv.handlePtr)
|
||||||
|
|
||||||
// Register mux handlers, always handle "consul."
|
// Register mux handlers, always handle "consul."
|
||||||
mux.HandleFunc(domain, srv.handleQuery)
|
mux.HandleFunc(domain, srv.handleQuery)
|
||||||
if domain != consulDomain {
|
if domain != consulDomain {
|
||||||
|
@ -162,6 +165,55 @@ START:
|
||||||
return addr.String(), nil
|
return addr.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handlePtr is used to handle "reverse" DNS queries
|
||||||
|
func (d *DNSServer) handlePtr(resp dns.ResponseWriter, req *dns.Msg) {
|
||||||
|
q := req.Question[0]
|
||||||
|
defer func(s time.Time) {
|
||||||
|
d.logger.Printf("[DEBUG] dns: request for %v (%v)", q, time.Now().Sub(s))
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
|
// Setup the message response
|
||||||
|
m := new(dns.Msg)
|
||||||
|
m.SetReply(req)
|
||||||
|
m.Authoritative = true
|
||||||
|
m.RecursionAvailable = (len(d.recursors) > 0)
|
||||||
|
|
||||||
|
// Only add the SOA if requested
|
||||||
|
if req.Question[0].Qtype == dns.TypeSOA {
|
||||||
|
d.addSOA(d.domain, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
datacenter := d.agent.config.Datacenter
|
||||||
|
|
||||||
|
// Get the QName without the domain suffix
|
||||||
|
qName := strings.ToLower(dns.Fqdn(req.Question[0].Name))
|
||||||
|
|
||||||
|
args := structs.DCSpecificRequest{
|
||||||
|
Datacenter: datacenter,
|
||||||
|
QueryOptions: structs.QueryOptions{AllowStale: d.config.AllowStale},
|
||||||
|
}
|
||||||
|
var out structs.IndexedNodes
|
||||||
|
|
||||||
|
if err := d.agent.RPC("Catalog.ListNodes", &args, &out); err == nil {
|
||||||
|
for _, n := range out.Nodes {
|
||||||
|
arpa, _ := dns.ReverseAddr(n.Address)
|
||||||
|
if arpa == qName {
|
||||||
|
ptr := &dns.PTR{
|
||||||
|
Hdr: dns.RR_Header{Name: q.Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0},
|
||||||
|
Ptr: fmt.Sprintf("%s.node.%s.consul.", n.Node, datacenter),
|
||||||
|
}
|
||||||
|
m.Answer = append(m.Answer, ptr)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write out the complete response
|
||||||
|
if err := resp.WriteMsg(m); err != nil {
|
||||||
|
d.logger.Printf("[WARN] dns: failed to respond: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// handleQUery is used to handle DNS queries in the configured domain
|
// handleQUery is used to handle DNS queries in the configured domain
|
||||||
func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) {
|
func (d *DNSServer) handleQuery(resp dns.ResponseWriter, req *dns.Msg) {
|
||||||
q := req.Question[0]
|
q := req.Question[0]
|
||||||
|
|
|
@ -304,6 +304,89 @@ func TestDNS_NodeLookup_CNAME(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDNS_ReverseLookup(t *testing.T) {
|
||||||
|
dir, srv := makeDNSServer(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
defer srv.agent.Shutdown()
|
||||||
|
|
||||||
|
testutil.WaitForLeader(t, srv.agent.RPC, "dc1")
|
||||||
|
|
||||||
|
// Register node
|
||||||
|
args := &structs.RegisterRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Node: "foo2",
|
||||||
|
Address: "127.0.0.2",
|
||||||
|
}
|
||||||
|
|
||||||
|
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("2.0.0.127.in-addr.arpa.", 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrRec, ok := in.Answer[0].(*dns.PTR)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
if ptrRec.Ptr != "foo2.node.dc1.consul." {
|
||||||
|
t.Fatalf("Bad: %#v", ptrRec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDNS_ReverseLookup_IPV6(t *testing.T) {
|
||||||
|
dir, srv := makeDNSServer(t)
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
defer srv.agent.Shutdown()
|
||||||
|
|
||||||
|
testutil.WaitForLeader(t, srv.agent.RPC, "dc1")
|
||||||
|
|
||||||
|
// Register node
|
||||||
|
args := &structs.RegisterRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
Node: "bar",
|
||||||
|
Address: "::4242:4242",
|
||||||
|
}
|
||||||
|
|
||||||
|
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("2.4.2.4.2.4.2.4.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
ptrRec, ok := in.Answer[0].(*dns.PTR)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
if ptrRec.Ptr != "bar.node.dc1.consul." {
|
||||||
|
t.Fatalf("Bad: %#v", ptrRec)
|
||||||
|
}
|
||||||
|
}
|
||||||
func TestDNS_ServiceLookup(t *testing.T) {
|
func TestDNS_ServiceLookup(t *testing.T) {
|
||||||
dir, srv := makeDNSServer(t)
|
dir, srv := makeDNSServer(t)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
Loading…
Reference in New Issue