Traceroute TURN
Ein einfacher Traceroute prüft per ICMP oder UDP die Erreichbarkeit einer Gegenstelle und versucht den Weg aufzuzeichnen. Gerade beim Einsatz von VoIP mit Skype for Business und Teams ist es wichtig den Weg der Pakete vom Client zum STUN/TURN-Server zu kennen. In einem guten Setup ist es möglich eine UDP-Verbindung zum Port 3478 der Edge-Server zu starten. Realtime-Traffic (Sprache und Video) sollte aufgrund der speziellen Anforderungen (Realtime. viele kleine Pakete, kein Resend erforderlich) nie in TCP, HTTPS-Tunnel oder VPN eingekapselt werden.
Traceroute mit UDP Port 3478
Auf der Seite End2End-UDP3478 habe ich mir ein Skript gebaut, welches einen ICE-Handshake mit einen Skype for Business Edge-Server versucht. Es ist einfacher Verbindungtest. Diesen Code habe ich etwas verfeinert, um mehrere UDP-Anfragen mit aufsteigendem TTL zu senden:
# Simple Skype for Business Online Edge Turn test param ( [int]$sourceudpport=50000, [int]$remoteudpport=3478, [string]$remoteip = "13.107.8.2", [byte]$maxttl=20 ) Write-host "Start UDP-Client on $($sourceudpport)" $udpClient = new-Object System.Net.Sockets.Udpclient($sourceudpport) $udpClient.Client.ReceiveTimeout = 1000 # STUN 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); $result=@{} Write-host "Connect to $($remoteip):$($remoteudpport)" $udpclient.Connect($remoteip, $remoteudpport) for ($ttl=1; $ttl -le $maxttl; $ttl++) { Write-host "Send STUN-Request with TTL $($ttl) " -nonewline $udpclient.ttl = $ttl $sentbytes = $udpClient.Send($byteBuffer, $byteBuffer.length) try { $result[$ttl]=$udpClient.Receive([ref]$remoteIpendpoint) write-host "Answer received" break } catch { write-host "NO Answer received" } } Write-host "Closing UDP" $udpClient.close() $udpClient.dispose() Write-host "Done"
Das Skript können Sie einfach ausführen und wenn ihr Client mit dem Quellport 50.000 den Skype for Business Online Server "13.107.8.2" auf Port 3478/UDP erreichen kann, dann wird das Skript irgendwann mit einer Erfolgsmeldung antworten.
PS C:\temp> .\end2end-stun.ps1 Start UDP-Client on 50000 Connect to 13.107.8.2:3478 Send STUN-Request with TTL 1 NO Answer received Send STUN-Request with TTL 2 NO Answer received Send STUN-Request with TTL 3 NO Answer received Send STUN-Request with TTL 4 NO Answer received Send STUN-Request with TTL 5 NO Answer received Send STUN-Request with TTL 6 NO Answer received Send STUN-Request with TTL 7 NO Answer received Send STUN-Request with TTL 8 NO Answer received Send STUN-Request with TTL 9 NO Answer received Send STUN-Request with TTL 10 NO Answer received Send STUN-Request with TTL 11 NO Answer received Send STUN-Request with TTL 12 NO Answer received Send STUN-Request with TTL 13 NO Answer received Send STUN-Request with TTL 14 Answer received Closing UDP Done
Wenn Sie mit Wireshark (vormals Ethereal) die Pakete mitschneiden, dann ist gut der aufsteigende TTL zu sehen
Die ersten beiden Stationen senden noch ein "TTL exceeded" zurück. Interessant, dass Sie dies mit einem Start TTL von 64 machen. Die nächsten Pakete 3,4 und 5 laufen quasi ins "Leere", zumindest kommt kein "TTL exceeded" zurück. Paket 6 wird wieder aktiv gemeldet und der Absender scheint einen TTL von 254 zu nutzen, denn bei mir kommt ein TTL von 248 an, was 6 Hops entspricht. Paket 7 und 8 ist wieder unbekannt ehe dann 9,10,11 wieder gemeldet werden. Nachdem dann 12,13,14 ohne Bericht verworfen werden kommt das Paket mit dem TTL 15 bei der Gegenstelle an und wird auch beantwortet. Es kommt mit einem TTL 115 zurück und auch alle nachfolgenden Pakete kommen mit dem gleichen TTL an. Wie viele Hops auf dem Rückweg genommen werden, kann man aber nicht ermitteln da der Startwert von der Gegenstelle vorgegeben wird. Ich kann nur vermuten, dass es vielleicht 128 ist und dann 13 Hops anstehen. Allerdings wäre das dann weniger Stationen als auf dem Hinweg mit 14. Ich bekomme aber schon einen einfachen Trace damit hin:
Herausforderung ICMP-Verarbeitung
Die Herausforderung bei diesem Skript ist es, die ICMP-Rückmeldungen zuzuordnen. Nun ist ICMP aber ein komplett anderes Protokoll und kann nicht über den Powershell UDP-Client empfangen werden. Ich hätte ja gerne eine Funktion gesehen, dass der UDPClient.Receive mit einer Exception abbricht aber dennoch etwas zurück liefert. Nämlich das ICMP-Paket, welches bei einigen Routern durchaus umfangreiche Daten beinhalten kann. Hier ein solches Paket in Wireshark
Leider scheint das NET-Framework solche ICMP-Pakete nicht dem Client wieder zuzuordnen oder anderweitig für das Programm verfügbar zu machen. Das steht so noch auf meiner Wunschliste. Hier erst ein mal ein paar Links, die ich bei der Recherche dazu gefunden aber mir noch keine Lösung gebracht haben. Vermutlich müsste ich selbst ICMP annehmen und zuordnen oder mich auf WINSOCK-Ebene herunter begeben. Ein Versuch meinerseits das per Skript zu machen, hat zumindest noch keinen Erfolg verbucht. Wenn ich aber die folgenden Links anschaue, dann sollte es machbar sein:
- A .Net based PowerShell packet generator
https://GitHub.com/sperner/PowerShell/blob/master/Packet.ps1 - A .Net based PowerShell packet sniffer
https://GitHub.com/sperner/PowerShell/blob/master/Sniffer.ps1 - How to write a basic sniffer in
PowerShell
http://www.drowningintechnicaldebt.com/RoyAshbrook/archive/2013/03/08/how-to-write-a-basic-sniffer-in-powershell.aspx
Dann bleibt nur die Auswertung der ICMP-Antwort, dass Sie auch zu meiner UDP-Verbindung gehört. Mit dem folgenden Code-Schnipsel ist es mir zumindest schon gelungen die ICMP-Pakete zu bekommen. Allerdings muss das Skript dazu als Administrator gestartet werden. Ich finde es aber schon interessant, dass man so quasi auch fremde Pakete mitschneiden kann.
#ICMP-Receiver $RemoteIpEndPoint = New-Object System.Net.IPEndPoint([system.net.IPAddress]::Parse("0.0.0.0"),0); $socket = New-Object System.Net.Sockets.Socket( [System.Net.Sockets.AddressFamily]::InterNetwork, [System.Net.Sockets.SocketType]::Raw, [System.Net.Sockets.ProtocolType]::Icmp) $socket.Bind($RemoteIpEndPoint); $socket.iocontrol( ` [Net.Sockets.IOControlCode]::ReceiveAll, [BitConverter]::GetBytes(1), $null) $socket.ReceiveTimeout = 5000 $ReceiveBuffer = New-Object Byte[] 256 $inBytes = $socket.ReceiveFrom($ReceiveBuffer, $ReceiveBuffer.length, 0, [ref]$RemoteIpEndPoint); if ($ReceiveBuffer[20] -eq 11) { # ICMP type = Delivery failed Write-host "TTL Exceeded" Write-host " Sender: $($RemoteIpEndPoint.ToString())" Write-host "Destination: $($ReceiveBuffer[44]).$($ReceiveBuffer[45]).$($ReceiveBuffer[46]).$($ReceiveBuffer[47])" } else { Write-host "ICMP-Paket $($ReceiveBuffer[20]) received" }
Aktuell habe ich aber noch nicht den Code soweit, dass ich die Rückantworten der Zwischenstationen erfasse und auswerte. Ich beschränke mich daher auf die "Entfernungsmessung" und generelle Erreichbarkeit
Aufgrund von Missbrauchs durch Viren um das Jahr 2000 hat Microsoft die Verwendung von Raw-Sockets auf Nicht-Server-Editionen des Windows-Betriebssystems eingeschränkt.
On Windows 7, Windows Vista, Windows XP
with Service Pack 2 (SP2), and Windows XP with Service
Pack 3 (SP3), the ability to send traffic over raw sockets
has been restricted in several ways:
https://docs.microsoft.com/en-us/windows/win32/winsock/tcp-ip-raw-sockets-2#limitations-on-raw-sockets
Hier noch ein paar weiterführende Links:
- Socket.SetSocketOption-Methode
https://msdn.microsoft.com/de-de/library/e160993d(v=vs.110).aspx
Vielleicht muss man ja erst eine Option setzen - UdpClient.Connect-Methode
https://msdn.microsoft.com/de-de/library/c4w4cta7%28v=vs.110%29.aspx
Bei UDP gibt es eigentlich keinen Connect. Aber angeblich könnte Windows dann die ICMP-Antworten zuordnen - Send and Receive data via UDP in PowerShell
https://stackoverflow.com/questions/12148666/send-and-receive-data-via-udp-in-powershell - Bug in overlapped UDP port unreachable errors ?
http://www.lenholgate.com/blog/2007/12/bug-in-overlapped-udp-port-unreachable-errors.html - Listen for ICMP packets in C#
https://stackoverflow.com/questions/626541/listen-for-icmp-packets-in-c-sharp
Enthält z.B. die Aussage "Just use connected udp sockets and the OS will match the icmp unreachable and return an error in the udp socket. - Socket.IOControl-Methode: (IOControlCode, Byte[], Byte[])
https://msdn.microsoft.com/de-de/library/8a3744sh(v=vs.110).aspx - IOControlCode-Enumeration
https://msdn.microsoft.com/de-de/library/system.net.sockets.iocontrolcode(v=vs.110).aspx - Read ICMP packets in C# using raw
sockets
https://tewarid.GitHub.io/2013/11/27/read-icmp-packets-in-c-using-raw-sockets.html
Weitere Links
- End2End-UDP3478
- PowerShell und UDP
- End2End-Ping
- ICMP
https://de.wikipedia.org/wiki/Internet_Control_Message_Protocol - What You Need to Know about Traceroute
https://blog.paessler.com/what-you-need-to-know-about-Traceroute