func setup(t *testing.T) (*MDNSClient, *dns.Server, error) { InitDefaultLogging(testing.Verbose()) server, err := RunLocalMulticastServer() if err != nil { t.Fatalf("Unable to run test server: %s. No default multicast interface?", err) } mdnsClient, err := NewMDNSClient() wt.AssertNoErr(t, err) err = mdnsClient.Start(nil) wt.AssertNoErr(t, err) return mdnsClient, server, err }
func TestZone(t *testing.T) { var ( containerID = "deadbeef" otherContainerID = "cowjuice" successTestName = "test1.weave." testAddr1 = "10.2.2.1/24" ) var zone = NewZoneDb(DefaultLocalDomain) ip, _, _ := net.ParseCIDR(testAddr1) err := zone.AddRecord(containerID, successTestName, ip) wt.AssertNoErr(t, err) // Add a few more records to make the job harder err = zone.AddRecord("abcdef0123", "adummy.weave.", net.ParseIP("10.2.0.1")) wt.AssertNoErr(t, err) err = zone.AddRecord("0123abcdef", "zdummy.weave.", net.ParseIP("10.2.0.2")) wt.AssertNoErr(t, err) // Check that the address is now there. foundIP, err := zone.LookupName(successTestName) wt.AssertNoErr(t, err) if !foundIP[0].IP().Equal(ip) { t.Fatal("Unexpected result for", successTestName, foundIP) } // See if we can find the address by IP. foundName, err := zone.LookupInaddr("1.2.2.10.in-addr.arpa.") wt.AssertNoErr(t, err) if foundName[0].Name() != successTestName { t.Fatal("Unexpected result for", ip, foundName) } err = zone.AddRecord(containerID, successTestName, ip) wt.AssertErrorType(t, err, (*DuplicateError)(nil), "duplicate add") err = zone.AddRecord(otherContainerID, successTestName, ip) // Delete the record for the original container err = zone.DeleteRecord(containerID, ip) wt.AssertNoErr(t, err) _, err = zone.LookupName(successTestName) wt.AssertNoErr(t, err) err = zone.DeleteRecord(otherContainerID, ip) wt.AssertNoErr(t, err) // Check that the address is not there now. _, err = zone.LookupName(successTestName) wt.AssertErrorType(t, err, (*LookupError)(nil), "after deleting record") // Delete a record that isn't there err = zone.DeleteRecord(containerID, net.ParseIP("0.0.0.0")) wt.AssertErrorType(t, err, (*LookupError)(nil), "when deleting record that doesn't exist") }
// perform a DNS query and assert the reply code, number or answers, etc func assertExchange(t *testing.T, z string, ty uint16, minAnswers int, maxAnswers int, expErr int) *dns.Msg { c := new(dns.Client) c.UDPSize = testUDPBufSize m := new(dns.Msg) m.RecursionDesired = true m.SetQuestion(z, ty) m.SetEdns0(testUDPBufSize, false) // we don't want to play with truncation here... r, _, err := c.Exchange(m, fmt.Sprintf("127.0.0.1:%d", testPort)) t.Logf("Response:\n%+v\n", r) wt.AssertNoErr(t, err) if minAnswers == 0 && maxAnswers == 0 { wt.AssertStatus(t, r.Rcode, expErr, "DNS response code") } else { wt.AssertStatus(t, r.Rcode, dns.RcodeSuccess, "DNS response code") } answers := len(r.Answer) if minAnswers >= 0 && answers < minAnswers { wt.Fatalf(t, "Number of answers >= %d", minAnswers) } if maxAnswers >= 0 && answers > maxAnswers { wt.Fatalf(t, "Number of answers <= %d", maxAnswers) } return r }
func (c *testContext) checkResponse(t *testing.T, channelOk bool, resp *Response) { if !channelOk { c.channel = nil return } wt.AssertNoErr(t, resp.err) log.Printf("Got address response %s addr %s", resp.Name(), resp.IP()) c.receivedAddr = resp.IP() c.receivedCount++ }
func TestAsLookup(t *testing.T) { mdnsClient, server, _ := setup(t) defer mdnsClient.Shutdown() defer server.Shutdown() ips, err := mdnsClient.LookupName(successTestName) wt.AssertNoErr(t, err) if !testAddr.Equal(ips[0].IP()) { t.Fatalf("Returned address incorrect %s", ips) } ips, err = mdnsClient.LookupName("foo.example.com.") wt.AssertErrorType(t, err, (*LookupError)(nil), "unknown hostname") names, err := mdnsClient.LookupInaddr(testInAddr) wt.AssertNoErr(t, err) if !(successTestName == names[0].Name()) { t.Fatalf("Expected name %s, got %s", successTestName, names) } }
func TestDeleteFor(t *testing.T) { var ( id = "foobar" name = "foo.weave." addr1 = "10.2.2.3/24" addr2 = "10.2.7.8/24" ) zone := NewZoneDb(DefaultLocalDomain) for _, addr := range []string{addr1, addr2} { ip, _, _ := net.ParseCIDR(addr) err := zone.AddRecord(id, name, ip) wt.AssertNoErr(t, err) } _, err := zone.LookupName(name) wt.AssertNoErr(t, err) err = zone.DeleteRecordsFor(id) _, err = zone.LookupName(name) wt.AssertErrorType(t, err, (*LookupError)(nil), "after deleting records for ident") }
func TestFieldValidator(t *testing.T) { testMap := map[string]string{"a": "a"} fv := NewFieldValidator(testMap) val, err := fv.Value("a") wt.AssertNoErr(t, err) wt.AssertNoErr(t, fv.Err()) wt.AssertEqualString(t, val, "a", "") _, err = fv.Value("x") wt.AssertFalse(t, err == nil || fv.Err() == nil, "Expected error") _, err = fv.Value("a") wt.AssertFalse(t, err == nil || fv.Err() == nil, "Previous error should be retained") fv = NewFieldValidator(testMap) err = fv.CheckEqual("a", "a") wt.AssertNoErr(t, err) wt.AssertNoErr(t, fv.Err()) err = fv.CheckEqual("a", "b") wt.AssertFalse(t, err == nil || fv.Err() == nil, "Expected error") err = fv.CheckEqual("a", "a") wt.AssertFalse(t, err == nil || fv.Err() == nil, "Previous error should be retained") }
func TestAddrs(t *testing.T) { InitDefaultLogging(testing.Verbose()) Info.Println("TestAddrs starting") ip, err := addrToIPv4("10.13.12.11") wt.AssertNoErr(t, err) wt.AssertTrue(t, net.ParseIP("10.13.12.11").Equal(ip.toNetIP()), "IP") ip, err = raddrToIPv4("11.12.13.10.in-addr.arpa.") wt.AssertNoErr(t, err) wt.AssertTrue(t, net.ParseIP("10.13.12.11").Equal(ip.toNetIP()), "IP") // some malformed addresses ip, err = addrToIPv4("10.13.12") wt.AssertTrue(t, err != nil, "when parsing malformed address") ip, err = addrToIPv4("10.13.AA.12") wt.AssertTrue(t, err != nil, "when parsing malformed address") ip, err = raddrToIPv4("11.12.13.10.in-axxx.arpa.") wt.AssertTrue(t, err != nil, "when parsing malformed address") ip, err = raddrToIPv4("11.12.13.10.in-addr") wt.AssertTrue(t, err != nil, "when parsing malformed address") }
// Check that the cache keeps its intended capacity constant func TestCacheLength(t *testing.T) { InitDefaultLogging(testing.Verbose()) Info.Println("TestCacheLength starting") const cacheLen = 128 l, err := NewCache(cacheLen, nil) wt.AssertNoErr(t, err) insTime := time.Now() t.Logf("Inserting 256 questions in the cache at '%s', with TTL from 0 to 255", insTime) for i := 0; i < cacheLen*2; i++ { name := fmt.Sprintf("name%d", i) questionMsg := new(dns.Msg) questionMsg.SetQuestion(name, dns.TypeA) questionMsg.RecursionDesired = true question := &questionMsg.Question[0] ip := net.ParseIP(fmt.Sprintf("10.0.1.%d", i)) records := []ZoneRecord{Record{name, ip, 0, 0, 0}} reply := makeAddressReply(questionMsg, question, records) reply.Answer[0].Header().Ttl = uint32(i) l.Put(questionMsg, reply, 0, 0) } wt.AssertEqualInt(t, l.Len(), cacheLen, "cache length") minExpectedTime := insTime.Add(time.Duration(cacheLen) * time.Second) t.Logf("Checking all remaining entries expire after insert_time + %d secs='%s'", cacheLen, minExpectedTime) for _, entry := range l.entries { if entry.validUntil.Before(minExpectedTime) { t.Fatalf("Entry valid until %s", entry.validUntil) } } }
func TestServerSimpleQuery(t *testing.T) { var ( testRecord1 = Record{"test.weave.local.", net.ParseIP("10.20.20.10"), 0, 0, 0} testRecord2 = Record{"test.weave.local.", net.ParseIP("10.20.20.20"), 0, 0, 0} testInAddr1 = "10.20.20.10.in-addr.arpa." ) InitDefaultLogging(testing.Verbose()) Info.Println("TestServerSimpleQuery starting") mzone := newMockedZoneWithRecords([]ZoneRecord{testRecord1, testRecord2}) mdnsServer, err := NewMDNSServer(mzone) wt.AssertNoErr(t, err) err = mdnsServer.Start(nil) wt.AssertNoErr(t, err) defer mdnsServer.Stop() receivedAddrs := make([]net.IP, 0) receivedName := "" recvChan := make(chan interface{}) receivedCount := 0 // Implement a minimal listener for responses multicast, err := LinkLocalMulticastListener(nil) wt.AssertNoErr(t, err) handleMDNS := func(w dns.ResponseWriter, r *dns.Msg) { // Only handle responses here if len(r.Answer) > 0 { t.Logf("Received %d answer(s)", len(r.Answer)) for _, answer := range r.Answer { switch rr := answer.(type) { case *dns.A: t.Logf("... A:\n%+v", rr) receivedAddrs = append(receivedAddrs, rr.A) receivedCount++ case *dns.PTR: t.Logf("... PTR:\n%+v", rr) receivedName = rr.Ptr receivedCount++ } } recvChan <- "ok" } } sendQuery := func(name string, querytype uint16) { receivedAddrs = make([]net.IP, 0) receivedName = "" receivedCount = 0 recvChan = make(chan interface{}) m := new(dns.Msg) m.SetQuestion(name, querytype) m.RecursionDesired = false buf, err := m.Pack() wt.AssertNoErr(t, err) conn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0}) wt.AssertNoErr(t, err) Debug.Printf("Sending UDP packet to %s", ipv4Addr) _, err = conn.WriteTo(buf, ipv4Addr) wt.AssertNoErr(t, err) Debug.Printf("Waiting for response") select { case <-recvChan: return case <-time.After(100 * time.Millisecond): Debug.Printf("Timeout while waiting for response") return } } listener := &dns.Server{ Unsafe: true, PacketConn: multicast, Handler: dns.HandlerFunc(handleMDNS), ReadTimeout: 100 * time.Millisecond} go listener.ActivateAndServe() defer listener.Shutdown() time.Sleep(100 * time.Millisecond) // Allow for server to get going Debug.Printf("Checking that we get 2 IPs fo name '%s' [A]", testRecord1.Name()) sendQuery(testRecord1.Name(), dns.TypeA) if receivedCount != 2 { t.Fatalf("Unexpected result count %d for %s", receivedCount, testRecord1.Name()) } if !(receivedAddrs[0].Equal(testRecord1.IP()) || receivedAddrs[0].Equal(testRecord2.IP())) { t.Fatalf("Unexpected result %s for %s", receivedAddrs, testRecord1.Name()) } if !(receivedAddrs[1].Equal(testRecord1.IP()) || receivedAddrs[1].Equal(testRecord2.IP())) { t.Fatalf("Unexpected result %s for %s", receivedAddrs, testRecord1.Name()) } Debug.Printf("Checking that 'testfail.weave.' [A] gets no answers") sendQuery("testfail.weave.", dns.TypeA) if receivedCount != 0 { t.Fatalf("Unexpected result count %d for testfail.weave", receivedCount) } Debug.Printf("Checking that '%s' [PTR] gets one name", testInAddr1) sendQuery(testInAddr1, dns.TypePTR) if receivedCount != 1 { t.Fatalf("Expected an answer to %s, got %d answers", testInAddr1, receivedCount) } else if !(testRecord1.Name() == receivedName) { t.Fatalf("Expected answer %s to query for %s, got %s", testRecord1.Name(), testInAddr1, receivedName) } }
// Check that the cache entries are ok func TestCacheEntries(t *testing.T) { InitDefaultLogging(testing.Verbose()) Info.Println("TestCacheEntries starting") Info.Println("Checking cache consistency") const cacheLen = 128 clk := clock.NewMock() l, err := NewCache(cacheLen, clk) wt.AssertNoErr(t, err) questionMsg := new(dns.Msg) questionMsg.SetQuestion("some.name", dns.TypeA) questionMsg.RecursionDesired = true question := &questionMsg.Question[0] t.Logf("Trying to get a name") resp, err := l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) if resp != nil { t.Logf("Got\n%s", resp) t.Fatalf("ERROR: Did not expect a reponse from Get() yet") } t.Logf("Trying to get it again") resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) if resp != nil { t.Logf("Got\n%s", resp) t.Fatalf("ERROR: Did not expect a reponse from Get() yet") } t.Logf("Inserting the reply") records := []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.1"), 0, 0, 0}} reply1 := makeAddressReply(questionMsg, question, records) l.Put(questionMsg, reply1, nullTTL, 0) t.Logf("Checking we can Get() the reply now") resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) wt.AssertTrue(t, resp != nil, "reponse from Get()") t.Logf("Received '%s'", resp.Answer[0]) wt.AssertType(t, resp.Answer[0], (*dns.A)(nil), "DNS record") ttlGet1 := resp.Answer[0].Header().Ttl clk.Add(time.Duration(1) * time.Second) t.Logf("Checking that a second Get(), after 1 second, gets the same result, but with reduced TTL") resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) wt.AssertTrue(t, resp != nil, "reponse from a second Get()") t.Logf("Received '%s'", resp.Answer[0]) wt.AssertType(t, resp.Answer[0], (*dns.A)(nil), "DNS record") ttlGet2 := resp.Answer[0].Header().Ttl wt.AssertEqualInt(t, int(ttlGet1-ttlGet2), 1, "TTL difference") clk.Add(time.Duration(localTTL) * time.Second) t.Logf("Checking that a third Get(), after %d second, gets no result", localTTL) resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) if resp != nil { t.Logf("Got\n%s", resp) t.Fatalf("ERROR: Did NOT expect a reponse from the second Get()") } t.Logf("Checking that an Remove() results in Get() returning nothing") records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.9.9"), 0, 0, 0}} replyTemp := makeAddressReply(questionMsg, question, records) l.Put(questionMsg, replyTemp, nullTTL, 0) lenBefore := l.Len() l.Remove(question) wt.AssertEqualInt(t, l.Len(), lenBefore-1, "cache length") l.Remove(question) // do it again: should have no effect... wt.AssertEqualInt(t, l.Len(), lenBefore-1, "cache length") resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) wt.AssertTrue(t, resp == nil, "reponse from the Get() after a Remove()") t.Logf("Inserting a two replies for the same query") records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.2"), 0, 0, 0}} reply2 := makeAddressReply(questionMsg, question, records) l.Put(questionMsg, reply2, nullTTL, 0) clk.Add(time.Duration(1) * time.Second) records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.1.3"), 0, 0, 0}} reply3 := makeAddressReply(questionMsg, question, records) l.Put(questionMsg, reply3, nullTTL, 0) t.Logf("Checking we get the last one...") resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) wt.AssertTrue(t, resp != nil, "reponse from the Get()") t.Logf("Received '%s'", resp.Answer[0]) wt.AssertType(t, resp.Answer[0], (*dns.A)(nil), "DNS record") wt.AssertEqualString(t, resp.Answer[0].(*dns.A).A.String(), "10.0.1.3", "IP address") wt.AssertEqualInt(t, int(resp.Answer[0].Header().Ttl), int(localTTL), "TTL") clk.Add(time.Duration(localTTL-1) * time.Second) resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) wt.AssertTrue(t, resp != nil, "reponse from the Get()") t.Logf("Received '%s'", resp.Answer[0]) wt.AssertType(t, resp.Answer[0], (*dns.A)(nil), "DNS record") wt.AssertEqualString(t, resp.Answer[0].(*dns.A).A.String(), "10.0.1.3", "IP address") wt.AssertEqualInt(t, int(resp.Answer[0].Header().Ttl), 1, "TTL") t.Logf("Checking we get empty replies when they are expired...") lenBefore = l.Len() clk.Add(time.Duration(localTTL) * time.Second) resp, err = l.Get(questionMsg, minUDPSize) wt.AssertNoErr(t, err) if resp != nil { t.Logf("Got\n%s", resp.Answer[0]) t.Fatalf("ERROR: Did NOT expect a reponse from the Get()") } wt.AssertEqualInt(t, l.Len(), lenBefore-1, "cache length (after getting an expired entry)") questionMsg2 := new(dns.Msg) questionMsg2.SetQuestion("some.other.name", dns.TypeA) questionMsg2.RecursionDesired = true question2 := &questionMsg2.Question[0] t.Logf("Trying to Get() a name") resp, err = l.Get(questionMsg2, minUDPSize) wt.AssertNoErr(t, err) wt.AssertNil(t, resp, "reponse from Get() yet") t.Logf("Checking that an Remove() between Get() and Put() does not break things") records = []ZoneRecord{Record{"some.name", net.ParseIP("10.0.9.9"), 0, 0, 0}} replyTemp2 := makeAddressReply(questionMsg2, question2, records) l.Remove(question2) l.Put(questionMsg2, replyTemp2, nullTTL, 0) resp, err = l.Get(questionMsg2, minUDPSize) wt.AssertNoErr(t, err) wt.AssertNotNil(t, resp, "reponse from Get()") questionMsg3 := new(dns.Msg) questionMsg3.SetQuestion("some.other.name", dns.TypeA) questionMsg3.RecursionDesired = true question3 := &questionMsg3.Question[0] t.Logf("Checking that a entry with CacheNoLocalReplies return an error") l.Put(questionMsg3, nil, nullTTL, CacheNoLocalReplies) resp, err = l.Get(questionMsg3, minUDPSize) wt.AssertNil(t, resp, "Get() response with CacheNoLocalReplies") wt.AssertNotNil(t, err, "Get() error with CacheNoLocalReplies") clk.Add(time.Second * time.Duration(negLocalTTL+1)) t.Logf("Checking that we get an expired response after %f seconds", negLocalTTL) resp, err = l.Get(questionMsg3, minUDPSize) wt.AssertNil(t, resp, "expired Get() response with CacheNoLocalReplies") wt.AssertNil(t, err, "expired Get() error with CacheNoLocalReplies") l.Remove(question3) t.Logf("Checking that Put&Get with CacheNoLocalReplies with a Remove in the middle returns nothing") l.Put(questionMsg3, nil, nullTTL, CacheNoLocalReplies) l.Remove(question3) resp, err = l.Get(questionMsg3, minUDPSize) wt.AssertNil(t, resp, "Get() reponse with CacheNoLocalReplies") wt.AssertNil(t, err, "Get() error with CacheNoLocalReplies") }
func TestUDPDNSServer(t *testing.T) { setupForTest(t) const ( containerID = "foobar" successTestName = "test1.weave.local." failTestName = "test2.weave.local." nonLocalName = "weave.works." testAddr1 = "10.2.2.1" ) testCIDR1 := testAddr1 + "/24" InitDefaultLogging(true) var zone = NewZoneDb(DefaultLocalDomain) ip, _, _ := net.ParseCIDR(testCIDR1) zone.AddRecord(containerID, successTestName, ip) fallbackHandler := func(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 == nonLocalName && 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." + nonLocalName} } else if q.Name == nonLocalName && q.Qtype == dns.TypeANY { m.Answer = make([]dns.RR, 512/len("mailn."+nonLocalName)+1) for i := range m.Answer { m.Answer[i] = &dns.MX{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypeMX, Class: dns.ClassINET, Ttl: 0}, Mx: fmt.Sprintf("mail%d.%s", i, nonLocalName)} } } 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) } // Run another DNS server for fallback s, fallbackAddr, err := runLocalUDPServer(t, "127.0.0.1:0", fallbackHandler) 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} srv, err := NewDNSServer(DNSServerConfig{UpstreamCfg: config, Port: testPort}, zone, nil) wt.AssertNoErr(t, err) defer srv.Stop() go srv.Start() time.Sleep(100 * time.Millisecond) // Allow sever goroutine to start var r *dns.Msg r = assertExchange(t, successTestName, dns.TypeA, 1, 1, 0) wt.AssertType(t, r.Answer[0], (*dns.A)(nil), "DNS record") wt.AssertEqualString(t, r.Answer[0].(*dns.A).A.String(), testAddr1, "IP address") assertExchange(t, failTestName, dns.TypeA, 0, 0, dns.RcodeNameError) r = assertExchange(t, testRDNSsuccess, dns.TypePTR, 1, 1, 0) wt.AssertType(t, r.Answer[0], (*dns.PTR)(nil), "DNS record") wt.AssertEqualString(t, r.Answer[0].(*dns.PTR).Ptr, successTestName, "IP address") assertExchange(t, testRDNSfail, dns.TypePTR, 0, 0, dns.RcodeNameError) // This should fail because we don't have information about MX records assertExchange(t, successTestName, dns.TypeMX, 0, 0, dns.RcodeNameError) // This non-local query for an MX record should succeed by being // passed on to the fallback server assertExchange(t, nonLocalName, dns.TypeMX, 1, -1, 0) // Now ask a query that we expect to return a lot of data. assertExchange(t, nonLocalName, dns.TypeANY, 5, -1, 0) assertExchange(t, testRDNSnonlocal, dns.TypePTR, 1, -1, 0) // Not testing MDNS functionality of server here (yet), since it // needs two servers, each listening on its own address }
func TestTCPDNSServer(t *testing.T) { setupForTest(t) const ( numAnswers = 512 nonLocalName = "weave.works." ) dnsAddr := fmt.Sprintf("localhost:%d", testPort) InitDefaultLogging(true) var zone = NewZoneDb(DefaultLocalDomain) // generate a list of `numAnswers` IP addresses var addrs []ZoneRecord bs := make([]byte, 4) for i := 0; i < numAnswers; i++ { binary.LittleEndian.PutUint32(bs, uint32(i)) addrs = append(addrs, Record{"", net.IPv4(bs[0], bs[1], bs[2], bs[3]), 0, 0, 0}) } // handler for the fallback server: it will just return a very long response fallbackUDPHandler := func(w dns.ResponseWriter, req *dns.Msg) { maxLen := getMaxReplyLen(req, protUDP) t.Logf("Fallback UDP server got asked: returning %d answers", numAnswers) q := req.Question[0] m := makeAddressReply(req, &q, addrs) mLen := m.Len() m.SetEdns0(uint16(maxLen), false) if mLen > maxLen { t.Logf("... truncated response (%d > %d)", mLen, maxLen) m.Truncated = true } w.WriteMsg(m) } fallbackTCPHandler := func(w dns.ResponseWriter, req *dns.Msg) { t.Logf("Fallback TCP server got asked: returning %d answers", numAnswers) q := req.Question[0] m := makeAddressReply(req, &q, addrs) w.WriteMsg(m) } t.Logf("Running a DNS fallback server with UDP") us, fallbackUDPAddr, err := runLocalUDPServer(t, "127.0.0.1:0", fallbackUDPHandler) wt.AssertNoErr(t, err) defer us.Shutdown() _, fallbackPort, err := net.SplitHostPort(fallbackUDPAddr) wt.AssertNoErr(t, err) t.Logf("Starting another fallback server, with TCP, on the same port as the UDP server") fallbackTCPAddr := fmt.Sprintf("127.0.0.1:%s", fallbackPort) ts, fallbackTCPAddr, err := runLocalTCPServer(t, fallbackTCPAddr, fallbackTCPHandler) wt.AssertNoErr(t, err) defer ts.Shutdown() t.Logf("Creating a WeaveDNS server instance, falling back to 127.0.0.1:%s", fallbackPort) config := &dns.ClientConfig{Servers: []string{"127.0.0.1"}, Port: fallbackPort} srv, err := NewDNSServer(DNSServerConfig{UpstreamCfg: config, Port: testPort}, zone, nil) wt.AssertNoErr(t, err) defer srv.Stop() go srv.Start() time.Sleep(100 * time.Millisecond) // Allow sever goroutine to start t.Logf("Creating a UDP and a TCP client") uc := new(dns.Client) uc.UDPSize = minUDPSize tc := new(dns.Client) tc.Net = "tcp" t.Logf("Creating DNS query message") m := new(dns.Msg) m.RecursionDesired = true m.SetQuestion(nonLocalName, dns.TypeA) t.Logf("Checking the fallback server at %s returns a truncated response with UDP", fallbackUDPAddr) r, _, err := uc.Exchange(m, fallbackUDPAddr) t.Logf("Got response from fallback server (UDP) with %d answers", len(r.Answer)) t.Logf("Response:\n%+v\n", r) wt.AssertNoErr(t, err) wt.AssertTrue(t, r.MsgHdr.Truncated, "DNS truncated reponse flag") wt.AssertNotEqualInt(t, len(r.Answer), numAnswers, "number of answers (UDP)") t.Logf("Checking the WeaveDNS server at %s returns a truncated reponse with UDP", dnsAddr) r, _, err = uc.Exchange(m, dnsAddr) t.Logf("UDP Response:\n%+v\n", r) wt.AssertNoErr(t, err) wt.AssertNotNil(t, r, "response") t.Logf("%d answers", len(r.Answer)) wt.AssertTrue(t, r.MsgHdr.Truncated, "DNS truncated reponse flag") wt.AssertNotEqualInt(t, len(r.Answer), numAnswers, "number of answers (UDP)") t.Logf("Checking the WeaveDNS server at %s does not return a truncated reponse with TCP", dnsAddr) r, _, err = tc.Exchange(m, dnsAddr) t.Logf("TCP Response:\n%+v\n", r) wt.AssertNoErr(t, err) wt.AssertNotNil(t, r, "response") t.Logf("%d answers", len(r.Answer)) wt.AssertFalse(t, r.MsgHdr.Truncated, "DNS truncated response flag") wt.AssertEqualInt(t, len(r.Answer), numAnswers, "number of answers (TCP)") t.Logf("Checking the WeaveDNS server at %s does not return a truncated reponse with UDP with a bigger buffer", dnsAddr) m.SetEdns0(testUDPBufSize, false) r, _, err = uc.Exchange(m, dnsAddr) t.Logf("UDP-large Response:\n%+v\n", r) wt.AssertNoErr(t, err) wt.AssertNotNil(t, r, "response") t.Logf("%d answers", len(r.Answer)) wt.AssertNoErr(t, err) wt.AssertFalse(t, r.MsgHdr.Truncated, "DNS truncated response flag") wt.AssertEqualInt(t, len(r.Answer), numAnswers, "number of answers (UDP-long)") }
func TestHttp(t *testing.T) { var ( containerID = "deadbeef" testDomain = "weave.local." successTestName = "test1." + testDomain testAddr1 = "10.2.2.1/24" dockerIP = "9.8.7.6" ) zone := NewZoneDb(DefaultLocalDomain) port := rand.Intn(10000) + 32768 fmt.Println("Http test on port", port) go ListenHTTP("", nil, testDomain, zone, port) time.Sleep(100 * time.Millisecond) // Allow for http server to get going // Ask the http server to add our test address into the database addrParts := strings.Split(testAddr1, "/") addrURL := fmt.Sprintf("http://localhost:%d/name/%s/%s", port, containerID, addrParts[0]) resp, err := genForm("PUT", addrURL, url.Values{"fqdn": {successTestName}, "local_ip": {dockerIP}, "routing_prefix": {addrParts[1]}}) wt.AssertNoErr(t, err) wt.AssertStatus(t, resp.StatusCode, http.StatusOK, "http response") // Check that the address is now there. ip, _, _ := net.ParseCIDR(testAddr1) foundIP, err := zone.LookupName(successTestName) wt.AssertNoErr(t, err) if !foundIP[0].IP().Equal(ip) { t.Fatalf("Unexpected result for %s: received %s, expected %s", successTestName, foundIP, ip) } // Adding exactly the same address should be OK resp, err = genForm("PUT", addrURL, url.Values{"fqdn": {successTestName}, "local_ip": {dockerIP}, "routing_prefix": {addrParts[1]}}) wt.AssertNoErr(t, err) wt.AssertStatus(t, resp.StatusCode, http.StatusOK, "http success response for duplicate add") // Now try adding the same address again with a different ident -- // again should be fine otherURL := fmt.Sprintf("http://localhost:%d/name/%s/%s", port, "other", addrParts[0]) resp, err = genForm("PUT", otherURL, url.Values{"fqdn": {successTestName}, "local_ip": {dockerIP}, "routing_prefix": {addrParts[1]}}) wt.AssertNoErr(t, err) wt.AssertStatus(t, resp.StatusCode, http.StatusOK, "http response") // Delete the address resp, err = genForm("DELETE", addrURL, nil) wt.AssertNoErr(t, err) wt.AssertStatus(t, resp.StatusCode, http.StatusOK, "http response") // Check that the address is still resolvable. x, err := zone.LookupName(successTestName) t.Logf("Got %s", x) wt.AssertNoErr(t, err) // Delete the address record mentioning the other container resp, err = genForm("DELETE", otherURL, nil) wt.AssertNoErr(t, err) wt.AssertStatus(t, resp.StatusCode, http.StatusOK, "http response") // Check that the address is gone x, err = zone.LookupName(successTestName) t.Logf("Got %s", x) wt.AssertErrorType(t, err, (*LookupError)(nil), "fully-removed address") // Would like to shut down the http server at the end of this test // but it's complicated. // See https://groups.google.com/forum/#!topic/golang-nuts/vLHWa5sHnCE }