diff --git a/nameserver/mdns_client.go b/nameserver/mdns_client.go index 7acf45a5..d602d1d9 100644 --- a/nameserver/mdns_client.go +++ b/nameserver/mdns_client.go @@ -26,7 +26,7 @@ var ( } ) -type ResponseA struct { +type Response struct { Name string Addr net.IP Err error @@ -34,7 +34,7 @@ type ResponseA struct { type responseInfo struct { timeout time.Time // if no answer by this time, give up - ch chan<- *ResponseA + ch chan<- *Response } // Represents one query that we have sent for one name. @@ -60,7 +60,7 @@ type MDNSClient struct { type mDNSQueryInfo struct { name string querytype uint16 - responseCh chan<- *ResponseA + responseCh chan<- *Response } func NewMDNSClient() (*MDNSClient, error) { @@ -121,7 +121,7 @@ func (c *MDNSClient) Shutdown() { } // Async -func (c *MDNSClient) SendQuery(name string, querytype uint16, responseCh chan<- *ResponseA) { +func (c *MDNSClient) SendQuery(name string, querytype uint16, responseCh chan<- *Response) { c.queryChan <- &MDNSInteraction{ code: CSendQuery, payload: mDNSQueryInfo{name, querytype, responseCh}, @@ -209,7 +209,7 @@ func (c *MDNSClient) handleSendQuery(q mDNSQueryInfo) { m.RecursionDesired = false buf, err := m.Pack() if err != nil { - q.responseCh <- &ResponseA{Err: err} + q.responseCh <- &Response{Err: err} close(q.responseCh) return } @@ -218,7 +218,7 @@ func (c *MDNSClient) handleSendQuery(q mDNSQueryInfo) { id: m.Id, } if _, err = c.conn.WriteTo(buf, c.addr); err != nil { - q.responseCh <- &ResponseA{Err: err} + q.responseCh <- &Response{Err: err} close(q.responseCh) return } @@ -235,19 +235,29 @@ func (c *MDNSClient) handleSendQuery(q mDNSQueryInfo) { func (c *MDNSClient) handleResponse(r *dns.Msg) { for _, answer := range r.Answer { + var name string + var res *Response + switch rr := answer.(type) { case *dns.A: - name := rr.Hdr.Name - if query, found := c.inflight[name]; found { - for _, resp := range query.responseInfos { - resp.ch <- &ResponseA{Name: rr.Hdr.Name, Addr: rr.A} - close(resp.ch) - } - delete(c.inflight, name) - } else { - // We've received a response that didn't match a query - // Do we want to cache it? + name = rr.Hdr.Name + res = &Response{Addr: rr.A} + case *dns.PTR: + name = rr.Hdr.Name + res = &Response{Name: rr.Ptr} + default: + return + } + + if query, found := c.inflight[name]; found { + for _, resp := range query.responseInfos { + resp.ch <- res + close(resp.ch) } + delete(c.inflight, name) + } else { + // We've received a response that didn't match a query + // Do we want to cache it? } } } diff --git a/nameserver/mdns_client_test.go b/nameserver/mdns_client_test.go index 1297b4c1..012bc107 100644 --- a/nameserver/mdns_client_test.go +++ b/nameserver/mdns_client_test.go @@ -13,9 +13,27 @@ var ( successTestName = "test1.weave." failTestName = "test2.weave." testAddr = net.ParseIP("9.8.7.6") + testInAddr = "6.7.8.9.in-addr.arpa." ) func minimalServer(w dns.ResponseWriter, req *dns.Msg) { + + sendAnswer := func(m *dns.Msg) { + buf, err := m.Pack() + checkFatal(err) + if buf == nil { + log.Fatal("Nil buffer") + } + //log.Println("minimalServer sending:", buf) + // This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work + sendconn, err := net.DialUDP("udp", nil, ipv4Addr) + checkFatal(err) + + _, err = sendconn.Write(buf) + sendconn.Close() + checkFatal(err) + } + //log.Println("minimalServer received:", req) if len(req.Answer) > 0 { return // Only interested in questions. @@ -23,31 +41,24 @@ func minimalServer(w dns.ResponseWriter, req *dns.Msg) { if len(req.Question) != 1 { return // We only handle single-question messages } - if req.Question[0].Name != successTestName { - return // This is not the DNS record you are looking for + + if req.Question[0].Qtype == dns.TypeA && req.Question[0].Name == successTestName { + m := new(dns.Msg) + m.SetReply(req) + hdr := dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA, + Class: dns.ClassINET, Ttl: 3600} + a := &dns.A{hdr, testAddr} + m.Answer = append(m.Answer, a) + sendAnswer(m) + } else if req.Question[0].Qtype == dns.TypePTR && req.Question[0].Name == testInAddr { + m := new(dns.Msg) + m.SetReply(req) + hdr := dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypePTR, + Class: dns.ClassINET, Ttl: 3600} + a := &dns.PTR{hdr, successTestName} + m.Answer = append(m.Answer, a) + sendAnswer(m) } - - m := new(dns.Msg) - m.SetReply(req) - - hdr := dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeA, - Class: dns.ClassINET, Ttl: 3600} - a := &dns.A{hdr, testAddr} - m.Answer = append(m.Answer, a) - - buf, err := m.Pack() - checkFatal(err) - if buf == nil { - log.Fatal("Nil buffer") - } - //log.Println("minimalServer sending:", buf) - // This is a bit of a kludge - per the RFC we should send responses from 5353, but that doesn't seem to work - sendconn, err := net.DialUDP("udp", nil, ipv4Addr) - checkFatal(err) - - _, err = sendconn.Write(buf) - sendconn.Close() - checkFatal(err) } func RunLocalMulticastServer() (*dns.Server, error) { @@ -76,14 +87,14 @@ func setup(t *testing.T) (*MDNSClient, *dns.Server, error) { type testContext struct { receivedAddr net.IP receivedCount int - channel chan *ResponseA + channel chan *Response } func newTestContext() *testContext { - return &testContext{channel: make(chan *ResponseA, 4)} + return &testContext{channel: make(chan *Response, 4)} } -func (c *testContext) checkResponse(t *testing.T, channelOk bool, resp *ResponseA) { +func (c *testContext) checkResponse(t *testing.T, channelOk bool, resp *Response) { if !channelOk { c.channel = nil return @@ -166,4 +177,10 @@ func TestAsLookup(t *testing.T) { ip, err = mdnsClient.LookupLocal("foo.example.com.") wt.AssertErrorType(t, err, (*LookupError)(nil), "unknown hostname") + + name, err := mdnsClient.ReverseLookupLocal(testInAddr) + wt.AssertNoErr(t, err) + if !(successTestName == name) { + t.Fatalf("Expected name %s, got %s", successTestName, name) + } } diff --git a/nameserver/mdns_lookup.go b/nameserver/mdns_lookup.go index 5fa9cdd4..dddc03b3 100644 --- a/nameserver/mdns_lookup.go +++ b/nameserver/mdns_lookup.go @@ -6,8 +6,8 @@ import ( "net" ) -func mdnsLookup(client *MDNSClient, name string, qtype uint16) (*ResponseA, error) { - channel := make(chan *ResponseA) +func mdnsLookup(client *MDNSClient, name string, qtype uint16) (*Response, error) { + channel := make(chan *Response) client.SendQuery(name, qtype, channel) for resp := range channel { Debug.Printf("Got response name %s addr %s", resp.Name, resp.Addr)