// 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 }
// 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), } }
// 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 }
// 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, ), ), )) }