Testing STUN/TURN server connectivity from external networks through UDP 3478 by using Powershell

Hi there,

 

While working on a Lync connectivity test tool, I developed a STUN/TURN server connectivity test script in powershell which might be handy when you want to make sure that your external clients will be able to communicate with STUN/TURN server via UDP 3478 (STUN/TURN connectivity through TCP will also be added later on). Actually we have a resource kit tool called MsTurnPing which provides similar functionality (and more): 

https://technet.microsoft.com/en-us/library/jj945604.aspx Lync Server 2013 Resource Kit Tools Documentation

MsTurnPing

--------------------------------------------------------------------------------

The MSTurnPing tool allows an administrator of Microsoft Lync Server 2013 communications software to check the status of the servers running the Audio/Video Edge and Audio/Video Authentication services as well as the servers that are running Bandwidth Policy Services in the topology.

 

Description

--------------------------------------------------------------------------------

The MSTurnPing tool allows an administrator of Lync Server 2013 communications software to check the status of the servers running the Audio/Video Edge and Audio/Video Authentication services as well as the servers that are running Bandwidth Policy Services in the topology.

The tool allows the administrator to perform the following tests:

1. A/V Edge Server test: The tool performs tests against all A/V Edge Servers in the topology by doing the following:

? Verifying that the Lync Server Audio/Video Authentication service is started and can issue proper credentials.

? Verifying that the Lync Server Audio/Video Edge service is started and can allocate the resources on the external edge successfully.

2. Bandwidth Policy Service test: The tool performs tests against all the servers that are running the Bandwidth Policy Services in the topology by doing the following:

? Verifying that the Lync Server Bandwidth Policy Service (Authentication) is started and can issue proper credentials.

? Verifying that the Lync Server Bandwidth Policy Service (Core) is started and can perform the bandwidth check successfully.

This tool must be run from a computer that is part of the topology and has the local store installed.

Unfortunately MsTurnPing tool doesn’t allow you to do the testing from an external client.

Now let me further explain what the powershell script does to test TURN/STUN connectivity test:

 

1) First of all, to do the testing you need to provide your AV edge server’s name/IP address information as a parameter to the powershell script:

Example:

PS C:\> turn.ps1 av.contoso.com

 

2) Once the powershell script runs, it does:

- Resolve the name

- If the given name is successfully resolved, it then sends a UDP datagram with a STUN allocate payload

- It waits on a response on the UDP socket for a timeout period and if there’s a STUN allocate response it prints “Received response from STUN Server!”

- If no response is received within the given timeout period, it prints an error.

 

Some example outputs:

 

If you get such a failure, one of the first things that you can do is to run the below commands on your Edge server(s) and see if listens on UDP port 3478 on the internal IP and on the AV Edge IP:

 

C:\Users\Administrator.CONTOSO>netstat -ano | find ":3478"

  UDP 10.2.2.10:3478 *:* 1952

  UDP 10.3.3.12:3478 *:* 1952

 

C:\Users\Administrator.CONTOSO>tasklist /svc | find "1952"

MediaRelaySvc.exe 1952 RTCMEDIARELAY

 

If you don’t know what is your AV Edge server name/IP address, you can check it from the topology file:

 

 

 

=> Here is the full Powershell script source:

 

#------------SCRIPT STARTS HERE-----------

 

function ResolveLyncNames {

 

param($LyncFqdn)

 

try {

$ipaddr = [System.Net.Dns]::GetHostAddresses($LyncFqdn)

Write-Host "Successfully resolved $LyncFqdn to $ipaddr" -ForegroundColor Green

return $ipaddr

}

 

catch {

 

$exception = New-Object system.net.sockets.socketexception

$errorcode = $exception.ErrorCode

write-host "Requested name '$LyncFqdn' could not be resolved, error code:$errorcode" -foregroundcolor Red

write-host "Error details: $exception" -foregroundcolor Red

return 0

}

 

}

  

 

if($args[0] -eq $NULL)

 

{

 

Write-host "Please specify a STUN server name or IP address to test"

Write-Host "Example: turn.ps1 av.contoso.com"

 

return

}

 

$stunserver1 = $args[0]

 

