Azure Virtual Desktop RDP Shortpath for public networks (preview)

Remote Desktop Protocol (RDP) can use multiple different types of network transport to establish a connection between Remote Desktop Client and Session host.

  • Reverse connect - by default, RDP uses a TCP-based reverse connect transport. This transport provides the best compatibility with various networking configurations and has a high success rate for establishing RDP connections. This transport is also used as a fallback if the RDP Shortpath connection is unsuccessful.
  • RDP Shortpath for managed networks - UDP-based transport designed for direct connectivity in controlled network setups. For example, connectivity over the ExpressRoute or Azure Stack HCI deployments. For more information, see the documentation.
  • RDP Shortpath for public networks, currently in preview, is described in this document.

Note

During the preview, RDP Shortpath for managed networks is incompatible with RDP Shortpath for public networks. If you want to participate in the preview, refer to the documentation for disabling RDP Shortpath for managed networks.

RDP Shortpath transport is a feature of Azure Virtual Desktop that establishes a direct UDP data flow between Remote Desktop Client and Session host. RDP uses this data flow to deliver Remote Desktop and RemoteApp while offering better reliability and consistent latency.

Key benefits

Both RDP Shortpath for managed and public networks provide the same set of core benefits:

  • RDP Shortpath transport is based on the Universal Rate Control Protocol (URCP). URCP enhances UDP with active monitoring of the network conditions and provides fair and full link utilization. URCP operates at low delay and loss levels as needed by Remote Desktop. URCP achieves the best performance by dynamically learning network parameters and providing protocol with a rate control mechanism.
  • RDP Shortpath establishes the direct connectivity between the Remote Desktop client and the session host. Direct connectivity reduces dependency on the Azure Virtual Desktop gateways, improves the connection's reliability, and increases available bandwidth for each user session.
  • The removal of extra relay reduces round-trip time, which improves user experience with latency-sensitive applications and input methods.

Connection security

RDP Shortpath for public networks extends RDP multi-transport capabilities. It doesn't replace the reverse connect transport but complements it. The initial session brokering is managed through the Azure Virtual Desktop infrastructure. Each RDP session uses a dynamically assigned UDP socket that accepts the Shortpath traffic previously authenticated over a reverse connect transport. This socket will ignore all connection attempts unless they match the reverse connect session. Before the UDP socket is open, any new RDP session must establish the unique reverse connect transport. RDP Shortpath uses a TLS connection between the client and the session host using the session host's certificates. By default, the certificate used for RDP encryption is self-generated by the OS during the deployment. If desired, customers may deploy centrally managed certificates issued by the enterprise certification authority. For more information about certificate configurations, see Windows Server documentation.

Network Address Translation and firewalls

Most Azure Virtual Desktop clients run on computers on the private network. Internet access is provided through a Network Address Translation (NAT) gateway device. Therefore, the NAT gateway modifies all network requests from the private network and destined to the Internet. Such modification intends to share a single public IP address across all of the computers on the private network. Because of IP packet modification, the recipient of the traffic will see the public IP address of the NAT gateway instead of the actual sender. When traffic comes back to the NAT gateway, it will take care to forward it to the intended recipient without the sender's knowledge. In most scenarios, the computers hidden behind such a NAT aren't aware translation is happening and don't know the network address of the NAT gateway.

NAT is also applicable to the Azure Virtual Networks, where all session hosts reside. When a session host tries to reach the network address on the Internet, the NAT Gateway or Azure Load Balancer performs the address translation. For more information about various types of Source Network Address Translation, see the documentation.

Most networks typically include firewalls that inspect traffic and block it based on rules. Most customers configure their firewalls to prevent incoming connections (that is, unsolicited packets from the Internet sent without a request). Firewalls employ different techniques to track data flow to distinguish between solicited and unsolicited traffic. In the context of TCP, the firewall tracks SYN and ACK packets, and the process is straightforward. UDP firewalls usually use heuristics based on packet addresses to associate traffic with UDP flows and allow or block it. There are many different NAT implementations available. In most cases, NAT gateway and firewall are the functions of the same physical or virtual device.

How RDP Shortpath works for public networks

