Skip to content

SSH/HTTPS multiplexer

Hm, this nmap scan looked funny:
PORT    STATE SERVICE VERSION
22/tcp  open  ssh     OpenSSH 5.2 (protocol 2.0)
80/tcp  open  http    Gatling httpd 0.13
443/tcp open  ssh     OpenSSH 5.2 (protocol 2.0)
SSH listening on :443, yet the site was serving a website there? Looking around a bit I came across a few SSH/HTTP/HTTPS multiplexers. There are even binary packages out there for a few distributions, nice! So, how is it done?

ssh-https


When using ssh-https.c, the ports are hardcoded:
$ grep execl ssh-https.c
                execl("/bin/nc", "/bin/nc", "localhost", "8443", NULL);
                execl("/bin/nc", "/bin/nc", "localhost", "22", NULL);

$ gcc -o ssh-https ssh-https.c
$ mv ssh-https /usr/local/sbin/
SSH will continue to listen on :22, the webserver will have to listen on :8443 and ssh-https will listen on :443:
$ grep ssh-https /etc/inetd.conf
https   stream  tcp  nowait  nobody  /usr/sbin/tcpd /usr/local/sbin/ssh-https

sslh


sslh is a bit more flexible, as ports can be passed on the command line:
$ grep sslh /etc/inetd.conf
https   stream  tcp  nowait  sslh  /usr/sbin/tcpd /usr/sbin/sslh \
       --listen 10.0.0.23:443 --inetd --ssh localhost:22 --ssl localhost:8443
In any case, we should now have 3 listening ports:
$ netstat -anptu | grep LISTEN
[...]
tcp    0      0 0.0.0.0:22      0.0.0.0:\*   LISTEN    2211/dropbear
tcp    0      0 0.0.0.0:443     0.0.0.0:\*   LISTEN    6510/inetd
tcp    0      0 0.0.0.0:8443    0.0.0.0:\*   LISTEN    6012/lighttpd
And it's even working :-)
$ ssh-keyscan -p 443 10.0.0.23
# foo SSH-2.0-dropbear_2012.55

$ wget -qO- https://10.0.0.23/
Hello, world :-)

MacOS X disk I/O

While we're at it, some more "benchmarks". On a MacBook Pro with a Crucial m4 SSD inside:
$ dd if=/dev/rdisk0 bs=1024k count=2048 2>/dev/null | pv > /dev/null
   2GiB 0:00:09 [ 215MiB/s]
Oddly enough, the blockdevice of the same disk had much worse performance:
$ ls -lgo /dev/{r,}disk0
brw-r-----  1    14,   0 Dec 14 08:13 /dev/disk0
crw-r-----  1    14,   0 Dec 14 08:13 /dev/rdisk0

$ dd if=/dev/disk0 bs=1024k count=2048 2>/dev/null | pv > /dev/null
   2GiB 0:01:06 [30.8MiB/s]
On the same machine, Debian/wheezy was running in a VirtualBox virtual machine, we're still getting half the performance:
vm$ dd if=/dev/sda bs=1024k count=2048 2>/dev/null | pv > /dev/null
   2GB 0:00:18 [ 109MB/s]
And inside this virtual machine, another Debian/wheezy installation was running as a Xen DomU virtual machine, performance halves again:
vm|domU$ dd if=/dev/xvda1 bs=1024k count=2048 2>/dev/null | pv > /dev/null
   2GB 0:00:29 [69.4MB/s]

dm-crypt benchmarks

While setting up encrypted swap on yet another Linux machine, I wondered what the "best" crypto algorithm would be.

There are plenty of combinations of ciphers, modes, hash algorithms and keysizes to chose from with cryptsetup(8), let's see if we can find a fast, yet sufficiently "secure" one.

Before testing these combinations I wanted to find out which combinations were actually possible. E.g. setting up a dm-crypt device with aes-cbc-plain with a keysize of 128 or 256 bit would be possible - but any larger keysize was rejected. There were many "invalid" combinations, for reasons rooted deeply in their mathematical properties. So, let's find out these valid combinations then:
[...]
cryptsetup -c $CIPHER -s $KEYSIZE -d /dev/urandom create test /dev/sdc 2>/dev/null
if [ $? = 0 ]; then
      echo "Valid combination: cipher $CIPHER size $KEYSIZE"
else
      echo "Invalid combination: cipher $CIPHER - size $KEYSIZE"
fi
After quite some iterations over a predefined set of combinations (12 ciphers, 7 modes, 14 hashing algorithms, 5 keysizes), there were 1125 valid combinations left. Yeah, testing took a while :-)

Now we wanted to see which combinations performed "best". As stated above, the usecase was a blockdevice for encrypted swap - so "fast, yet pretty secure" were the criteria to look for. As a (very) simple test, the following should be done for each newly set up crypto block device:
while [ $i -lt 30 ]; do
      # Empty all caches, including filesystem buffers  
      sysctl -qw vm.drop_caches=3
      dd if=/dev/mapper/test of=/dev/null bs=1M 2>/dev/null
      i=$((i+1))
done

The results, summarized:
  • cipher_null* is the fastest - but it's absolutely insecure, because...well, it's a NULL cipher :-)
  • Interestingly, PCBC mode is sometimes very slow. As per the Wikipedia article, this mode is not very common anyway, so we'll not choose this one.
  • As expected, Twofish is very fast, along with AES and Blowfish.
Ruling out some of the obvious combinations and omitting some of the "exotic" algorithms, these are my winners:
$ egrep -v 'cipher_null|-(ecb|lrw|pcbc)-|-plain|md[45]|rmd|tgr|crc32|sha1' results | \
    grep ' / 256' | sort -nk5  | head -10
twofish-ctr-essiv:sha256 / 256 : 66            <== 66 seconds for 30 runs. Lower is better.
twofish-cbc-essiv:sha256 / 256 : 69
twofish-xts-essiv:sha256 / 256 : 73
aes-xts-essiv:sha256 / 256 : 79
blowfish-cbc-essiv:sha256 / 256 : 81
blowfish-ctr-essiv:sha256 / 256 : 86
aes-ctr-essiv:sha256 / 256 : 90
aes-cbc-essiv:sha256 / 256 : 91
camellia-xts-essiv:sha256 / 256 : 103
serpent-ctr-essiv:sha256 / 256 : 103

Now my /etc/crypttab proably looks like this:
swap /dev/sda2 /dev/urandom swap,cipher=twofish-xts-essiv:sha256,size=256,hash=sha512
Word of caution: this is a benchmark - some arbitrary test for a very special usecase, executed on one machine and one machine only (Fedora 18 in an ESX virtual machine, equipped with 2 AMD Opteron 848 processors). Before applying these results to your environment, run the benchmark yourself or, better yet: write your own benchmark for your usecase!