End2End-UDP3478

Für eine effektive Übertragung von Audio/Video eignet sich am besten eine direkte Verbindung per UDP. Da dies oft nicht geht, ist eine indirekte Verbindung per STUN/TURN erforderlich. Der dazu genutzte Port ist eigentlich immer 3478/UDP. Es ist daher wichtig einen Test zu haben, ob dieser Port erreichbar ist und wie weit er "weg" ist. Daher habe ich mir end2end-UDP3478 geschrieben.


https://www.youtube.com/watch?v=fR9b1ZO3xio

Funktionsweise

Zuerst habe ich einer funktionierenden Verbindung auf die Finger geschaut. Mit dem Skype for Business Online Network Assessment Tool habe ich einen Test-Call ausgeführt und die ersten Pakete betrachtet. Sie sehen direkt einen "STUN Allocate Request" der aber ohne Anmeldedaten natürlich daneben geht. Aber mir reicht das um das anfragende Paket zu erhalten.

Diese Daten habe ich nun direkt als Byte-Array in meinem PowerShell-Script genutzt, um das gleiche Paket abzusenden.

$byteBuffer = @(0x00,0x03,0x00,0x54,0x21,0x12,0xa4,0x42,0xd2,0x79,0xaa,0x56,0x87,0x86,0x48,
                0x73,0x8f,0x92,0xef,0x58,0x00,0x0f,0x00,0x04,0x72,0xc6,0x4b,0xc6,0x80,0x08,
                0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x06,0x00,0x30,0x04,0x00,0x00,0x1c,0x00,
                0x09,0xbe,0x58,0x24,0xe4,0xc5,0x1c,0x33,0x4c,0xd2,0x3f,0x50,0xf1,0x5d,0xce,
                0x81,0xff,0xa9,0xbe,0x00,0x00,0x00,0x01,0xeb,0x15,0x53,0xbd,0x75,0xe2,0xca,
                0x14,0x1e,0x36,0x31,0xbb,0xe3,0xf5,0x4a,0xa1,0x32,0x45,0xcb,0xf9,0x00,0x10,
                0x00,0x04,0x00,0x00,0x01,0x5e,0x80,0x06,0x00,0x04,0x00,0x00,0x00,0x01)

Das Paket sende ich dann per UDP-Client (Siehe auch PowerShell und UDP) an die Adresse und warte auf die Antwort.

Der Verhalten bei Microsoft Teams ist sehr ähnlich, was den ersten Kontakt angehen: Wobei hier mehrere Ziel-IP-Adressen angesprochen werden.

Schaut man aber genau hin, dann gibt es auch hier Verbindungen, die wie bei Skype for Business einen "Allocate Bandwidth" machen. In meinem Beispiel ist es hier die 52.113.193.5 und eine Verbindung zu diesem Server funktioniert genau wie auch bei Skype for Business.

Erreichbarkeitstest

Um zu prüfen, ob die Gegenstelle erreichbar ist, sende ich dann einfach das Paket los. Auf meine Anfrage bekomme ich dann auch eine Antwort zurück, die ich mit dem gleichen UDP-Client annehmen kann. Die empfangenen Daten kann ich prüfen, ob es ein "STUN Allocate Error" ist und damit die erfolgreiche Verbindung über Port 3478 bestätigen. Selbst ohne eine genaue Prüfung ist schon allein der Empfang einer UDP-Antwort ein ausreichend guter Indikator, so dass folgender Code schon alle Merkmale mitbringt:

# Simple Skype for Business Online Edge Turn test
[int]$sourceudpport=50000
[int]$remoteudpport=3478
[string]$remoteip = "13.107.8.2"

$udpClient = new-Object System.Net.Sockets.Udpclient($sourceudpport) 
$udpClient.Client.ReceiveTimeout = 1000   
#$udpClient.Client.Blocking = $true

# Session Traversal Utilities for NAT
# STSUN Packet from SfB Network Assessment Tool
$byteBuffer = @(0x00,0x03,0x00,0x54,0x21,0x12,0xa4,0x42,0xd2,0x79,0xaa,0x56,0x87,0x86,0x48,
                0x73,0x8f,0x92,0xef,0x58,0x00,0x0f,0x00,0x04,0x72,0xc6,0x4b,0xc6,0x80,0x08,
                0x00,0x04,0x00,0x00,0x00,0x04,0x00,0x06,0x00,0x30,0x04,0x00,0x00,0x1c,0x00,
                0x09,0xbe,0x58,0x24,0xe4,0xc5,0x1c,0x33,0x4c,0xd2,0x3f,0x50,0xf1,0x5d,0xce,
                0x81,0xff,0xa9,0xbe,0x00,0x00,0x00,0x01,0xeb,0x15,0x53,0xbd,0x75,0xe2,0xca,
                0x14,0x1e,0x36,0x31,0xbb,0xe3,0xf5,0x4a,0xa1,0x32,0x45,0xcb,0xf9,0x00,0x10,
                0x00,0x04,0x00,0x00,0x01,0x5e,0x80,0x06,0x00,0x04,0x00,0x00,0x00,0x01)

