Availability Anywhere Part 10 — Slightly better poor man’s channel bonding for RDP

This is the tenth part of the Availability Anywhere series. For your convenience you can find other parts in the table of contents in Part 1 – Connecting to SSH tunnel automatically in Windows

We already examined how to do channel bonding in Windows for RDP usage. Today we are going to use something slightly better.

This time we’re actually going to do an actual channel bonding. The idea is: we’ll implement an application for sending a package over multiple network routes (so do actual link aggregation with broadcast) and use it to set up an SSH tunnel. So the actual networking will look like this:

We have 3 machines here:

  • Road runner RR
  • vps.com VPS
  • rdpserver TARGET

RR wants to connect to TARGET over RDP. We also have an additional server VPS for hosting our channel bonding code.

We want to connect RDP using our custom channel bonding. So we set up a bonding client listening on port 50000 and connecting to VPS port 60000 using two networks: one identified by 192.168.0.10 and the other by 192.168.1.10. Bonding client needs to take care of broadcasting packets, deduplicating them on the other side and refreshing the connection when one network goes down.

We have all pieces in place apart from the bonding client. Let’s take this quick and dirty solution: Github paste

Now, how do we do the link aggregation? We need to implement a simple protocol on top of TCP to deduplicate packages. The client waits for any incoming connection on the port 50000. Once it gets the connection, it randomizes some 32-bit stream identifier (line 74). It then opens connections to the server on the other side.

Once a new connection is opened to the server, we first send 4 bytes long identifier and wait for the same value being returned (line 471). This uniquely identifies the stream. Next, we just take any data from the client and send it to the other side with deduplication logic. So we take bytes from the client, prepend them with two integers: one being the message number (just a counter), another being the content length (line 195). When reading on the other end, we first read these two integers and then get full data (line 415). We then remove duplicates (line 317).

That’s basically it. There is quite a lot of bookkeeping code around to handle exceptions, maintain state etc., but generally this does the trick. One day I may clean the code up and push to Github.

Obviously, this solution could be extended to other usages. For instances, we could connect over SSH instead of RDP, set up a SOCKS proxy and browse the internet this way. Or we could then route OpenVPN via the OpenSSH and have whole traffic bonded this way. Once we have the link aggregation we can do anything.