SSH WAN Optimization

Note: SSH WAN Optimization is currently not available in any releases of WANProxy, but is available for pre-release use from the Subversion repository.

Individual Unix users, small businesses and large enterprises rely on SSH for its security as well as its convenience. Much as the rsh(1) and rcp(1) tools were in decades past, ssh(1) and scp(1) are today. Most of us who work as engineers or systems administration rely on them daily.

Because of this, WANProxy now includes support for doing WAN optimization, namely deduplication and compression, of SSH traffic. Obviously SSH includes support for zlib compression, so for single transfers WANProxy is unlikely to offer much benefit. Deduplication is a very different story.

Some SSH implementations come with support for disabling encryption out of the box, which obviously would enable WANProxy to deduplicate and compress traffic as it can for any other TCP connection, but this is not available to most users. And besides, do you really want to lose all of the security properties of SSH to be able to deduplicate traffic?

In order to make it possible to deduplicate SSH sessions, including file transfer with scp(1), WANProxy provides a unique SSH proxy mode. In this mode, a local instance of WANProxy receives an incoming connection from ssh(1) or ssh(1). It negotiates the connection with the client as any other server would, and then connects to a remote instance of WANProxy.

The connection between the two WANProxy instances can use the XCodec and zlib compression like any other WANProxy configuration, but the connection is not simply a decrypted version of the SSH stream. The WANProxy instances also negotiate an SSH connection between each other.

The remote instance then creates an SSH connection to the original destination server, and things proceed as normal.

The implementation is brand new, and certainly is incomplete and contains some bugs. But the initial framework is there, and is suitable for some testing. It's a compelling feature: how many people and organizations rely on scp(1) for offsite backups or to transfer files between offices?

The gains are similar to using WANProxy with a vanilla TCP connection. Let's work an example.

Copying files between branches

I have a system I use for hosting that's hundreds of miles away. I sometimes need to move files between it and my home office. The link between us isn't the most direct or high-bandwidth. As a result, here's what a normal file transfer from the remote site to home looks like. For reference, I'm copying the FreeBSD 8.3-RELEASE amd64 livefs CD image with scp.

Plain SCP

   % scp .
   FreeBSD-8.3-RELEASE-amd64-livefs.iso          100%  340MB   1.4MB/s   03:59

All things considered, that's not bad. But it could be better. And when I have to copy files that are similarly-large multiple times in a day, it gets frustrating quickly. It's going to take just as long each and every time. Let's see how it looks with WANProxy.

WANProxy + SCP, first download

   % scp -P 2200 test@localhost:FreeBSD-8.3-RELEASE-amd64-livefs.iso .
   test@localhost's password:
   FreeBSD-8.3-RELEASE-amd64-livefs.iso          100%  340MB   3.7MB/s   01:31

That's the first download, so we're getting minimal-to-no benefit from deduplication, and the compression settings are doing most of the work. If SSH compression is used instead of WANProxy in this case, the results are very similar, with slightly-better performance with SSH compression, likely due to the lower overhead involved in that case. (On the order of 5% better, in tests.)

There's a couple of things to note about this transcript that give some useful information about how WANProxy works as an SSH proxy. Firstly, we are connecting to port 2200 on localhost, where WANProxy is listening, and it is connecting to the remote system for us. In this case, WANProxy on the remote system is listening on port 2201, and is connecting us to the server on localhost port 22.

Second, and importantly, note that we're having to use password authentication. This is because SSH's public key authentication (which was used on the first transfer) doesn't work with a proxy between the client and the server for security reasons. It may be possible to work around this limitation by using ssh-agent to pass authentication requests to the client, but hopefully SSH won't allow us to do that. (Otherwise, it would have a pretty glaring security vulnerability.) More likely, WANProxy will eventually need to be able to be configured with the client's private key and authenticate itself to the server that way.

WANProxy + SCP, second download

   % scp -P 2200 test@localhost:FreeBSD-8.3-RELEASE-amd64-livefs.iso .
   test@localhost's password:
   FreeBSD-8.3-RELEASE-amd64-livefs.iso          100%  340MB  21.3MB/s   00:16

That's much better. Subsequent transfers give the same results. A factor of 15 improvement over plain scp. The result speaks for itself.


WANProxy shows that using WAN optimization techniques with SSH is possible today, and that the improvements are excellent. And this is with minimal support for the SSH protocol. Many SSH workloads, too, are interactive. In those cases, it may be that round-trips can be avoided with advanced protocol-aware optimizations, to make interactive SSH performance more tolerable on high-latency links.


At present, the SSH support really is simple, even simplistic. Some of the code was written to a less exacting standard than the rest of WANProxy in order to provide a proof-of-concept sooner rather than later. It is expected that the code will be improved and made production-ready in the near future.

Because WANProxy is providing SSH support for WAN optimization here, there are some interesting design trade-offs that pose interesting security questions. For instance, SSH uses randomized padding to frustrate traffic analysis and certain kinds of cryptographic attacks. With WANProxy, this doesn't make as much sense. First, traffic is already slightly less predictable due to the use of deduplication. Secondly, the goal is to reduce the size of the packets transmitted, so adding random padding would seem to be wasteful. Instead, WANProxy uses the minimal amount of padding required by the SSH standard in order to meet the block size requirements of the block cipher. Further research is needed to determine whether this is the right trade-off to make.

Which brings us to the final point: this is all new and in a state of flux. Some of the code has been around for two or three years in one form or another, and some has just been written in the last few hours at the time of writing. Shortcomings that exist today may be gone tomorrow, but it's useful to set expectations conservatively here and now, until WANProxy's SSH support is more like production-ready and its use can be encouraged with confidence.

Note that is used as a fictitious host name for the remote system, and test is used as a fictitious user name for the remote user. The output is taken verbatim from actual sessions and has not been manipulated in any other way. Significantly, bandwidth, file size and transfer time statistics are exactly as reported by the original programs.


These are the configuration files that were used on the client and on the server. Note that both instances will require an RSA private key to be placed in the directory where WANProxy is run in a file named "ssh-server1.pem". This will be used for the proxy server that WANProxy provides.

This is the configuration file on the client:

   create codec codec0
   set codec0.codec XCodec
   set codec0.compressor zlib
   set codec0.compressor_level 6
   activate codec0

   create interface if0
   set IP
   set "localhost"
   set if0.port "2200"
   activate if0

   create peer peer0
   set IP
   set ""
   set peer0.port "2201"
   activate peer0

   create proxy proxy0
   set proxy0.type SSH-SSH
   set proxy0.interface if0
   set proxy0.interface_codec None
   set proxy0.peer peer0
   set proxy0.peer_codec codec0
   activate proxy0

This is the configuration file on the server:

   create codec codec1
   set codec1.codec XCodec
   set codec1.compressor zlib
   set codec1.compressor_level 6
   activate codec1

   create interface if1
   set IP
   set ""
   set if1.port "2201"
   activate if1

   create peer peer1
   set IP
   set "localhost"
   set peer1.port "22"
   activate peer1

   create proxy proxy1
   set proxy1.type SSH-SSH
   set proxy1.interface if1
   set proxy1.interface_codec codec1
   set proxy1.peer peer1
   set proxy1.peer_codec None
   activate proxy1

Copyright © 2008-2015