$RemoteIpEndPoint = New-Object System.Net.IPEndPoint([system.net.IPAddress]::Parse("0.0.0.0"),0);

$sentbytes = $udpClient.Send($byteBuffer, $byteBuffer.length, $remoteip, $remoteudpport)
try {
   $receive=$udpClient.Receive([ref]$remoteIpEndpoint)
   write-host "TTL $($_) Answer received"
   $result=[System.BitConverter]::ToString($receive);
}
catch {
   write-host "TTL $($_) NO Answer received"
}

So einfach ist schon mal die generelle Durchgängigkeit von einem Client zu einem Office 365 STUN-Server zu prüfen. Sie können natürlich daraus auch eine Überwachung machen. Allerdings ist ein STUN-Request noch kein RTP-Paket. Um für VoIP aussagekräftige Daten zu bekommen, sollten Sie schon RTP übertragen und dafür eignet sich das Skype for Business Online Network Assessment Tool viel besser.

Auswerten der Rückantwort

Ob ich nun wirklich einen STUN/TURN-Server erreicht habe, kann ich nur durch einen Vergleich der Antwort mit einem Sollwert überprüfen. Auch hier hilft mir WireShark mit, welcher die Antwort nicht nur anzeigt, sondern auch parst. Da es sein kann, dass die Antwort sich verändert, wollte ich nun nicht den kompletten Rückgabewert vergleichen sondern nur einen Teil davon.

Ich beschränke mich auf den Wert "01 13", der für einen "Allocate Error Response" steht und am Ende das "rtcmedia" steht. Das geht ganz einfach mit:

if ($result.startswith("01-13") -and $result.endswith("72-74-63-6D-65-64-69-61-22")){
   write-host "Edge reachable"
}
else {
   write-host "unexpected answer"
}

PRTG Modul

Ich habe das Skript dann gleich noch etwas erweitert, dass es als Custom Sensor unter PRTG eingesetzt werden kann. Es erweitert die Rückgabe dann einfach um eine XML-Struktur, die von PRTG ausgewertet wird. Der Einsatz unter PRTG ist als PRTG - Custom Sensor einzurichten. Nach einigen Stunden sollten Sie dann eine Grafik sehen:

Das ist mein T-DSL Anschluss zuhause, der interessanterweise nicht nur eine längere Latenzzeit in den Abendstunden aufweist (Netflix?) sondern dann auch die Anzahl der Hops anfängt zu schwanken. Da wäre es schon mal interessant, welche Stationen da genau durchlaufen werden. Auch sieht man gut, dass die Roundtriptime (RTT) in der Zeit auch zunimmt. Ich bin mal gespannt, wie die Werte bei Firmenanschlüssen aussehen.

Um aber mehr Details über die Leitwege zu bekommen, müsste ich einen Traceroute mit ICMP-Verarbeitung aufsetzen, was mit dem PowerShell UDP-Manager meines Wissens nicht so einfach möglich ist.

Aber auch so ist der Monitor sehr hilfreich um z.B. schnell zu erkennen, wenn eine Regeländerung der Firewall Port 3478 plötzlich sperrt oder Störungen im WAN zu größeren Umwegen führen. Insofern sollten Sie nach der Einrichtung des Sensors auch entsprechende Warn- und Fehlergrenzwerte samt Benachrichtigung in PRTG konfigurieren. Bei einer Firmen-Installation hatte ich dann folgende Bild:

Die Entfernung ist eigentlich immer 12 Hops aber es gibt auch hier die ein oder andere Veränderungen im Routing. Seit dem 26.12.2018 scheint der HopCount sich auf höherem Niveau stabilisiert zu haben. Die Roundtrip-Time ist dadurch zumindest noch nicht sichtbar schlechter geworden. Auch hier ist eine Betrachtung über mehrere Monate natürlich interessant. Der Sensor lief aber erst einige Wochen.

Die End2End-UDP3478 Funktion ist aber nicht auf Office 365 beschränkt. Sie können damit jeden TURN-Server, also auch den eigenen Edge-Server testen. Das funktioniert auch von einer Niederlassung über das eigene WAN zum Edge-Server in der Hub-Site. Hier sollten Sie dann natürlich deutlich schnellere Werte erhalten:

Ergänzend zu dem Sensor können Sie natürlich auch mit anderen Sensoren weiter Daten ermitteln:

Download/Tool

Das folgende PowerShell-Script können Sie einfach interaktiv starten oder als Custom-Sensor in PRTG einbinden. Über den Parameter "Remote-IP" könne sie ihren eigenen Edge-Server einbinden. Wenn Sie "o365" oder "teams" eingeben, nutzt das Skript hinterlegte IP-Adressen, die aber zukünftig ggfls. falsch sein können. Wenn Sie eine PRTG-URl als Parameter oder Umgebungsvariable gesetzt haben, dann sendet Das Skript per HTTPPush die Daten am Ende jedes Durchlaufs an einen PRTG - HTTP Push-Sensor . Das macht natürlich nur Sinn, wenn Sie mit "averageintervalsec" einen ausreichend langen Zeitraum, z.B. 60 Sek) angeben.

