Visualizing TCP connections with Powershell and Graphviz

I've recently been somewhat obsessed with Graphviz, particularly with the PSGraph Powershell Module.  At work I use it as part of the CI/CD of various projects to automatically document the flow of information between functions, servers, etc. 

But in this post, I want to show how i start with the ss command (socket statistics), and end up with a graph that shows who you're connected to, and how.

First of all, you need a few things:

  • A Linux distro. I use Pop OS.
  • Powershell
  • PSGraph
  • Graphviz (sudo apt-get install graphviz)
This is the script that does all the fun:

So first, I create a class with the properties I want.
Then I run the ss command, and declare an empty array.
Then I loop through the output of the ss command, parse it into the individual pieces of information I want, and add it to the array.

Then the PSGraph magic. To be honest, I struggle to explain in great detail how it works, but the things to note are:
  • -FromScript are the "start" boxes
  • -ToScript are the "end" boxes. 
  • label is the text on the line
And then just show the graph. The command also supports saving it in various formats.

Running it as I type this post, this is the generated graph:


I find this fascinating, as it may tell you about something nefarious or just interesting.
For example here, I can see that Chrome is talking to my Chromecasts, and Syncthing is talking to my file server.

As a bonus, here is my folder tree under /dev 

Just slightly modified from the example in the documentation.

That's all for now!

/Kevin

Comments

  1. Hi Kevin
    You could do all this job using only PS. Let me show a sample code.

    Import-Module PSGraph
    # Gathering Data
    $TCPConnection = Get-NetTCPConnection -State Established |
    Where-Object -FilterScript {$_.RemoteAddress -NotLike "127.0.0.1" -and $_.RemoteAddress -NotLike "192.168.0.x"} |
    Select-Object -Property @{Label = "LocalAddress" ; Expression = {$_.LocalAddress}},
    @{Label = "LocalPort" ; Expression = {$_.LocalPort}},
    @{Label = "RemoteAddress" ; Expression = {$_.RemoteAddress}},
    @{Label = "RemoteName" ; Expression = {(Resolve-DnsName -Name $_.RemoteAddress -Type A).NameHost}},
    @{Label = "RemotePort" ; Expression = {$_.RemotePort}},
    @{Label = "ProcessName" ; Expression = {(Get-Process -id $_.OwningProcess).ProcessName }},
    @{Label = "OwningProcess" ; Expression = {$_.OwningProcess}}
    $TCPConnection # RemoteName are not resolved in any cases.

    # Graph Data
    graph network @{rankdir='LR'} {
    node @{shape='rect'}
    #edge $TCPConnection -FromScript {$_.ProcessName} -ToScript {$_.RemoteAddress} @{Label={'{0}:{1}' -f $_.LocalPort, $_.RemoteAdress}}
    edge $TCPConnection -FromScript {$_.ProcessName} -ToScript {$_.RemoteAddress} @{Label={$_.RemotePort}}
    } | Export-PSGraph -ShowGraph -GraphVizPath "C:\Program Files\PackageManagement\NuGet\Packages\Graphviz.2.38.0.2\dot.exe"

    Nota 1: I'm using Get-NTCConnection cmdlet (like nbtstat -a in a cmd) but the output is an object.
    Nota 2: I'm using Filtening at different level (State, RemoteAddress not like LoopBack IP and Non-Routable IP.
    Nota3: I'm selecting a custom output (i.e. to get the ProcessName)
    At this step, my object $TCPConnection is as i would like.
    Then, I'm using Graphviz to graph
    Nota4: I've had an error, cause the install path for Graphviz is not one of them defined in the module PSGraph, then I'm passing the InstallPatch for graphvizwith the Export-PSGraph cmdlet.

    Object - Object - Object : everywhere objects. No need to parse a "legacy" (DOS or bash command) to an object, when a equivalent cmdlet is allready existing. :-)

    ReplyDelete

Post a Comment

Popular posts from this blog

Hidden settings in the Raspberry Pi Imager

Getting the Miyoo Mini Plus battery into Home Assistant

Getting Company Portal apps locally using PowerShell (no auth!)