TCP-Connection Report

Wenn viele Outlook Clients sich mit Servern verbinden und Router, Proxy-Server und WAN-Optimierer dazwischen sind, lohnt sich ein Blick auf die TCP-Verbindungen. Mit etwas PowerShell und PowerBI lassen sich interessante Werte ermitteln, die sogar für ein Monitoring interessant sein können. Zudem sind sie natürlich für Cloud-Szenarien durchaus relevant.

Firmen, die NetFlow einsetzen, können auf die hier beschriebene Datengewinnung meist verzichten, da per NetFlow diese Informationen sogar noch besser ermittelt werden können.

Verbindungen ermitteln

Zuerst müssen wir natürlich erst einmal die Daten über aktuelle Verbindungen erhalten. Früher hat man dazu NETSTAT oder WMI genutzt. Mittlerweile geht das per PowerShell sehr viel schöner. Hier ein Beispiel:

Get-NetTCPConnection `
| where {(($_.localport -eq 443) -and ($_.remoteport -ne 0))} `
| select LocalAddress,RemoteAddress,RemotePort,State,CreationTime} `
| export-csv $dateiname

Dieses Skript kann ich regelmäßig auf dem Server starten. Die Filter sorgen dafür, dass ich mich auf den IIS-Port 443 beschränke, über den bei Exchange 2013/2016 alle Clients mit RPC/HTTP oder MAPI/HTTP und natürlich OWA, ActiveSync, EWS, Autodiscover zugreifen. Eine Unterscheidung nach den Diensten kann ich hier nicht machen. Das wäre dann wieder über die IISLogs möglich. Wenn der RemotePort = 0 ist, dann ist es eine "Listen" Verbindung, die mich auch nicht interessiert.

Ich habe den Code natürlich noch etwas erweitert, da quasi alle Kunden heute eine DAG aus mehreren Servern nutzen. Wer zu klein für eine DAG ist, ist vielleicht in Office 365 besser aufgehoben. Also steuere ich die Abfragen von einem "Job-Server" mit Remote PowerShell.

param (
   $servers = ("EX-NODE1","EX-NODE2")
)

foreach ($computer in $servers){
   write-host "collect-netstatdata: Server $($computer)"
   Invoke-Command `
      -ComputerName $computer `
      -asjob `
      -ScriptBlock {Get-NetTCPConnection `
         | where {(($_.localport -eq 443) -and ($_.remoteport -ne 0))} `
         | select LocalAddress,RemoteAddress,RemotePort,State,CreationTime}
}
get-job | wait-job
$result = get-job | receive-job 
Get-Job | remove-job
$result

Zuerst starte ich auf jedem Server aus der Ferne den Get-NetTCPConnection und warte dann auf das Ende der Jobs um dann die Ergebnisse einzusammeln. Es handelt sich dabei immer um eine Momentaufnahme. Ich werde also keine Clients sehen, die im fraglichen Zeitraum keine Verbindung haben,

Daten speichern

Diese Daten exportiere ich dann als CSV-Datei. Auch dabei werden ein paar Felder selektiert und zudem errechne ich die aus dem Feld CreationTime und dem aktuellen Zeitpunkt die Dauer, seit dem die Verbindung besteht.

$result `
| select @{name="datetime";expression={$now}}, `
         LocalAddress, `
         RemoteAddress, `
         RemotePort, `
         State, `
         CreationTime, `
         @{name="duration";expression={[long]($nowdt-[datetime]($_.creationtime)).totalseconds}} `
| export-csv `
   -delimiter "," `
   -encoding unicode `
   -path ".\tcpconnection.csv" `
   -notypeinformation

Zusätzlich gibt es noch weiteren Code um mit einem "Group remoteaddress" die Ergebnisse zusammen zu fassen. So bekomme ich dann pro Client die Anzahl der Verbindungen. Diese Liste wird dann noch mal weiter verarbeitet um die Clients entsprechend dem Subnetz zu einer AD-Site zuordnen zu können. So bekomme ich dann auch die Information., in welchem Standort wie viele Clients stehen und wie viele Verbindungen diese im Schnitt benutzen.

Auswerten