end2end-udp3478.ps1
Hinweis: Die CSV-Dateien sind nicht kompatibel. Benennen Sie eine bestehende ältere CSV-Datei um und starten sie mit eine neuen Datei

Je nach System müssen Sie den verwendeten Sourceport (Default:UDP 50019) noch in der Firewall freigeben

Beim einfachen Aufruf sehen Sie die Aktionen und Ergebnisse direkt auf dem Bildschirm. Hier die Betriebsart "End2End", bei der quasi kontinuierlich Pakete mit ca. 20ms Abstand sende. (Also immer 20ms nachdem die Antwort angekommen ist.

Wenn ich die Betriebsart "TTLCheck" nutze, dann werden nur wenige Latenztest gemacht um dann aber mit dem absteigenden TTL die Entfernung zu ermitteln:

Hier wir per Default nur eine Sekunde mit maximaler Wiederholrate gemessen und dann die Distanz ermittelt. Ich habe mittlerweile die Detailausgaben alle mit "Write-Verbose" versteckt und mittels Farbe die Antworten sichtbar gemacht. Die Daten landen natürlich auch in der CSV-Datei für spätere Auswertungen und können auch z.B. an PRTG gesendet werden.

Parameter

Wenn Sie in den Sourcecode schauen, dann finden Sie einige Parameter am Anfang. Sie müssen diese nicht nutzen. Per Default macht das Skript einen end2end-Test gegen die Skype for Business Online Server. Sie können aber das Verhalten auch ihren Anforderungen anpassen. Die Bedeutung ist:

Parameter Werte Default Beschreibung

mode

end2end
ttlcheck

end2end

Damit bestimmten Sie, ob das Skript einen End2End-Dauertest macht oder zwischendrin einen TTL-Entfernungstest addiert, aber in der Zeit keine Roundtrip-Tests machen kann.

remoteip

O365, Teams
IP-Adresse, Hostname

O365

Per Default wird der Skype for Business Online Edge-Server genutzt. Sie können aber auch Teams oder sogar ihren eigenen Skype for Business Edge-Server verwenden. Dann geben Sie bitte die IP-Adresse oder den DNS-Namen ein

sourceudpport

0..65535

50019

Mit diesem Port geht das Skript raus. Es bietet sich an, einen Port der Skype for Business Audio-Ports zu nutzen, um den gleichen Firewall-Regeln und QoS-Einstufungen unterworfen zu werden.

remoteudpport

0..65535

3478

Der UDP-Port auf der anderen Seite, auf der TURN-Server reagiert. Das ist eigentlich immer 3478

maxttl

0-.128

20 bei TTLCheck
128 bei End2End

Mit diesem TTL werden die Pakete auf die Reise geschickt. Jeder Router erniedrigt den Counter und bei 0 wird das Paket verworfen.

maxretries

0..65535

5 bei TTLCheck
0 bei End2End

Wenn ein Paket nicht innerhalb der bei $ReceiveTimeout angegeben Millisekunden beantwortet wurde, dann wird es so oft wiederholt

avgintervalsec

0..65535

1 bei TTLCheck
60 bei End2End

Beim TTLCheck wird eine Sekunde lang die Roundtripzeit gemessen und dann der TTL-Check absteigend von $maxttl ausgeführt. Beim End2End-Check sammle ich die Daten 60 Sekunden ein

interpacketsleepms

0..65535

0 bei TTLCheck
20 bei End2End

Beim TTLCheck lege ich keine Pause nach der Verarbeitung ein. Beim End2End-Check warte ich 20ms nach der Verarbeitung ab. Der Abstand zwischen Paketen wird also etwas länger sein.

sleeptime

0..65535

0 bei TTLCheck
0 bei End2End

Nach Durchlaufen einer Runde kann ich eine Pause einlegen. Bei beiden Betriebsarten ist dies per Default nicht der Fall

ReceiveTimeout

500

0..65535

Zeit in Millisekunden, die der UDP-Listener nach dem Versand eines Pakets wartet. Nach 500ms bricht der Empfang ab und ich fange den Fehler ab. Das Paket zählt nach der Zeit als "verloren". Es wird je nach Einstellung von $maxretries erneut gesendet.

SendToPipeline

$false

$true/$False

Wenn Sie die Ergebnisse mit einem anderen Programm weiter verarbeiten wollen, dann können Sie mit dem Schalter die Ausgabe des Result-Objects in die Pipeline anfordern. Per Default ist dies abgeschaltet, um die Bildschirmausgabe nicht zu stören.

resultcsv

Dateipfad

Dateipfad

In diese CSV-Datei werden die Ergebnisse geschrieben. So können Sie das Skript auch lange laufen lassen und später die Daten auswerten oder mit anderen Endpunkten vergleichen.

prtgpushurl

$null

URI

Am Ende jedes Laufs schreibt end2end-udp3478 nicht nur die CSV-Datei, sondern kann die Daten acuh an eine PRTG-Instanz übermitteln. Richten Sie dazu einen PRTG - HTTP Push-Sensor ein und geben Sie hier die URI an, z.B. "http://<prtgserver>:<pushport>/<sensorcode>

Weitere Links