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.

Context
Before jumping to the solution let's take a look on RDP Connection Sequence (https://msdn.microsoft.com/en-us/library/cc240452.aspx?f=255&MSPPError=-2147217396).
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.

Implementation
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: https://github.com/vunvulear/Stuff/tree/master/Azure/relay-hybrid-connections-rdp-initial

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)
      myLocalHost.write(event.data);
    };
    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.
net.createServer(function(localsocket)
{
  myLocalHost = localsocket;
  myLocalHost.on('data', function(d) {
    relaysocket.send(d);
    myLocalHost.on('error', function(err) {console.log("Socket close: " + err.stack)});
  });
}).listen(localport);

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) {
                        relayclient.send(data);
                    });
                    localsocket.on('error', function(err) {console.log("Socket close: " + err.stack)});
                }
                localsocket.write(event.data);
            };            
        }
    ); 

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.

Conclusion
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.

Comments

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

    ReplyDelete
  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

    ReplyDelete

Post a Comment

Popular posts from this blog

Windows Docker Containers can make WIN32 API calls, use COM and ASP.NET WebForms

After the last post , I received two interesting questions related to Docker and Windows. People were interested if we do Win32 API calls from a Docker container and if there is support for COM. WIN32 Support To test calls to WIN32 API, let’s try to populate SYSTEM_INFO class. [StructLayout(LayoutKind.Sequential)] public struct SYSTEM_INFO { public uint dwOemId; public uint dwPageSize; public uint lpMinimumApplicationAddress; public uint lpMaximumApplicationAddress; public uint dwActiveProcessorMask; public uint dwNumberOfProcessors; public uint dwProcessorType; public uint dwAllocationGranularity; public uint dwProcessorLevel; public uint dwProcessorRevision; } ... [DllImport("kernel32")] static extern void GetSystemInfo(ref SYSTEM_INFO pSI); ... SYSTEM_INFO pSI = new SYSTEM_INFO(...

How to audit an Azure Cosmos DB

In this post, we will talk about how we can audit an Azure Cosmos DB database. Before jumping into the problem let us define the business requirement: As an Administrator I want to be able to audit all changes that were done to specific collection inside my Azure Cosmos DB. The requirement is simple, but can be a little tricky to implement fully. First of all when you are using Azure Cosmos DB or any other storage solution there are 99% odds that you’ll have more than one system that writes data to it. This means that you have or not have control on the systems that are doing any create/update/delete operations. Solution 1: Diagnostic Logs Cosmos DB allows us activate diagnostics logs and stream the output a storage account for achieving to other systems like Event Hub or Log Analytics. This would allow us to have information related to who, when, what, response code and how the access operation to our Cosmos DB was done. Beside this there is a field that specifies what was th...

Cloud Myths: Cloud is Cheaper (Pill 1 of 5 / Cloud Pills)

Cloud Myths: Cloud is Cheaper (Pill 1 of 5 / Cloud Pills) The idea that moving to the cloud reduces the costs is a common misconception. The cloud infrastructure provides flexibility, scalability, and better CAPEX, but it does not guarantee lower costs without proper optimisation and management of the cloud services and infrastructure. Idle and unused resources, overprovisioning, oversize databases, and unnecessary data transfer can increase running costs. The regional pricing mode, multi-cloud complexity, and cost variety add extra complexity to the cost function. Cloud adoption without a cost governance strategy can result in unexpected expenses. Improper usage, combined with a pay-as-you-go model, can result in a nightmare for business stakeholders who cannot track and manage the monthly costs. Cloud-native services such as AI services, managed databases, and analytics platforms are powerful, provide out-of-the-shelve capabilities, and increase business agility and innovation. H...