Allein mit den CSV-Dateien kann man in Excel und besser noch in Power Bi sehr schöne Auswertungen erstellen. Diese sind aktuell nur "OnDemand" von Hand möglich. Natürlich könnte man die Werte natürlich auch automatisch verarbeiten und auf einer Statusseite hinterlegen oder als Monitoring nutzen. Ich führe hier nur ein paar Beispiele auf, um die Möglichkeiten zu demonstrieren.

Auswertung Beispiel

Connection Status

Fangen wir mal einfach an. Ein Feld in den Verbindungen ist der Connection Status. "Established" ist ok und die anderen "sollten" alle relativ unsichtbar sein. Sie sind zwar nie ganz 0 aber gering.

Remote Port Verteilung

Da in den Rohdaten auch die Quellports der Clients enthalten sind, kann man sich diese ja auch einmal anzeigen lassen. der QuellPort ist die X-Achse und die Anzahl als Summe auf der Y-Achse. Hier scheint es also keine "Firewall" o.ä., zu geben, die bestimmte Bereiche bei Quellports blocken würde.

Gut zu sehen ist auch, dass die ersten 1024 Ports frei geblieben sind.

Connections pro Server

In dem Fall hatte ich vier Server hinter einen Loadbalancer. Im Idealfall ist die Anzahl der Verbindungen auf jedem Server etwas gleich. Das ist übrigens auch ein Wert, der gut in einem Monitoring genutzt werden kann.

Anzahl Clients nach Anzahl Verbindungen

Ich war ja auf der Suche nach den Clients, die viele Verbindungen offen halten aber wollte auch wissen, wie die Clients denn so "verteilt" sind. Auch hier hilft einfach eine Verteilung auf einer Linie oder als Kuchendiagramm.

Ein sehr großer Anteil der Clients hat 2-8 Connections und sicher mehr als 90% der Clients hat unter 20 Verbindungen. Die Massenbenutzer" sieht man so erst mal gar nicht.

Top Connection User

Wenn es aber so wenig Benutzer sind, dann ist eine Tabelle hier besser. Hier fällt natürlich das System mit der 10.10.10.50 auf, welches im gleichen LAN wie die vier Exchange Server steht. In dem Fall ist es ein System, welcher per EWS auf verschiedene Postfächer zugreift. All die anderen Clients sind natürlich zu untersuchen

Auch wenn es nicht viel ist lässt sich durch eine einfache numerische Erfassung von TCP-Verbindung schon die ein oder andere Aussage über Server, Loadbalancer und Clients machen. Natürlich wird ein "richtiger Netzwerker" dafür natürlich NetFlow dafür einsetzen und nicht erst auf den Server Stichproben sammeln. Aber vielleicht geht das ja nicht oder der Windows Admin mit Exchange Verantwortung möchte einfach seine eigenen Daten erheben.

Mapping auf ADSites

Nun kann ich persönlich nicht so viel mit IP-Adressen anfangen. Interessant wäre auf jeden Fall noch eine Auswertung nach IP-Subnetzen oder idealerweise noch nach Standorten. Wenn Sie ihre "Active Directory Standorte und Dienste" (Sites and Services) akkurat gepflegt haben, sollte es kein Problem sein zu jeder IP-Adresse auch einen Standort zu finden. Wenn Sie alle Subnetze mit der gleichen Netzmaske betreiben, dann reicht sogar eine einfache String-Operation um das letzten Byte auf "0" zu setzen und damit alle Client in einem Subnetz zusammen zu fassen. PowerBI kann das schon alleine über die Manipulation der Tabelle beim Import. Ich habe einfach den String am "rechten Punkt" getrennt und damit aus der Spalte der Remote-IP eine Spalte mit einem Class-C-Netz und einer zweiten Spalte mit dem Hostanteil gemacht.

Nach einigen Läufen habe ich dann aber auch diese Logik in das PowerShell Script gemacht und dort auch weiter schon ausgewertet. Am Ende kommen dann gleich drei Dateien zur weiteren Visualisierung heraus:

  • iisports-yyyymmdd-hhMM.csv
    Die nackte Liste der IP-Verbindungen zum Messzeitpunkt. Ausgangsmaterial für alle weiteren Auswertungen. Das Format sieht etwas wie folgt aus. Die erste Spalte legt das Skript als Zeitstempel der Messung:
"datetime","LocalAddress","RemoteAddress","RemotePort","State","CreationTime"
"20170821-1143","127.0.0.1","127.0.0.1","50768","TimeWait","1/1/1601 1:00:00 AM"
"20170821-1143","127.0.0.1","127.0.0.1","50687","TimeWait","1/1/1601 1:00:00 AM"
"20170821-1143","10.10.10.16","10.1.17.36","6533","Established","8/21/2017 9:02:30 AM"
"20170821-1143","10.10.10.16","10.1.17.125","6552","Established","8/21/2017 8:45:38 AM"
  • iisports-yyyymmdd-hhMM-groupbyremoteaddress.csv
    Listet die Connections pro IP-Adresse auf. In Powershell ist das ja eine einfache "Group"-Verkettung aber so kann man das recht einfach in Excel weiter verarbeiten.
"RemoteAddress","Count"
"::1","1208"
"127.0.0.1","151"
"10.1.17.36","216"
"10.1.17.125","1381"
"10.1.17.124","1755"
"10.10.10.82","22"
  • iisports-yyyymmdd-hhMM-connectionbysite.csv
    Zusammenfassung der RemoteAddresses nach „ClassC-Schema” mit Anzahl der Client, Average Connections und Max Connections. Hier scheint "Berlin" mit 30 Verbindungen bei 10 Client hoch zu sein. Ein Client hat angeblich sogar 162 Connections. Da kann man schon mal nachschauen.
"SubnetB","Client","Sitename","avgconnection","maxconnection"
"10.10.10","12","PaderbornServer","135","1810"
"10.1.1","43","PaderbornClient","5","50"
"10.2.1","10","Berlin","30","162"

Für die Zuordnung des Subnetz zu einer Site habe ich ein eigenes Skript, um die AD-:Sites auszulesen und die Daten in eine CSV-Datei abzulegen. Das hat den Charme, dass man die CSV-Datei einmal erstellt und dann von Hand noch optimieren kann. Leider sind die AD Sites&Services bei den meisten Firmen doch nicht so gut gepflegt. Ich hatte schon immer mal vor per SNMP die Liste der Netzwerk selbst zu erstellen. Aber das ist ein anderen Projekt.

Auch die hier ermittelten Verbindungen könnte man sehr schön in eine SQL-Datenbank ablegen und dann dynamisch flexible Reports generieren zu lassen. Auf Dauer werden CSV-Dateien nicht wirklich handhabbar. Wenn so eine DAG mit 10.000 ca. 300kb pro "Snaphots" erstellt, dann werden bei einem 5 Minuten Intervall an einem Tag schon 86MB generiert.

Matching auf IISLogs

Die Analyse der TCP-Verbindung ist natürlich nur ein erster Ansatz. Wenn ein Client hier "auffällig" ist, dann kann ein Administrator mit der Source-IP nun die nächste Analyse starten und z.B. im IISLOG nach dem Client suchen. Dort ist zumindest recht gut zu erkennen, welches Protokoll der Client nutzt und auch der UserAgent wird daraus sichtbar.

Skript: Collect-TCPConnections

Weiter oben habe ich ja schon die essentiellen Skriptzeilen in Auszügen dokumentiert. Hier noch mal zwei Skripte zum Download.

  • generate-subnet2sitefromad.ps
    Dieses Skript liest ihre AD Sites&Services-Konfiguration aus und erzeugt eine CSV-Datei mit einer Liste der Subnetze und den AD-Standort. Ich habe mir die Aufgabe sehr einfach gemacht und gehe davon aus, dass alle Subnetze reine "Class-C"-Netze sind. In den meisten Fällen passt das schon und die wenigen Ausnahmen habe ich dann in der CSV-Datei von Hand nachgepflegt. Ich erspare mir damit die "Rechnerei" mit Subnetzen und Bitmasken im nächsten Skript.

generate-subnet2sitefromad.20170927.ps.txt

  • collect-tcpconnections.ps1
    Das ist das eigentliche Hauptskript, welches von den per Parameter übergebenen Servern die TCP-Connections einsammelt und dann die drei CSV-Dateien generiert.

Sie "müssen" dem Skript die Servernamen der fraglichen Server mitteilen, da die Defaults sicher nicht passen.

collect-tcpconnections.20170927.ps1.txt

Die resultierenden CSV-Dateien können Sie dann problemlos mit Excel, Power Bi und anderen Werkzeugen auswerten.

Weitere Links