RDP Shortpath uses a standardized set of methods for traversal of NAT gateways. As a result, user sessions directly establish a UDP flow between the client and the session host. More specifically, RDP Shortpath uses STUN protocol to discover the external IP address of the NAT router. There are four primary components used to establish the RDP Shortpath data flow:

  • Remote Desktop Client
  • Session Host
  • Azure Virtual Desktop Gateway
  • Azure Virtual Desktop STUN Server

In Azure Virtual Desktop, every RDP connection starts with establishing the reverse connect transport over the Azure Virtual Desktop Gateway. After the user authentication, the client and session host establish the initial RDP transport, and the client and session host start exchanging their capabilities. If RDP Shortpath for public networks is enabled on the session host, then the session host initiates a process called Candidate Gathering.

  • At this stage, the session host enumerates all network interfaces assigned to a VM, including virtual interfaces like VPN and Teredo.
  • Remote Desktop Service allocates UDP socket on each interface and stores the IP:Port pair in the candidate table as a local candidate.
  • Remote Desktop Service uses each UDP socket allocated in the previous step to try reaching the Azure Virtual Desktop STUN Server on the public Internet. Communication is done by sending a small UDP packet to port 3478
  • If the packet reaches the STUN server, the STUN server responds with the session host public IP and listener port. This information is stored in the candidate table as a reflexive candidate.

After the session host gathers all candidates, the session host uses the established reverse connect transport to pass the candidate list to the client. When the client receives the list of candidates from the server, the client performs the candidate gathering on its side. Then the client sends its candidate list to the session host. After the session host and client exchange their candidate lists, both parties attempt to connect with each other using all the gathered candidates. This connection attempt is simultaneous on both sides. Many of the NAT gateways are configured to allow the incoming traffic to the socket as soon as the outbound data transfer initializes it. This behavior of NAT gateways is the reason the simultaneous connection is essential. After the initial packet exchange, the client and session host may establish one or many data flows. After that, Remote Desktop Protocol chooses the fastest network path. Client then establishes a secure TLS connection with the session host and initiates the RDP Shortpath transport. After RDP establishes the Shortpath, all Dynamic Virtual Channels (DVCs), including remote graphics, input, and device redirection move to the new transport.

Enabling the preview of RDP Shortpath for public networks

To participate in the preview of RDP Shortpath, you need to enable the Shortpath functionality. You can configure RDP Shortpath on any number of session hosts used in your environment. There's no requirement to enable RDP Shortpath on all hosts in the pool. We recommend you use a validation host pool by following the steps in Define your host pool as a validation host pool.

Follow the steps below to configure session host:

  1. Connect to the session host
  2. Open the elevated command prompt
  3. Enable the RDP Shortpath for public networks:
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations" /v ICEControl /t REG_DWORD  /d 2 /f

Disabling the preview of RDP Shortpath for public networks

If you decide to disable the preview of RDP Shortpath, you can disable the Shortpath functionality.

Follow the steps below to configure session host:

  1. Connect to the session host
  2. Open elevated command prompt
  3. Disable the RDP Shortpath for public networks:
REG DELETE "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations" /v ICEControl /f

Network configuration

To support RDP Shortpath for public networks, you typically don't need any particular configuration. Azure Virtual Desktop client and Session host will automatically discover the direct data flow if it's possible in your network configuration. However, every environment is unique, and some network configurations may negatively affect the rate of success of the direct connection. Follow the recommendations below to increase the probability of a direct data flow.

Allow outbound UDP connectivity

RDP Shortpath uses UDP to establish a data flow. If a firewall on your network blocks UDP traffic, RDP Shortpath will fail, and the connection will fall back to TCP-based reverse connect transport. Azure Virtual Desktop uses STUN servers provided by Azure Communication Services and Microsoft Teams. By the nature of the feature, outbound connectivity from the session hosts to the client is required. Unfortunately, you can't predict where your users are located in most cases. Therefore, we recommend allowing outbound UDP connectivity to the Internet. You can limit the port range used to listen to the incoming UDP flow. Use the following table for reference when configuring firewalls for RDP Shortpath.

Session host virtual network

