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:

class SS {
[string]$LocalAddress
[string]$LocalPort
[string]$RemoteAddress
[string]$RemotePort
[int]$PID
[string]$ProcessName
}
$SSRaw = ss -t -r -p -o state established --no-header
$SSArr = @()
1..($SSRaw.Count -1) | ForEach-Object {
$SSLine = $SSRaw[$PSItem]
$Split = $SSLine.Split(' ') | Where-Object {$_}
$SS = New-Object -TypeName SS
$SS.LocalAddress = $Split[2].Split(':')[-2]
$SS.LocalPort = $Split[2].Split(':')[-1]
$SS.RemoteAddress = $Split[3].Split(':')[-2].Replace(']','')
$SS.RemotePort = $Split[3].Split(':')[-1]
$SS.ProcessName = $Split[4].Split('"')[1]
$SS.PID = $Split[4].Split('=')[1].Replace(',fd','')
$SSArr += $SS
}
graph network @{rankdir='LR'} {
node @{shape='rect'}
edge $SSArr -FromScript {$_.ProcessName} -ToScript {$_.RemoteAddress} @{label={$_.RemotePort}}
} | Export-PSGraph -ShowGraph
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

RUNK is a Kickstarter scam

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