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.
This commit is contained in:
Michael Bridgen committed 2015-01-08 13:39:33 +00:00
1 parent 3866bd5e63
commit bf752d2d1f
4 files changed
+85 -41

No files matched your search

+15
View File
@@ -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")
}
+37
View File
@@ -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
}
}
+27 -39
View File
@@ -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)
+6 -2
View File
@@ -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 {