diff --git a/main.go b/main.go index e764517a..c787dc2e 100644 --- a/main.go +++ b/main.go @@ -31,23 +31,6 @@ var ( mdnsServer *weavedns.MDNSServer ) -func handleMDNS(w dns.ResponseWriter, r *dns.Msg) { - // Ignore answers to other questions - if len(r.Answer) == 0 && len(r.Question) > 0 { - q := r.Question[0] - ip, err := zone.MatchLocal(q.Name) - if err == nil { - m := makeDNSReply(r, q.Name, ip) - mdnsServer.SendResponse(m) - } else if mdnsClient.IsInflightQuery(r) { - log.Println("Inflight Query", w.RemoteAddr(), w.LocalAddr()) - // ignore this - it's our own query received via multicast - } else { - log.Printf("Failed MDNS lookup for %s", q.Name) - } - } -} - func handleLocal(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] ip, err := zone.MatchLocal(q.Name) @@ -123,13 +106,7 @@ func main() { LocalServeMux.HandleFunc(LOCAL_DOMAIN, handleLocal) go weavedns.ListenHttp(zone) - MDNSServeMux := dns.NewServeMux() - MDNSServeMux.HandleFunc(LOCAL_DOMAIN, handleMDNS) - - conn, err := weavedns.LinkLocalMulticastListener(iface) - if err != nil { - log.Fatal(err) - } + var err error mdnsClient, err = weavedns.NewMDNSClient() if err != nil { log.Fatal(err) @@ -140,12 +117,14 @@ func main() { if err != nil { log.Fatal(err) } - mdnsServer, err = weavedns.NewMDNSServer() + mdnsServer, err = weavedns.NewMDNSServer(zone) + if err != nil { + log.Fatal(err) + } + err = mdnsServer.Start(iface) if err != nil { log.Fatal(err) } - - go dns.ActivateAndServe(nil, conn, MDNSServeMux) address := fmt.Sprintf(":%d", dnsPort) err = dns.ListenAndServe(address, "udp", LocalServeMux) diff --git a/server/mdns_server.go b/server/mdns_server.go index 89aaa340..4716d1df 100644 --- a/server/mdns_server.go +++ b/server/mdns_server.go @@ -2,24 +2,83 @@ package weavedns import ( "github.com/miekg/dns" + "log" "net" ) type MDNSServer struct { - sendconn *net.UDPConn + localAddrs []net.Addr + sendconn *net.UDPConn + zone *ZoneDb } -func NewMDNSServer() (*MDNSServer, error) { +func NewMDNSServer(zone *ZoneDb) (*MDNSServer, error) { //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.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) if err != nil { return nil, err } - retval := &MDNSServer{sendconn: sendconn} + retval := &MDNSServer{sendconn: sendconn, zone: zone} + return retval, nil } +func makeDNSReply(r *dns.Msg, name string, addr net.IP) *dns.Msg { + m := new(dns.Msg) + m.SetReply(r) + hdr := dns.RR_Header{Name: name, Rrtype: dns.TypeA, + Class: dns.ClassINET, Ttl: 3600} + a := &dns.A{hdr, addr} + m.Answer = append(m.Answer, a) + return m +} + +// Return true if testaddr is a UDP address with IP matching my local i/f +func (s *MDNSServer) addrIsLocal(testaddr net.Addr) bool { + if udpaddr, ok := testaddr.(*net.UDPAddr); ok { + for _, localaddr := range s.localAddrs { + if ipnetlocal, ok := localaddr.(*net.IPNet); ok { + if ipnetlocal.IP.Equal(udpaddr.IP) { + return true + } + } + } + } + return false +} + +func (s *MDNSServer) Start(ifi *net.Interface) error { + handleMDNS := func(w dns.ResponseWriter, r *dns.Msg) { + // Ignore answers to other questions + if len(r.Answer) == 0 && len(r.Question) > 0 { + q := r.Question[0] + ip, err := s.zone.MatchLocal(q.Name) + if err == nil { + m := makeDNSReply(r, q.Name, ip) + s.SendResponse(m) + } else if s.addrIsLocal(w.RemoteAddr()) { + // ignore this - it's our own query received via multicast + } else { + log.Printf("Failed MDNS lookup for %s", q.Name) + } + } + } + + conn, err := LinkLocalMulticastListener(ifi) + if err != nil { + return err + } + s.localAddrs, err = ifi.Addrs() + if err != nil { + return err + } + + go dns.ActivateAndServe(nil, conn, dns.HandlerFunc(handleMDNS)) + + return err +} + func (s *MDNSServer) SendResponse(m *dns.Msg) error { buf, err := m.Pack() if err != nil {