Skip to main content

Initial RDP connection on a remote machine over Relay Hybrid Connection and Web Sockets - Azure Relay

In one of my latest post I presented how we can establish a PuTTy connection between two different machines through Azure Relay Hybrid Connection using web sockets.
Today, we will take a look over a Node.JS sample that initiate the tunnel that can be used for an RDP connection between two machines over Azure Relay.

Before jumping to the solution let's take a look on RDP Connection Sequence (
As we can see in the connection sequence flow, there are multiple connections that are open during a RDP session. The initial session that is open between client and server is used for the initial handshake and credentials validation. Once the credential are validated, the current connection is closed and other socket connection are open automatically.
In the current sample, we will update the original one that was written for Telnet. The first 5 steps from the flow will be supported, until in the moment when the initial socket connection is close and a new one is open.
More information on what we should do after this steps are presented at the end of the post.

The implementation is straightforward and similar with the one that was used for PuTTy connection. There are only some small things that we need to take into account.
GitHub Source code:

Server.js needs to run on the machine that we want to access. In our code, we will need to open the socket and redirect all the content that is send through Azure Relay Hybrid Connection to the local socket.
function (socket) {
    relaysocket = socket;
    console.log('New connection from client');
    relaysocket.onmessage = function (event) {
      // Send data to local socket (local port)
    relaysocket.on('close', function () {
      console.log('Relay connectin was closed');

The second step needs to be done on our local socket, where is necessary to redirect the content from our local socket to our web socket.
  myLocalHost = localsocket;
  myLocalHost.on('data', function(d) {
    myLocalHost.on('error', function(err) {console.log("Socket close: " + err.stack)});

On the other machine, where we run client.js we will do a similar thing. Listen to web socket that is communication with Azure Relay Hybrid Connection and redirect content to local port and redirect all content from the local port to our web socket.
var relayclient = webrelay.relayedConnect(
        webrelay.createRelaySendUri(ns, path),
        webrelay.createRelayToken('http://'+ns, keyrule, key),
        function (socket) {
            // Create local socket to the given port                               
            console.log("Connected to relay")
            relayclient.onmessage = function (event) {
                if(typeof localsocket === "undefined")
                    localsocket = net.connect(sourceport,function(socket)  {
                            console.log("New socket");
                    localsocket.on('data', function(data) {
                    localsocket.on('error', function(err) {console.log("Socket close: " + err.stack)});

Next steps
What if we would like to extend the current solution to be able to do a full RDP connection over Azure Relay Hybrid Connection? There are two clear steps that need to be done.

1. Support multiple connection
We shall extend client.js and server.js to be able to send through the web sockets multiple socket connections. This would required that on one side to mark each package that we send over Azure Relay with a flag that would allow us to know on the other side on what socket we need to redirect the content.

2. Buffering
Even if the solution will work, it is pretty clear that we need a buffering mechanism that is able to stream uniformly all content that is send over Azure Relay. If we would have only one connection open, this would not be necessary. Having multiple open connection that goes over the same web socket, then it is required to have a buffering  mechanism.
Without it, the solution will work, but the connection will not be stable enough.

Yes, it is possible to tunnel a RDP connection over Azure Relay. We have all the functionality and tools available already. The support for multiple connection and buffering are two features that are necessary for any kind of remote connection that we will want to establish.
Once we will do this, we will be able to tunnel a VNC or a FTP connection without any problems.


  1. Works great! Thank you for the good work.

  2. am working on RDP(Remote Desktop Sharing) project in which the remote desktop and client are firewall protected , so one can not directly use VNC viewer and VNC connect directly as the devices doesn't have their public IP exposed , I came to know such kind of situation is handled using Service Relay (Azure) which act as a tunnel between the devices to allow remote sharing .It will be very thankful if somebody can help me in solving me this situation of Sevice relay,by providing some useful links of the projects ,or such concepts ,aur any site that had implemented this logic .Thanks in advance .I am using c/c++ for implementation


Post a Comment

Popular posts from this blog

ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded

Today blog post will be started with the following error when running DB tests on the CI machine:
threw exception: System.InvalidOperationException: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See for more information. at System.Data.Entity.Infrastructure.DependencyResolution.ProviderServicesFactory.GetInstance(String providerTypeName, String providerInvariantName) This error happened only on the Continuous Integration machine. On the devs machines, everything has fine. The classic problem – on my machine it’s working. The CI has the following configuration:

TeamCity.NET 4.51EF 6.0.2VS2013
It seems that there …

GET call of REST API that contains '/'-slash character in the value of a parameter

Let’s assume that we have the following scenario: I have a public HTTP endpoint and I need to post some content using GET command. One of the parameters contains special characters like “\” and “/”. If the endpoint is an ApiController than you may have problems if you encode the parameter using the http encoder.
using (var httpClient = new HttpClient()) { httpClient.BaseAddress = baseUrl; Task<HttpResponseMessage> response = httpClient.GetAsync(string.Format("api/foo/{0}", "qwert/qwerqwer"))); response.Wait(); response.Result.EnsureSuccessStatusCode(); } One possible solution would be to encode the query parameter using UrlTokenEncode method of HttpServerUtility class and GetBytes method ofUTF8. In this way you would get the array of bytes of the parameter and encode them as a url token.
The following code show to you how you could write the encode and decode methods.

Entity Framework (EF) TransactionScope vs Database.BeginTransaction

In today blog post we will talk a little about a new feature that is available on EF6+ related to Transactions.
Until now, when we had to use transaction we used ‘TransactionScope’. It works great and I would say that is something that is now in our blood.
using (var scope = new TransactionScope(TransactionScopeOption.Required)) { using (SqlConnection conn = new SqlConnection("...")) { conn.Open(); SqlCommand sqlCommand = new SqlCommand(); sqlCommand.Connection = conn; sqlCommand.CommandText = ... sqlCommand.ExecuteNonQuery(); ... } scope.Complete(); } Starting with EF6.0 we have a new way to work with transactions. The new approach is based on Database.BeginTransaction(), Database.Rollback(), Database.Commit(). Yes, no more TransactionScope.
In the followi…