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.

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.

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.

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. Es läuft einmal und beendet sich dann wieder. Es ist kein "Dauertest".

end2end-udp3478.ps1

Beim einfachen Aufruf sehen Sie die Aktionen interaktiv:

PS C:\> .\end2end-udp3478.ps1
Start UDP-Client on 50000
Connect to 13.107.8.2:3478
Calculate average Rounttrip
Answer received 36 ms
Answer received 23 ms
Answer received 23 ms
Answer received 23 ms
Answer received 23 ms
RTT Avg: 26
RTT Max: 36
RTT Min: 23
Start TTL Distance Check
Send STUN-Request with TTL 32 Answer received
Send STUN-Request with TTL 31 Answer received
Send STUN-Request with TTL 30 Answer received
Send STUN-Request with TTL 29 Answer received
Send STUN-Request with TTL 28 Answer received
Send STUN-Request with TTL 27 Answer received
Send STUN-Request with TTL 26 Answer received
Send STUN-Request with TTL 25 Answer received
Send STUN-Request with TTL 24 Answer received
Send STUN-Request with TTL 23 Answer received
Send STUN-Request with TTL 22 Answer received
Send STUN-Request with TTL 21 Answer received
Send STUN-Request with TTL 20 Answer received
Send STUN-Request with TTL 19 Answer received
Send STUN-Request with TTL 18 Answer received
Send STUN-Request with TTL 17 Answer received
Send STUN-Request with TTL 16 Answer received
Send STUN-Request with TTL 15 Answer received
Send STUN-Request with TTL 14 Answer received
Send STUN-Request with TTL 13 NO Answer received. Retry 0
Send STUN-Request with TTL 13 NO Answer received. Retry 1
Send STUN-Request with TTL 13 NO Answer received. Retry 2
Send STUN-Request with TTL 13 NO Answer received. Retry 3
Send STUN-Request with TTL 13 NO Answer received. Retry 4
Send STUN-Request with TTL 13 NO Answer received. Retry 5
Closing UDP
Result: Distance 14
Done

Es wird nichts auf der lokalen Festplatte gelesen oder geschrieben. Eventuell grätscht noch eine Firewall dazwischen.

Weitere Links