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 {