func TestTombstoneDeletion(t *testing.T) { oldNow := now defer func() { now = oldNow }() now = func() int64 { return 1234 } peername, err := mesh.PeerNameFromString("00:00:00:02:00:00") require.Nil(t, err) nameserver := makeNameserver(peername) nameserver.AddEntry("hostname", "containerid", peername, address.Address(0)) require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname")) nameserver.deleteTombstones() require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname")) nameserver.Delete("hostname", "containerid", "", address.Address(0)) require.Equal(t, []address.Address{}, nameserver.Lookup("hostname")) require.Equal(t, l(Entries{Entry{ ContainerID: "containerid", Origin: peername, Addr: address.Address(0), Hostname: "hostname", Version: 1, Tombstone: 1234, }}), nameserver.entries) now = func() int64 { return 1234 + int64(tombstoneTimeout/time.Second) + 1 } nameserver.deleteTombstones() require.Equal(t, Entries{}, nameserver.entries) }
// ClaimForPeers claims the entire ring for the array of peers passed // in. Only works for empty rings. func (r *Ring) ClaimForPeers(peers []mesh.PeerName) { common.Assert(r.Empty()) defer r.assertInvariants() defer r.updateExportedVariables() totalSize := r.distance(r.Start, r.End) share := totalSize/address.Offset(len(peers)) + 1 remainder := totalSize % address.Offset(len(peers)) pos := r.Start for i, peer := range peers { if address.Offset(i) == remainder { share-- if share == 0 { break } } if e, found := r.Entries.get(pos); found { e.update(peer, share) } else { r.Entries.insert(entry{Token: pos, Peer: peer, Free: share}) } pos += address.Address(share) } common.Assert(pos == r.End) r.Seeds = peers }
func TestContainerAndPeerDeath(t *testing.T) { peername, err := mesh.PeerNameFromString("00:00:00:02:00:00") require.Nil(t, err) nameserver := makeNameserver(peername) nameserver.AddEntry("hostname", "containerid", peername, address.Address(0)) require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname")) nameserver.ContainerDied("containerid") require.Equal(t, []address.Address{}, nameserver.Lookup("hostname")) nameserver.AddEntry("hostname", "containerid", peername, address.Address(0)) require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname")) nameserver.PeerGone(peername) require.Equal(t, []address.Address{}, nameserver.Lookup("hostname")) }
func TestContainerAndPeerDeath(t *testing.T) { peername, err := router.PeerNameFromString("00:00:00:02:00:00") require.Nil(t, err) nameserver := New(peername, nil, "") err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0)) require.Nil(t, err) require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname")) nameserver.ContainerDied("containerid") require.Equal(t, []address.Address{}, nameserver.Lookup("hostname")) err = nameserver.AddEntry("hostname", "containerid", peername, address.Address(0)) require.Nil(t, err) require.Equal(t, []address.Address{0}, nameserver.Lookup("hostname")) nameserver.PeerGone(&router.Peer{Name: peername}) require.Equal(t, []address.Address{}, nameserver.Lookup("hostname")) }
func TestTruncation(t *testing.T) { //common.SetLogLevel("debug") peername, err := router.PeerNameFromString("00:00:00:02:00:00") require.Nil(t, err) nameserver := New(peername, nil, nil, "") dnsserver, err := NewDNSServer(nameserver, "weave.local.", "0.0.0.0:0", 30, 5*time.Second) require.Nil(t, err) udpPort := dnsserver.servers[0].PacketConn.LocalAddr().(*net.UDPAddr).Port tcpPort := dnsserver.servers[1].Listener.Addr().(*net.TCPAddr).Port go dnsserver.ActivateAndServe() defer dnsserver.Stop() // Add 100 mappings to nameserver addrs := []address.Address{} for i := address.Address(0); i < 100; i++ { addrs = append(addrs, i) nameserver.AddEntry("foo.weave.local.", "", peername, i) } doRequest := func(client *dns.Client, request *dns.Msg, port int) *dns.Msg { request.SetQuestion("foo.weave.local.", dns.TypeA) response, _, err := client.Exchange(request, fmt.Sprintf("127.0.0.1:%d", port)) require.Nil(t, err) return response } // do a udp query, ensure we get a truncated response { udpClient := dns.Client{Net: "udp", UDPSize: minUDPSize} response := doRequest(&udpClient, &dns.Msg{}, udpPort) require.Nil(t, err) require.True(t, response.MsgHdr.Truncated) require.True(t, len(response.Answer) < 100) } // do a udp query with big size, ensure we don't get a truncated response { udpClient := dns.Client{Net: "udp", UDPSize: 65535} request := &dns.Msg{} request.SetEdns0(65535, false) response := doRequest(&udpClient, request, udpPort) require.False(t, response.MsgHdr.Truncated) require.Equal(t, len(response.Answer), 100) } // do a tcp query, ensure we don't get a truncated response { tcpClient := dns.Client{Net: "tcp"} response := doRequest(&tcpClient, &dns.Msg{}, tcpPort) require.False(t, response.MsgHdr.Truncated) require.Equal(t, len(response.Answer), 100) } }
func TestAdd(t *testing.T) { oldNow := now defer func() { now = oldNow }() now = func() int64 { return 1234 } entries := Entries{} entries.add("A", "", mesh.UnknownPeerName, address.Address(0)) expected := l(Entries{ Entry{Hostname: "A", Origin: mesh.UnknownPeerName, Addr: address.Address(0)}, }) require.Equal(t, entries, expected) entries.tombstone(mesh.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" }) expected = l(Entries{ Entry{Hostname: "A", Origin: mesh.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234}, }) require.Equal(t, entries, expected) entries.add("A", "", mesh.UnknownPeerName, address.Address(0)) expected = l(Entries{ Entry{Hostname: "A", Origin: mesh.UnknownPeerName, Addr: address.Address(0), Version: 2}, }) require.Equal(t, entries, expected) }
func TestTruncation(t *testing.T) { //common.SetLogLevel("debug") dnsserver, nameserver, udpPort, tcpPort := startServer(t, nil) defer dnsserver.Stop() // Add 100 mappings to nameserver addrs := []address.Address{} for i := address.Address(0); i < 100; i++ { addrs = append(addrs, i) nameserver.AddEntry("foo.weave.local.", "", mesh.UnknownPeerName, i) } doRequest := func(client *dns.Client, request *dns.Msg, port int, expectedErr error) *dns.Msg { request.SetQuestion("foo.weave.local.", dns.TypeA) response, _, err := client.Exchange(request, fmt.Sprintf("127.0.0.1:%d", port)) require.Equal(t, expectedErr, err) return response } // do a udp query, ensure we get a truncated response { udpClient := dns.Client{Net: "udp", UDPSize: minUDPSize} response := doRequest(&udpClient, &dns.Msg{}, udpPort, dns.ErrTruncated) require.True(t, response.MsgHdr.Truncated) require.True(t, len(response.Answer) < 100) } // do a udp query with big size, ensure we don't get a truncated response { udpClient := dns.Client{Net: "udp", UDPSize: 65535} request := &dns.Msg{} request.SetEdns0(65535, false) response := doRequest(&udpClient, request, udpPort, nil) require.False(t, response.MsgHdr.Truncated) require.Equal(t, len(response.Answer), 100) } // do a tcp query, ensure we don't get a truncated response { tcpClient := dns.Client{Net: "tcp"} response := doRequest(&tcpClient, &dns.Msg{}, tcpPort, nil) require.False(t, response.MsgHdr.Truncated) require.Equal(t, len(response.Answer), 100) } }
func TestTruncateResponse(t *testing.T) { header := dns.RR_Header{ Name: "host.domain.com", Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 30, } for i := 0; i < 10000; i++ { // generate a random answer set numAnswers := 40 + rand.Intn(200) answers := make([]dns.RR, numAnswers) for j := 0; j < numAnswers; j++ { answers[j] = &dns.A{Hdr: header, A: address.Address(j).IP4()} } // pick a random max size, truncate response to that, check it maxSize := 512 + rand.Intn(2*512) h := handler{maxResponseSize: maxSize} response := h.makeResponse(&dns.Msg{}, answers) require.True(t, response.Len() <= maxSize) } }
func TestRecursiveCompress(t *testing.T) { const ( hostname = "foo.example." maxSize = 512 ) // Construct a response that is >512 when uncompressed, <512 when compressed response := dns.Msg{} response.Authoritative = true response.Answer = []dns.RR{} header := dns.RR_Header{ Name: hostname, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 10, } for response.Len() <= maxSize { ip := address.Address(rand.Uint32()).IP4() response.Answer = append(response.Answer, &dns.A{Hdr: header, A: ip}) } response.Compress = true require.True(t, response.Len() <= maxSize) // A dns server that returns the above response var gotRequest = make(chan struct{}, 1) handleRecursive := func(w dns.ResponseWriter, req *dns.Msg) { gotRequest <- struct{}{} require.Equal(t, req.Question[0].Name, hostname) response.SetReply(req) err := w.WriteMsg(&response) require.Nil(t, err) } mux := dns.NewServeMux() mux.HandleFunc(topDomain, handleRecursive) udpListener, err := net.ListenPacket("udp", "0.0.0.0:0") require.Nil(t, err) udpServer := &dns.Server{PacketConn: udpListener, Handler: mux} udpServerPort := udpListener.LocalAddr().(*net.UDPAddr).Port go udpServer.ActivateAndServe() defer udpServer.Shutdown() // The weavedns server, pointed at the above server dnsserver, _, udpPort, _ := startServer(t, &dns.ClientConfig{ Servers: []string{"127.0.0.1"}, Port: strconv.Itoa(udpServerPort), Ndots: 1, Timeout: 5, Attempts: 2, }) defer dnsserver.Stop() // Now do lookup, check its what we expected. // NB this doesn't really test golang's resolver behaves correctly, as I can't see // a way to point golangs resolver at a specific hosts. req := new(dns.Msg) req.Id = dns.Id() req.RecursionDesired = true req.Question = make([]dns.Question, 1) req.Question[0] = dns.Question{ Name: hostname, Qtype: dns.TypeA, Qclass: dns.ClassINET, } c := new(dns.Client) res, _, err := c.Exchange(req, fmt.Sprintf("127.0.0.1:%d", udpPort)) require.Nil(t, err) require.True(t, len(gotRequest) > 0) require.True(t, res.Len() > maxSize) }
func TestNameservers(t *testing.T) { //common.SetLogLevel("debug") lookupTimeout := 10 // ms nameservers, grouter := makeNetwork(30) defer stopNetwork(nameservers, grouter) // This subset will sometimes lose touch with some of the others badNameservers := nameservers[25:] // This subset will remain well-connected, and we will deal mainly with them nameservers = nameservers[:25] nameserversByName := map[mesh.PeerName]*Nameserver{} for _, n := range nameservers { nameserversByName[n.ourName] = n } mappings := []mapping{} check := func(nameserver *Nameserver, expected mapping) { have := []address.Address{} for i := 0; i < lookupTimeout; i++ { have = nameserver.Lookup(expected.hostname) sort.Sort(addrs(have)) if reflect.DeepEqual(have, expected.Addrs()) { return } time.Sleep(1 * time.Millisecond) } want := expected.Addrs() require.Equal(t, addrs(want).String(), addrs(have).String()) } addMapping := func() { nameserver := nameservers[rand.Intn(len(nameservers))] addr := address.Address(rand.Int31()) // Create a hostname which has some upper and lowercase letters, // and a unique number so we don't have to check if we allocated it already randomBits := rand.Int63() firstLetter := 'H' + (randomBits&1)*32 secondLetter := 'O' + (randomBits&2)*16 randomBits = randomBits >> 2 hostname := fmt.Sprintf("%c%cstname%d", firstLetter, secondLetter, randomBits) mapping := mapping{hostname, []pair{{nameserver.ourName, addr}}} mappings = append(mappings, mapping) nameserver.AddEntry(hostname, "", nameserver.ourName, addr) check(nameserver, mapping) } addExtraMapping := func() { if len(mappings) <= 0 { return } nameserver := nameservers[rand.Intn(len(nameservers))] i := rand.Intn(len(mappings)) mapping := mappings[i] addr := address.Address(rand.Int31()) mapping.addrs = append(mapping.addrs, pair{nameserver.ourName, addr}) mappings[i] = mapping nameserver.AddEntry(mapping.hostname, "", nameserver.ourName, addr) check(nameserver, mapping) } loseConnection := func() { nameserver1 := badNameservers[rand.Intn(len(badNameservers))] nameserver2 := nameservers[rand.Intn(len(nameservers))] nameserver1.PeerGone(nameserver2.ourName) } deleteMapping := func() { if len(mappings) <= 0 { return } i := rand.Intn(len(mappings)) mapping := mappings[i] if len(mapping.addrs) <= 0 { return } j := rand.Intn(len(mapping.addrs)) pair := mapping.addrs[j] mapping.addrs = append(mapping.addrs[:j], mapping.addrs[j+1:]...) mappings[i] = mapping nameserver := nameserversByName[pair.origin] nameserver.Delete(mapping.hostname, "*", pair.addr.String(), pair.addr) check(nameserver, mapping) } doLookup := func() { if len(mappings) <= 0 { return } mapping := mappings[rand.Intn(len(mappings))] nameserver := nameservers[rand.Intn(len(nameservers))] check(nameserver, mapping) } doReverseLookup := func() { if len(mappings) <= 0 { return } mapping := mappings[rand.Intn(len(mappings))] if len(mapping.addrs) <= 0 { return } nameserver := nameservers[rand.Intn(len(nameservers))] hostname := "" var err error for i := 0; i < lookupTimeout; i++ { hostname, err = nameserver.ReverseLookup(mapping.addrs[0].addr) if err != nil && mapping.hostname == hostname { return } time.Sleep(1 * time.Millisecond) } require.Nil(t, err) require.Equal(t, mapping.hostname, hostname) } for i := 0; i < 800; i++ { r := rand.Float32() switch { case r < 0.1: addMapping() case 0.1 <= r && r < 0.2: addExtraMapping() case 0.2 <= r && r < 0.3: deleteMapping() case 0.3 <= r && r < 0.35: loseConnection() case 0.35 <= r && r < 0.9: doLookup() case 0.9 <= r: doReverseLookup() } grouter.Flush() } }
func TestFuzzRing(t *testing.T) { var ( numPeers = 25 iterations = 1000 ) peers := make([]mesh.PeerName, numPeers) for i := 0; i < numPeers; i++ { peers[i] = makePeerName(i) } // Make a valid, random ring makeGoodRandomRing := func() *Ring { addressSpace := end - start numTokens := rand.Intn(int(addressSpace)) tokenMap := make(map[address.Address]bool) for i := 0; i < numTokens; i++ { tokenMap[address.Address(rand.Intn(int(addressSpace)))] = true } var tokens []address.Address for token := range tokenMap { tokens = append(tokens, token) } sort.Sort(addressSlice(tokens)) peer := peers[rand.Intn(len(peers))] ring := New(start, end, peer) for _, token := range tokens { peer = peers[rand.Intn(len(peers))] ring.Entries = append(ring.Entries, &entry{Token: start + token, Peer: peer}) } ring.assertInvariants() return ring } for i := 0; i < iterations; i++ { // make 2 random rings ring1 := makeGoodRandomRing() ring2 := makeGoodRandomRing() // Merge them - this might fail, we don't care // We just want to make sure it doesn't panic ring1.Merge(*ring2) // Check whats left still passes assertions ring1.assertInvariants() ring2.assertInvariants() } // Make an invalid, random ring makeBadRandomRing := func() *Ring { addressSpace := end - start numTokens := rand.Intn(int(addressSpace)) tokens := make([]address.Address, numTokens) for i := 0; i < numTokens; i++ { tokens[i] = address.Address(rand.Intn(int(addressSpace))) } peer := peers[rand.Intn(len(peers))] ring := New(start, end, peer) for _, token := range tokens { peer = peers[rand.Intn(len(peers))] ring.Entries = append(ring.Entries, &entry{Token: start + token, Peer: peer}) } return ring } for i := 0; i < iterations; i++ { // make 2 random rings ring1 := makeGoodRandomRing() ring2 := makeBadRandomRing() // Merge them - this might fail, we don't care // We just want to make sure it doesn't panic ring1.Merge(*ring2) // Check whats left still passes assertions ring1.assertInvariants() } }
func testNameservers(t *testing.T) { //common.SetLogLevel("debug") lookupTimeout := 10 // ms nameservers, grouter := makeNetwork(50) defer stopNetwork(nameservers, grouter) nameserversByName := map[router.PeerName]*Nameserver{} for _, n := range nameservers { nameserversByName[n.ourName] = n } mappings := []mapping{} check := func(nameserver *Nameserver, expected mapping) { have := []address.Address{} for i := 0; i < lookupTimeout; i++ { have = nameserver.Lookup(expected.hostname) sort.Sort(addrs(have)) if reflect.DeepEqual(have, expected.Addrs()) { return } time.Sleep(1 * time.Millisecond) } want := expected.Addrs() require.Equal(t, addrs(want).String(), addrs(have).String()) } addMapping := func() { nameserver := nameservers[rand.Intn(len(nameservers))] addr := address.Address(rand.Int31()) hostname := fmt.Sprintf("hostname%d", rand.Int63()) mapping := mapping{hostname, []pair{{nameserver.ourName, addr}}} mappings = append(mappings, mapping) require.Nil(t, nameserver.AddEntry(hostname, "", nameserver.ourName, addr)) check(nameserver, mapping) } addExtraMapping := func() { if len(mappings) <= 0 { return } nameserver := nameservers[rand.Intn(len(nameservers))] i := rand.Intn(len(mappings)) mapping := mappings[i] addr := address.Address(rand.Int31()) mapping.addrs = append(mapping.addrs, pair{nameserver.ourName, addr}) mappings[i] = mapping require.Nil(t, nameserver.AddEntry(mapping.hostname, "", nameserver.ourName, addr)) check(nameserver, mapping) } deleteMapping := func() { if len(mappings) <= 0 { return } i := rand.Intn(len(mappings)) mapping := mappings[i] if len(mapping.addrs) <= 0 { return } j := rand.Intn(len(mapping.addrs)) pair := mapping.addrs[j] mapping.addrs = append(mapping.addrs[:j], mapping.addrs[j+1:]...) mappings[i] = mapping nameserver := nameserversByName[pair.origin] require.Nil(t, nameserver.Delete(mapping.hostname, "*", pair.addr.String(), pair.addr)) check(nameserver, mapping) } doLookup := func() { if len(mappings) <= 0 { return } mapping := mappings[rand.Intn(len(mappings))] nameserver := nameservers[rand.Intn(len(nameservers))] check(nameserver, mapping) } doReverseLookup := func() { if len(mappings) <= 0 { return } mapping := mappings[rand.Intn(len(mappings))] if len(mapping.addrs) <= 0 { return } nameserver := nameservers[rand.Intn(len(nameservers))] hostname := "" var err error for i := 0; i < lookupTimeout; i++ { hostname, err = nameserver.ReverseLookup(mapping.addrs[0].addr) if err != nil && mapping.hostname == hostname { return } time.Sleep(1 * time.Millisecond) } require.Nil(t, err) require.Equal(t, mapping.hostname, hostname) } for i := 0; i < 1000; i++ { r := rand.Float32() switch { case r < 0.1: addMapping() case 0.1 <= r && r < 0.2: addExtraMapping() case 0.2 <= r && r < 0.3: deleteMapping() case 0.3 <= r && r < 0.9: doLookup() case 0.9 <= r: doReverseLookup() } grouter.Flush() } }