Example #1
0
// MapContainer2IP maps container nodes to their IP addresses (outputs
// multiple nodes).  This allows container to be joined directly with
// the endpoint topology.
func MapContainer2IP(m RenderableNode, _ report.Networks) RenderableNodes {
	result := RenderableNodes{}
	if addrs, ok := m.Sets.Lookup(docker.ContainerIPsWithScopes); ok {
		for _, addr := range addrs {
			scope, addr, ok := report.ParseAddressNodeID(addr)
			if !ok {
				continue
			}
			id := report.MakeScopedEndpointNodeID(scope, addr, "")
			node := NewRenderableNodeWith(id, "", "", "", m)
			node.Counters = node.Counters.Add(ipsKey, 1)
			result[id] = node
		}
	}

	// Also output all the host:port port mappings (see above comment).
	// In this case we assume this doesn't need a scope, as they are for host IPs.
	ports, _ := m.Sets.Lookup(docker.ContainerPorts)
	for _, portMapping := range ports {
		if mapping := portMappingMatch.FindStringSubmatch(portMapping); mapping != nil {
			ip, port := mapping[1], mapping[2]
			id := report.MakeScopedEndpointNodeID("", ip, port)
			node := NewRenderableNodeWith(id, "", "", "", m.WithParents(report.EmptySets))
			node.Counters = node.Counters.Add(ipsKey, 1)
			result[id] = node
		}
	}

	return result
}
Example #2
0
// MapEndpoint2IP maps endpoint nodes to their IP address, for joining
// with container nodes.  We drop endpoint nodes with pids, as they
// will be joined to containers through the process topology, and we
// don't want to double count edges.
func MapEndpoint2IP(m RenderableNode, local report.Networks) RenderableNodes {
	// Don't include procspied connections, to prevent double counting
	_, ok := m.Latest.Lookup(endpoint.Procspied)
	if ok {
		return RenderableNodes{}
	}
	scope, addr, port, ok := report.ParseEndpointNodeID(m.ID)
	if !ok {
		return RenderableNodes{}
	}
	if ip := net.ParseIP(addr); ip != nil && !local.Contains(ip) {
		return RenderableNodes{TheInternetID: newDerivedPseudoNode(TheInternetID, TheInternetMajor, m)}
	}

	// We don't always know what port a container is listening on, and
	// container-to-container communications can be unambiguously identified
	// without ports. OTOH, connections to the host IPs which have been port
	// mapped to a container can only be unambiguously identified with the port.
	// So we need to emit two nodes, for two different cases.
	id := report.MakeScopedEndpointNodeID(scope, addr, "")
	idWithPort := report.MakeScopedEndpointNodeID(scope, addr, port)
	m = m.WithParents(report.EmptySets)
	return RenderableNodes{
		id:         NewRenderableNodeWith(id, "", "", "", m),
		idWithPort: NewRenderableNodeWith(idWithPort, "", "", "", m),
	}
}
Example #3
0
// MapContainer2IP maps container nodes to their IP addresses (outputs
// multiple nodes).  This allows container to be joined directly with
// the endpoint topology.
func MapContainer2IP(m report.Node) []string {
	// if this container doesn't make connections, we can ignore it
	_, doesntMakeConnections := m.Latest.Lookup(report.DoesNotMakeConnections)
	if doesntMakeConnections {
		return nil
	}

	result := []string{}
	if addrs, ok := m.Sets.Lookup(docker.ContainerIPsWithScopes); ok {
		for _, addr := range addrs {
			scope, addr, ok := report.ParseAddressNodeID(addr)
			if !ok {
				continue
			}
			id := report.MakeScopedEndpointNodeID(scope, addr, "")
			result = append(result, id)
		}
	}

	// Also output all the host:port port mappings (see above comment).
	// In this case we assume this doesn't need a scope, as they are for host IPs.
	ports, _ := m.Sets.Lookup(docker.ContainerPorts)
	for _, portMapping := range ports {
		if mapping := portMappingMatch.FindStringSubmatch(portMapping); mapping != nil {
			ip, port := mapping[1], mapping[2]
			id := report.MakeScopedEndpointNodeID("", ip, port)
			result = append(result, id)
		}
	}

	return result
}
Example #4
0
// ShortLivedConnectionJoin joins the given renderer with short lived connections
// from the endpoints topology, using the toIPs function to extract IPs from
// the nodes.
func ShortLivedConnectionJoin(r Renderer, toIPs func(report.Node) []string) Renderer {
	nodeToIP := func(n report.Node, _ report.Networks) report.Nodes {
		result := report.Nodes{}
		for _, ip := range toIPs(n) {
			result[ip] = NewDerivedNode(ip, n).
				WithTopology(IP).
				WithLatests(map[string]string{
					originalNodeID:       n.ID,
					originalNodeTopology: n.Topology,
				}).
				WithCounters(map[string]int{IP: 1})
		}
		return result
	}

	ipToNode := func(n report.Node, _ report.Networks) report.Nodes {
		// If an IP is shared between multiple nodes, we can't
		// reliably attribute an connection based on its IP
		if count, _ := n.Counters.Lookup(IP); count > 1 {
			return report.Nodes{}
		}

		// Propagate the internet pseudo node
		if strings.HasSuffix(n.ID, TheInternetID) {
			return report.Nodes{n.ID: n}
		}

		// If this node is not of the original type, exclude it.
		// This excludes all the nodes we've dragged in from endpoint
		// that we failed to join to a node.
		id, ok := n.Latest.Lookup(originalNodeID)
		if !ok {
			return report.Nodes{}
		}
		topology, ok := n.Latest.Lookup(originalNodeTopology)
		if !ok {
			return report.Nodes{}
		}

		return report.Nodes{
			id: NewDerivedNode(id, n).
				WithTopology(topology),
		}
	}

	// MapEndpoint2IP maps endpoint nodes to their IP address, for joining
	// with container nodes.  We drop endpoint nodes with pids, as they
	// will be joined to containers through the process topology, and we
	// don't want to double count edges.
	endpoint2IP := func(m report.Node, local report.Networks) report.Nodes {
		// Don't include procspied connections, to prevent double counting
		_, ok := m.Latest.Lookup(endpoint.Procspied)
		if ok {
			return report.Nodes{}
		}
		scope, addr, port, ok := report.ParseEndpointNodeID(m.ID)
		if !ok {
			return report.Nodes{}
		}
		if ip := net.ParseIP(addr); ip != nil && !local.Contains(ip) {
			node := theInternetNode(m)
			return report.Nodes{node.ID: node}
		}

		// We also allow for joining on ip:port pairs.  This is useful
		// for connections to the host IPs which have been port
		// mapped to a container can only be unambiguously identified with the port.
		// So we need to emit two nodes, for two different cases.
		id := report.MakeScopedEndpointNodeID(scope, addr, "")
		idWithPort := report.MakeScopedEndpointNodeID(scope, addr, port)
		return report.Nodes{
			id:         NewDerivedNode(id, m).WithTopology(IP),
			idWithPort: NewDerivedNode(idWithPort, m).WithTopology(IP),
		}
	}

	return FilterUnconnected(MakeMap(
		ipToNode,
		MakeReduce(
			MakeMap(
				nodeToIP,
				r,
			),
			MakeMap(
				endpoint2IP,
				SelectEndpoint,
			),
		),
	))
}