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