From bf752d2d1f939bb9df306d80be0cc0b1972ec55f Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Wed, 7 Jan 2015 15:59:44 +0000 Subject: [PATCH] Implement zone lookup with MDNSCLient This separates Zone into the DB ops and the Lookup ops, and implements the latter for MDNSClient so it can be used just like the zonedb. A notable change is that Lookup methods only ever return one result, while MDNSClient.SendQuery could in theory return multiple results (though it wouldn't, because no server would supply more than one result in a response, and it stops waiting after getting one response ..). ReverseLookupLocal is implemented even though no MDNSServer will answer at present (hence no test yet). Lastly, the handler (creating) functions can now be given a list of Lookup implementations to try in order. --- nameserver/mdns_client_test.go | 15 ++++++++ nameserver/mdns_lookup.go | 37 +++++++++++++++++++ nameserver/server.go | 66 ++++++++++++++-------------------- nameserver/zone.go | 8 +++-- 4 files changed, 85 insertions(+), 41 deletions(-) create mode 100644 nameserver/mdns_lookup.go diff --git a/nameserver/mdns_client_test.go b/nameserver/mdns_client_test.go index b50fcfd5..1297b4c1 100644 --- a/nameserver/mdns_client_test.go +++ b/nameserver/mdns_client_test.go @@ -152,3 +152,18 @@ outerloop: t.Fatal("Unexpected result for", successTestName, context1.receivedAddr, context2.receivedAddr, context1.receivedCount, context2.receivedCount) } } + +func TestAsLookup(t *testing.T) { + mdnsClient, server, _ := setup(t) + defer mdnsClient.Shutdown() + defer server.Shutdown() + + ip, err := mdnsClient.LookupLocal(successTestName) + wt.AssertNoErr(t, err) + if !testAddr.Equal(ip) { + t.Fatalf("Returned address incorrect %s", ip) + } + + ip, err = mdnsClient.LookupLocal("foo.example.com.") + wt.AssertErrorType(t, err, (*LookupError)(nil), "unknown hostname") +} diff --git a/nameserver/mdns_lookup.go b/nameserver/mdns_lookup.go new file mode 100644 index 00000000..5fa9cdd4 --- /dev/null +++ b/nameserver/mdns_lookup.go @@ -0,0 +1,37 @@ +package nameserver + +import ( + "github.com/miekg/dns" + . "github.com/zettio/weave/common" + "net" +) + +func mdnsLookup(client *MDNSClient, name string, qtype uint16) (*ResponseA, error) { + channel := make(chan *ResponseA) + client.SendQuery(name, qtype, channel) + for resp := range channel { + Debug.Printf("Got response name %s addr %s", resp.Name, resp.Addr) + if err := resp.Err; err != nil { + return nil, err + } else { + return resp, nil + } + } + return nil, LookupError(name) +} + +func (client *MDNSClient) LookupLocal(name string) (net.IP, error) { + if r, e := mdnsLookup(client, name, dns.TypeA); r != nil { + return r.Addr, nil + } else { + return nil, e + } +} + +func (client *MDNSClient) ReverseLookupLocal(inaddr string) (string, error) { + if r, e := mdnsLookup(client, inaddr, dns.TypePTR); r != nil { + return r.Name, nil + } else { + return "", e + } +} diff --git a/nameserver/server.go b/nameserver/server.go index 61540836..723e3483 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -31,57 +31,45 @@ func makeDNSFailResponse(r *dns.Msg) *dns.Msg { return m } -func queryHandler(zone Zone, mdnsClient *MDNSClient) dns.HandlerFunc { +func queryHandler(lookups []Lookup) dns.HandlerFunc { return func(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] - Debug.Printf("Local query: %+v", q) + Debug.Printf("Query: %+v", q) if q.Qtype == dns.TypeA { - if ip, err := zone.LookupLocal(q.Name); err == nil { - m := makeAddressReply(r, &q, []net.IP{ip}) - w.WriteMsg(m) - } else { - Debug.Printf("Failed lookup for %s; sending mDNS query", q.Name) - // We don't know the answer; see if someone else does - channel := make(chan *ResponseA) - replies := make([]net.IP, 0) - go func() { - for resp := range channel { - Debug.Printf("Got address response %s to query %s addr %s", resp.Name, q.Name, resp.Addr) - replies = append(replies, resp.Addr) - } - var responseMsg *dns.Msg - if len(replies) > 0 { - responseMsg = makeAddressReply(r, &q, replies) - } else { - responseMsg = makeDNSFailResponse(r) - } - w.WriteMsg(responseMsg) - }() - mdnsClient.SendQuery(q.Name, dns.TypeA, channel) + for _, lookup := range lookups { + if ip, err := lookup.LookupLocal(q.Name); err == nil { + m := makeAddressReply(r, &q, []net.IP{ip}) + w.WriteMsg(m) + return + } } + Debug.Printf("Query failed for %s", q.Name) + w.WriteMsg(makeDNSFailResponse(r)) } else { - Warning.Printf("Local query not handled: %+v", q) - m := makeDNSFailResponse(r) - w.WriteMsg(m) + Warning.Printf("Query not handled: %+v", q) + w.WriteMsg(makeDNSFailResponse(r)) } return } } -func rdnsHandler(zone Zone, mdnsClient *MDNSClient) dns.HandlerFunc { +func rdnsHandler(lookups []Lookup) dns.HandlerFunc { return func(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] - Debug.Printf("Local rdns query: %+v", q) + Debug.Printf("Reverse query: %+v", q) if q.Qtype == dns.TypePTR { - if name, err := zone.ReverseLookupLocal(q.Name); err == nil { - Debug.Printf("Found name: %s", name) - m := makePTRReply(r, &q, []string{name}) - w.WriteMsg(m) - } else { - Debug.Printf("Failed lookup for %s; sending mDNS query", q.Name) - // We don't know the answer; see if someone else does - // TODO + for _, lookup := range lookups { + if name, err := lookup.ReverseLookupLocal(q.Name); err == nil { + m := makePTRReply(r, &q, []string{name}) + w.WriteMsg(m) + return + } } + Debug.Printf("Reverse query failed for %s", q.Name) + w.WriteMsg(makeDNSFailResponse(r)) + } else { + Warning.Printf("Reverse query not handled: %+v", q) + w.WriteMsg(makeDNSFailResponse(r)) } } } @@ -125,8 +113,8 @@ func StartServer(zone Zone, iface *net.Interface, dnsPort int, httpPort int, wai checkFatal(err) LocalServeMux := dns.NewServeMux() - LocalServeMux.HandleFunc(LOCAL_DOMAIN, queryHandler(zone, mdnsClient)) - LocalServeMux.HandleFunc(RDNS_DOMAIN, rdnsHandler(zone, mdnsClient)) + LocalServeMux.HandleFunc(LOCAL_DOMAIN, queryHandler([]Lookup{zone, mdnsClient})) + LocalServeMux.HandleFunc(RDNS_DOMAIN, rdnsHandler([]Lookup{zone, mdnsClient})) LocalServeMux.HandleFunc(".", notUsHandler()) mdnsServer, err := NewMDNSServer(zone) diff --git a/nameserver/zone.go b/nameserver/zone.go index 82f28f38..fd2ceaaf 100644 --- a/nameserver/zone.go +++ b/nameserver/zone.go @@ -14,12 +14,16 @@ const ( // +1 to also exclude a dot var rdnsDomainLen = len(RDNS_DOMAIN) + 1 +type Lookup interface { + LookupLocal(name string) (net.IP, error) + ReverseLookupLocal(inaddr string) (string, error) +} + type Zone interface { AddRecord(ident string, name string, ip net.IP) error DeleteRecord(ident string, ip net.IP) error DeleteRecordsFor(ident string) error - LookupLocal(name string) (net.IP, error) - ReverseLookupLocal(inaddr string) (string, error) + Lookup } type Record struct {