Name Source Destination Port Protocol Destination Action
RDP Shortpath Server Endpoint VM Subnet 1024-65535 UDP * Allow
STUN Access VM Subnet 3478 UDP 13.107.17.41/32, 13.107.64.0/18, 20.202.0.0/16, 52.112.0.0/14, 52.120.0.0/14 Allow

Client network

Name Source Destination Port Protocol Destination Action
RDP Shortpath Server Endpoint Client network 1024-65535 UDP Public IP addresses assigned to NAT Gateway or Azure Firewall Allow
STUN Access Client network 3478 UDP 13.107.17.41/32, 13.107.64.0/18, 20.202.0.0/16, 52.112.0.0/14, 52.120.0.0/14 Allow

Note

The IP ranges for STUN servers used in preview would change at the feature's release to General Availability.

Limiting port range used on the client side

By default, RDP Shortpath for public networks uses an ephemeral port range (49152–65535) to establish a direct path between server and client. However, you may want to configure the server to use a smaller, predictable port range in some cases. To enable a limited port range, you can use the following command on the session host:

REG ADD HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services /v ICEEnableClientPortRange /t REG_DWORD /d 1 /f

When you enable this setting on the session host, the Azure Virtual Desktop client will randomly select the port from the range for every connection. If the specified port range is exhausted, the client's operating system will choose a port to use. By default, when the port range configuration is enabled, the client will choose a port from the range of 38300-39299. If you want to change the port numbers, you can customize a UDP port range for the Azure Virtual Desktop client. When choosing the base and pool size, consider the number of ports setting to ensure that the upper bound doesn't exceed 49151. For example, if you select 38300 as a port base and 1000 as pool size, the upper bound will be 39299. To specify the port range, use the following commands, substituting the base port and the number of ports.

reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services /v ICEClientPortBase /t REG_DWORD /d 38300 /f
reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services /v ICEClientPortRange /t REG_DWORD /d 1000 /f

Disabling RDP Shortpath on the client

To disable RDP Shortpath for a specific client, you can use the following Group Policy to disable the UDP support:

  1. On the client, run gpedit.msc.
  2. Go to Computer Configuration > Administration Templates > Windows Components > Remote Desktop Services > Remote Desktop Connection Client.
  3. Set the "Turn Off UDP On Client" setting to Enabled

Teredo support

While not required for RDP Shortpath, Teredo adds extra NAT traversal candidates and increases the chance of the successful RDP Shortpath connection in IPv4-only networks. You can enable Teredo on both Session host and Client side by running the following command:

netsh interface Teredo set state type=enterpriseclient

UPnP support

To improve the chances of a direct connection, on the side of the Remote Desktop client, RDP Shortpath may use UPnP to configure a port mapping on the NAT router. UPnP is a standard technology used by various applications, such as Xbox, Delivery Optimization, and Teredo. UPnP is generally available on the routers typically found on a home network. UPnP protocol is enabled by default on most home routers and access points. UPnP is often disabled on corporate networking.

General recommendations

  • Avoid using force tunneling configurations if your users access Azure Virtual desktop over the Internet.
  • Make sure you aren't using double NAT or Carrier-Grade-NAT (CGN) configurations.
  • Recommend users to not disable UPnP on their home routers.
  • Avoid using cloud packet-inspection Services
  • Avoid using TCP-based VPN solutions
  • Enable IPv6 connectivity or Teredo

Verify your network connectivity

Next, you'll need to make sure your network is using RDP Shortpath. You can verify the transport with either a "Connection Information" dialog or by using Log Analytics.

Connection Information dialog

To make sure connections are using RDP Shortpath, open the "Connection Information" dialog by going to the Connection tool bar on the top of the screen and select the antenna icon, as shown in the following screenshot.

Image of Remote Desktop Connection Bar of remote desktop client

Image of Remote Desktop Connection Info dialog

Use Log Analytics

If you're using Azure Log Analytics, you can monitor connections by querying the WVDConnections table. A column named UdpUse indicates whether Azure Virtual Desktop RDP Stack is using UDP protocol on the current user connection. The possible values are:

  • 0 - user connection isn't using RDP Shortpath.
  • 1 - The user connection is using RDP Shortpath for managed networks.
  • 2 - The user connection is using RDP Shortpath for public networks.

