func TestEndpointNodeID(t *testing.T) { for _, bad := range []string{ clientAddressNodeID, serverAddressNodeID, unknownAddressNodeID, clientHostNodeID, serverHostNodeID, "host.com;1.2.3.4", "a;b", "a;", ";b", ";", "", } { if haveName, haveAddress, havePort, ok := report.ParseEndpointNodeID(bad); ok { t.Errorf("%q: expected failure, but got {%q, %q, %q}", bad, haveName, haveAddress, havePort) } } for input, want := range map[string]struct{ name, address, port string }{ report.MakeEndpointNodeID("host.com", "1.2.3.4", "c"): {"", "1.2.3.4", "c"}, "a;b;c": {"a", "b", "c"}, } { haveName, haveAddress, havePort, ok := report.ParseEndpointNodeID(input) if !ok { t.Errorf("%q: not OK", input) continue } if want.name != haveName || want.address != haveAddress || want.port != havePort { t.Errorf("%q: want %q, have {%q, %q, %q}", input, want, haveName, haveAddress, havePort) } } }
func outgoingConnectionsSummary(topologyID string, r report.Report, n report.Node, ns report.Nodes) ConnectionsSummary { localEndpoints := endpointChildrenOf(n) // For each node which has an edge FROM me counts := map[connection]int{} for _, id := range n.Adjacency { node, ok := ns[id] if !ok { continue } remoteNode := node.Copy() remoteEndpointIDs := endpointChildIDsOf(remoteNode) for _, localEndpoint := range localEndpoints { _, localAddr, _, ok := report.ParseEndpointNodeID(localEndpoint.ID) if !ok { continue } for _, remoteEndpointID := range localEndpoint.Adjacency.Intersection(remoteEndpointIDs) { _, _, port, ok := report.ParseEndpointNodeID(remoteEndpointID) if !ok { continue } key := connection{ localNode: &n, remoteNode: &remoteNode, port: port, } if isInternetNode(n) { endpointNode := r.Endpoint.Nodes[remoteEndpointID] key.localNode = &endpointNode key.localAddr = localAddr } counts[key] = counts[key] + 1 } } } columnHeaders := NormalColumns if isInternetNode(n) { columnHeaders = InternetColumns } return ConnectionsSummary{ ID: "outgoing-connections", TopologyID: topologyID, Label: "Outbound", Columns: columnHeaders, Connections: connectionRows(r, counts, isInternetNode(n)), } }
// 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 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) { return report.Nodes{TheInternetID: theInternetNode(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) return report.Nodes{ id: NewDerivedNode(id, m).WithTopology(IP), idWithPort: NewDerivedNode(idWithPort, m).WithTopology(IP), } }
func incomingConnectionsSummary(topologyID string, r report.Report, n report.Node, ns report.Nodes) ConnectionsSummary { localEndpointIDs := endpointChildIDsOf(n) // For each node which has an edge TO me counts := map[connection]int{} for _, node := range ns { if !node.Adjacency.Contains(n.ID) { continue } remoteNode := node.Copy() // Work out what port they are talking to, and count the number of // connections to that port. // This is complicated as for internet nodes we break out individual // address, both when the internet node is remote (an incoming // connection from the internet) and 'local' (ie you are loading // details on the internet node) for _, child := range endpointChildrenOf(node) { for _, localEndpointID := range child.Adjacency.Intersection(localEndpointIDs) { _, localAddr, port, ok := report.ParseEndpointNodeID(localEndpointID) if !ok { continue } key := connection{ localNode: &n, remoteNode: &remoteNode, port: port, } if isInternetNode(n) { endpointNode := r.Endpoint.Nodes[localEndpointID] key.localNode = &endpointNode key.localAddr = localAddr } counts[key] = counts[key] + 1 } } } columnHeaders := NormalColumns if isInternetNode(n) { columnHeaders = InternetColumns } return ConnectionsSummary{ ID: "incoming-connections", TopologyID: topologyID, Label: "Inbound", Columns: columnHeaders, Connections: connectionRows(r, counts, isInternetNode(n)), } }