From 9ae3f4c692410c89af9a36cf0f8db83e6054dab3 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 2 Feb 2015 11:32:20 +0000 Subject: [PATCH 1/4] Only read /etc/resolv.conf once --- nameserver/server.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/nameserver/server.go b/nameserver/server.go index 20fa94c5..f1e2816d 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -50,8 +50,8 @@ func queryHandler(lookups []Lookup) dns.HandlerFunc { } } -func rdnsHandler(lookups []Lookup) dns.HandlerFunc { - fallback := notUsHandler() +func rdnsHandler(config *dns.ClientConfig, lookups []Lookup) dns.HandlerFunc { + fallback := notUsHandler(config) return func(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] Debug.Printf("Reverse query: %+v", q) @@ -75,9 +75,7 @@ func rdnsHandler(lookups []Lookup) dns.HandlerFunc { /* When we receive a request for a name outside of our '.weave.local.' domain, ask the configured DNS server as a fallback. */ -func notUsHandler() dns.HandlerFunc { - config, err := dns.ClientConfigFromFile("/etc/resolv.conf") - checkFatal(err) +func notUsHandler(config *dns.ClientConfig) dns.HandlerFunc { return func(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] Debug.Printf("[dns msgid %d] Fallback query: %+v", r.MsgHdr.Id, q) @@ -116,10 +114,12 @@ func StartServer(zone Zone, iface *net.Interface, dnsPort int, wait int) error { err = mdnsClient.Start(iface) checkFatal(err) + config, err := dns.ClientConfigFromFile("/etc/resolv.conf") + checkFatal(err) LocalServeMux := dns.NewServeMux() LocalServeMux.HandleFunc(LOCAL_DOMAIN, queryHandler([]Lookup{zone, mdnsClient})) - LocalServeMux.HandleFunc(RDNS_DOMAIN, rdnsHandler([]Lookup{zone, mdnsClient})) - LocalServeMux.HandleFunc(".", notUsHandler()) + LocalServeMux.HandleFunc(RDNS_DOMAIN, rdnsHandler(config, []Lookup{zone, mdnsClient})) + LocalServeMux.HandleFunc(".", notUsHandler(config)) mdnsServer, err := NewMDNSServer(zone) checkFatal(err) From e5a08a505df8738e12947b721f72db5ada651716 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 2 Feb 2015 13:03:03 +0000 Subject: [PATCH 2/4] Change DNS fallback test to use a locally-run server to generate long responses reliably --- nameserver/server.go | 8 +++-- nameserver/server_test.go | 71 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 72 insertions(+), 7 deletions(-) diff --git a/nameserver/server.go b/nameserver/server.go index f1e2816d..c23816e6 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -103,6 +103,12 @@ func notUsHandler(config *dns.ClientConfig) dns.HandlerFunc { } func StartServer(zone Zone, iface *net.Interface, dnsPort int, wait int) error { + config, err := dns.ClientConfigFromFile("/etc/resolv.conf") + checkFatal(err) + return startServerWithConfig(config, zone, iface, dnsPort, wait) +} + +func startServerWithConfig(config *dns.ClientConfig, zone Zone, iface *net.Interface, dnsPort int, wait int) error { mdnsClient, err := NewMDNSClient() checkFatal(err) @@ -114,8 +120,6 @@ func StartServer(zone Zone, iface *net.Interface, dnsPort int, wait int) error { err = mdnsClient.Start(iface) checkFatal(err) - config, err := dns.ClientConfigFromFile("/etc/resolv.conf") - checkFatal(err) LocalServeMux := dns.NewServeMux() LocalServeMux.HandleFunc(LOCAL_DOMAIN, queryHandler([]Lookup{zone, mdnsClient})) LocalServeMux.HandleFunc(RDNS_DOMAIN, rdnsHandler(config, []Lookup{zone, mdnsClient})) diff --git a/nameserver/server_test.go b/nameserver/server_test.go index f38c510b..c42fc4d7 100644 --- a/nameserver/server_test.go +++ b/nameserver/server_test.go @@ -10,6 +10,12 @@ import ( "time" ) +const ( + testRDNSsuccess = "1.2.0.10.in-addr.arpa." + testRDNSfail = "4.3.2.1.in-addr.arpa." + testRDNSnonlocal = "8.8.8.8.in-addr.arpa." +) + func TestDNSServer(t *testing.T) { const ( port = 17625 @@ -17,8 +23,6 @@ func TestDNSServer(t *testing.T) { failTestName = "test2.weave.local." nonLocalName = "weave.works." testAddr1 = "10.0.2.1" - testRDNSsuccess = "1.2.0.10.in-addr.arpa." - testRDNSfail = "4.3.2.1.in-addr.arpa." ) dnsAddr := fmt.Sprintf("localhost:%d", port) testCIDR1 := testAddr1 + "/24" @@ -28,10 +32,20 @@ func TestDNSServer(t *testing.T) { ip, _, _ := net.ParseCIDR(testCIDR1) zone.AddRecord(containerID, successTestName, ip) - go StartServer(zone, nil, port, 0) + // Run another DNS server for fallback + s, fallbackAddr, err := RunLocalUDPServer("127.0.0.1:0") + wt.AssertNoErr(t, err) + defer s.Shutdown() + + _, fallbackPort, err := net.SplitHostPort(fallbackAddr) + wt.AssertNoErr(t, err) + + config := &dns.ClientConfig{Servers: []string{"127.0.0.1"}, Port: fallbackPort} + go startServerWithConfig(config, zone, nil, port, 0) time.Sleep(100 * time.Millisecond) // Allow sever goroutine to start c := new(dns.Client) + c.UDPSize = UDPBufSize m := new(dns.Msg) m.SetQuestion(successTestName, dns.TypeA) m.RecursionDesired = true @@ -69,7 +83,7 @@ func TestDNSServer(t *testing.T) { wt.AssertEqualInt(t, len(r.Answer), 0, "Number of answers") // This non-local query for an MX record should succeed by being - // passed on to the configured (/etc/resolv.conf) DNS server. + // passed on to the fallback server m.SetQuestion(nonLocalName, dns.TypeMX) r, _, err = c.Exchange(m, dnsAddr) wt.AssertNoErr(t, err) @@ -77,8 +91,16 @@ func TestDNSServer(t *testing.T) { if !(len(r.Answer) > 0) { t.Fatal("Number of answers > 0") } + // Now ask a query that we expect to return a lot of data. + m.SetQuestion(nonLocalName, dns.TypeANY) + r, _, err = c.Exchange(m, dnsAddr) + wt.AssertNoErr(t, err) + wt.AssertStatus(t, r.Rcode, dns.RcodeSuccess, "DNS response code") + if !(len(r.Extra) > 5) { + t.Fatal("Number of answers > 5") + } - m.SetQuestion("8.8.8.8.in-addr.arpa.", dns.TypePTR) + m.SetQuestion(testRDNSnonlocal, dns.TypePTR) r, _, err = c.Exchange(m, dnsAddr) wt.AssertNoErr(t, err) wt.AssertStatus(t, r.Rcode, dns.RcodeSuccess, "DNS success response code") @@ -89,3 +111,42 @@ func TestDNSServer(t *testing.T) { // Not testing MDNS functionality of server here (yet), since it // needs two servers, each listening on its own address } + +func fallbackHandler(w dns.ResponseWriter, req *dns.Msg) { + m := new(dns.Msg) + m.SetReply(req) + if len(req.Question) == 1 { + q := req.Question[0] + if q.Name == "weave.works." && q.Qtype == dns.TypeMX { + m.Answer = make([]dns.RR, 1) + m.Answer[0] = &dns.MX{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 0}, Mx: "mail.weave.works."} + } else if q.Name == "weave.works." && q.Qtype == dns.TypeANY { + const N = 10 + m.Extra = make([]dns.RR, N) + for i, _ := range m.Extra { + m.Extra[i] = &dns.TXT{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeTXT, Class: dns.ClassINET, Ttl: 0}, Txt: []string{"Lots and lots and lots and lots and lots and lots and lots and lots and lots of data"}} + } + } else if q.Name == testRDNSnonlocal && q.Qtype == dns.TypePTR { + m.Answer = make([]dns.RR, 1) + m.Answer[0] = &dns.PTR{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, Ptr: "ns1.google.com."} + } else if q.Name == testRDNSfail && q.Qtype == dns.TypePTR { + m.Rcode = dns.RcodeNameError + } + } + w.WriteMsg(m) +} + +func RunLocalUDPServer(laddr string) (*dns.Server, string, error) { + pc, err := net.ListenPacket("udp", laddr) + if err != nil { + return nil, "", err + } + server := &dns.Server{PacketConn: pc, Handler: dns.HandlerFunc(fallbackHandler)} + + go func() { + server.ActivateAndServe() + pc.Close() + }() + + return server, pc.LocalAddr().String(), nil +} From 458ef12da696be77ec9f5861621d33e3d19994fa Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Mon, 2 Feb 2015 13:26:44 +0000 Subject: [PATCH 3/4] Use a larger buffer than the default, so that more queries will succeed --- nameserver/server.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/nameserver/server.go b/nameserver/server.go index c23816e6..298570de 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -9,6 +9,7 @@ import ( const ( LOCAL_DOMAIN = "weave.local." + UDPBufSize = 1400 // bigger than the default 512, but under usual packet limits ) func checkFatal(e error) { @@ -76,11 +77,13 @@ func rdnsHandler(config *dns.ClientConfig, lookups []Lookup) dns.HandlerFunc { domain, ask the configured DNS server as a fallback. */ func notUsHandler(config *dns.ClientConfig) dns.HandlerFunc { + dnsClient := new(dns.Client) + dnsClient.UDPSize = UDPBufSize return func(w dns.ResponseWriter, r *dns.Msg) { q := r.Question[0] Debug.Printf("[dns msgid %d] Fallback query: %+v", r.MsgHdr.Id, q) for _, server := range config.Servers { - reply, err := dns.Exchange(r, fmt.Sprintf("%s:%s", server, config.Port)) + reply, _, err := dnsClient.Exchange(r, fmt.Sprintf("%s:%s", server, config.Port)) if err != nil { Debug.Printf("[dns msgid %d] Network error trying %s (%s)", r.MsgHdr.Id, server, err) From 04a7aa1405f484412bd8a327599073c00d62139e Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Wed, 4 Feb 2015 14:58:21 +0000 Subject: [PATCH 4/4] Use buffer size 4096 on advice from a DNS expert --- nameserver/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nameserver/server.go b/nameserver/server.go index 298570de..1846717b 100644 --- a/nameserver/server.go +++ b/nameserver/server.go @@ -9,7 +9,7 @@ import ( const ( LOCAL_DOMAIN = "weave.local." - UDPBufSize = 1400 // bigger than the default 512, but under usual packet limits + UDPBufSize = 4096 // bigger than the default 512 ) func checkFatal(e error) {