The following query lets you review connection information. You can run this query in the Log Analytics query editor. For each query, replace userupn with the UPN of the user you want to look up.

let Events = WVDConnections | where UserName == "userupn" ;
Events
| where State == "Connected"
| project CorrelationId , UserName, ResourceAlias , StartTime=TimeGenerated, UdpUse, SessionHostName, SessionHostSxSStackVersion
| join (Events
| where State == "Completed"
| project EndTime=TimeGenerated, CorrelationId, UdpUse)
on CorrelationId
| project StartTime, Duration = EndTime - StartTime, ResourceAlias, UdpUse,  SessionHostName, SessionHostSxSStackVersion
| sort by StartTime asc

You can verify if RDP Shortpath is enabled for a specific user session by running the following Log Analytics query:

WVDCheckpoints 
|where Name contains "Shortpath"

Troubleshooting

Verifying STUN server connectivity and NAT type

If you're unable to establish connection using the RDP Shortpath transport, you use the following PowerShell script to validate connectivity to STUN servers

function Test-StunEndpoint 
{
  param
  (
    [Parameter(Mandatory)]
    $UdpClient,
    [Parameter(Mandatory)]
    $StunEndpoint
  )
  $ipendpoint = $null
  try 
  {
    $UdpClient.client.ReceiveTimeout = 5000 
    $listenport = $UdpClient.client.localendpoint.port
    $endpoint = New-Object -TypeName System.Net.IPEndPoint -ArgumentList ([IPAddress]::Any, $listenport)

  
    [Byte[]] $payload = 
    0x00, 0x01, # Message Type: 0x0001 (Binding Request)
    0x00, 0x00, # Message Length: 0 bytes excluding header
    0x21, 0x12, 0xa4, 0x42 # Magic Cookie: Always 0x2112A442

    $LocalTransactionId = ([guid]::NewGuid()).ToByteArray()[1..12]
    $payload = $payload + $LocalTransactionId
    try 
    {
      $null = $UdpClient.Send($payload, $payload.length, $StunEndpoint)
    }
    catch 
    {
      throw "Unable to send data, check if $($StunEndpoint.AddressFamily) is configured"
    }
  
  
    try 
    {
      $content = $UdpClient.Receive([ref]$endpoint)
    }
    catch 
    {
      try 
      {
        $null = $UdpClient.Send($payload, $payload.length, $StunEndpoint)
        $content = $UdpClient.Receive([ref]$endpoint)
      }
      catch 
      {
        try 
        {
          $null = $UdpClient.Send($payload, $payload.length, $StunEndpoint)
          $content = $UdpClient.Receive([ref]$endpoint)
        }
        catch 
        {
          throw "Unable to receive data, check if firewall allows access to $($StunEndpoint.ToString())"
        }
      }
    }
    
    
    if (-not $content) 
    {
      throw  'Null response.'
    }
  
    [Byte[]]$messageType = $content[0..1]
    [Byte[]]$messageCookie = $content[4..7]
    [Byte[]]$TransactionId = $content[8..19]
    [Byte[]]$AttributeType = $content[20..21]
    [Byte[]]$AttributeLength = $content[22..23]

    if ([System.BitConverter]::IsLittleEndian) 
    {
      [Array]::Reverse($AttributeLength)
    }

    if ( -not ([BitConverter]::ToString($messageType)) -eq '01-01') 
    {
      throw  "Invalid message type: $([BitConverter]::ToString($messageType))"
    }
    if ( -not ([BitConverter]::ToString($messageCookie)) -eq '21-12-A4-42') 
    {
      throw  "Invalid message cookie: $([BitConverter]::ToString($messageCookie))"
    }
  
    if (-not  ([BitConverter]::ToString($TransactionId)) -eq [BitConverter]::ToString($LocalTransactionId) ) 
    {
      throw  "Invalid message id: $([BitConverter]::ToString($TransactionId))"
    }
    if (-not  ([BitConverter]::ToString($AttributeType)) -eq '00-20' ) 
    {
      throw  "Invalid Attribute Type: $([BitConverter]::ToString($AttributeType))"
    }
    $ProtocolByte = $content[25]
    if (-not (($ProtocolByte -eq 1) -or ($ProtocolByte -eq 2))) 
    {
      throw "Invalid Address Type: $([BitConverter]::ToString($ProtocolByte))"
    }
    $portArray = $content[26..27]
    if ([System.BitConverter]::IsLittleEndian) 
    {
      [Array]::Reverse($portArray)
    }

    $port = [Bitconverter]::ToUInt16($portArray, 0) -bxor 0x2112
          
    if ($ProtocolByte -eq 1) 
    {
      $IPbytes = $content[28..31]
      if ([System.BitConverter]::IsLittleEndian) 
      {
        [Array]::Reverse($IPbytes)
      }
      $IPByte = [System.BitConverter]::GetBytes(([Bitconverter]::ToUInt32($IPbytes, 0) -bxor 0x2112a442))
        
      if ([System.BitConverter]::IsLittleEndian) 
      {
        [Array]::Reverse($IPByte)
      }
      $IP = [ipaddress]::new($IPByte)
    }
    elseif ($ProtocolByte -eq 2) 
    {
      $IPbytes = $content[28..44]
      [Byte[]]$magic = $content[4..19]
      for ($i = 0; $i -lt $IPbytes.Count; $i ++) 
      {
        $IPbytes[$i] = $IPbytes[$i] -bxor $magic[$i]
      }
      $IP = [ipaddress]::new($IPbytes)
    }
    $ipendpoint = [IPEndpoint]::new($IP, $port)
  }
  catch 
  {
    Write-Host -Object "Failed to communicate $($StunEndpoint.ToString()) with error: $_" -ForegroundColor Red
  }
  return $ipendpoint
}


