Beispiel #1
0
func TestSpyNoProcesses(t *testing.T) {
	procspy.SetFixtures(fixConnections)

	const (
		nodeID   = "heinz-tomato-ketchup" // TODO rename to hostID
		nodeName = "frenchs-since-1904"   // TODO rename to hostNmae
	)

	reporter := endpoint.NewReporter(nodeID, nodeName, false, false)
	r, _ := reporter.Report()
	//buf, _ := json.MarshalIndent(r, "", "    ")
	//t.Logf("\n%s\n", buf)

	// No process nodes, please
	if want, have := 0, len(r.Endpoint.Nodes); want != have {
		t.Fatalf("want %d, have %d", want, have)
	}

	var (
		scopedLocal  = report.MakeAddressNodeID(nodeID, fixLocalAddress.String())
		scopedRemote = report.MakeAddressNodeID(nodeID, fixRemoteAddress.String())
	)

	if want, have := nodeName, r.Address.Nodes[scopedLocal].Metadata[docker.Name]; want != have {
		t.Fatalf("want %q, have %q", want, have)
	}

	if want, have := 1, len(r.Address.Nodes[scopedRemote].Adjacency); want != have {
		t.Fatalf("want %d, have %d", want, have)
	}

	if want, have := scopedLocal, r.Address.Nodes[scopedRemote].Adjacency[0]; want != have {
		t.Fatalf("want %q, have %q", want, have)
	}
}
Beispiel #2
0
func TestMerge(t *testing.T) {
	var (
		hostID = "xyz"
		src    = newMockSource([]byte{}, nil)
		on     = time.Millisecond
		off    = time.Millisecond
		rpt    = report.MakeReport()
		p      = sniff.Packet{
			SrcIP:     "1.0.0.0",
			SrcPort:   "1000",
			DstIP:     "2.0.0.0",
			DstPort:   "2000",
			Network:   512,
			Transport: 256,
		}

		_, ipnet, _ = net.ParseCIDR(p.SrcIP + "/24") // ;)
		localNets   = report.Networks([]*net.IPNet{ipnet})
	)
	sniff.New(hostID, localNets, src, on, off).Merge(p, &rpt)

	var (
		srcEndpointNodeID = report.MakeEndpointNodeID(hostID, p.SrcIP, p.SrcPort)
		dstEndpointNodeID = report.MakeEndpointNodeID(hostID, p.DstIP, p.DstPort)
	)
	if want, have := (report.Topology{
		Nodes: report.Nodes{
			srcEndpointNodeID: report.MakeNode().WithEdge(dstEndpointNodeID, report.EdgeMetadata{
				EgressPacketCount: newu64(1),
				EgressByteCount:   newu64(256),
			}),
			dstEndpointNodeID: report.MakeNode(),
		},
	}), rpt.Endpoint; !reflect.DeepEqual(want, have) {
		t.Errorf("%s", test.Diff(want, have))
	}

	var (
		srcAddressNodeID = report.MakeAddressNodeID(hostID, p.SrcIP)
		dstAddressNodeID = report.MakeAddressNodeID(hostID, p.DstIP)
	)
	if want, have := (report.Topology{
		Nodes: report.Nodes{
			srcAddressNodeID: report.MakeNode().WithEdge(dstAddressNodeID, report.EdgeMetadata{
				EgressPacketCount: newu64(1),
				EgressByteCount:   newu64(512),
			}),
			dstAddressNodeID: report.MakeNode(),
		},
	}), rpt.Address; !reflect.DeepEqual(want, have) {
		t.Errorf("%s", test.Diff(want, have))
	}
}
Beispiel #3
0
func (rep *reporter) addConnection(r *report.Report, c *procspy.Connection) {
	var (
		scopedLocal  = report.MakeAddressNodeID(rep.hostID, c.LocalAddress.String())
		scopedRemote = report.MakeAddressNodeID(rep.hostID, c.RemoteAddress.String())
		key          = report.MakeAdjacencyID(scopedLocal)
		edgeKey      = report.MakeEdgeID(scopedLocal, scopedRemote)
	)

	r.Address.Adjacency[key] = r.Address.Adjacency[key].Add(scopedRemote)

	if _, ok := r.Address.NodeMetadatas[scopedLocal]; !ok {
		r.Address.NodeMetadatas[scopedLocal] = report.NodeMetadata{
			"name": rep.hostName,
			"addr": c.LocalAddress.String(),
		}
	}

	// Count the TCP connection.
	edgeMeta := r.Address.EdgeMetadatas[edgeKey]
	edgeMeta.WithConnCountTCP = true
	edgeMeta.MaxConnCountTCP++
	r.Address.EdgeMetadatas[edgeKey] = edgeMeta

	if c.Proc.PID > 0 {
		var (
			scopedLocal  = report.MakeEndpointNodeID(rep.hostID, c.LocalAddress.String(), strconv.Itoa(int(c.LocalPort)))
			scopedRemote = report.MakeEndpointNodeID(rep.hostID, c.RemoteAddress.String(), strconv.Itoa(int(c.RemotePort)))
			key          = report.MakeAdjacencyID(scopedLocal)
			edgeKey      = report.MakeEdgeID(scopedLocal, scopedRemote)
		)

		r.Endpoint.Adjacency[key] = r.Endpoint.Adjacency[key].Add(scopedRemote)

		if _, ok := r.Endpoint.NodeMetadatas[scopedLocal]; !ok {
			// First hit establishes NodeMetadata for scoped local address + port
			md := report.NodeMetadata{
				"addr": c.LocalAddress.String(),
				"port": strconv.Itoa(int(c.LocalPort)),
				"pid":  fmt.Sprintf("%d", c.Proc.PID),
			}

			r.Endpoint.NodeMetadatas[scopedLocal] = md
		}
		// Count the TCP connection.
		edgeMeta := r.Endpoint.EdgeMetadatas[edgeKey]
		edgeMeta.WithConnCountTCP = true
		edgeMeta.MaxConnCountTCP++
		r.Endpoint.EdgeMetadatas[edgeKey] = edgeMeta
	}
}
Beispiel #4
0
func addScopeToIPs(hostID string, ips []string) []string {
	ipsWithScopes := []string{}
	for _, ip := range ips {
		ipsWithScopes = append(ipsWithScopes, report.MakeAddressNodeID(hostID, ip))
	}
	return ipsWithScopes
}
Beispiel #5
0
func TestEdgeID(t *testing.T) {
	for _, bad := range []string{
		client54001EndpointNodeID,
		client54002EndpointNodeID,
		unknown1EndpointNodeID,
		unknown2EndpointNodeID,
		unknown3EndpointNodeID,
		clientAddressNodeID,
		serverAddressNodeID,
		unknownAddressNodeID,
		clientHostNodeID,
		serverHostNodeID,
		">1.2.3.4",
		">",
		";",
		"",
	} {
		if srcNodeID, dstNodeID, ok := report.ParseEdgeID(bad); ok {
			t.Errorf("%q: expected failure, but got (%q, %q)", bad, srcNodeID, dstNodeID)
		}
	}

	for input, want := range map[string]struct{ srcNodeID, dstNodeID string }{
		report.MakeEdgeID("a", report.MakeEndpointNodeID("a", "b", "c")): {"a", report.MakeEndpointNodeID("a", "b", "c")},
		report.MakeEdgeID("a", report.MakeAddressNodeID("a", "b")):       {"a", report.MakeAddressNodeID("a", "b")},
		report.MakeEdgeID("a", report.MakeProcessNodeID("a", "b")):       {"a", report.MakeProcessNodeID("a", "b")},
		report.MakeEdgeID("a", report.MakeHostNodeID("a")):               {"a", report.MakeHostNodeID("a")},
		"host.com|1.2.3.4":                                               {"host.com", "1.2.3.4"},
		"a|b;c":                                                          {"a", "b;c"},
		"a|b":                                                            {"a", "b"},
		"a|":                                                             {"a", ""},
		"|b":                                                             {"", "b"},
		"|":                                                              {"", ""},
	} {
		srcNodeID, dstNodeID, ok := report.ParseEdgeID(input)
		if !ok {
			t.Errorf("%q: not OK", input)
			continue
		}
		if want, have := want.srcNodeID, srcNodeID; want != have {
			t.Errorf("%q: want %q, have %q", input, want, have)
		}
		if want, have := want.dstNodeID, dstNodeID; want != have {
			t.Errorf("%q: want %q, have %q", input, want, have)
		}
	}
}
Beispiel #6
0
func (r *Reporter) addConnection(rpt *report.Report, c *procspy.Connection) {
	var (
		scopedLocal  = report.MakeAddressNodeID(r.hostID, c.LocalAddress.String())
		scopedRemote = report.MakeAddressNodeID(r.hostID, c.RemoteAddress.String())
		key          = report.MakeAdjacencyID(scopedLocal)
		edgeKey      = report.MakeEdgeID(scopedLocal, scopedRemote)
	)

	rpt.Address.Adjacency[key] = rpt.Address.Adjacency[key].Add(scopedRemote)

	if _, ok := rpt.Address.NodeMetadatas[scopedLocal]; !ok {
		rpt.Address.NodeMetadatas[scopedLocal] = report.NewNodeMetadata(map[string]string{
			docker.Name: r.hostName,
			docker.Addr: c.LocalAddress.String(),
		})
	}

	countTCPConnection(rpt.Address.EdgeMetadatas, edgeKey)

	if c.Proc.PID > 0 {
		var (
			scopedLocal  = report.MakeEndpointNodeID(r.hostID, c.LocalAddress.String(), strconv.Itoa(int(c.LocalPort)))
			scopedRemote = report.MakeEndpointNodeID(r.hostID, c.RemoteAddress.String(), strconv.Itoa(int(c.RemotePort)))
			key          = report.MakeAdjacencyID(scopedLocal)
			edgeKey      = report.MakeEdgeID(scopedLocal, scopedRemote)
		)

		rpt.Endpoint.Adjacency[key] = rpt.Endpoint.Adjacency[key].Add(scopedRemote)

		if _, ok := rpt.Endpoint.NodeMetadatas[scopedLocal]; !ok {
			// First hit establishes NodeMetadata for scoped local address + port
			md := report.NewNodeMetadata(map[string]string{
				"addr": c.LocalAddress.String(),
				"port": strconv.Itoa(int(c.LocalPort)),
				"pid":  fmt.Sprintf("%d", c.Proc.PID),
			})

			rpt.Endpoint.NodeMetadatas[scopedLocal] = md
		}

		countTCPConnection(rpt.Endpoint.EdgeMetadatas, edgeKey)
	}
}
Beispiel #7
0
func (r *Reporter) addConnection(rpt *report.Report, c *procspy.Connection) {
	var (
		localAddressNodeID  = report.MakeAddressNodeID(r.hostID, c.LocalAddress.String())
		remoteAddressNodeID = report.MakeAddressNodeID(r.hostID, c.RemoteAddress.String())
		adjecencyID         = report.MakeAdjacencyID(localAddressNodeID)
		edgeID              = report.MakeEdgeID(localAddressNodeID, remoteAddressNodeID)
	)

	rpt.Address.Adjacency[adjecencyID] = rpt.Address.Adjacency[adjecencyID].Add(remoteAddressNodeID)

	if _, ok := rpt.Address.NodeMetadatas[localAddressNodeID]; !ok {
		rpt.Address.NodeMetadatas[localAddressNodeID] = report.MakeNodeMetadataWith(map[string]string{
			"name": r.hostName,
			Addr:   c.LocalAddress.String(),
		})
	}

	countTCPConnection(rpt.Address.EdgeMetadatas, edgeID)

	if c.Proc.PID > 0 {
		var (
			localEndpointNodeID  = report.MakeEndpointNodeID(r.hostID, c.LocalAddress.String(), strconv.Itoa(int(c.LocalPort)))
			remoteEndpointNodeID = report.MakeEndpointNodeID(r.hostID, c.RemoteAddress.String(), strconv.Itoa(int(c.RemotePort)))
			adjecencyID          = report.MakeAdjacencyID(localEndpointNodeID)
			edgeID               = report.MakeEdgeID(localEndpointNodeID, remoteEndpointNodeID)
		)

		rpt.Endpoint.Adjacency[adjecencyID] = rpt.Endpoint.Adjacency[adjecencyID].Add(remoteEndpointNodeID)

		if _, ok := rpt.Endpoint.NodeMetadatas[localEndpointNodeID]; !ok {
			// First hit establishes NodeMetadata for scoped local address + port
			md := report.MakeNodeMetadataWith(map[string]string{
				Addr:        c.LocalAddress.String(),
				Port:        strconv.Itoa(int(c.LocalPort)),
				process.PID: fmt.Sprint(c.Proc.PID),
			})

			rpt.Endpoint.NodeMetadatas[localEndpointNodeID] = md
		}

		countTCPConnection(rpt.Endpoint.EdgeMetadatas, edgeID)
	}
}
Beispiel #8
0
func TestCollector(t *testing.T) {
	log.SetOutput(ioutil.Discard)

	// Swap out ticker
	publish := make(chan time.Time)
	oldTick := tick
	tick = func(time.Duration) <-chan time.Time { return publish }
	defer func() { tick = oldTick }()

	// Build a collector
	collector := NewCollector(time.Second, "id")
	defer collector.Stop()

	concreteCollector, ok := collector.(*realCollector)
	if !ok {
		t.Fatal("type assertion failure")
	}

	// Build a test publisher
	reports := make(chan interface{})
	ln := testPublisher(t, reports)
	defer ln.Close()

	// Connect the collector to the test publisher
	addr := ln.Addr().String()
	collector.Add(addr)
	collector.Add(addr) // test duplicate case
	runtime.Gosched()   // make sure it connects

	// Push a report through everything
	r := report.Report{
		Address: report.Topology{
			NodeMetadatas: report.NodeMetadatas{
				report.MakeAddressNodeID("a", "b"): report.NodeMetadata{},
			},
		},
	}

	reports <- r
	poll(t, 100*time.Millisecond, func() bool {
		return len(concreteCollector.peek().Address.NodeMetadatas) == 1
	}, "missed the report")

	go func() { publish <- time.Now() }()
	collected := <-collector.Reports()
	if reflect.DeepEqual(r, collected) {
		t.Errorf(test.Diff(r, collected))
	}

	collector.Remove(addr)
	collector.Remove(addr) // test duplicate case
}
Beispiel #9
0
func TestAddressIDAddresser(t *testing.T) {
	if nodeID := "1.2.4.5"; report.AddressIDAddresser(nodeID) != nil {
		t.Errorf("%q: bad node ID parsed as good", nodeID)
	}
	var (
		nodeID = report.MakeAddressNodeID(clientHostID, clientAddress)
		want   = net.ParseIP(clientAddress)
		have   = report.AddressIDAddresser(nodeID)
	)
	if !reflect.DeepEqual(want, have) {
		t.Errorf("want %s, have %s", want, have)
	}
}
Beispiel #10
0
// Tag implements Tagger.
func (w *Weave) Tag(r report.Report) (report.Report, error) {
	w.mtx.RLock()
	defer w.mtx.RUnlock()

	// Put information from weaveDNS on the container nodes
	for _, entry := range w.statusCache.DNS.Entries {
		if entry.Tombstone > 0 {
			continue
		}
		nodeID := report.MakeContainerNodeID(entry.ContainerID)
		node, ok := r.Container.Nodes[nodeID]
		if !ok {
			continue
		}
		w, _ := node.Latest.Lookup(WeaveDNSHostname)
		hostnames := report.IDList(strings.Fields(w))
		hostnames = hostnames.Add(strings.TrimSuffix(entry.Hostname, "."))
		r.Container.Nodes[nodeID] = node.WithLatests(map[string]string{WeaveDNSHostname: strings.Join(hostnames, " ")})
	}

	// Put information from weave ps on the container nodes
	const maxPrefixSize = 12
	for id, node := range r.Container.Nodes {
		prefix, ok := node.Latest.Lookup(docker.ContainerID)
		if !ok {
			continue
		}
		if len(prefix) > maxPrefixSize {
			prefix = prefix[:maxPrefixSize]
		}
		entry, ok := w.psCache[prefix]
		if !ok {
			continue
		}

		ipsWithScope := report.MakeStringSet()
		for _, ip := range entry.IPs {
			ipsWithScope = ipsWithScope.Add(report.MakeAddressNodeID("", ip))
		}
		node = node.WithSet(docker.ContainerIPs, report.MakeStringSet(entry.IPs...))
		node = node.WithSet(docker.ContainerIPsWithScopes, ipsWithScope)
		node = node.WithLatests(map[string]string{
			WeaveMACAddress: entry.MACAddress,
		})
		r.Container.Nodes[id] = node
	}
	return r, nil
}
Beispiel #11
0
// Tag implements Tagger.
func (w *Weave) Tag(r report.Report) (report.Report, error) {
	w.mtx.RLock()
	defer w.mtx.RUnlock()

	// Put information from weaveDNS on the container nodes
	for _, entry := range w.status.DNS.Entries {
		if entry.Tombstone > 0 {
			continue
		}
		nodeID := report.MakeContainerNodeID(w.hostID, entry.ContainerID)
		node, ok := r.Container.Nodes[nodeID]
		if !ok {
			continue
		}
		hostnames := report.IDList(strings.Fields(node.Metadata[WeaveDNSHostname]))
		hostnames = hostnames.Add(strings.TrimSuffix(entry.Hostname, "."))
		node.Metadata[WeaveDNSHostname] = strings.Join(hostnames, " ")
	}

	// Put information from weave ps on the container nodes
	psEntries, err := w.ps()
	if err != nil {
		return r, nil
	}
	psEntriesByPrefix := map[string]psEntry{}
	for _, entry := range psEntries {
		psEntriesByPrefix[entry.containerIDPrefix] = entry
	}
	for id, node := range r.Container.Nodes {
		prefix := node.Metadata[docker.ContainerID][:12]
		entry, ok := psEntriesByPrefix[prefix]
		if !ok {
			continue
		}

		ipsWithScope := report.MakeStringSet()
		for _, ip := range entry.ips {
			ipsWithScope = ipsWithScope.Add(report.MakeAddressNodeID("", ip))
		}
		node = node.WithSet(docker.ContainerIPs, report.MakeStringSet(entry.ips...))
		node = node.WithSet(docker.ContainerIPsWithScopes, ipsWithScope)
		node.Metadata[WeaveMACAddress] = entry.macAddress
		r.Container.Nodes[id] = node
	}
	return r, nil
}
Beispiel #12
0
	ServerProcessNodeID       = report.MakeProcessNodeID(ServerHostID, ServerPID)
	NonContainerProcessNodeID = report.MakeProcessNodeID(ServerHostID, NonContainerPID)

	ClientContainerID     = "a1b2c3d4e5"
	ServerContainerID     = "5e4d3c2b1a"
	ClientContainerNodeID = report.MakeContainerNodeID(ClientHostID, ClientContainerID)
	ServerContainerNodeID = report.MakeContainerNodeID(ServerHostID, ServerContainerID)

	ClientContainerImageID     = "imageid123"
	ServerContainerImageID     = "imageid456"
	ClientContainerImageNodeID = report.MakeContainerNodeID(ClientHostID, ClientContainerImageID)
	ServerContainerImageNodeID = report.MakeContainerNodeID(ServerHostID, ServerContainerImageID)
	ClientContainerImageName   = "image/client"
	ServerContainerImageName   = "image/server"

	ClientAddressNodeID   = report.MakeAddressNodeID(ClientHostID, ClientIP)
	ServerAddressNodeID   = report.MakeAddressNodeID(ServerHostID, ServerIP)
	UnknownAddress1NodeID = report.MakeAddressNodeID(ServerHostID, UnknownClient1IP)
	UnknownAddress2NodeID = report.MakeAddressNodeID(ServerHostID, UnknownClient2IP)
	UnknownAddress3NodeID = report.MakeAddressNodeID(ServerHostID, UnknownClient3IP)
	RandomAddressNodeID   = report.MakeAddressNodeID(ServerHostID, RandomClientIP) // this should become an internet node

	Report = report.Report{
		Endpoint: report.Topology{
			Nodes: report.Nodes{
				// Node is arbitrary. We're free to put only precisely what we
				// care to test into the fixture. Just be sure to include the bits
				// that the mapping funcs extract :)
				Client54001NodeID: report.MakeNode().WithMetadata(map[string]string{
					endpoint.Addr:     ClientIP,
					endpoint.Port:     ClientPort54001,
Beispiel #13
0
	ClientProcessNodeID       = report.MakeProcessNodeID(ClientHostID, ClientPID)
	ServerProcessNodeID       = report.MakeProcessNodeID(ServerHostID, ServerPID)
	NonContainerProcessNodeID = report.MakeProcessNodeID(ServerHostID, NonContainerPID)

	ClientContainerID     = "a1b2c3d4e5"
	ServerContainerID     = "5e4d3c2b1a"
	ClientContainerNodeID = report.MakeContainerNodeID(ClientHostID, ClientContainerID)
	ServerContainerNodeID = report.MakeContainerNodeID(ServerHostID, ServerContainerID)

	ClientContainerImageID     = "imageid123"
	ServerContainerImageID     = "imageid456"
	ClientContainerImageNodeID = report.MakeContainerNodeID(ClientHostID, ClientContainerImageID)
	ServerContainerImageNodeID = report.MakeContainerNodeID(ServerHostID, ServerContainerImageID)

	ClientAddressNodeID   = report.MakeAddressNodeID(ClientHostID, "10.10.10.20")
	ServerAddressNodeID   = report.MakeAddressNodeID(ServerHostID, "192.168.1.1")
	UnknownAddress1NodeID = report.MakeAddressNodeID(ServerHostID, "10.10.10.10")
	UnknownAddress2NodeID = report.MakeAddressNodeID(ServerHostID, "10.10.10.11")
	RandomAddressNodeID   = report.MakeAddressNodeID(ServerHostID, "51.52.53.54") // this should become an internet node

	Report = report.Report{
		Endpoint: report.Topology{
			Adjacency: report.Adjacency{
				report.MakeAdjacencyID(Client54001NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(Client54002NodeID): report.MakeIDList(Server80NodeID),
				report.MakeAdjacencyID(Server80NodeID): report.MakeIDList(
					Client54001NodeID, Client54002NodeID, UnknownClient1NodeID, UnknownClient2NodeID,
					UnknownClient3NodeID, RandomClientNodeID),
			},
			NodeMetadatas: report.NodeMetadatas{
Beispiel #14
0
func (r *Reporter) addConnection(rpt *report.Report, localAddr, remoteAddr string, localPort, remotePort uint16, extraLocalNode, extraRemoteNode *report.Node) {
	localIsClient := int(localPort) > int(remotePort)

	// Update address topology
	{
		var (
			localAddressNodeID  = report.MakeAddressNodeID(r.hostID, localAddr)
			remoteAddressNodeID = report.MakeAddressNodeID(r.hostID, remoteAddr)
			localNode           = report.MakeNodeWith(map[string]string{
				"name": r.hostName,
				Addr:   localAddr,
			})
			remoteNode = report.MakeNodeWith(map[string]string{
				Addr: remoteAddr,
			})
		)

		// In case we have a reverse resolution for the IP, we can use it for
		// the name...
		if revRemoteName, err := r.revResolver.Get(remoteAddr); err == nil {
			remoteNode = remoteNode.WithMetadata(map[string]string{
				"name": revRemoteName,
			})
		}

		if localIsClient {
			// New nodes are merged into the report so we don't need to do any
			// counting here; the merge does it for us.
			localNode = localNode.WithEdge(remoteAddressNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		} else {
			remoteNode = localNode.WithEdge(localAddressNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		}

		if extraLocalNode != nil {
			localNode = localNode.Merge(*extraLocalNode)
		}
		if extraRemoteNode != nil {
			remoteNode = remoteNode.Merge(*extraRemoteNode)
		}
		rpt.Address = rpt.Address.AddNode(localAddressNodeID, localNode)
		rpt.Address = rpt.Address.AddNode(remoteAddressNodeID, remoteNode)
	}

	// Update endpoint topology
	if r.includeProcesses {
		var (
			localEndpointNodeID  = report.MakeEndpointNodeID(r.hostID, localAddr, strconv.Itoa(int(localPort)))
			remoteEndpointNodeID = report.MakeEndpointNodeID(r.hostID, remoteAddr, strconv.Itoa(int(remotePort)))

			localNode = report.MakeNodeWith(map[string]string{
				Addr: localAddr,
				Port: strconv.Itoa(int(localPort)),
			})
			remoteNode = report.MakeNodeWith(map[string]string{
				Addr: remoteAddr,
				Port: strconv.Itoa(int(remotePort)),
			})
		)

		// In case we have a reverse resolution for the IP, we can use it for
		// the name...
		if revRemoteName, err := r.revResolver.Get(remoteAddr); err == nil {
			remoteNode = remoteNode.WithMetadata(map[string]string{
				"name": revRemoteName,
			})
		}

		if localIsClient {
			// New nodes are merged into the report so we don't need to do any
			// counting here; the merge does it for us.
			localNode = localNode.WithEdge(remoteEndpointNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		} else {
			remoteNode = remoteNode.WithEdge(localEndpointNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		}

		if extraLocalNode != nil {
			localNode = localNode.Merge(*extraLocalNode)
		}
		if extraRemoteNode != nil {
			remoteNode = remoteNode.Merge(*extraRemoteNode)
		}
		rpt.Endpoint = rpt.Endpoint.AddNode(localEndpointNodeID, localNode)
		rpt.Endpoint = rpt.Endpoint.AddNode(remoteEndpointNodeID, remoteNode)
	}
}
Beispiel #15
0
// DemoReport makes up a report.
func DemoReport(nodeCount int) report.Report {
	r := report.MakeReport()

	// Make up some plausible IPv4 numbers
	hosts := []string{}
	ip := [4]int{192, 168, 1, 1}
	for range make([]struct{}, nodeCount) {
		hosts = append(hosts, fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]))
		ip[3]++
		if ip[3] > 200 {
			ip[2]++
			ip[3] = 1
		}
	}
	// Some non-local ones.
	hosts = append(hosts, []string{"1.2.3.4", "2.3.4.5"}...)

	_, localNet, err := net.ParseCIDR("192.168.0.0/16")
	if err != nil {
		panic(err)
	}

	type conn struct {
		srcProc, dstProc string
		dstPort          int
	}
	procPool := []conn{
		{srcProc: "curl", dstPort: 80, dstProc: "apache"},
		{srcProc: "wget", dstPort: 80, dstProc: "apache"},
		{srcProc: "curl", dstPort: 80, dstProc: "nginx"},
		{srcProc: "curl", dstPort: 8080, dstProc: "app1"},
		{srcProc: "nginx", dstPort: 8080, dstProc: "app1"},
		{srcProc: "nginx", dstPort: 8080, dstProc: "app2"},
		{srcProc: "nginx", dstPort: 8080, dstProc: "app3"},
	}
	connectionCount := nodeCount * 8
	for i := 0; i < connectionCount; i++ {
		var (
			c            = procPool[rand.Intn(len(procPool))]
			src          = hosts[rand.Intn(len(hosts))]
			dst          = hosts[rand.Intn(len(hosts))]
			srcPort      = rand.Intn(50000) + 10000
			srcPortID    = report.MakeEndpointNodeID("", src, strconv.Itoa(srcPort))
			dstPortID    = report.MakeEndpointNodeID("", dst, strconv.Itoa(c.dstPort))
			srcAddressID = report.MakeAddressNodeID("", src)
			dstAddressID = report.MakeAddressNodeID("", dst)
		)

		// Endpoint topology
		r.Endpoint = r.Endpoint.WithNode(srcPortID, report.MakeNode().WithMetadata(map[string]string{
			"pid":    "4000",
			"name":   c.srcProc,
			"domain": "node-" + src,
		}).WithEdge(dstPortID, report.EdgeMetadata{
			MaxConnCountTCP: newu64(uint64(rand.Intn(100) + 10)),
		}))
		r.Endpoint = r.Endpoint.WithNode(dstPortID, report.MakeNode().WithMetadata(map[string]string{
			"pid":    "4000",
			"name":   c.dstProc,
			"domain": "node-" + dst,
		}).WithEdge(srcPortID, report.EdgeMetadata{
			MaxConnCountTCP: newu64(uint64(rand.Intn(100) + 10)),
		}))

		// Address topology
		r.Address = r.Address.WithNode(srcAddressID, report.MakeNode().WithMetadata(map[string]string{
			"name": src,
		}).WithAdjacent(dstAddressID))
		r.Address = r.Address.WithNode(dstAddressID, report.MakeNode().WithMetadata(map[string]string{
			"name": dst,
		}).WithAdjacent(srcAddressID))

		// Host data
		r.Host = r.Host.WithNode("hostX", report.MakeNodeWith(map[string]string{
			"ts":             time.Now().UTC().Format(time.RFC3339Nano),
			"host_name":      "host-x",
			"local_networks": localNet.String(),
			"os":             "linux",
		}))
	}

	return r
}
					endpoint.Port:        duplicatedPort,
					endpoint.Conntracked: "true",
				}).
					WithTopology(report.Endpoint),
			},
		},
		Container: report.Topology{
			Nodes: report.Nodes{
				container1NodeID: report.MakeNodeWith(container1NodeID, map[string]string{
					docker.ContainerID:   container1ID,
					docker.ContainerName: container1Name,
					report.HostNodeID:    serverHostNodeID,
				}).
					WithSets(report.EmptySets.
						Add(docker.ContainerIPs, report.MakeStringSet(container1IP)).
						Add(docker.ContainerIPsWithScopes, report.MakeStringSet(report.MakeAddressNodeID("", container1IP))).
						Add(docker.ContainerPorts, report.MakeStringSet(fmt.Sprintf("%s:%s->%s/tcp", serverIP, serverPort, serverPort))),
					).WithTopology(report.Container),
				container2NodeID: report.MakeNodeWith(container2NodeID, map[string]string{
					docker.ContainerID:   container2ID,
					docker.ContainerName: container2Name,
					report.HostNodeID:    serverHostNodeID,
				}).
					WithSets(report.EmptySets.
						Add(docker.ContainerIPs, report.MakeStringSet(container2IP)).
						Add(docker.ContainerIPsWithScopes, report.MakeStringSet(report.MakeAddressNodeID("", container2IP))),
					).WithTopology(report.Container),
				pauseContainerNodeID: report.MakeNodeWith(pauseContainerNodeID, map[string]string{
					docker.ContainerID:   pauseContainerID,
					docker.ContainerName: pauseContainerName,
					report.HostNodeID:    serverHostNodeID,
Beispiel #17
0
// DemoReport makes up a report.
func DemoReport(nodeCount int) report.Report {
	r := report.MakeReport()

	// Make up some plausible IPv4 numbers
	hosts := []string{}
	ip := [4]int{192, 168, 1, 1}
	for range make([]struct{}, nodeCount) {
		hosts = append(hosts, fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]))
		ip[3]++
		if ip[3] > 200 {
			ip[2]++
			ip[3] = 1
		}
	}
	// Some non-local ones.
	hosts = append(hosts, []string{"1.2.3.4", "2.3.4.5"}...)

	_, localNet, err := net.ParseCIDR("192.168.0.0/16")
	if err != nil {
		panic(err)
	}

	type conn struct {
		srcProc, dstProc string
		dstPort          int
	}
	procPool := []conn{
		{srcProc: "curl", dstPort: 80, dstProc: "apache"},
		{srcProc: "wget", dstPort: 80, dstProc: "apache"},
		{srcProc: "curl", dstPort: 80, dstProc: "nginx"},
		{srcProc: "curl", dstPort: 8080, dstProc: "app1"},
		{srcProc: "nginx", dstPort: 8080, dstProc: "app1"},
		{srcProc: "nginx", dstPort: 8080, dstProc: "app2"},
		{srcProc: "nginx", dstPort: 8080, dstProc: "app3"},
	}
	connectionCount := nodeCount * 2
	for i := 0; i < connectionCount; i++ {
		var (
			c                = procPool[rand.Intn(len(procPool))]
			src              = hosts[rand.Intn(len(hosts))]
			dst              = hosts[rand.Intn(len(hosts))]
			srcPort          = rand.Intn(50000) + 10000
			srcPortID        = report.MakeEndpointNodeID("", src, strconv.Itoa(srcPort))
			dstPortID        = report.MakeEndpointNodeID("", dst, strconv.Itoa(c.dstPort))
			srcID            = report.MakeAdjacencyID(srcPortID)
			dstID            = report.MakeAdjacencyID(dstPortID)
			srcAddressID     = report.MakeAddressNodeID("", src)
			dstAddressID     = report.MakeAddressNodeID("", dst)
			nodeSrcAddressID = report.MakeAdjacencyID(srcAddressID)
			nodeDstAddressID = report.MakeAdjacencyID(dstAddressID)
		)

		// Endpoint topology
		if _, ok := r.Endpoint.NodeMetadatas[srcPortID]; !ok {
			r.Endpoint.NodeMetadatas[srcPortID] = report.NewNodeMetadata(map[string]string{
				docker.PID:    "4000",
				docker.Name:   c.srcProc,
				docker.Domain: "node-" + src,
			})
		}
		r.Endpoint.Adjacency[srcID] = r.Endpoint.Adjacency[srcID].Add(dstPortID)
		if _, ok := r.Endpoint.NodeMetadatas[dstPortID]; !ok {
			r.Endpoint.NodeMetadatas[dstPortID] = report.NewNodeMetadata(map[string]string{
				docker.PID:    "4000",
				docker.Name:   c.dstProc,
				docker.Domain: "node-" + dst,
			})
		}
		r.Endpoint.Adjacency[dstID] = r.Endpoint.Adjacency[dstID].Add(srcPortID)
		var (
			edgeKeyEgress  = report.MakeEdgeID(srcPortID, dstPortID)
			edgeKeyIngress = report.MakeEdgeID(dstPortID, srcPortID)
		)
		r.Endpoint.EdgeMetadatas[edgeKeyEgress] = report.EdgeMetadata{
			WithConnCountTCP: true,
			MaxConnCountTCP:  uint(rand.Intn(100) + 10),
		}
		r.Endpoint.EdgeMetadatas[edgeKeyIngress] = report.EdgeMetadata{
			WithConnCountTCP: true,
			MaxConnCountTCP:  uint(rand.Intn(100) + 10),
		}

		// Address topology
		if _, ok := r.Address.NodeMetadatas[srcAddressID]; !ok {
			r.Address.NodeMetadatas[srcAddressID] = report.NewNodeMetadata(map[string]string{
				docker.Name: src,
			})
		}
		r.Address.Adjacency[nodeSrcAddressID] = r.Address.Adjacency[nodeSrcAddressID].Add(dstAddressID)
		if _, ok := r.Address.NodeMetadatas[dstAddressID]; !ok {
			r.Address.NodeMetadatas[dstAddressID] = report.NewNodeMetadata(map[string]string{
				docker.Name: dst,
			})
		}
		r.Address.Adjacency[nodeDstAddressID] = r.Address.Adjacency[nodeDstAddressID].Add(srcAddressID)

		// Host data
		r.Host.NodeMetadatas["hostX"] = report.NewNodeMetadata(map[string]string{
			"ts":             time.Now().UTC().Format(time.RFC3339Nano),
			"host_name":      "host-x",
			"local_networks": localNet.String(),
			"os":             "linux",
		})
	}

	return r
}
Beispiel #18
0
	clientAddress    = "10.10.10.20"
	serverHostID     = "server.host.com"
	serverHostName   = serverHostID
	serverHostNodeID = report.MakeHostNodeID(serverHostID)
	serverAddress    = "10.10.10.1"
	unknownHostID    = ""              // by definition, we don't know it
	unknownAddress   = "172.16.93.112" // will be a pseudonode, no corresponding host

	client54001EndpointNodeID = report.MakeEndpointNodeID(clientHostID, clientAddress, "54001") // i.e. curl
	client54002EndpointNodeID = report.MakeEndpointNodeID(clientHostID, clientAddress, "54002") // also curl
	server80EndpointNodeID    = report.MakeEndpointNodeID(serverHostID, serverAddress, "80")    // i.e. apache
	unknown1EndpointNodeID    = report.MakeEndpointNodeID(unknownHostID, unknownAddress, "10001")
	unknown2EndpointNodeID    = report.MakeEndpointNodeID(unknownHostID, unknownAddress, "10002")
	unknown3EndpointNodeID    = report.MakeEndpointNodeID(unknownHostID, unknownAddress, "10003")

	clientAddressNodeID  = report.MakeAddressNodeID(clientHostID, clientAddress)
	serverAddressNodeID  = report.MakeAddressNodeID(serverHostID, serverAddress)
	unknownAddressNodeID = report.MakeAddressNodeID(unknownHostID, unknownAddress)
)

func TestAdjacencyID(t *testing.T) {
	for _, bad := range []string{
		client54001EndpointNodeID,
		client54002EndpointNodeID,
		unknown1EndpointNodeID,
		unknown2EndpointNodeID,
		unknown3EndpointNodeID,
		clientAddressNodeID,
		serverAddressNodeID,
		unknownAddressNodeID,
		clientHostNodeID,
Beispiel #19
0
func (r *Reporter) addConnection(rpt *report.Report, localAddr, remoteAddr string, localPort, remotePort uint16, proc *procspy.Proc) {
	localIsClient := int(localPort) > int(remotePort)

	// Update address topology
	{
		var (
			localAddressNodeID  = report.MakeAddressNodeID(r.hostID, localAddr)
			remoteAddressNodeID = report.MakeAddressNodeID(r.hostID, remoteAddr)
			adjacencyID         = ""
			edgeID              = ""
		)

		if localIsClient {
			adjacencyID = report.MakeAdjacencyID(localAddressNodeID)
			rpt.Address.Adjacency[adjacencyID] = rpt.Address.Adjacency[adjacencyID].Add(remoteAddressNodeID)

			edgeID = report.MakeEdgeID(localAddressNodeID, remoteAddressNodeID)
		} else {
			adjacencyID = report.MakeAdjacencyID(remoteAddressNodeID)
			rpt.Address.Adjacency[adjacencyID] = rpt.Address.Adjacency[adjacencyID].Add(localAddressNodeID)

			edgeID = report.MakeEdgeID(remoteAddressNodeID, localAddressNodeID)
		}

		countTCPConnection(rpt.Address.EdgeMetadatas, edgeID)

		if _, ok := rpt.Address.NodeMetadatas[localAddressNodeID]; !ok {
			rpt.Address.NodeMetadatas[localAddressNodeID] = report.MakeNodeMetadataWith(map[string]string{
				"name": r.hostName,
				Addr:   localAddr,
			})
		}
	}

	// Update endpoint topology
	if r.includeProcesses {
		var (
			localEndpointNodeID  = report.MakeEndpointNodeID(r.hostID, localAddr, strconv.Itoa(int(localPort)))
			remoteEndpointNodeID = report.MakeEndpointNodeID(r.hostID, remoteAddr, strconv.Itoa(int(remotePort)))
			adjacencyID          = ""
			edgeID               = ""
		)

		if localIsClient {
			adjacencyID = report.MakeAdjacencyID(localEndpointNodeID)
			rpt.Endpoint.Adjacency[adjacencyID] = rpt.Endpoint.Adjacency[adjacencyID].Add(remoteEndpointNodeID)

			edgeID = report.MakeEdgeID(localEndpointNodeID, remoteEndpointNodeID)
		} else {
			adjacencyID = report.MakeAdjacencyID(remoteEndpointNodeID)
			rpt.Endpoint.Adjacency[adjacencyID] = rpt.Endpoint.Adjacency[adjacencyID].Add(localEndpointNodeID)

			edgeID = report.MakeEdgeID(remoteEndpointNodeID, localEndpointNodeID)
		}

		countTCPConnection(rpt.Endpoint.EdgeMetadatas, edgeID)

		md, ok := rpt.Endpoint.NodeMetadatas[localEndpointNodeID]
		updated := !ok
		if !ok {
			md = report.MakeNodeMetadataWith(map[string]string{
				Addr: localAddr,
				Port: strconv.Itoa(int(localPort)),
			})
		}
		if proc != nil && proc.PID > 0 {
			pid := strconv.FormatUint(uint64(proc.PID), 10)
			updated = updated || md.Metadata[process.PID] != pid
			md.Metadata[process.PID] = pid
		}
		if updated {
			rpt.Endpoint.NodeMetadatas[localEndpointNodeID] = md
		}
	}
}
Beispiel #20
0
// Merge puts the packet into the report.
//
// Note that, for the moment, we encode bidirectional traffic as ingress and
// egress traffic on a single edge whose src is local and dst is remote. That
// is, if we see a packet from the remote addr 9.8.7.6 to the local addr
// 1.2.3.4, we apply it as *ingress* on the edge (1.2.3.4 -> 9.8.7.6).
func (s *Sniffer) Merge(p Packet, rpt *report.Report) {
	if p.SrcIP == "" || p.DstIP == "" {
		return
	}

	// One end of the traffic has to be local. Otherwise, we don't know how to
	// construct the edge.
	//
	// If we need to get around this limitation, we may be able to change the
	// semantics of the report, and allow the src side of edges to be from
	// anywhere. But that will have ramifications throughout Scope (read: it
	// may violate implicit invariants) and needs to be thought through.
	var (
		srcLocal   = s.localNets.Contains(net.ParseIP(p.SrcIP))
		dstLocal   = s.localNets.Contains(net.ParseIP(p.DstIP))
		localIP    string
		remoteIP   string
		localPort  string
		remotePort string
		egress     bool
	)
	switch {
	case srcLocal && !dstLocal:
		localIP, localPort, remoteIP, remotePort, egress = p.SrcIP, p.SrcPort, p.DstIP, p.DstPort, true
	case !srcLocal && dstLocal:
		localIP, localPort, remoteIP, remotePort, egress = p.DstIP, p.DstPort, p.SrcIP, p.SrcPort, false
	case srcLocal && dstLocal:
		localIP, localPort, remoteIP, remotePort, egress = p.SrcIP, p.SrcPort, p.DstIP, p.DstPort, true // loopback
	case !srcLocal && !dstLocal:
		log.Printf("sniffer ignoring remote-to-remote (%s -> %s) traffic", p.SrcIP, p.DstIP)
		return
	}

	addAdjacency := func(t report.Topology, srcNodeID, dstNodeID string) report.Topology {
		result := t.WithNode(srcNodeID, report.MakeNode().WithAdjacent(dstNodeID))
		result = result.WithNode(dstNodeID, report.MakeNode())
		return result
	}

	// For sure, we can add to the address topology.
	{
		var (
			srcNodeID = report.MakeAddressNodeID(s.hostID, localIP)
			dstNodeID = report.MakeAddressNodeID(s.hostID, remoteIP)
		)

		rpt.Address = addAdjacency(rpt.Address, srcNodeID, dstNodeID)

		emd := rpt.Address.Nodes[srcNodeID].Edges[dstNodeID]
		if egress {
			if emd.EgressPacketCount == nil {
				emd.EgressPacketCount = new(uint64)
			}
			*emd.EgressPacketCount++
			if emd.EgressByteCount == nil {
				emd.EgressByteCount = new(uint64)
			}
			*emd.EgressByteCount += uint64(p.Network)
		} else {
			if emd.IngressPacketCount == nil {
				emd.IngressPacketCount = new(uint64)
			}
			*emd.IngressPacketCount++
			if emd.IngressByteCount == nil {
				emd.IngressByteCount = new(uint64)
			}
			*emd.IngressByteCount += uint64(p.Network)
		}
		rpt.Address.Nodes[srcNodeID].Edges[dstNodeID] = emd
	}

	// If we have ports, we can add to the endpoint topology, too.
	if p.SrcPort != "" && p.DstPort != "" {
		var (
			srcNodeID = report.MakeEndpointNodeID(s.hostID, localIP, localPort)
			dstNodeID = report.MakeEndpointNodeID(s.hostID, remoteIP, remotePort)
		)

		rpt.Endpoint = addAdjacency(rpt.Endpoint, srcNodeID, dstNodeID)

		emd := rpt.Endpoint.Nodes[srcNodeID].Edges[dstNodeID]
		if egress {
			if emd.EgressPacketCount == nil {
				emd.EgressPacketCount = new(uint64)
			}
			*emd.EgressPacketCount++
			if emd.EgressByteCount == nil {
				emd.EgressByteCount = new(uint64)
			}
			*emd.EgressByteCount += uint64(p.Transport)
		} else {
			if emd.IngressPacketCount == nil {
				emd.IngressPacketCount = new(uint64)
			}
			*emd.IngressPacketCount++
			if emd.IngressByteCount == nil {
				emd.IngressByteCount = new(uint64)
			}
			*emd.IngressByteCount += uint64(p.Transport)
		}
		rpt.Endpoint.Nodes[srcNodeID].Edges[dstNodeID] = emd
	}
}
Beispiel #21
0
func (r *Reporter) addConnection(rpt *report.Report, localAddr, remoteAddr string, localPort, remotePort uint16, proc *procspy.Proc) {
	var (
		localIsClient = int(localPort) > int(remotePort)
		hostNodeID    = report.MakeHostNodeID(r.hostID)
	)

	// Update address topology
	{
		var (
			localAddressNodeID  = report.MakeAddressNodeID(r.hostID, localAddr)
			remoteAddressNodeID = report.MakeAddressNodeID(r.hostID, remoteAddr)
			localNode           = report.MakeNodeWith(map[string]string{
				"name":            r.hostName,
				Addr:              localAddr,
				report.HostNodeID: hostNodeID,
			})
			remoteNode = report.MakeNodeWith(map[string]string{
				Addr: remoteAddr,
			})
		)

		if localIsClient {
			// New nodes are merged into the report so we don't need to do any counting here; the merge does it for us.
			localNode = localNode.WithEdge(remoteAddressNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		} else {
			remoteNode = localNode.WithEdge(localAddressNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		}

		rpt.Address = rpt.Address.WithNode(localAddressNodeID, localNode)
		rpt.Address = rpt.Address.WithNode(remoteAddressNodeID, remoteNode)
	}

	// Update endpoint topology
	if r.includeProcesses {
		var (
			localEndpointNodeID  = report.MakeEndpointNodeID(r.hostID, localAddr, strconv.Itoa(int(localPort)))
			remoteEndpointNodeID = report.MakeEndpointNodeID(r.hostID, remoteAddr, strconv.Itoa(int(remotePort)))

			localNode = report.MakeNodeWith(map[string]string{
				Addr:              localAddr,
				Port:              strconv.Itoa(int(localPort)),
				report.HostNodeID: hostNodeID,
			})
			remoteNode = report.MakeNodeWith(map[string]string{
				Addr: remoteAddr,
				Port: strconv.Itoa(int(remotePort)),
			})
		)

		if localIsClient {
			// New nodes are merged into the report so we don't need to do any counting here; the merge does it for us.
			localNode = localNode.WithEdge(remoteEndpointNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		} else {
			remoteNode = remoteNode.WithEdge(localEndpointNodeID, report.EdgeMetadata{
				MaxConnCountTCP: newu64(1),
			})
		}

		if proc != nil && proc.PID > 0 {
			localNode.Metadata[process.PID] = strconv.FormatUint(uint64(proc.PID), 10)
		}

		rpt.Endpoint = rpt.Endpoint.WithNode(localEndpointNodeID, localNode)
		rpt.Endpoint = rpt.Endpoint.WithNode(remoteEndpointNodeID, remoteNode)
	}
}