mirror of
https://github.com/maride/pancap.git
synced 2024-11-21 16:34:26 +00:00
Generate Graphviz graphs of network communication
This commit is contained in:
parent
1aa3572c30
commit
1989ae996f
@ -39,6 +39,9 @@ func Analyze(source *gopacket.PacketSource) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Register communication for graph
|
||||||
|
output.AddPkgToGraph(packet)
|
||||||
|
|
||||||
// Raise statistics
|
// Raise statistics
|
||||||
totalPackets += 1
|
totalPackets += 1
|
||||||
if processed {
|
if processed {
|
||||||
|
3
main.go
3
main.go
@ -36,6 +36,9 @@ func main() {
|
|||||||
// Extract found and requested files
|
// Extract found and requested files
|
||||||
output.StoreFiles()
|
output.StoreFiles()
|
||||||
|
|
||||||
|
// Create communication graph
|
||||||
|
output.CreateGraph()
|
||||||
|
|
||||||
// Show user analysis
|
// Show user analysis
|
||||||
analyze.PrintSummary()
|
analyze.PrintSummary()
|
||||||
|
|
||||||
|
@ -3,11 +3,12 @@ package output
|
|||||||
import "flag"
|
import "flag"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
fullOutput *bool
|
fullOutput *bool
|
||||||
printEmptyBlocks *bool
|
printEmptyBlocks *bool
|
||||||
targetFiles *string
|
targetFiles *string
|
||||||
targetAllFiles *bool
|
targetAllFiles *bool
|
||||||
targetOutput *string
|
targetOutput *string
|
||||||
|
graphOutput *string
|
||||||
)
|
)
|
||||||
|
|
||||||
func RegisterFlags() {
|
func RegisterFlags() {
|
||||||
@ -16,6 +17,5 @@ func RegisterFlags() {
|
|||||||
targetFiles = flag.String("extract-these", "", "Comma-separated list of files to extract.")
|
targetFiles = flag.String("extract-these", "", "Comma-separated list of files to extract.")
|
||||||
targetAllFiles = flag.Bool("extract-all", false, "Extract all files found.")
|
targetAllFiles = flag.Bool("extract-all", false, "Extract all files found.")
|
||||||
targetOutput = flag.String("extract-to", "./extracted", "Directory to store extracted files in.")
|
targetOutput = flag.String("extract-to", "./extracted", "Directory to store extracted files in.")
|
||||||
|
graphOutput = flag.String("create-graph", "", "Create a Graphviz graph out of collected communication")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
104
output/graph.go
Normal file
104
output/graph.go
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
package output
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"github.com/google/gopacket"
|
||||||
|
)
|
||||||
|
|
||||||
|
var graphPkgs []GraphPkg
|
||||||
|
|
||||||
|
// AddPkgToGraph adds the given packet as communication to the graph
|
||||||
|
func AddPkgToGraph(pkg gopacket.Packet) {
|
||||||
|
// Only proceed if pkg contains a network layer
|
||||||
|
if pkg.NetworkLayer() == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
src := pkg.NetworkLayer().NetworkFlow().Src().String()
|
||||||
|
dst := pkg.NetworkLayer().NetworkFlow().Dst().String()
|
||||||
|
|
||||||
|
// Search for the given communication pair
|
||||||
|
for _, p := range graphPkgs {
|
||||||
|
if p.from == src && p.to == dst {
|
||||||
|
// Communication pair found, add protocol and finish
|
||||||
|
p.AddProtocol("nil")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Communcation pair was not in graphPkgs, add to it
|
||||||
|
graphPkgs = append(graphPkgs, GraphPkg{
|
||||||
|
from: src,
|
||||||
|
to: dst,
|
||||||
|
protocol: []string{""},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateGraph writes out a Graphviz digraph
|
||||||
|
func CreateGraph() {
|
||||||
|
if *graphOutput == "" {
|
||||||
|
// No graph requested
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the Graphviz-specific header
|
||||||
|
dot := fmt.Sprintf("# Compile with `neato -Tpng %s > %s.png`\n", *graphOutput, *graphOutput)
|
||||||
|
dot += "digraph pancap {\n\toverlap = false;\n"
|
||||||
|
|
||||||
|
// First, gather all nodes as-is and write them out
|
||||||
|
dot += nodedef(graphPkgs)
|
||||||
|
|
||||||
|
// Iterate over communication
|
||||||
|
for _, p := range graphPkgs {
|
||||||
|
dot += fmt.Sprintf("\tn%s->n%s\n", hash(p.from), hash(p.to))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close
|
||||||
|
dot += "}\n"
|
||||||
|
|
||||||
|
// Write out
|
||||||
|
ioutil.WriteFile(*graphOutput, []byte(dot), 0644)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a list of distinct nodes, Graphviz-compatible
|
||||||
|
func nodedef(pkgs []GraphPkg) string {
|
||||||
|
output := ""
|
||||||
|
nodes := []string{}
|
||||||
|
for _, p := range graphPkgs {
|
||||||
|
// Check if src and dst are already present in nodes array
|
||||||
|
srcFound := false
|
||||||
|
dstFound := false
|
||||||
|
for _, n := range nodes {
|
||||||
|
if p.from == n {
|
||||||
|
srcFound = true
|
||||||
|
}
|
||||||
|
if p.to == n {
|
||||||
|
dstFound = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !srcFound {
|
||||||
|
// src not yet present, add to node list
|
||||||
|
nodes = append(nodes, p.from)
|
||||||
|
}
|
||||||
|
if !dstFound {
|
||||||
|
// dst not yet present, add to node list
|
||||||
|
nodes = append(nodes, p.to)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output Graphviz-compatible node definition
|
||||||
|
for _, n := range nodes {
|
||||||
|
// As the Graphviz charset for nodes is rather small, rely on hashes
|
||||||
|
output += fmt.Sprintf("\tn%s[label=\"%s\"]\n", hash(n), n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return output
|
||||||
|
}
|
||||||
|
|
||||||
|
func hash(s string) string {
|
||||||
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(s)))[:6]
|
||||||
|
}
|
19
output/graphpkg.go
Normal file
19
output/graphpkg.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package output
|
||||||
|
|
||||||
|
// GraphPkg resembles a directed communication from one address to another
|
||||||
|
// It wraps up required information to draw a graph of the communication, including spoken protocols.
|
||||||
|
type GraphPkg struct {
|
||||||
|
from string
|
||||||
|
to string
|
||||||
|
protocol []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddProtocol adds the given protocol to the list of protocols if not already present
|
||||||
|
func (p *GraphPkg) AddProtocol(protocol string) {
|
||||||
|
for _, p := range p.protocol {
|
||||||
|
if p == protocol {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.protocol = append(p.protocol, protocol)
|
||||||
|
}
|
@ -23,4 +23,10 @@ func Finalize() {
|
|||||||
// User avoided the files
|
// User avoided the files
|
||||||
printer.Println("Files found in stream. Add --extract-all or --extract-these <list> to extract them.")
|
printer.Println("Files found in stream. Add --extract-all or --extract-these <list> to extract them.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if something graph-worthy was collected
|
||||||
|
if *graphOutput == "" && len(graphPkgs) > 0 {
|
||||||
|
// User didn't want a graph
|
||||||
|
printer.Println("To summarize the communcation flow with a Graphviz graph, specify --create-graph <out.dot>.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user