$UdpClient6 = [Net.Sockets.UdpClient]::new([Net.Sockets.AddressFamily]::InterNetworkV6)
$UdpClient = [Net.Sockets.UdpClient]::new([Net.Sockets.AddressFamily]::InterNetwork)

  
$ipendpoint1 = Test-StunEndpoint -UdpClient $UdpClient -StunEndpoint ([IPEndpoint]::new(([Net.Dns]::GetHostAddresses('worldaz.turn.teams.microsoft.com')|Where-Object -FilterScript {$_.AddressFamily -EQ 'InterNetwork'})[0].Address, 3478))
$ipendpoint2 = Test-StunEndpoint -UdpClient $UdpClient -StunEndpoint ([IPEndpoint]::new([ipaddress]::Parse('13.107.17.41'), 3478))
$ipendpoint3 = Test-StunEndpoint -UdpClient $UdpClient6 -StunEndpoint ([IPEndpoint]::new([ipaddress]::Parse('2a01:111:202f::155'), 3478))


$localendpoint1 = $UdpClient.Client.LocalEndPoint
$localEndpoint2 = $UdpClient6.Client.LocalEndPoint


if ($null -ne $ipendpoint1) 
{
  if ($ipendpoint1.Port -eq $localendpoint1.Port) 
  {
    Write-Host  -Object 'Local NAT uses port preservation' -ForegroundColor Green
  }
  else 
  {
    Write-Host  -Object 'Local NAT does not use port preservation, custom port range may not work with Shortpath' -ForegroundColor Red
  }
  if ($null -eq $ipendpoint2) 
  {
    if ($ipendpoint1.Equals($ipendpoint2)) 
    {
      Write-Host -Object 'Local NAT reuses SNAT ports'  -ForegroundColor Green
    }
    else 
    {
      Write-Host -Object 'Local NAT does not reuse SNAT ports, preventing Shortpath from connecting this endpoint'  -ForegroundColor Red
    }
  }
}
Write-Output -InputObject "`nLocal endpoints:`n$localendpoint1`n$localEndpoint2"
Write-Output -InputObject "`nDiscovered external endpoints:`n$ipendpoint1`n$ipendpoint2`n$ipendpoint3`n"


$UdpClient.Close()
$UdpClient6.Close()


Pause

References

  • RFC 8839 - Session Description Protocol (SDP) Offer/Answer Procedures for Interactive Connectivity Establishment (ICE)
  • RFC 8489 - Session Traversal Utilities for NAT (STUN)
  • RFC 2663 - IP Network Address Translator (NAT) Terminology and Considerations

Next steps