if(ResolveLyncNames($stunserver1)) {

 

 

try {

 

$j = Start-Job -ScriptBlock {

$stunserver2 = $args[0]

$udpclient=new-Object System.Net.Sockets.UdpClient

$udpclient.Connect($stunserver2,3478)

 

[Byte[]] $payload =

0x00,0x03,0x00,0x64,0x21,0x12,0xa4,0x42,0xf1,0x3c,0x08,0x4b,

0x80,0x18,0x17,0x72,0x47,0x49,0x30,0x65,0x00,0x0f,0x00,0x04,

0x72,0xc6,0x4b,0xc6,0x80,0x08,0x00,0x04,0x00,0x00,0x00,0x04,

0x00,0x06,0x00,0x38,0x02,0x00,0x00,0x24,0x79,0xb7,0x95,0x2d,

0x01,0xce,0xa8,0x6e,0x4e,0x3d,0x76,0x22,0x64,0xaa,0xc7,0xb6,

0x2b,0xb8,0x78,0xde,0xee,0x8a,0xc0,0x88,0x84,0x49,0x1b,0x7c,

0x00,0x00,0x00,0x00,0x82,0x8b,0x73,0x75,0xdd,0x0c,0xae,0x66,

0x95,0xed,0xef,0x56,0xd0,0x4b,0x54,0xa4,0x7c,0xbd,0xfa,0x98,

0x00,0x10,0x00,0x04,0x00,0x00,0x00,0xc8,0x80,0x06,0x00,0x04,

0x00,0x00,0x00,0x01,0x80,0x55,0x00,0x04,0x00,0x01,0x00,0x00

  

$bytesSent=$udpclient.Send($payload,$payload.length)

$listenport = $udpclient.client.localendpoint.port

 

$endpoint = new-object System.Net.IPEndPoint ([IPAddress]::Any,$listenport)

$content = $udpclient.Receive([ref]$endpoint)

 

$Encoding = "ASCII"

 

switch ( $Encoding.ToUpper() )

{

"ASCII" { $EncodingType = "System.Text.ASCIIEncoding" }

"UNICODE" { $EncodingType = "System.Text.UnicodeEncoding" }

"UTF7" { $EncodingType = "System.Text.UTF7Encoding" }

"UTF8" { $EncodingType = "System.Text.UTF8Encoding" }

"UTF32" { $EncodingType = "System.Text.UTF32Encoding" }

Default { $EncodingType = "System.Text.ASCIIEncoding" }

}

$Encode = new-object $EncodingType

 

if ($Encode.GetString($content).Contains("The request did not contain a Message-Integrity attribute")) {

write-host "Received response from STUN Server!" -ForegroundColor Green

}

else {

write-host "STUN Server either is not reachable or doesn't respond" -ForegroundColor Red

}

 

$udpclient.Close()

 

} -ArgumentList $stunserver1

 

write-host "Sending TURN server port allocation request at UDP port 3478, it will be checked after 10 seconds to see if a response is received or not ..." -ForegroundColor Green

 

Start-Sleep -Seconds 10

 

if( $j.JobStateInfo.State -ne "completed" )

 

{

 

Write-Host "The request timed out, STUN Server '$stunserver1' is not reachable or doesn't respond to the request." -ForegroundColor Red

Write-host "Please check if UDP 3478 is allowed between the client and the STUN server" -ForegroundColor Red

Write-Host "Also please check if STUN server (MediaRelaySvc.exe) is running on the Edge server and listening on UDP 3478" -ForegroundColor Red

 

}

 

else {

$results = Receive-Job -Job $j

 

$results

 

}

 

}

 

catch {

 

$_.exception.message

 }

}

  

#------------SCRIPT ENDS HERE-----------

 

 

 

Hope this helps

 

Thanks,

Murat

Comments

  • Anonymous
    February 21, 2016
    Thanks, Murat -- it did help. Using this, I added a simple UDP port 3478 connectivity test to my own Powershell Lync client connectivity testing script. The only thing that irked me was sending a datagram to a server without understanding exactly what it did. I decoded it manually (an educational effort) and made a new version of your script with a "minimized" datagram (described in the comments) which has the same effect, without any "unnecessary" attributes. I'd post that script here, but comments must be 3072 characters or less, so I've posted it to the TechNet gallery instead, here:
    https://gallery.technet.microsoft.com/TURN-Connectivity-test-to-6dba61d2

    Thanks again!
  • Anonymous
    February 21, 2016
    Beautyful script and nice blog :-)