Created
March 4, 2019 17:41
-
-
Save MTN-RowinAndruscavage/e88097e6175a6b130ec81c0a02df8cb8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/python3 | |
| import argparse | |
| import re | |
| parser = argparse.ArgumentParser( | |
| description = "netstat output files to graph" | |
| ) | |
| parser.add_argument('--inputs', nargs='*') | |
| args = parser.parse_args() | |
| def parsefilename(filename): | |
| return filename.split('/')[-2] | |
| class Graph: | |
| def __init__(self): | |
| self.nodes = set() | |
| self.edges = list() | |
| self.nodeprop = dict() | |
| self.edgeprop = dict() | |
| def add_node(self, name, np={}): | |
| self.nodes.add(name) | |
| if np != {}: | |
| self.nodeprop[name] = np | |
| def add(self, src, target, ep={}): | |
| """ | |
| Append edge | |
| """ | |
| if src == target: | |
| # ignore self loops | |
| return | |
| self.nodes.add(src) | |
| self.nodes.add(target) | |
| self.edges.append((src, target)) | |
| if ep != {}: | |
| self.edgeprop[(src, target)] = ep | |
| def find(self, node): | |
| """ | |
| Find all edges containing the node | |
| """ | |
| results = [] | |
| for edge in self.edges: | |
| if node in edge: | |
| results.append(edge) | |
| return results | |
| def removenode(self, node): | |
| """ | |
| Remove node from list | |
| """ | |
| self.nodes.remove(node) | |
| def removeedge(self, edge): | |
| """ | |
| Remove edge from list | |
| """ | |
| self.edges.remove(edge) | |
| def writeGraphML(self, filename): | |
| """ | |
| Write graphml file for yEd | |
| """ | |
| with open(filename, "w") as f: | |
| f.write("""<?xml version="1.0" encoding="UTF-8"?>\n | |
| <graphml xmlns="http://graphml.graphdrawing.org/xmlns" | |
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
| xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns | |
| http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd" | |
| xmlns:y="http://www.yworks.com/xml/graphml"> | |
| <key id="d0" for="node" yfiles.type="nodegraphics"/> | |
| <key id="d1" for="edge" yfiles.type="edgegraphics"/> | |
| <key attr.name="description" attr.type="string" for="edge" id="d3"/> | |
| <key attr.name="description" attr.type="string" for="node" id="d4"/> | |
| """) | |
| f.write("""<graph id="G" edgedefault="directed">\n""") | |
| for edge in self.edges: | |
| port = self.edgeprop[edge]['port'] if edge in self.edgeprop else '' | |
| prog = self.edgeprop[edge]['prog'] if edge in self.edgeprop else '' | |
| state = self.edgeprop[edge]['state'] if edge in self.edgeprop else '' | |
| f.write(""" | |
| <edge id="e%s_e%s" source="n%s" target="n%s"> | |
| s<data key="d3" xml:space="preserve"><![CDATA[:%s %s %s]]></data> | |
| <data key="d1" > | |
| <y:Edge> | |
| <y:LineStyle type="line" width="1.0" color="#101010" /> | |
| <y:Arrows source="none" target="standard"/> | |
| </y:Edge> | |
| </data> | |
| </edge> | |
| """ % (edge[0], edge[1], edge[0], edge[1], port, prog, state)) | |
| for node in sorted(self.nodes): | |
| name = self.nodeprop[node]['name'] if node in self.nodeprop else '' | |
| f.write(""" | |
| <node id="n%s"> | |
| <data key="d4" xml:space="preserve"><![CDATA[%s]]></data> | |
| <data key="d0"> | |
| <y:UMLClassNode> | |
| <y:Fill color="#ffcc00" transparent="false"/> | |
| <y:NodeLabel>%s | |
| [%s]</y:NodeLabel> | |
| <y:UML> | |
| <y:AttributeLabel></y:AttributeLabel> | |
| <y:MethodLabel></y:MethodLabel> | |
| </y:UML> | |
| </y:UMLClassNode> | |
| </data> | |
| </node> | |
| """ % (node, node, name, node) ) | |
| f.write("</graph>\n</graphml>") | |
| def writeGraphViz(self, filename): | |
| """ | |
| Write dot file for graphviz | |
| """ | |
| graphheader = """ | |
| rankdir=LR; ranksep=2; | |
| node [ width=5 shape=box style=filled fillcolor=lightgrey ]; | |
| edge [ dir=back ]; | |
| """ | |
| with open(filename, "w") as f: | |
| f.write("digraph MinCut {\n%s" % graphheader) | |
| for edge in self.edges: | |
| f.write(" \"%s\" -> \"%s\" ;\n" % (edge[0], edge[1])) | |
| f.write("}\n") | |
| g = Graph() | |
| for arg in vars(args): | |
| files = getattr(args, arg) | |
| for arg in files: | |
| netstatlines = [] | |
| with open(arg, 'r') as f: | |
| netstatlines = f.read() | |
| # Strip headings from netstat output | |
| netstatlines = netstatlines.split('\n')[2:-1] | |
| for l in netstatlines: | |
| (proto, recvq, sendq, local, remote, state, pid) = l.split()[:7] | |
| if "LISTEN" in state: | |
| continue | |
| pid = pid.split('/') | |
| if pid[0] == '-': | |
| (pid, prog) = (pid, pid) | |
| else: | |
| (pid, prog) = (pid[0], pid[1]) | |
| # print(state, prog) | |
| (src, srcport) = local.split(':')[:2] | |
| (dst, dstport) = remote.split(':')[:2] | |
| nodeprop = { | |
| 'filename': arg, | |
| 'name': parsefilename(arg) | |
| } | |
| edgeprop = { | |
| 'port': dstport, | |
| 'state': state, | |
| 'prog': prog | |
| } | |
| g.add_node(src,nodeprop) | |
| g.add(src,dst,edgeprop) | |
| g.writeGraphViz('connections.dot') | |
| g.writeGraphML('connections.graphml') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| # | |
| # Pull netstat output from all servers in inventory | |
| TS=`date +'%Y-%m-%d_%H%M'` | |
| mkdir -p netstat | |
| time ansible all \ | |
| -m shell \ | |
| -a "netstat -pant > netstat.out" \ | |
| --become | |
| ansible all \ | |
| -m fetch \ | |
| -a "src=netstat.out dest=netstat/${TS}" | |
| pushd netstat > /dev/null | |
| pipenv run python ns2graph.py --inputs $TS/*/netstat.out | |
| popd > /dev/null |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Network connectivity visualization using the output of
netstat -panton all the hosts in your inventory. The update_netstat.sh example collects netstat output from all hosts in inventory using ansible ad-hoc commands.The resulting .graphml can be loaded into yEd
https://www.yworks.com/products/yed
Sample output: https://imgur.com/a/ORW4Pr6
Then select all, "Tools | Fit Label to Node" , then select a Layout to rearrange nodes and have some fun!
Notes: